On 09/06/2013 12:05 AM, amit daniel kachhap wrote:
On Fri, Aug 30, 2013 at 4:16 AM, al.stone@linaro.org wrote:
From: Al Stone ahs3@redhat.com
This code allows the Samsung pinctrl driver to use either FDT or ACPI in defining pin controllers (i.e., collections of GPIO controllers, in this case). On probe, the driver first attempts to configure a driver using FDT; failing that, using ACPI is attempted. The size of the patch is due to essentially having to duplicate the FDT paths for ACPI, since the FDT code made assumptions about data structures that are not necessarily available with ACPI.
Signed-off-by: Al Stone al.stone@linaro.org
drivers/pinctrl/pinctrl-samsung.c | 507 +++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 2 files changed, 503 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a7fa9e2..e135007 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -29,6 +29,7 @@ #include <linux/irqdomain.h> #include <linux/spinlock.h> #include <linux/syscore_ops.h> +#include <linux/acpi.h> [snip...snip...]
+/* Handle pin group info when a device is found */ +static acpi_status samsung_acpi_read_group(acpi_handle handle, u32 level,
void *data, void **return_value)
+{
acpi_status status;
struct samsung_pinctrl_drv_data *drvdata = data;
struct pinctrl_desc *pcdesc = &drvdata->pctl;
struct device *dev = drvdata->dev;
struct samsung_pin_group *grp;
struct samsung_pmx_func *pmx;
u64 value;
unsigned int *pins;
unsigned int npins;
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer format;
struct acpi_buffer info = { ACPI_ALLOCATE_BUFFER, NULL };
int ii, len;
u8 func;
char **pp, *pname, *pname2;
const int BUFSIZ = 256;
char buffer[BUFSIZ];
struct acpi_buffer name_buffer = { BUFSIZ, &buffer };
/* see if there is an available pin group...there better be */
grp = (struct samsung_pin_group *)&drvdata->pin_groups[0];
for (ii = 0; ii < drvdata->nr_groups; ii++, grp++) {
if (grp->num_pins == 0)
break;
}
if (!grp || ii >= drvdata->nr_groups) {
dev_err(dev, "too many pin groups defined for %s\n",
(char *)name_buffer.pointer);
return AE_BAD_PARAMETER;
}
/* see if there is a pin list to get -- no method == not a pin group */
status = acpi_evaluate_object(handle, "PINS", NULL, &buf);
if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
return AE_OK; /* the device is irrelevant */
}
status = acpi_evaluate_integer(handle, "NPIN", NULL, &value);
if (ACPI_FAILURE(status)) {
/* but, we should have NPIN if we have the PINS method */
ACPI_FREE(buf.pointer);
return status;
}
npins = (unsigned int)value;
grp->num_pins = npins;
/* find the function number to use for this group */
status = acpi_evaluate_integer(handle, "FUNC", NULL, &value);
if (ACPI_FAILURE(status)) {
/* we must have a function number */
ACPI_FREE(buf.pointer);
return status;
}
func = (u8)value;
grp->func = func;
/* find the name to use for this group */
memset(buffer, 0, BUFSIZ);
status = acpi_get_name(handle, ACPI_SINGLE_NAME, &name_buffer);
if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
return status;
}
len = strlen(name_buffer.pointer);
pname = devm_kzalloc(dev, len + GSUFFIX_LEN + 1, GFP_KERNEL);
if (!pname) {
dev_err(dev, "cannot alloc group name space for %s\n",
(char *)name_buffer.pointer);
ACPI_FREE(buf.pointer);
status = AE_NO_MEMORY;
}
memcpy(pname, name_buffer.pointer, len);
memcpy(pname + len, GROUP_SUFFIX, GSUFFIX_LEN);
grp->name = pname;
/* allocate the space needed for the pin list for this group */
pins = devm_kzalloc(dev, npins * sizeof(*(pcdesc->pins)), GFP_KERNEL);
if (!pins) {
dev_err(dev, "cannot alloc group pin list space for %s\n",
(char *)name_buffer.pointer);
ACPI_FREE(buf.pointer);
devm_kfree(dev, pname);
return AE_NO_MEMORY;
}
/* extract the strings from the package provided by the PINS method */
format.pointer = kzalloc((npins * sizeof(char)) + 1, GFP_KERNEL);
if (!format.pointer) {
ACPI_FREE(buf.pointer);
devm_kfree(dev, pname);
return AE_NO_MEMORY;
}
format.length = npins + 1;
memset(format.pointer, 'S', npins);
status = acpi_extract_package(buf.pointer, &format, &info);
if (ACPI_FAILURE(status)) {
dev_err(dev, "cannot parse pin names for %s\n",
(char *)name_buffer.pointer);
ACPI_FREE(buf.pointer);
if (info.pointer)
ACPI_FREE(info.pointer);
devm_kfree(dev, pname);
kfree(format.pointer);
return status;
}
kfree(format.pointer);
/* set up the group pins */
pp = (char **)info.pointer;
for (ii = 0; ii < grp->num_pins; ii++, pp++)
pins[ii] = ii;
Here pins actually means the index of the big pinctrl list. Since pinctrl_desc is not populated at this moment so I think this function samsung_acpi_read_group should be called in the same place as samsung_pinctrl_parse_dt.
I'm not sure I understand the comment. The indices should be from a global set of numbers, versus numbers specific to this pin group?
Unfortunately, samsung_acpi_read_group is a callback function that is called by ACPI while walking the tree of devices, so I don't think it can be called in the same place as samsung_pinctrl_parse_dt without rearranging and obfuscating quite a bit of code -- hence its current location.