Revision d3c56568f43807135f2c2a09582a69f809f0d8b7 authored by Takashi Iwai on 03 February 2014, 08:56:13 UTC, committed by Takashi Iwai on 05 February 2014, 06:17:49 UTC
We've seen often problems after suspend/resume on Acer Aspire One
AO725 with ALC271X codec as reported in kernel bugzilla, and it turned
out that some COEFs doesn't work and triggers the codec communication
stall.

Since these magic COEF setups are specific to ALC269VB for some PLL
configurations, the machine works even without these manual
adjustment.  So, let's simply avoid applying them for ALC271X.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=52181
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 4528eb1
Raw File
pdt.c
/* pdt.c: OF PROM device tree support code.
 *
 * Paul Mackerras	August 1996.
 * Copyright (C) 1996-2005 Paul Mackerras.
 *
 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
 *    {engebret|bergner}@us.ibm.com
 *
 *  Adapted for sparc by David S. Miller davem@davemloft.net
 *  Adapted for multiple architectures by Andres Salomon <dilinger@queued.net>
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_pdt.h>

static struct of_pdt_ops *of_pdt_prom_ops __initdata;

void __initdata (*of_pdt_build_more)(struct device_node *dp,
		struct device_node ***nextp);

#if defined(CONFIG_SPARC)
unsigned int of_pdt_unique_id __initdata;

#define of_pdt_incr_unique_id(p) do { \
	(p)->unique_id = of_pdt_unique_id++; \
} while (0)

static char * __init of_pdt_build_full_name(struct device_node *dp)
{
	int len, ourlen, plen;
	char *n;

	dp->path_component_name = build_path_component(dp);

	plen = strlen(dp->parent->full_name);
	ourlen = strlen(dp->path_component_name);
	len = ourlen + plen + 2;

	n = prom_early_alloc(len);
	strcpy(n, dp->parent->full_name);
	if (!of_node_is_root(dp->parent)) {
		strcpy(n + plen, "/");
		plen++;
	}
	strcpy(n + plen, dp->path_component_name);

	return n;
}

#else /* CONFIG_SPARC */

static inline void of_pdt_incr_unique_id(void *p) { }
static inline void irq_trans_init(struct device_node *dp) { }

static char * __init of_pdt_build_full_name(struct device_node *dp)
{
	static int failsafe_id = 0; /* for generating unique names on failure */
	char *buf;
	int len;

	if (of_pdt_prom_ops->pkg2path(dp->phandle, NULL, 0, &len))
		goto failsafe;

	buf = prom_early_alloc(len + 1);
	if (of_pdt_prom_ops->pkg2path(dp->phandle, buf, len, &len))
		goto failsafe;
	return buf;

 failsafe:
	buf = prom_early_alloc(strlen(dp->parent->full_name) +
			       strlen(dp->name) + 16);
	sprintf(buf, "%s/%s@unknown%i",
		of_node_is_root(dp->parent) ? "" : dp->parent->full_name,
		dp->name, failsafe_id++);
	pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf);
	return buf;
}

#endif /* !CONFIG_SPARC */

static struct property * __init of_pdt_build_one_prop(phandle node, char *prev,
					       char *special_name,
					       void *special_val,
					       int special_len)
{
	static struct property *tmp = NULL;
	struct property *p;
	int err;

	if (tmp) {
		p = tmp;
		memset(p, 0, sizeof(*p) + 32);
		tmp = NULL;
	} else {
		p = prom_early_alloc(sizeof(struct property) + 32);
		of_pdt_incr_unique_id(p);
	}

	p->name = (char *) (p + 1);
	if (special_name) {
		strcpy(p->name, special_name);
		p->length = special_len;
		p->value = prom_early_alloc(special_len);
		memcpy(p->value, special_val, special_len);
	} else {
		err = of_pdt_prom_ops->nextprop(node, prev, p->name);
		if (err) {
			tmp = p;
			return NULL;
		}
		p->length = of_pdt_prom_ops->getproplen(node, p->name);
		if (p->length <= 0) {
			p->length = 0;
		} else {
			int len;

			p->value = prom_early_alloc(p->length + 1);
			len = of_pdt_prom_ops->getproperty(node, p->name,
					p->value, p->length);
			if (len <= 0)
				p->length = 0;
			((unsigned char *)p->value)[p->length] = '\0';
		}
	}
	return p;
}

static struct property * __init of_pdt_build_prop_list(phandle node)
{
	struct property *head, *tail;

	head = tail = of_pdt_build_one_prop(node, NULL,
				     ".node", &node, sizeof(node));

	tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
	tail = tail->next;
	while(tail) {
		tail->next = of_pdt_build_one_prop(node, tail->name,
					    NULL, NULL, 0);
		tail = tail->next;
	}

	return head;
}

static char * __init of_pdt_get_one_property(phandle node, const char *name)
{
	char *buf = "<NULL>";
	int len;

	len = of_pdt_prom_ops->getproplen(node, name);
	if (len > 0) {
		buf = prom_early_alloc(len);
		len = of_pdt_prom_ops->getproperty(node, name, buf, len);
	}

	return buf;
}

static struct device_node * __init of_pdt_create_node(phandle node,
						    struct device_node *parent)
{
	struct device_node *dp;

	if (!node)
		return NULL;

	dp = prom_early_alloc(sizeof(*dp));
	of_pdt_incr_unique_id(dp);
	dp->parent = parent;

	kref_init(&dp->kref);

	dp->name = of_pdt_get_one_property(node, "name");
	dp->type = of_pdt_get_one_property(node, "device_type");
	dp->phandle = node;

	dp->properties = of_pdt_build_prop_list(node);

	irq_trans_init(dp);

	return dp;
}

static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
						   phandle node,
						   struct device_node ***nextp)
{
	struct device_node *ret = NULL, *prev_sibling = NULL;
	struct device_node *dp;

	while (1) {
		dp = of_pdt_create_node(node, parent);
		if (!dp)
			break;

		if (prev_sibling)
			prev_sibling->sibling = dp;

		if (!ret)
			ret = dp;
		prev_sibling = dp;

		*(*nextp) = dp;
		*nextp = &dp->allnext;

		dp->full_name = of_pdt_build_full_name(dp);

		dp->child = of_pdt_build_tree(dp,
				of_pdt_prom_ops->getchild(node), nextp);

		if (of_pdt_build_more)
			of_pdt_build_more(dp, nextp);

		node = of_pdt_prom_ops->getsibling(node);
	}

	return ret;
}

static void * __init kernel_tree_alloc(u64 size, u64 align)
{
	return prom_early_alloc(size);
}

void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
{
	struct device_node **nextp;

	BUG_ON(!ops);
	of_pdt_prom_ops = ops;

	of_allnodes = of_pdt_create_node(root_node, NULL);
#if defined(CONFIG_SPARC)
	of_allnodes->path_component_name = "";
#endif
	of_allnodes->full_name = "/";

	nextp = &of_allnodes->allnext;
	of_allnodes->child = of_pdt_build_tree(of_allnodes,
			of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp);

	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
	of_alias_scan(kernel_tree_alloc);
}
back to top