From: Al Stone ahs3@redhat.com
The first two versions of this patch set were in different submissions. The primary difference with this version is that I've combined and simplified the multiple sets into one comprehensive set, cleaned up the ordering of the patches, and made corrections based on feedback on v2.
The intent of this patch set is to enable the Arndale pinctrl devices under ACPI instead of FDT. The ACPI ASL has been submitted as a separate patch set. This patch set includes three of the four devices defined for Arndale. The final device defines GPIO interrupts which will be the subject of a later patch set (interrupts require a diversion into enabling GICs first).
NB: the first two patches are generic and can apply to all ACPI branches. The remainder are specific to Arndale and the acpi-ltfixes branch.
Al Stone (8): ACPI: make an error message a little cleaner ACPI: improve acpi_extract_package() utility ACPI: ARM: arndale: enable ACPI in the Samsung pinctrl driver ACPI: ARM: arndale: add CONFIG_ACPI ifdefs to pinctrl driver ACPI: ARM: arndale: move pin controller 4 of 4 from FDT to ACPI ACPI: ARM: arndale: move pin controller 3 of 4 from FDT to ACPI ACPI: ARM: arndale: move pin controller 2 of 4 from FDT to ACPI ACPI: ARM: arndale: whitelist the samsung-pinctrl driver for ACPI
arch/arm/boot/dts/exynos5250-arndale.dts | 26 ++ arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 2 + arch/arm/boot/dts/exynos5250.dtsi | 6 +- drivers/acpi/acpi_platform.c | 3 + drivers/acpi/osl.c | 2 +- drivers/acpi/utils.c | 17 +- drivers/pinctrl/pinctrl-samsung.c | 513 +++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 8 files changed, 559 insertions(+), 13 deletions(-)
From: Al Stone ahs3@redhat.com
Signed-off-by: Al Stone al.stone@linaro.org --- drivers/acpi/osl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index ebe34b3..b292a8e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -266,7 +266,7 @@ void acpi_find_arm_root_pointer(acpi_physical_address *pa) struct acpi_table_rsdp *rp;
if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) { - pr_err("failed to find rsdp info\n"); + pr_err("ACPI failed to find rsdp info\n"); *pa = (acpi_physical_address)NULL; return; }
From: Al Stone ahs3@redhat.com
The current version requires one to know the size of the package a priori; this is almost impossible if the package is composed of strings of variable length. This change allows the utility to allocate a buffer of the proper size if asked.
Signed-off-by: Al Stone al.stone@linaro.org --- drivers/acpi/utils.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 74437130..bcb78f1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -169,11 +169,20 @@ acpi_extract_package(union acpi_object *package, /* * Validate output buffer. */ - if (buffer->length < size_required) { + if (buffer->length == ACPI_ALLOCATE_BUFFER) { + buffer->pointer = ACPI_ALLOCATE(size_required); + if (!buffer->pointer) + return AE_NO_MEMORY; buffer->length = size_required; - return AE_BUFFER_OVERFLOW; - } else if (buffer->length != size_required || !buffer->pointer) { - return AE_BAD_PARAMETER; + memset(buffer->pointer, 0, size_required); + } else { + if (buffer->length < size_required) { + buffer->length = size_required; + return AE_BUFFER_OVERFLOW; + } else if (buffer->length != size_required || + !buffer->pointer) { + return AE_BAD_PARAMETER; + } }
head = buffer->pointer;
On Fri, Sep 06, 2013 at 10:59:30AM -0600, al.stone@linaro.org wrote:
From: Al Stone ahs3@redhat.com
The current version requires one to know the size of the package a priori; this is almost impossible if the package is composed of strings of variable length. This change allows the utility to allocate a buffer of the proper size if asked.
Signed-off-by: Al Stone al.stone@linaro.org
drivers/acpi/utils.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 74437130..bcb78f1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -169,11 +169,20 @@ acpi_extract_package(union acpi_object *package, /* * Validate output buffer. */
- if (buffer->length < size_required) {
- if (buffer->length == ACPI_ALLOCATE_BUFFER) {
buffer->pointer = ACPI_ALLOCATE(size_required);
This worries me as its an API change, who is responsible for freeing this memory?
if (!buffer->pointer)
buffer->length = size_required;return AE_NO_MEMORY;
return AE_BUFFER_OVERFLOW;
- } else if (buffer->length != size_required || !buffer->pointer) {
return AE_BAD_PARAMETER;
memset(buffer->pointer, 0, size_required);
- } else {
if (buffer->length < size_required) {
buffer->length = size_required;
return AE_BUFFER_OVERFLOW;
} else if (buffer->length != size_required ||
!buffer->pointer) {
return AE_BAD_PARAMETER;
}}
head = buffer->pointer; -- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On 09/11/2013 03:33 AM, Graeme Gregory wrote:
On Fri, Sep 06, 2013 at 10:59:30AM -0600, al.stone@linaro.org wrote:
From: Al Stone ahs3@redhat.com
The current version requires one to know the size of the package a priori; this is almost impossible if the package is composed of strings of variable length. This change allows the utility to allocate a buffer of the proper size if asked.
Signed-off-by: Al Stone al.stone@linaro.org
drivers/acpi/utils.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 74437130..bcb78f1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -169,11 +169,20 @@ acpi_extract_package(union acpi_object *package, /* * Validate output buffer. */
- if (buffer->length < size_required) {
- if (buffer->length == ACPI_ALLOCATE_BUFFER) {
buffer->pointer = ACPI_ALLOCATE(size_required);
This worries me as its an API change, who is responsible for freeing this memory?
Understandably. Since this is new functionality, there should be no effect on existing code.
This is also the same behavior as the other acpi_extract_*() calls; i.e., the caller is responsible for the ACPI_FREE() invocation. I guess I see this as more of a completion of the API as a result.
if (!buffer->pointer)
buffer->length = size_required;return AE_NO_MEMORY;
return AE_BUFFER_OVERFLOW;
- } else if (buffer->length != size_required || !buffer->pointer) {
return AE_BAD_PARAMETER;
memset(buffer->pointer, 0, size_required);
} else {
if (buffer->length < size_required) {
buffer->length = size_required;
return AE_BUFFER_OVERFLOW;
} else if (buffer->length != size_required ||
!buffer->pointer) {
return AE_BAD_PARAMETER;
}
}
head = buffer->pointer;
-- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On Wed, Sep 11, 2013 at 10:10:19AM -0600, Al Stone wrote:
On 09/11/2013 03:33 AM, Graeme Gregory wrote:
On Fri, Sep 06, 2013 at 10:59:30AM -0600, al.stone@linaro.org wrote:
From: Al Stone ahs3@redhat.com
The current version requires one to know the size of the package a priori; this is almost impossible if the package is composed of strings of variable length. This change allows the utility to allocate a buffer of the proper size if asked.
Signed-off-by: Al Stone al.stone@linaro.org
drivers/acpi/utils.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 74437130..bcb78f1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -169,11 +169,20 @@ acpi_extract_package(union acpi_object *package, /* * Validate output buffer. */
- if (buffer->length < size_required) {
- if (buffer->length == ACPI_ALLOCATE_BUFFER) {
buffer->pointer = ACPI_ALLOCATE(size_required);
This worries me as its an API change, who is responsible for freeing this memory?
Understandably. Since this is new functionality, there should be no effect on existing code.
This is also the same behavior as the other acpi_extract_*() calls; i.e., the caller is responsible for the ACPI_FREE() invocation. I guess I see this as more of a completion of the API as a result.
Ok that sounds fine then!
G
if (!buffer->pointer)
buffer->length = size_required;return AE_NO_MEMORY;
return AE_BUFFER_OVERFLOW;
- } else if (buffer->length != size_required || !buffer->pointer) {
return AE_BAD_PARAMETER;
memset(buffer->pointer, 0, size_required);
} else {
if (buffer->length < size_required) {
buffer->length = size_required;
return AE_BUFFER_OVERFLOW;
} else if (buffer->length != size_required ||
!buffer->pointer) {
return AE_BAD_PARAMETER;
}
}
head = buffer->pointer;
-- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
-- ciao, al
Al Stone Software Engineer Linaro Enterprise Group al.stone@linaro.org
On Wed, Sep 11, 2013 at 10:10:19AM -0600, Al Stone wrote:
On 09/11/2013 03:33 AM, Graeme Gregory wrote:
On Fri, Sep 06, 2013 at 10:59:30AM -0600, al.stone@linaro.org wrote:
From: Al Stone ahs3@redhat.com
The current version requires one to know the size of the package a priori; this is almost impossible if the package is composed of strings of variable length. This change allows the utility to allocate a buffer of the proper size if asked.
Signed-off-by: Al Stone al.stone@linaro.org
drivers/acpi/utils.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 74437130..bcb78f1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -169,11 +169,20 @@ acpi_extract_package(union acpi_object *package, /* * Validate output buffer. */
- if (buffer->length < size_required) {
- if (buffer->length == ACPI_ALLOCATE_BUFFER) {
buffer->pointer = ACPI_ALLOCATE(size_required);
This worries me as its an API change, who is responsible for freeing this memory?
Understandably. Since this is new functionality, there should be no effect on existing code.
This is also the same behavior as the other acpi_extract_*() calls; i.e., the caller is responsible for the ACPI_FREE() invocation. I guess I see this as more of a completion of the API as a result.
In light of the decision at Plumbers to start using _DSM for misc data values has this been sent upstream?
Graeme
if (!buffer->pointer)
buffer->length = size_required;return AE_NO_MEMORY;
return AE_BUFFER_OVERFLOW;
- } else if (buffer->length != size_required || !buffer->pointer) {
return AE_BAD_PARAMETER;
memset(buffer->pointer, 0, size_required);
} else {
if (buffer->length < size_required) {
buffer->length = size_required;
return AE_BUFFER_OVERFLOW;
} else if (buffer->length != size_required ||
!buffer->pointer) {
return AE_BAD_PARAMETER;
}
}
head = buffer->pointer;
-- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
-- ciao, al
Al Stone Software Engineer Linaro Enterprise Group al.stone@linaro.org
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 | 503 +++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 2 files changed, 499 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a7fa9e2..422e632 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>
#include "core.h" #include "pinctrl-samsung.h" @@ -716,12 +717,477 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, return 0; }
+/* parse the acpi resources for this pinctrl bank */ +static acpi_status samsung_pinctrl_bank_resource(struct acpi_resource *resource, + void *context) +{ + struct samsung_pinctrl_drv_data *drvdata = context; + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct device *dev = drvdata->dev; + struct samsung_pin_bank *bank = ctrl->pin_banks; + + switch (resource->type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: { + struct acpi_resource_fixed_memory32 *p = + &resource->data.fixed_memory32; + bank->pctl_offset = p->address; + return AE_OK; + } + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + default: + dev_info(dev, "Resource %d is not an MMIO resources\n", + resource->type); + } + + return AE_CTRL_TERMINATE; +} + +/* Handle pin bank info when a device is found */ +static acpi_status samsung_acpi_read_banks(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + acpi_status status; + struct samsung_pinctrl_drv_data *drvdata = data; + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + char *tag; + u64 value; + int ii; + u32 cnt, len; + + /* + * See if there is a TAG. If so, we're still interested -- this + * is what tells us it is a pin bank + */ + status = acpi_evaluate_object(handle, "TAG", NULL, &buf); + if (ACPI_FAILURE(status)) { + ACPI_FREE(buf.pointer); + return AE_OK; /* the device is irrelevant */ + } + cnt = *(u32 *)buf.pointer; + len = *(u32 *)(buf.pointer + sizeof(u32)); + if (cnt != 2 || len < 1) { + /* + * The object is supposed to have 2 fields, and + * the string length is supposed to > zero + */ + ACPI_FREE(buf.pointer); + return AE_BAD_PARAMETER; + } + /* + * We know that the first 4 bytes is the number of fields, + * the second four bytes is the string length. The next 8 + * bytes are the address that points to the beginning of + * the string in the buffer -- which is always immediately + * after the 8 bytes, in this case. So, just set our + * pointer to the right value and be done with it. + */ + tag = (char *)devm_kzalloc(drvdata->dev, len + 1, GFP_KERNEL); + if (!tag) { + ACPI_FREE(buf.pointer); + return AE_NO_MEMORY; + } + memcpy(tag, (char *)(buf.pointer + 16), len); + + /* find first available pin bank for this controller */ + for (ii = 0; ii < ctrl->nr_banks; ii++, bank++) + if (bank->type == NULL) + break; + if (ii >= ctrl->nr_banks) { + ACPI_FREE(buf.pointer); + devm_kfree(drvdata->dev, tag); + return AE_BUFFER_OVERFLOW; + } + + /* initialize the bank */ + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + samsung_pinctrl_bank_resource, drvdata); + if (ACPI_FAILURE(status)) { + ACPI_FREE(buf.pointer); + devm_kfree(drvdata->dev, tag); + return status; + } + + bank->type = devm_kzalloc(drvdata->dev, + sizeof(*(bank->type)), + GFP_KERNEL); + if (!(bank->type)) { + ACPI_FREE(buf.pointer); + devm_kfree(drvdata->dev, tag); + return AE_NO_MEMORY; + } + + status = acpi_evaluate_integer(handle, "BASE", NULL, &value); + if (ACPI_FAILURE(status)) { + /* but, we should have BASE if we have the TAG */ + ACPI_FREE(buf.pointer); + devm_kfree(drvdata->dev, tag); + devm_kfree(drvdata->dev, bank->type); + return status; + } + bank->pin_base = (u32)value + ctrl->nr_pins; + + 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); + devm_kfree(drvdata->dev, tag); + devm_kfree(drvdata->dev, bank->type); + return status; + } + bank->nr_pins = (u32)value; + ctrl->nr_pins += bank->nr_pins; + bank->gpio_chip.base = pin_base; + pin_base += bank->nr_pins; + + bank->name = tag; + bank->acpi_node = &drvdata->dev->acpi_node; + bank->drvdata = drvdata; + spin_lock_init(&bank->slock); + + ACPI_FREE(buf.pointer); + return AE_OK; +} + +/* initialize the samsung_pin_ctrl portion of the device data */ +static int samsung_pin_ctrl_acpi_parse( + struct samsung_pinctrl_drv_data *drvdata, + struct platform_device *pdev) +{ + acpi_status status; + struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev); + struct samsung_pin_ctrl *ctrl = NULL; + struct device *dev = &pdev->dev; + int nbanks; + struct samsung_pin_bank *banks; + u64 value; + + drvdata->dev = dev; + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) { + dev_err(dev, "cannot allocate memory for samsung_pin_ctrl\n"); + return -ENOMEM; + } + drvdata->ctrl = ctrl; + + status = acpi_evaluate_integer(dev_handle, "BNKS", NULL, &value); + if (ACPI_FAILURE(status)) { + devm_kfree(dev, ctrl); + dev_err(dev, "cannot get BNKS value\n"); + return -EINVAL; + } + nbanks = (int)value; + + banks = devm_kzalloc(dev, nbanks * sizeof(*banks), GFP_KERNEL); + if (!banks) { + devm_kfree(dev, ctrl); + dev_err(dev, "cannot allocate memory for pin banks list\n"); + return -ENOMEM; + } + ctrl->pin_banks = banks; + ctrl->nr_banks = nbanks; + ctrl->base = pin_base; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1, + samsung_acpi_read_banks, NULL, + drvdata, NULL); + if (ACPI_FAILURE(status)) { + devm_kfree(dev, banks); + devm_kfree(dev, ctrl); + dev_err(dev, "failure walking controller for banks\n"); + return -EINVAL; + } + + return 0; +} + +/* 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); + ACPI_FREE(info.pointer); + devm_kfree(dev, pname); + kfree(format.pointer); + return status; + } + kfree(format.pointer); /* match the kzalloc() above (vs ACPI_FREE) */ + ACPI_FREE(buf.pointer); + ACPI_FREE(info.pointer); + + /* set up the group pins */ + pp = (char **)info.pointer; + for (ii = 0; ii < grp->num_pins; ii++, pp++) { + pins[ii] = ii; + } + grp->pins = pins; + + /* set up the functions */ + len = strlen((char *)name_buffer.pointer); + pname2 = devm_kzalloc(dev, len + FSUFFIX_LEN + 1, GFP_KERNEL); + if (!pname2) { + dev_err(dev, "cannot alloc function name space for %s \n", + (char *)name_buffer.pointer); + devm_kfree(dev, pname); + return AE_NO_MEMORY; + } + memcpy(pname2, (char *)name_buffer.pointer, len); + memcpy(pname2 + len, FUNCTION_SUFFIX, FSUFFIX_LEN); + + pmx = (struct samsung_pmx_func *)drvdata->pmx_functions; + for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++) { + if (pmx->name) + if (strncmp(pmx->name, pname2, strlen(pname2)) == 0) + break; + } + if (ii >= drvdata->nr_functions) { + pmx = (struct samsung_pmx_func *)drvdata->pmx_functions; + for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++) + if (!pmx->name) + break; + } + if (ii >= drvdata->nr_functions) { + dev_err(dev, "too many pin functions defined for %s \n", + (char *)name_buffer.pointer); + devm_kfree(dev, pname); + devm_kfree(dev, pname2); + return AE_BAD_PARAMETER; + } + pmx->name = pname2; + + return AE_OK; +} + +/* + * Parse all of the pin group and function information available + * for this pin controller. A pin group is formed with all + * the pins returned by evaluating any PINS method found in any + * child node. + */ +static int samsung_pin_group_acpi_parse( + struct samsung_pinctrl_drv_data *drvdata, + struct platform_device *pdev) +{ + acpi_status status; + struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev); + struct device *dev = &pdev->dev; + u64 value; + int gcnt, fcnt; + struct samsung_pin_group *grps; + struct samsung_pmx_func *funcs; + + status = acpi_evaluate_integer(dev_handle, "NGRP", NULL, &value); + if (ACPI_FAILURE(status)) { + dev_err(dev, "cannot get NGRP value\n"); + return -EINVAL; + } + gcnt = (int)value; + fcnt = gcnt; + + grps = devm_kzalloc(dev, gcnt * sizeof(*grps), GFP_KERNEL); + if (!grps) { + dev_err(dev, "cannot allocate memory for pin group list\n"); + return -EINVAL; + } + + funcs = devm_kzalloc(dev, fcnt * sizeof(*funcs), GFP_KERNEL); + if (!funcs) { + devm_kfree(dev, grps); + dev_err(dev, "cannot allocate memory for function list\n"); + return -EINVAL; + } + + drvdata->dev = dev; + drvdata->pin_groups = grps; + drvdata->nr_groups = gcnt; + drvdata->pmx_functions = funcs; + drvdata->nr_functions = fcnt; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1, + samsung_acpi_read_group, NULL, + drvdata, NULL); + if (ACPI_FAILURE(status)) { + devm_kfree(dev, grps); + devm_kfree(dev, funcs); + dev_err(dev, "failure walking controller for groups\n"); + return -EINVAL; + } + + return 0; +} + +/* parse the acpi resources for this pin controller */ +static acpi_status samsung_pinctrl_resource(struct acpi_resource *resource, + void *context) +{ + struct samsung_pinctrl_drv_data *drvdata = context; + struct device *dev = drvdata->dev; + + switch (resource->type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: { + struct acpi_resource_fixed_memory32 *p = + &resource->data.fixed_memory32; + drvdata->virt_base = (void *)p->address; + return AE_OK; + } + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + default: + dev_info(dev, "Resource %d is not an MMIO resources\n", + resource->type); + } + + return AE_CTRL_TERMINATE; +} + +/* parse the ACPI tables */ +static const struct acpi_device_id samsung_pinctrl_acpi_match[]; + +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_acpi_data( + struct samsung_pinctrl_drv_data *drvdata, + struct platform_device *pdev) +{ + acpi_status status; + struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev); + struct samsung_pin_ctrl *ctrl = NULL; + struct device *dev = &pdev->dev; + int ret; + + if (!dev_handle) { + dev_err(&pdev->dev, "cannot get ACPI data with null handle\n"); + return NULL; + } + + /* where are the pin controller registers? */ + status = acpi_walk_resources(dev_handle, METHOD_NAME__CRS, + samsung_pinctrl_resource, drvdata); + if (ACPI_FAILURE(status)) { + dev_err(dev, "registers in _CRS are required\n"); + return NULL; + } + + /* initialize the samsung_pin_ctrl part of samsung_pinctrl_drv_data */ + ret = samsung_pin_ctrl_acpi_parse(drvdata, pdev); + if (ret) + return NULL; + + /* initialize the samsung_pin_group part of samsung_pinctrl_drv_data */ + ret = samsung_pin_group_acpi_parse(drvdata, pdev); + if (ret) + ctrl = NULL; + else + ctrl = drvdata->ctrl; + + return ctrl; +} + /* register the pinctrl interface with the pinctrl subsystem */ static int samsung_pinctrl_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { struct pinctrl_desc *ctrldesc = &drvdata->pctl; struct pinctrl_pin_desc *pindesc, *pdesc; + struct acpi_handle *dev_handle; struct samsung_pin_bank *pin_bank; char *pin_names; int pin, bank, ret; @@ -784,7 +1250,10 @@ static int samsung_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); }
- ret = samsung_pinctrl_parse_dt(pdev, drvdata); + dev_handle = ACPI_HANDLE(&pdev->dev); + ret = 0; + if (pdev->dev.of_node && !dev_handle) + ret = samsung_pinctrl_parse_dt(pdev, drvdata); if (ret) { pinctrl_unregister(drvdata->pctl_dev); return ret; @@ -828,6 +1297,9 @@ static int samsung_gpiolib_register(struct platform_device *pdev, gc->label, ret); goto fail; } + printk(KERN_DEBUG + "samsung-pinctrl: registered gpio %s, pins %d to %d\n", + gc->label, gc->base, gc->base + gc->ngpio - 1); }
return 0; @@ -861,7 +1333,7 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, static const struct of_device_id samsung_pinctrl_dt_match[];
/* retrieve the soc specific data */ -static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_of_data( struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { @@ -875,7 +1347,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
id = of_alias_get_id(node, "pinctrl"); if (id < 0) { - dev_err(&pdev->dev, "failed to get alias id\n"); + /* this node may be in ACPI so this may not be an error yet */ return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node); @@ -913,10 +1385,13 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct samsung_pin_ctrl *ctrl; struct resource *res; + struct acpi_handle *dev_handle; int ret;
- if (!dev->of_node) { - dev_err(dev, "device tree node not found\n"); + dev_handle = DEVICE_ACPI_HANDLE(dev); + + if (!pdev->dev.of_node && !dev_handle) { + dev_err(dev, "no device info available\n"); return -ENODEV; }
@@ -927,9 +1402,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; }
- ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); + ctrl = samsung_pinctrl_get_soc_of_data(drvdata, pdev); + if (!ctrl) { /* if not device tree, try ACPI */ + ctrl = samsung_pinctrl_get_soc_acpi_data(drvdata, pdev); + } if (!ctrl) { - dev_err(&pdev->dev, "driver data not available\n"); + dev_err(&pdev->dev, "cannot retrieve device details\n"); return -EINVAL; } drvdata->ctrl = ctrl; @@ -1134,12 +1612,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
+#ifdef CONFIG_ACPI +static const struct acpi_device_id samsung_pinctrl_acpi_match[] = { + { "LINA0002", }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, samsung_pinctrl_acpi_match); +#endif + static struct platform_driver samsung_pinctrl_driver = { .probe = samsung_pinctrl_probe, .driver = { .name = "samsung-pinctrl", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), +#ifdef CONFIG_ACPI + .acpi_match_table = ACPI_PTR(samsung_pinctrl_acpi_match), +#endif }, };
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 11bb75b..cfbb408 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -141,6 +141,9 @@ struct samsung_pin_bank { char *name; void *soc_priv; struct device_node *of_node; +#ifdef CONFIG_ACPI + struct acpi_dev_node *acpi_node; +#endif struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; struct gpio_chip gpio_chip;
On Fri, Sep 06, 2013 at 10:59:31AM -0600, 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 | 503 +++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 2 files changed, 499 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a7fa9e2..422e632 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> #include "core.h" #include "pinctrl-samsung.h" @@ -716,12 +717,477 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, return 0; } +/* parse the acpi resources for this pinctrl bank */ +static acpi_status samsung_pinctrl_bank_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct device *dev = drvdata->dev;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
bank->pctl_offset = p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* Handle pin bank info when a device is found */ +static acpi_status samsung_acpi_read_banks(acpi_handle handle, u32 level,
void *data, void **return_value)
+{
- acpi_status status;
- struct samsung_pinctrl_drv_data *drvdata = data;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
- char *tag;
- u64 value;
- int ii;
- u32 cnt, len;
- /*
* See if there is a TAG. If so, we're still interested -- this
* is what tells us it is a pin bank
*/
- status = acpi_evaluate_object(handle, "TAG", NULL, &buf);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
return AE_OK; /* the device is irrelevant */
- }
- cnt = *(u32 *)buf.pointer;
- len = *(u32 *)(buf.pointer + sizeof(u32));
- if (cnt != 2 || len < 1) {
/*
* The object is supposed to have 2 fields, and
* the string length is supposed to > zero
*/
ACPI_FREE(buf.pointer);
return AE_BAD_PARAMETER;
- }
- /*
* We know that the first 4 bytes is the number of fields,
* the second four bytes is the string length. The next 8
* bytes are the address that points to the beginning of
* the string in the buffer -- which is always immediately
* after the 8 bytes, in this case. So, just set our
* pointer to the right value and be done with it.
*/
- tag = (char *)devm_kzalloc(drvdata->dev, len + 1, GFP_KERNEL);
- if (!tag) {
ACPI_FREE(buf.pointer);
return AE_NO_MEMORY;
- }
- memcpy(tag, (char *)(buf.pointer + 16), len);
- /* find first available pin bank for this controller */
- for (ii = 0; ii < ctrl->nr_banks; ii++, bank++)
if (bank->type == NULL)
break;
- if (ii >= ctrl->nr_banks) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_BUFFER_OVERFLOW;
- }
- /* initialize the bank */
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
samsung_pinctrl_bank_resource, drvdata);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return status;
- }
- bank->type = devm_kzalloc(drvdata->dev,
sizeof(*(bank->type)),
GFP_KERNEL);
- if (!(bank->type)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_NO_MEMORY;
- }
- status = acpi_evaluate_integer(handle, "BASE", NULL, &value);
- if (ACPI_FAILURE(status)) {
/* but, we should have BASE if we have the TAG */
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
These error paths are quite tedious, might be better to jump to a label that performs these actions at the end of the function rather than repeat this over and over.
Also does this actually need devm_kfree()? If probe fails becuase of this then the memory is de-allocated for us.
- bank->pin_base = (u32)value + ctrl->nr_pins;
- 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);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
- bank->nr_pins = (u32)value;
- ctrl->nr_pins += bank->nr_pins;
- bank->gpio_chip.base = pin_base;
- pin_base += bank->nr_pins;
- bank->name = tag;
- bank->acpi_node = &drvdata->dev->acpi_node;
- bank->drvdata = drvdata;
- spin_lock_init(&bank->slock);
- ACPI_FREE(buf.pointer);
- return AE_OK;
+}
+/* initialize the samsung_pin_ctrl portion of the device data */ +static int samsung_pin_ctrl_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int nbanks;
- struct samsung_pin_bank *banks;
- u64 value;
- drvdata->dev = dev;
- ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl) {
dev_err(dev, "cannot allocate memory for samsung_pin_ctrl\n");
return -ENOMEM;
- }
- drvdata->ctrl = ctrl;
- status = acpi_evaluate_integer(dev_handle, "BNKS", NULL, &value);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot get BNKS value\n");
return -EINVAL;
- }
- nbanks = (int)value;
- banks = devm_kzalloc(dev, nbanks * sizeof(*banks), GFP_KERNEL);
- if (!banks) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot allocate memory for pin banks list\n");
return -ENOMEM;
- }
- ctrl->pin_banks = banks;
- ctrl->nr_banks = nbanks;
- ctrl->base = pin_base;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_banks, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, banks);
devm_kfree(dev, ctrl);
dev_err(dev, "failure walking controller for banks\n");
return -EINVAL;
- }
- return 0;
+}
+/* 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);
ACPI_FREE(info.pointer);
devm_kfree(dev, pname);
kfree(format.pointer);
return status;
- }
- kfree(format.pointer); /* match the kzalloc() above (vs ACPI_FREE) */
- ACPI_FREE(buf.pointer);
- ACPI_FREE(info.pointer);
- /* set up the group pins */
- pp = (char **)info.pointer;
- for (ii = 0; ii < grp->num_pins; ii++, pp++) {
pins[ii] = ii;
- }
- grp->pins = pins;
- /* set up the functions */
- len = strlen((char *)name_buffer.pointer);
- pname2 = devm_kzalloc(dev, len + FSUFFIX_LEN + 1, GFP_KERNEL);
- if (!pname2) {
dev_err(dev, "cannot alloc function name space for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
return AE_NO_MEMORY;
- }
- memcpy(pname2, (char *)name_buffer.pointer, len);
- memcpy(pname2 + len, FUNCTION_SUFFIX, FSUFFIX_LEN);
- pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
- for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++) {
if (pmx->name)
if (strncmp(pmx->name, pname2, strlen(pname2)) == 0)
break;
- }
- if (ii >= drvdata->nr_functions) {
pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++)
if (!pmx->name)
break;
- }
- if (ii >= drvdata->nr_functions) {
dev_err(dev, "too many pin functions defined for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
devm_kfree(dev, pname2);
return AE_BAD_PARAMETER;
- }
- pmx->name = pname2;
- return AE_OK;
+}
+/*
- Parse all of the pin group and function information available
- for this pin controller. A pin group is formed with all
- the pins returned by evaluating any PINS method found in any
- child node.
- */
+static int samsung_pin_group_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct device *dev = &pdev->dev;
- u64 value;
- int gcnt, fcnt;
- struct samsung_pin_group *grps;
- struct samsung_pmx_func *funcs;
- status = acpi_evaluate_integer(dev_handle, "NGRP", NULL, &value);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "cannot get NGRP value\n");
return -EINVAL;
- }
- gcnt = (int)value;
- fcnt = gcnt;
- grps = devm_kzalloc(dev, gcnt * sizeof(*grps), GFP_KERNEL);
- if (!grps) {
dev_err(dev, "cannot allocate memory for pin group list\n");
return -EINVAL;
- }
- funcs = devm_kzalloc(dev, fcnt * sizeof(*funcs), GFP_KERNEL);
- if (!funcs) {
devm_kfree(dev, grps);
dev_err(dev, "cannot allocate memory for function list\n");
return -EINVAL;
- }
- drvdata->dev = dev;
- drvdata->pin_groups = grps;
- drvdata->nr_groups = gcnt;
- drvdata->pmx_functions = funcs;
- drvdata->nr_functions = fcnt;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_group, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, grps);
devm_kfree(dev, funcs);
dev_err(dev, "failure walking controller for groups\n");
return -EINVAL;
- }
- return 0;
+}
+/* parse the acpi resources for this pin controller */ +static acpi_status samsung_pinctrl_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct device *dev = drvdata->dev;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
drvdata->virt_base = (void *)p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* parse the ACPI tables */ +static const struct acpi_device_id samsung_pinctrl_acpi_match[];
+static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_acpi_data(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int ret;
- if (!dev_handle) {
dev_err(&pdev->dev, "cannot get ACPI data with null handle\n");
return NULL;
- }
- /* where are the pin controller registers? */
- status = acpi_walk_resources(dev_handle, METHOD_NAME__CRS,
samsung_pinctrl_resource, drvdata);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "registers in _CRS are required\n");
return NULL;
- }
- /* initialize the samsung_pin_ctrl part of samsung_pinctrl_drv_data */
- ret = samsung_pin_ctrl_acpi_parse(drvdata, pdev);
- if (ret)
return NULL;
- /* initialize the samsung_pin_group part of samsung_pinctrl_drv_data */
- ret = samsung_pin_group_acpi_parse(drvdata, pdev);
- if (ret)
ctrl = NULL;
- else
ctrl = drvdata->ctrl;
- return ctrl;
+}
/* register the pinctrl interface with the pinctrl subsystem */ static int samsung_pinctrl_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { struct pinctrl_desc *ctrldesc = &drvdata->pctl; struct pinctrl_pin_desc *pindesc, *pdesc;
- struct acpi_handle *dev_handle; struct samsung_pin_bank *pin_bank; char *pin_names; int pin, bank, ret;
@@ -784,7 +1250,10 @@ static int samsung_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); }
- ret = samsung_pinctrl_parse_dt(pdev, drvdata);
- dev_handle = ACPI_HANDLE(&pdev->dev);
- ret = 0;
- if (pdev->dev.of_node && !dev_handle)
if (ret) { pinctrl_unregister(drvdata->pctl_dev); return ret;ret = samsung_pinctrl_parse_dt(pdev, drvdata);
@@ -828,6 +1297,9 @@ static int samsung_gpiolib_register(struct platform_device *pdev, gc->label, ret); goto fail; }
printk(KERN_DEBUG
"samsung-pinctrl: registered gpio %s, pins %d to %d\n",
}gc->label, gc->base, gc->base + gc->ngpio - 1);
return 0; @@ -861,7 +1333,7 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, static const struct of_device_id samsung_pinctrl_dt_match[]; /* retrieve the soc specific data */ -static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_of_data( struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { @@ -875,7 +1347,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( id = of_alias_get_id(node, "pinctrl"); if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node);/* this node may be in ACPI so this may not be an error yet */
@@ -913,10 +1385,13 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct samsung_pin_ctrl *ctrl; struct resource *res;
- struct acpi_handle *dev_handle; int ret;
- if (!dev->of_node) {
dev_err(dev, "device tree node not found\n");
- dev_handle = DEVICE_ACPI_HANDLE(dev);
- if (!pdev->dev.of_node && !dev_handle) {
return -ENODEV; }dev_err(dev, "no device info available\n");
@@ -927,9 +1402,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; }
- ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
- ctrl = samsung_pinctrl_get_soc_of_data(drvdata, pdev);
- if (!ctrl) { /* if not device tree, try ACPI */
ctrl = samsung_pinctrl_get_soc_acpi_data(drvdata, pdev);
- } if (!ctrl) {
dev_err(&pdev->dev, "driver data not available\n");
return -EINVAL; } drvdata->ctrl = ctrl;dev_err(&pdev->dev, "cannot retrieve device details\n");
@@ -1134,12 +1612,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id samsung_pinctrl_acpi_match[] = {
- { "LINA0002", },
- {},
+}; +MODULE_DEVICE_TABLE(acpi, samsung_pinctrl_acpi_match); +#endif
static struct platform_driver samsung_pinctrl_driver = { .probe = samsung_pinctrl_probe, .driver = { .name = "samsung-pinctrl", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), +#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(samsung_pinctrl_acpi_match),
+#endif }, }; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 11bb75b..cfbb408 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -141,6 +141,9 @@ struct samsung_pin_bank { char *name; void *soc_priv; struct device_node *of_node; +#ifdef CONFIG_ACPI
- struct acpi_dev_node *acpi_node;
+#endif struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; struct gpio_chip gpio_chip; -- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On 09/11/2013 03:38 AM, Graeme Gregory wrote:
On Fri, Sep 06, 2013 at 10:59:31AM -0600, 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 | 503 +++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 2 files changed, 499 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a7fa9e2..422e632 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>
#include "core.h" #include "pinctrl-samsung.h" @@ -716,12 +717,477 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, return 0; }
+/* parse the acpi resources for this pinctrl bank */ +static acpi_status samsung_pinctrl_bank_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct device *dev = drvdata->dev;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
bank->pctl_offset = p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* Handle pin bank info when a device is found */ +static acpi_status samsung_acpi_read_banks(acpi_handle handle, u32 level,
void *data, void **return_value)
+{
- acpi_status status;
- struct samsung_pinctrl_drv_data *drvdata = data;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
- char *tag;
- u64 value;
- int ii;
- u32 cnt, len;
- /*
* See if there is a TAG. If so, we're still interested -- this
* is what tells us it is a pin bank
*/
- status = acpi_evaluate_object(handle, "TAG", NULL, &buf);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
return AE_OK; /* the device is irrelevant */
- }
- cnt = *(u32 *)buf.pointer;
- len = *(u32 *)(buf.pointer + sizeof(u32));
- if (cnt != 2 || len < 1) {
/*
* The object is supposed to have 2 fields, and
* the string length is supposed to > zero
*/
ACPI_FREE(buf.pointer);
return AE_BAD_PARAMETER;
- }
- /*
* We know that the first 4 bytes is the number of fields,
* the second four bytes is the string length. The next 8
* bytes are the address that points to the beginning of
* the string in the buffer -- which is always immediately
* after the 8 bytes, in this case. So, just set our
* pointer to the right value and be done with it.
*/
- tag = (char *)devm_kzalloc(drvdata->dev, len + 1, GFP_KERNEL);
- if (!tag) {
ACPI_FREE(buf.pointer);
return AE_NO_MEMORY;
- }
- memcpy(tag, (char *)(buf.pointer + 16), len);
- /* find first available pin bank for this controller */
- for (ii = 0; ii < ctrl->nr_banks; ii++, bank++)
if (bank->type == NULL)
break;
- if (ii >= ctrl->nr_banks) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_BUFFER_OVERFLOW;
- }
- /* initialize the bank */
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
samsung_pinctrl_bank_resource, drvdata);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return status;
- }
- bank->type = devm_kzalloc(drvdata->dev,
sizeof(*(bank->type)),
GFP_KERNEL);
- if (!(bank->type)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_NO_MEMORY;
- }
- status = acpi_evaluate_integer(handle, "BASE", NULL, &value);
- if (ACPI_FAILURE(status)) {
/* but, we should have BASE if we have the TAG */
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
These error paths are quite tedious, might be better to jump to a label that performs these actions at the end of the function rather than repeat this over and over.
Yeah, fair enough. I personally go back and forth on this. Part of it is just having it pounded into me early on that "goto's are evil"; I'm still recovering.
I'll rearrange this.
Also does this actually need devm_kfree()? If probe fails becuase of this then the memory is de-allocated for us.
Aha. I don't know why I was unaware of that. If that's the case, then I'll simplify based on that.
- bank->pin_base = (u32)value + ctrl->nr_pins;
- 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);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
- bank->nr_pins = (u32)value;
- ctrl->nr_pins += bank->nr_pins;
- bank->gpio_chip.base = pin_base;
- pin_base += bank->nr_pins;
- bank->name = tag;
- bank->acpi_node = &drvdata->dev->acpi_node;
- bank->drvdata = drvdata;
- spin_lock_init(&bank->slock);
- ACPI_FREE(buf.pointer);
- return AE_OK;
+}
+/* initialize the samsung_pin_ctrl portion of the device data */ +static int samsung_pin_ctrl_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int nbanks;
- struct samsung_pin_bank *banks;
- u64 value;
- drvdata->dev = dev;
- ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl) {
dev_err(dev, "cannot allocate memory for samsung_pin_ctrl\n");
return -ENOMEM;
- }
- drvdata->ctrl = ctrl;
- status = acpi_evaluate_integer(dev_handle, "BNKS", NULL, &value);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot get BNKS value\n");
return -EINVAL;
- }
- nbanks = (int)value;
- banks = devm_kzalloc(dev, nbanks * sizeof(*banks), GFP_KERNEL);
- if (!banks) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot allocate memory for pin banks list\n");
return -ENOMEM;
- }
- ctrl->pin_banks = banks;
- ctrl->nr_banks = nbanks;
- ctrl->base = pin_base;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_banks, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, banks);
devm_kfree(dev, ctrl);
dev_err(dev, "failure walking controller for banks\n");
return -EINVAL;
- }
- return 0;
+}
+/* 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);
ACPI_FREE(info.pointer);
devm_kfree(dev, pname);
kfree(format.pointer);
return status;
- }
- kfree(format.pointer); /* match the kzalloc() above (vs ACPI_FREE) */
- ACPI_FREE(buf.pointer);
- ACPI_FREE(info.pointer);
- /* set up the group pins */
- pp = (char **)info.pointer;
- for (ii = 0; ii < grp->num_pins; ii++, pp++) {
pins[ii] = ii;
- }
- grp->pins = pins;
- /* set up the functions */
- len = strlen((char *)name_buffer.pointer);
- pname2 = devm_kzalloc(dev, len + FSUFFIX_LEN + 1, GFP_KERNEL);
- if (!pname2) {
dev_err(dev, "cannot alloc function name space for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
return AE_NO_MEMORY;
- }
- memcpy(pname2, (char *)name_buffer.pointer, len);
- memcpy(pname2 + len, FUNCTION_SUFFIX, FSUFFIX_LEN);
- pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
- for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++) {
if (pmx->name)
if (strncmp(pmx->name, pname2, strlen(pname2)) == 0)
break;
- }
- if (ii >= drvdata->nr_functions) {
pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++)
if (!pmx->name)
break;
- }
- if (ii >= drvdata->nr_functions) {
dev_err(dev, "too many pin functions defined for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
devm_kfree(dev, pname2);
return AE_BAD_PARAMETER;
- }
- pmx->name = pname2;
- return AE_OK;
+}
+/*
- Parse all of the pin group and function information available
- for this pin controller. A pin group is formed with all
- the pins returned by evaluating any PINS method found in any
- child node.
- */
+static int samsung_pin_group_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct device *dev = &pdev->dev;
- u64 value;
- int gcnt, fcnt;
- struct samsung_pin_group *grps;
- struct samsung_pmx_func *funcs;
- status = acpi_evaluate_integer(dev_handle, "NGRP", NULL, &value);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "cannot get NGRP value\n");
return -EINVAL;
- }
- gcnt = (int)value;
- fcnt = gcnt;
- grps = devm_kzalloc(dev, gcnt * sizeof(*grps), GFP_KERNEL);
- if (!grps) {
dev_err(dev, "cannot allocate memory for pin group list\n");
return -EINVAL;
- }
- funcs = devm_kzalloc(dev, fcnt * sizeof(*funcs), GFP_KERNEL);
- if (!funcs) {
devm_kfree(dev, grps);
dev_err(dev, "cannot allocate memory for function list\n");
return -EINVAL;
- }
- drvdata->dev = dev;
- drvdata->pin_groups = grps;
- drvdata->nr_groups = gcnt;
- drvdata->pmx_functions = funcs;
- drvdata->nr_functions = fcnt;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_group, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, grps);
devm_kfree(dev, funcs);
dev_err(dev, "failure walking controller for groups\n");
return -EINVAL;
- }
- return 0;
+}
+/* parse the acpi resources for this pin controller */ +static acpi_status samsung_pinctrl_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct device *dev = drvdata->dev;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
drvdata->virt_base = (void *)p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* parse the ACPI tables */ +static const struct acpi_device_id samsung_pinctrl_acpi_match[];
+static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_acpi_data(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int ret;
- if (!dev_handle) {
dev_err(&pdev->dev, "cannot get ACPI data with null handle\n");
return NULL;
- }
- /* where are the pin controller registers? */
- status = acpi_walk_resources(dev_handle, METHOD_NAME__CRS,
samsung_pinctrl_resource, drvdata);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "registers in _CRS are required\n");
return NULL;
- }
- /* initialize the samsung_pin_ctrl part of samsung_pinctrl_drv_data */
- ret = samsung_pin_ctrl_acpi_parse(drvdata, pdev);
- if (ret)
return NULL;
- /* initialize the samsung_pin_group part of samsung_pinctrl_drv_data */
- ret = samsung_pin_group_acpi_parse(drvdata, pdev);
- if (ret)
ctrl = NULL;
- else
ctrl = drvdata->ctrl;
- return ctrl;
+}
- /* register the pinctrl interface with the pinctrl subsystem */ static int samsung_pinctrl_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { struct pinctrl_desc *ctrldesc = &drvdata->pctl; struct pinctrl_pin_desc *pindesc, *pdesc;
- struct acpi_handle *dev_handle; struct samsung_pin_bank *pin_bank; char *pin_names; int pin, bank, ret;
@@ -784,7 +1250,10 @@ static int samsung_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); }
- ret = samsung_pinctrl_parse_dt(pdev, drvdata);
- dev_handle = ACPI_HANDLE(&pdev->dev);
- ret = 0;
- if (pdev->dev.of_node && !dev_handle)
if (ret) { pinctrl_unregister(drvdata->pctl_dev); return ret;ret = samsung_pinctrl_parse_dt(pdev, drvdata);
@@ -828,6 +1297,9 @@ static int samsung_gpiolib_register(struct platform_device *pdev, gc->label, ret); goto fail; }
printk(KERN_DEBUG
"samsung-pinctrl: registered gpio %s, pins %d to %d\n",
gc->label, gc->base, gc->base + gc->ngpio - 1);
}
return 0;
@@ -861,7 +1333,7 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, static const struct of_device_id samsung_pinctrl_dt_match[];
/* retrieve the soc specific data */ -static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_of_data( struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { @@ -875,7 +1347,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
id = of_alias_get_id(node, "pinctrl"); if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node);/* this node may be in ACPI so this may not be an error yet */
@@ -913,10 +1385,13 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct samsung_pin_ctrl *ctrl; struct resource *res;
- struct acpi_handle *dev_handle; int ret;
- if (!dev->of_node) {
dev_err(dev, "device tree node not found\n");
- dev_handle = DEVICE_ACPI_HANDLE(dev);
- if (!pdev->dev.of_node && !dev_handle) {
return -ENODEV; }dev_err(dev, "no device info available\n");
@@ -927,9 +1402,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; }
- ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
- ctrl = samsung_pinctrl_get_soc_of_data(drvdata, pdev);
- if (!ctrl) { /* if not device tree, try ACPI */
ctrl = samsung_pinctrl_get_soc_acpi_data(drvdata, pdev);
- } if (!ctrl) {
dev_err(&pdev->dev, "driver data not available\n");
return -EINVAL; } drvdata->ctrl = ctrl;dev_err(&pdev->dev, "cannot retrieve device details\n");
@@ -1134,12 +1612,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
+#ifdef CONFIG_ACPI +static const struct acpi_device_id samsung_pinctrl_acpi_match[] = {
- { "LINA0002", },
- {},
+}; +MODULE_DEVICE_TABLE(acpi, samsung_pinctrl_acpi_match); +#endif
- static struct platform_driver samsung_pinctrl_driver = { .probe = samsung_pinctrl_probe, .driver = { .name = "samsung-pinctrl", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_pinctrl_dt_match),
+#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(samsung_pinctrl_acpi_match),
+#endif }, };
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 11bb75b..cfbb408 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -141,6 +141,9 @@ struct samsung_pin_bank { char *name; void *soc_priv; struct device_node *of_node; +#ifdef CONFIG_ACPI
- struct acpi_dev_node *acpi_node;
+#endif struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; struct gpio_chip gpio_chip; -- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On Wed, Sep 11, 2013 at 10:15:08AM -0600, Al Stone wrote:
On 09/11/2013 03:38 AM, Graeme Gregory wrote:
On Fri, Sep 06, 2013 at 10:59:31AM -0600, 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 | 503 +++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-samsung.h | 3 + 2 files changed, 499 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a7fa9e2..422e632 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>
#include "core.h" #include "pinctrl-samsung.h" @@ -716,12 +717,477 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, return 0; }
+/* parse the acpi resources for this pinctrl bank */ +static acpi_status samsung_pinctrl_bank_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct device *dev = drvdata->dev;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
bank->pctl_offset = p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* Handle pin bank info when a device is found */ +static acpi_status samsung_acpi_read_banks(acpi_handle handle, u32 level,
void *data, void **return_value)
+{
- acpi_status status;
- struct samsung_pinctrl_drv_data *drvdata = data;
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
- char *tag;
- u64 value;
- int ii;
- u32 cnt, len;
- /*
* See if there is a TAG. If so, we're still interested -- this
* is what tells us it is a pin bank
*/
- status = acpi_evaluate_object(handle, "TAG", NULL, &buf);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
return AE_OK; /* the device is irrelevant */
- }
- cnt = *(u32 *)buf.pointer;
- len = *(u32 *)(buf.pointer + sizeof(u32));
- if (cnt != 2 || len < 1) {
/*
* The object is supposed to have 2 fields, and
* the string length is supposed to > zero
*/
ACPI_FREE(buf.pointer);
return AE_BAD_PARAMETER;
- }
- /*
* We know that the first 4 bytes is the number of fields,
* the second four bytes is the string length. The next 8
* bytes are the address that points to the beginning of
* the string in the buffer -- which is always immediately
* after the 8 bytes, in this case. So, just set our
* pointer to the right value and be done with it.
*/
- tag = (char *)devm_kzalloc(drvdata->dev, len + 1, GFP_KERNEL);
- if (!tag) {
ACPI_FREE(buf.pointer);
return AE_NO_MEMORY;
- }
- memcpy(tag, (char *)(buf.pointer + 16), len);
- /* find first available pin bank for this controller */
- for (ii = 0; ii < ctrl->nr_banks; ii++, bank++)
if (bank->type == NULL)
break;
- if (ii >= ctrl->nr_banks) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_BUFFER_OVERFLOW;
- }
- /* initialize the bank */
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
samsung_pinctrl_bank_resource, drvdata);
- if (ACPI_FAILURE(status)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return status;
- }
- bank->type = devm_kzalloc(drvdata->dev,
sizeof(*(bank->type)),
GFP_KERNEL);
- if (!(bank->type)) {
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
return AE_NO_MEMORY;
- }
- status = acpi_evaluate_integer(handle, "BASE", NULL, &value);
- if (ACPI_FAILURE(status)) {
/* but, we should have BASE if we have the TAG */
ACPI_FREE(buf.pointer);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
These error paths are quite tedious, might be better to jump to a label that performs these actions at the end of the function rather than repeat this over and over.
Yeah, fair enough. I personally go back and forth on this. Part of it is just having it pounded into me early on that "goto's are evil"; I'm still recovering.
I'll rearrange this.
Also does this actually need devm_kfree()? If probe fails becuase of this then the memory is de-allocated for us.
Aha. I don't know why I was unaware of that. If that's the case, then I'll simplify based on that.
The whole point of the devm_* API is that the memory is attached to the device if the device goes away ie probe() fails or remove() is called then the memory is de-allocated automatically.
Graeme
- bank->pin_base = (u32)value + ctrl->nr_pins;
- 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);
devm_kfree(drvdata->dev, tag);
devm_kfree(drvdata->dev, bank->type);
return status;
- }
- bank->nr_pins = (u32)value;
- ctrl->nr_pins += bank->nr_pins;
- bank->gpio_chip.base = pin_base;
- pin_base += bank->nr_pins;
- bank->name = tag;
- bank->acpi_node = &drvdata->dev->acpi_node;
- bank->drvdata = drvdata;
- spin_lock_init(&bank->slock);
- ACPI_FREE(buf.pointer);
- return AE_OK;
+}
+/* initialize the samsung_pin_ctrl portion of the device data */ +static int samsung_pin_ctrl_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int nbanks;
- struct samsung_pin_bank *banks;
- u64 value;
- drvdata->dev = dev;
- ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl) {
dev_err(dev, "cannot allocate memory for samsung_pin_ctrl\n");
return -ENOMEM;
- }
- drvdata->ctrl = ctrl;
- status = acpi_evaluate_integer(dev_handle, "BNKS", NULL, &value);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot get BNKS value\n");
return -EINVAL;
- }
- nbanks = (int)value;
- banks = devm_kzalloc(dev, nbanks * sizeof(*banks), GFP_KERNEL);
- if (!banks) {
devm_kfree(dev, ctrl);
dev_err(dev, "cannot allocate memory for pin banks list\n");
return -ENOMEM;
- }
- ctrl->pin_banks = banks;
- ctrl->nr_banks = nbanks;
- ctrl->base = pin_base;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_banks, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, banks);
devm_kfree(dev, ctrl);
dev_err(dev, "failure walking controller for banks\n");
return -EINVAL;
- }
- return 0;
+}
+/* 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);
ACPI_FREE(info.pointer);
devm_kfree(dev, pname);
kfree(format.pointer);
return status;
- }
- kfree(format.pointer); /* match the kzalloc() above (vs ACPI_FREE) */
- ACPI_FREE(buf.pointer);
- ACPI_FREE(info.pointer);
- /* set up the group pins */
- pp = (char **)info.pointer;
- for (ii = 0; ii < grp->num_pins; ii++, pp++) {
pins[ii] = ii;
- }
- grp->pins = pins;
- /* set up the functions */
- len = strlen((char *)name_buffer.pointer);
- pname2 = devm_kzalloc(dev, len + FSUFFIX_LEN + 1, GFP_KERNEL);
- if (!pname2) {
dev_err(dev, "cannot alloc function name space for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
return AE_NO_MEMORY;
- }
- memcpy(pname2, (char *)name_buffer.pointer, len);
- memcpy(pname2 + len, FUNCTION_SUFFIX, FSUFFIX_LEN);
- pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
- for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++) {
if (pmx->name)
if (strncmp(pmx->name, pname2, strlen(pname2)) == 0)
break;
- }
- if (ii >= drvdata->nr_functions) {
pmx = (struct samsung_pmx_func *)drvdata->pmx_functions;
for (ii = 0; ii < drvdata->nr_functions; ii++, pmx++)
if (!pmx->name)
break;
- }
- if (ii >= drvdata->nr_functions) {
dev_err(dev, "too many pin functions defined for %s \n",
(char *)name_buffer.pointer);
devm_kfree(dev, pname);
devm_kfree(dev, pname2);
return AE_BAD_PARAMETER;
- }
- pmx->name = pname2;
- return AE_OK;
+}
+/*
- Parse all of the pin group and function information available
- for this pin controller. A pin group is formed with all
- the pins returned by evaluating any PINS method found in any
- child node.
- */
+static int samsung_pin_group_acpi_parse(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct device *dev = &pdev->dev;
- u64 value;
- int gcnt, fcnt;
- struct samsung_pin_group *grps;
- struct samsung_pmx_func *funcs;
- status = acpi_evaluate_integer(dev_handle, "NGRP", NULL, &value);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "cannot get NGRP value\n");
return -EINVAL;
- }
- gcnt = (int)value;
- fcnt = gcnt;
- grps = devm_kzalloc(dev, gcnt * sizeof(*grps), GFP_KERNEL);
- if (!grps) {
dev_err(dev, "cannot allocate memory for pin group list\n");
return -EINVAL;
- }
- funcs = devm_kzalloc(dev, fcnt * sizeof(*funcs), GFP_KERNEL);
- if (!funcs) {
devm_kfree(dev, grps);
dev_err(dev, "cannot allocate memory for function list\n");
return -EINVAL;
- }
- drvdata->dev = dev;
- drvdata->pin_groups = grps;
- drvdata->nr_groups = gcnt;
- drvdata->pmx_functions = funcs;
- drvdata->nr_functions = fcnt;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, dev_handle, 1,
samsung_acpi_read_group, NULL,
drvdata, NULL);
- if (ACPI_FAILURE(status)) {
devm_kfree(dev, grps);
devm_kfree(dev, funcs);
dev_err(dev, "failure walking controller for groups\n");
return -EINVAL;
- }
- return 0;
+}
+/* parse the acpi resources for this pin controller */ +static acpi_status samsung_pinctrl_resource(struct acpi_resource *resource,
void *context)
+{
- struct samsung_pinctrl_drv_data *drvdata = context;
- struct device *dev = drvdata->dev;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
struct acpi_resource_fixed_memory32 *p =
&resource->data.fixed_memory32;
drvdata->virt_base = (void *)p->address;
return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
- default:
dev_info(dev, "Resource %d is not an MMIO resources\n",
resource->type);
- }
- return AE_CTRL_TERMINATE;
+}
+/* parse the ACPI tables */ +static const struct acpi_device_id samsung_pinctrl_acpi_match[];
+static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_acpi_data(
struct samsung_pinctrl_drv_data *drvdata,
struct platform_device *pdev)
+{
- acpi_status status;
- struct acpi_handle *dev_handle = ACPI_HANDLE(&pdev->dev);
- struct samsung_pin_ctrl *ctrl = NULL;
- struct device *dev = &pdev->dev;
- int ret;
- if (!dev_handle) {
dev_err(&pdev->dev, "cannot get ACPI data with null handle\n");
return NULL;
- }
- /* where are the pin controller registers? */
- status = acpi_walk_resources(dev_handle, METHOD_NAME__CRS,
samsung_pinctrl_resource, drvdata);
- if (ACPI_FAILURE(status)) {
dev_err(dev, "registers in _CRS are required\n");
return NULL;
- }
- /* initialize the samsung_pin_ctrl part of samsung_pinctrl_drv_data */
- ret = samsung_pin_ctrl_acpi_parse(drvdata, pdev);
- if (ret)
return NULL;
- /* initialize the samsung_pin_group part of samsung_pinctrl_drv_data */
- ret = samsung_pin_group_acpi_parse(drvdata, pdev);
- if (ret)
ctrl = NULL;
- else
ctrl = drvdata->ctrl;
- return ctrl;
+}
/* register the pinctrl interface with the pinctrl subsystem */ static int samsung_pinctrl_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { struct pinctrl_desc *ctrldesc = &drvdata->pctl; struct pinctrl_pin_desc *pindesc, *pdesc;
- struct acpi_handle *dev_handle; struct samsung_pin_bank *pin_bank; char *pin_names; int pin, bank, ret;
@@ -784,7 +1250,10 @@ static int samsung_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); }
- ret = samsung_pinctrl_parse_dt(pdev, drvdata);
- dev_handle = ACPI_HANDLE(&pdev->dev);
- ret = 0;
- if (pdev->dev.of_node && !dev_handle)
if (ret) { pinctrl_unregister(drvdata->pctl_dev); return ret;ret = samsung_pinctrl_parse_dt(pdev, drvdata);
@@ -828,6 +1297,9 @@ static int samsung_gpiolib_register(struct platform_device *pdev, gc->label, ret); goto fail; }
printk(KERN_DEBUG
"samsung-pinctrl: registered gpio %s, pins %d to %d\n",
gc->label, gc->base, gc->base + gc->ngpio - 1);
}
return 0;
@@ -861,7 +1333,7 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, static const struct of_device_id samsung_pinctrl_dt_match[];
/* retrieve the soc specific data */ -static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_of_data( struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { @@ -875,7 +1347,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
id = of_alias_get_id(node, "pinctrl"); if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node);/* this node may be in ACPI so this may not be an error yet */
@@ -913,10 +1385,13 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct samsung_pin_ctrl *ctrl; struct resource *res;
- struct acpi_handle *dev_handle; int ret;
- if (!dev->of_node) {
dev_err(dev, "device tree node not found\n");
- dev_handle = DEVICE_ACPI_HANDLE(dev);
- if (!pdev->dev.of_node && !dev_handle) {
return -ENODEV; }dev_err(dev, "no device info available\n");
@@ -927,9 +1402,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; }
- ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
- ctrl = samsung_pinctrl_get_soc_of_data(drvdata, pdev);
- if (!ctrl) { /* if not device tree, try ACPI */
ctrl = samsung_pinctrl_get_soc_acpi_data(drvdata, pdev);
- } if (!ctrl) {
dev_err(&pdev->dev, "driver data not available\n");
return -EINVAL; } drvdata->ctrl = ctrl;dev_err(&pdev->dev, "cannot retrieve device details\n");
@@ -1134,12 +1612,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
+#ifdef CONFIG_ACPI +static const struct acpi_device_id samsung_pinctrl_acpi_match[] = {
- { "LINA0002", },
- {},
+}; +MODULE_DEVICE_TABLE(acpi, samsung_pinctrl_acpi_match); +#endif
static struct platform_driver samsung_pinctrl_driver = { .probe = samsung_pinctrl_probe, .driver = { .name = "samsung-pinctrl", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), +#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(samsung_pinctrl_acpi_match),
+#endif }, };
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 11bb75b..cfbb408 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -141,6 +141,9 @@ struct samsung_pin_bank { char *name; void *soc_priv; struct device_node *of_node; +#ifdef CONFIG_ACPI
- struct acpi_dev_node *acpi_node;
+#endif struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; struct gpio_chip gpio_chip; -- 1.8.3.1
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
-- ciao, al
Al Stone Software Engineer Linaro Enterprise Group al.stone@linaro.org
From: Al Stone ahs3@redhat.com
This will allow the samsung-pinctrl driver to compile properly regardless of whether or not ACPI is enabled
Signed-off-by: Al Stone al.stone@linaro.org --- drivers/pinctrl/pinctrl-samsung.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 422e632..7cddb7c 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -29,7 +29,9 @@ #include <linux/irqdomain.h> #include <linux/spinlock.h> #include <linux/syscore_ops.h> +#ifdef CONFIG_ACPI #include <linux/acpi.h> +#endif
#include "core.h" #include "pinctrl-samsung.h" @@ -717,6 +719,7 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, return 0; }
+#ifdef CONFIG_ACPI /* parse the acpi resources for this pinctrl bank */ static acpi_status samsung_pinctrl_bank_resource(struct acpi_resource *resource, void *context) @@ -1180,6 +1183,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_acpi_data(
return ctrl; } +#endif /* CONFIG_ACPI */
/* register the pinctrl interface with the pinctrl subsystem */ static int samsung_pinctrl_register(struct platform_device *pdev, @@ -1385,12 +1389,16 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct samsung_pin_ctrl *ctrl; struct resource *res; - struct acpi_handle *dev_handle; int ret; +#ifdef CONFIG_ACPI + struct acpi_handle *dev_handle;
dev_handle = DEVICE_ACPI_HANDLE(dev);
if (!pdev->dev.of_node && !dev_handle) { +#else + if (!pdev->dev.of_node) { +#endif dev_err(dev, "no device info available\n"); return -ENODEV; } @@ -1403,9 +1411,11 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) }
ctrl = samsung_pinctrl_get_soc_of_data(drvdata, pdev); +#ifdef CONFIG_ACPI if (!ctrl) { /* if not device tree, try ACPI */ ctrl = samsung_pinctrl_get_soc_acpi_data(drvdata, pdev); } +#endif if (!ctrl) { dev_err(&pdev->dev, "cannot retrieve device details\n"); return -EINVAL;
From: Al Stone ahs3@redhat.com
These are FDT changes only.
Signed-off-by: Al Stone al.stone@linaro.org --- arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 2 ++ arch/arm/boot/dts/exynos5250.dtsi | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 724a22f..03f5b89 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -770,6 +770,7 @@ }; };
+ /* moved to ACPI pinctrl@03860000 { gpz: gpz { gpio-controller; @@ -787,4 +788,5 @@ samsung,pin-drv = <0>; }; }; + */ }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index ef57277..f7aa20f 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -49,7 +49,7 @@ pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; - pinctrl3 = &pinctrl_3; + /* pinctrl3 = &pinctrl_3; */ };
cpus { @@ -152,11 +152,13 @@ interrupts = <0 50 0>; };
+ /* pinctrl_3: pinctrl@03860000 { compatible = "samsung,exynos5250-pinctrl"; reg = <0x03860000 0x1000>; interrupts = <0 47 0>; }; + */
watchdog { clocks = <&clock 336>; @@ -420,7 +422,7 @@ samsung,supports-secdai; samsung,idma-addr = <0x03000000>; pinctrl-names = "default"; - pinctrl-0 = <&i2s0_bus>; + /* pinctrl-0 = <&i2s0_bus>; */ };
i2s1: i2s@12D60000 {
From: Al Stone ahs3@redhat.com
These are FDT changes only.
Signed-off-by: Al Stone al.stone@linaro.org --- arch/arm/boot/dts/exynos5250-arndale.dts | 26 ++++++++++++++++++++++++++ arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 2 +- arch/arm/boot/dts/exynos5250.dtsi | 6 ++++-- 3 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 3937993..95c08e7 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -485,4 +485,30 @@ rtc { status = "okay"; }; + + leds { + compatible = "gpio-leds"; + + user1 { + label = "D12"; + gpios = <&gpy6 5 1 0 0>; + linux,default-trigger = "heartbeat"; + }; + + user2 { + label = "D13"; + gpios = <&gpy6 6 1 0 0>; + }; + + user3 { + label = "D14"; + gpios = <&gpy6 7 1 0 0>; + }; + + user4 { + label = "D15"; + gpios = <&gpy6 4 1 0 0>; + }; + }; + }; diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 03f5b89..7e26955 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -708,6 +708,7 @@ }; };
+ /* moved to ACPI pinctrl@10d10000 { gpv0: gpv0 { gpio-controller; @@ -770,7 +771,6 @@ }; };
- /* moved to ACPI pinctrl@03860000 { gpz: gpz { gpio-controller; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index f7aa20f..515f79e 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -48,8 +48,10 @@ i2c8 = &i2c_8; pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; + /* Moved to ACPI pinctrl2 = &pinctrl_2; - /* pinctrl3 = &pinctrl_3; */ + pinctrl3 = &pinctrl_3; + */ };
cpus { @@ -146,13 +148,13 @@ interrupts = <0 45 0>; };
+ /* Moved to ACPI pinctrl_2: pinctrl@10d10000 { compatible = "samsung,exynos5250-pinctrl"; reg = <0x10d10000 0x1000>; interrupts = <0 50 0>; };
- /* pinctrl_3: pinctrl@03860000 { compatible = "samsung,exynos5250-pinctrl"; reg = <0x03860000 0x1000>;
From: Al Stone ahs3@redhat.com
These are FDT changes only.
Signed-off-by: Al Stone al.stone@linaro.org --- arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 2 +- arch/arm/boot/dts/exynos5250.dtsi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 7e26955..656e381 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -562,6 +562,7 @@ }; };
+ /* moved to ACPI pinctrl@13400000 { gpe0: gpe0 { gpio-controller; @@ -708,7 +709,6 @@ }; };
- /* moved to ACPI pinctrl@10d10000 { gpv0: gpv0 { gpio-controller; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 515f79e..7262532 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -47,8 +47,8 @@ i2c7 = &i2c_7; i2c8 = &i2c_8; pinctrl0 = &pinctrl_0; - pinctrl1 = &pinctrl_1; /* Moved to ACPI + pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; pinctrl3 = &pinctrl_3; */ @@ -142,13 +142,13 @@ }; };
+ /* Moved to ACPI pinctrl_1: pinctrl@13400000 { compatible = "samsung,exynos5250-pinctrl"; reg = <0x13400000 0x1000>; interrupts = <0 45 0>; };
- /* Moved to ACPI pinctrl_2: pinctrl@10d10000 { compatible = "samsung,exynos5250-pinctrl"; reg = <0x10d10000 0x1000>;
From: Al Stone ahs3@redhat.com
Signed-off-by: Al Stone al.stone@linaro.org --- drivers/acpi/acpi_platform.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index c5eed01..05ded3b 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -30,6 +30,9 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
{ "PNP0D40" },
+ /* Arndale-only platform devices */ + { "LINA0002" }, + /* arm64 platform devices */ { "LINA0003" }, { "LINA0005" },