mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-17 14:18:14 +01:00
pinctrl: at91-pio4: Add support for pinctrl config subnodes
Previously, in order for the `pinctrl-*` DT node properties to be properly processed, the pinctrl's subnodes were limited to only having the `pinmux` property as well as other additional properties (slew-rate, bias-disable, etc.). Now, with this patch the pinctrl driver is made to work similarly to the one from Linux. It can now distinguish between one subnode and a subnode with multiple subnodes. Signed-off-by: Sergiu Moga <sergiu.moga@microchip.com>
This commit is contained in:
parent
2ed96a87d2
commit
7086defa04
@ -15,6 +15,7 @@
|
|||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <dm/uclass-internal.h>
|
||||||
#include <mach/atmel_pio4.h>
|
#include <mach/atmel_pio4.h>
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
@ -151,12 +152,11 @@ static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
|
|||||||
|
|
||||||
#define MAX_PINMUX_ENTRIES 40
|
#define MAX_PINMUX_ENTRIES 40
|
||||||
|
|
||||||
static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
|
static int atmel_process_config_dev(struct udevice *dev, struct udevice *config)
|
||||||
{
|
{
|
||||||
struct atmel_pio4_plat *plat = dev_get_plat(dev);
|
struct atmel_pio4_plat *plat = dev_get_plat(dev);
|
||||||
struct atmel_pio4_port *bank_base;
|
|
||||||
const void *blob = gd->fdt_blob;
|
|
||||||
int node = dev_of_offset(config);
|
int node = dev_of_offset(config);
|
||||||
|
struct atmel_pio4_port *bank_base;
|
||||||
u32 offset, func, bank, line;
|
u32 offset, func, bank, line;
|
||||||
u32 cells[MAX_PINMUX_ENTRIES];
|
u32 cells[MAX_PINMUX_ENTRIES];
|
||||||
u32 i, conf;
|
u32 i, conf;
|
||||||
@ -164,18 +164,17 @@ static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
|
|||||||
|
|
||||||
conf = atmel_pinctrl_get_pinconf(config, plat);
|
conf = atmel_pinctrl_get_pinconf(config, plat);
|
||||||
|
|
||||||
count = fdtdec_get_int_array_count(blob, node, "pinmux",
|
/*
|
||||||
|
* The only case where this function returns a negative error value
|
||||||
|
* is when there is no "pinmux" property attached to this node
|
||||||
|
*/
|
||||||
|
count = fdtdec_get_int_array_count(gd->fdt_blob, node, "pinmux",
|
||||||
cells, ARRAY_SIZE(cells));
|
cells, ARRAY_SIZE(cells));
|
||||||
if (count < 0) {
|
if (count < 0)
|
||||||
printf("%s: bad pinmux array %d\n", __func__, count);
|
return count;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > MAX_PINMUX_ENTRIES) {
|
if (count > MAX_PINMUX_ENTRIES)
|
||||||
printf("%s: unsupported pinmux array count %d\n",
|
|
||||||
__func__, count);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0 ; i < count; i++) {
|
for (i = 0 ; i < count; i++) {
|
||||||
offset = ATMEL_GET_PIN_NO(cells[i]);
|
offset = ATMEL_GET_PIN_NO(cells[i]);
|
||||||
@ -195,6 +194,56 @@ static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
|
||||||
|
{
|
||||||
|
int node = dev_of_offset(config);
|
||||||
|
struct udevice *subconfig;
|
||||||
|
int subnode, subnode_count = 0, ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this function returns a negative error code then that means
|
||||||
|
* that either the "pinmux" property of the node is missing, which is
|
||||||
|
* the case for pinctrl nodes that do not have all the pins with the
|
||||||
|
* same configuration and are split in multiple subnodes, or something
|
||||||
|
* else went wrong and we have to stop. For the latter case, it would
|
||||||
|
* mean that the node failed even though it has no subnodes.
|
||||||
|
*/
|
||||||
|
ret = atmel_process_config_dev(dev, config);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we reach here, it means that the subnode pinctrl's DT has multiple
|
||||||
|
* subnodes. If it does not, then something else went wrong in the
|
||||||
|
* previous call to atmel_process_config_dev.
|
||||||
|
*/
|
||||||
|
fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
|
||||||
|
/* Get subnode as an udevice */
|
||||||
|
ret = uclass_find_device_by_of_offset(UCLASS_PINCONFIG, subnode,
|
||||||
|
&subconfig);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this time the function returns an error code on a subnode
|
||||||
|
* then something is totally wrong so abort.
|
||||||
|
*/
|
||||||
|
ret = atmel_process_config_dev(dev, subconfig);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
subnode_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we somehow got here and we do not have any subnodes, abort.
|
||||||
|
*/
|
||||||
|
if (!subnode_count)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const struct pinctrl_ops atmel_pinctrl_ops = {
|
const struct pinctrl_ops atmel_pinctrl_ops = {
|
||||||
.set_state = atmel_pinctrl_set_state,
|
.set_state = atmel_pinctrl_set_state,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user