pinctrl: sunxi: Add pinctrl variants

Some SoCs are either supposed to be pin compatible (A10 and A20 for
example), or are just repackaged versions of the same die (A10s, A13, GR8).

In those case, having a full blown pinctrl driver just introduces
duplication in both data size and maintainance effort.

Add a variant option to both pins and functions to be able to limit the
pins and functions described only to a subset of the SoC we support with a
given driver.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Maxime Ripard 2017-01-08 22:31:15 +01:00 committed by Linus Walleij
parent 3429fb3cda
commit 578db85f67
2 changed files with 81 additions and 22 deletions

View File

@ -1041,21 +1041,35 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
int i; int i;
pctl->ngroups = pctl->desc->npins; /*
* Allocate groups
*
* We assume that the number of groups is the number of pins
* given in the data array.
/* Allocate groups */ * This will not always be true, since some pins might not be
* available in the current variant, but fortunately for us,
* this means that the number of pins is the maximum group
* number we will ever see.
*/
pctl->groups = devm_kzalloc(&pdev->dev, pctl->groups = devm_kzalloc(&pdev->dev,
pctl->ngroups * sizeof(*pctl->groups), pctl->desc->npins * sizeof(*pctl->groups),
GFP_KERNEL); GFP_KERNEL);
if (!pctl->groups) if (!pctl->groups)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < pctl->desc->npins; i++) { for (i = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i; const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_pinctrl_group *group = pctl->groups + i; struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
if (pin->variant && !(pctl->variant & pin->variant))
continue;
group->name = pin->pin.name; group->name = pin->pin.name;
group->pin = pin->pin.number; group->pin = pin->pin.number;
/* And now we count the actual number of pins / groups */
pctl->ngroups++;
} }
/* /*
@ -1063,17 +1077,23 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
* we'll reallocate that later anyway * we'll reallocate that later anyway
*/ */
pctl->functions = devm_kzalloc(&pdev->dev, pctl->functions = devm_kzalloc(&pdev->dev,
pctl->desc->npins * sizeof(*pctl->functions), pctl->ngroups * sizeof(*pctl->functions),
GFP_KERNEL); GFP_KERNEL);
if (!pctl->functions) if (!pctl->functions)
return -ENOMEM; return -ENOMEM;
/* Count functions and their associated groups */ /* Count functions and their associated groups */
for (i = 0; i < pctl->desc->npins; i++) { for (i = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i; const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func = pin->functions; struct sunxi_desc_function *func;
if (pin->variant && !(pctl->variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
if (func->variant && !(pctl->variant & func->variant))
continue;
while (func->name) {
/* Create interrupt mapping while we're at it */ /* Create interrupt mapping while we're at it */
if (!strcmp(func->name, "irq")) { if (!strcmp(func->name, "irq")) {
int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
@ -1081,22 +1101,32 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
} }
sunxi_pinctrl_add_function(pctl, func->name); sunxi_pinctrl_add_function(pctl, func->name);
func++;
} }
} }
/* And now allocated and fill the array for real */
pctl->functions = krealloc(pctl->functions, pctl->functions = krealloc(pctl->functions,
pctl->nfunctions * sizeof(*pctl->functions), pctl->nfunctions * sizeof(*pctl->functions),
GFP_KERNEL); GFP_KERNEL);
if (!pctl->functions) {
kfree(pctl->functions);
return -ENOMEM;
}
for (i = 0; i < pctl->desc->npins; i++) { for (i = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i; const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func = pin->functions; struct sunxi_desc_function *func;
while (func->name) { if (pin->variant && !(pctl->variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
struct sunxi_pinctrl_function *func_item; struct sunxi_pinctrl_function *func_item;
const char **func_grp; const char **func_grp;
if (func->variant && !(pctl->variant & func->variant))
continue;
func_item = sunxi_pinctrl_find_function_by_name(pctl, func_item = sunxi_pinctrl_find_function_by_name(pctl,
func->name); func->name);
if (!func_item) if (!func_item)
@ -1116,7 +1146,6 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
func_grp++; func_grp++;
*func_grp = pin->pin.name; *func_grp = pin->pin.name;
func++;
} }
} }
@ -1208,15 +1237,16 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
return 0; return 0;
} }
int sunxi_pinctrl_init(struct platform_device *pdev, int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc) const struct sunxi_pinctrl_desc *desc,
unsigned long variant)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct pinctrl_desc *pctrl_desc; struct pinctrl_desc *pctrl_desc;
struct pinctrl_pin_desc *pins; struct pinctrl_pin_desc *pins;
struct sunxi_pinctrl *pctl; struct sunxi_pinctrl *pctl;
struct resource *res; struct resource *res;
int i, ret, last_pin; int i, ret, last_pin, pin_idx;
struct clk *clk; struct clk *clk;
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
@ -1233,6 +1263,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
pctl->dev = &pdev->dev; pctl->dev = &pdev->dev;
pctl->desc = desc; pctl->desc = desc;
pctl->variant = variant;
pctl->irq_array = devm_kcalloc(&pdev->dev, pctl->irq_array = devm_kcalloc(&pdev->dev,
IRQ_PER_BANK * pctl->desc->irq_banks, IRQ_PER_BANK * pctl->desc->irq_banks,
@ -1253,8 +1284,14 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
if (!pins) if (!pins)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < pctl->desc->npins; i++) for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
pins[i] = pctl->desc->pins[i].pin; const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
if (pin->variant && !(pctl->variant & pin->variant))
continue;
pins[pin_idx++] = pin->pin;
}
pctrl_desc = devm_kzalloc(&pdev->dev, pctrl_desc = devm_kzalloc(&pdev->dev,
sizeof(*pctrl_desc), sizeof(*pctrl_desc),
@ -1265,7 +1302,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
pctrl_desc->name = dev_name(&pdev->dev); pctrl_desc->name = dev_name(&pdev->dev);
pctrl_desc->owner = THIS_MODULE; pctrl_desc->owner = THIS_MODULE;
pctrl_desc->pins = pins; pctrl_desc->pins = pins;
pctrl_desc->npins = pctl->desc->npins; pctrl_desc->npins = pctl->ngroups;
pctrl_desc->confops = &sunxi_pconf_ops; pctrl_desc->confops = &sunxi_pconf_ops;
pctrl_desc->pctlops = &sunxi_pctrl_ops; pctrl_desc->pctlops = &sunxi_pctrl_ops;
pctrl_desc->pmxops = &sunxi_pmx_ops; pctrl_desc->pmxops = &sunxi_pmx_ops;

View File

@ -83,6 +83,7 @@
#define SUN4I_FUNC_IRQ 6 #define SUN4I_FUNC_IRQ 6
struct sunxi_desc_function { struct sunxi_desc_function {
unsigned long variant;
const char *name; const char *name;
u8 muxval; u8 muxval;
u8 irqbank; u8 irqbank;
@ -91,6 +92,7 @@ struct sunxi_desc_function {
struct sunxi_desc_pin { struct sunxi_desc_pin {
struct pinctrl_pin_desc pin; struct pinctrl_pin_desc pin;
unsigned long variant;
struct sunxi_desc_function *functions; struct sunxi_desc_function *functions;
}; };
@ -128,6 +130,7 @@ struct sunxi_pinctrl {
unsigned *irq_array; unsigned *irq_array;
spinlock_t lock; spinlock_t lock;
struct pinctrl_dev *pctl_dev; struct pinctrl_dev *pctl_dev;
unsigned long variant;
}; };
#define SUNXI_PIN(_pin, ...) \ #define SUNXI_PIN(_pin, ...) \
@ -137,12 +140,27 @@ struct sunxi_pinctrl {
__VA_ARGS__, { } }, \ __VA_ARGS__, { } }, \
} }
#define SUNXI_PIN_VARIANT(_pin, _variant, ...) \
{ \
.pin = _pin, \
.variant = _variant, \
.functions = (struct sunxi_desc_function[]){ \
__VA_ARGS__, { } }, \
}
#define SUNXI_FUNCTION(_val, _name) \ #define SUNXI_FUNCTION(_val, _name) \
{ \ { \
.name = _name, \ .name = _name, \
.muxval = _val, \ .muxval = _val, \
} }
#define SUNXI_FUNCTION_VARIANT(_val, _name, _variant) \
{ \
.name = _name, \
.muxval = _val, \
.variant = _variant, \
}
#define SUNXI_FUNCTION_IRQ(_val, _irq) \ #define SUNXI_FUNCTION_IRQ(_val, _irq) \
{ \ { \
.name = "irq", \ .name = "irq", \
@ -290,7 +308,11 @@ static inline u32 sunxi_irq_status_offset(u16 irq)
return irq_num * IRQ_STATUS_IRQ_BITS; return irq_num * IRQ_STATUS_IRQ_BITS;
} }
int sunxi_pinctrl_init(struct platform_device *pdev, int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc); const struct sunxi_pinctrl_desc *desc,
unsigned long variant);
#define sunxi_pinctrl_init(_dev, _desc) \
sunxi_pinctrl_init_with_variant(_dev, _desc, 0)
#endif /* __PINCTRL_SUNXI_H */ #endif /* __PINCTRL_SUNXI_H */