pinctrl: zynqmp: Support muxing individual pins
While muxing groups of pins at once can be convenient for large interfaces, it can also be rigid. This is because the group is set to all pins which support a particular function, even though not all pins may be used. For example, the sdhci0 function may be used with a 8-bit eMMC, 4-bit SD card, or even a 1-bit SD card. In these cases, the extra pins may be repurposed for other uses, but this is not currently allowed. There is not too much point in pin "groups" when there are not actual pin groups at the hardware level. The pins can all be muxed individually, so there's no point in adding artificial groups on top. Just mux the pins like the hardware allows. To this effect, add a new group for each pin which can be muxed. These groups are part of each function the pin can be muxed to. We treat group selectors beyond the number of groups as "pin" groups. To set this up, we initialize groups before functions, and then create a bitmap of used pins for each function. These used pins are appended to the function's list of groups. Signed-off-by: Sean Anderson <sean.anderson@linux.dev> Reviewed-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> Acked-by: Michal Simek <michal.simek@amd.com> Link: https://lore.kernel.org/r/20240610223550.2449230-3-sean.anderson@linux.dev Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
58ba921150
commit
f28cbab9bb
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
|
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
|
||||||
|
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
@ -97,7 +98,7 @@ static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
|||||||
{
|
{
|
||||||
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
return pctrl->ngroups;
|
return pctrl->ngroups + zynqmp_desc.npins;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev,
|
static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||||
@ -105,7 +106,10 @@ static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev,
|
|||||||
{
|
{
|
||||||
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
|
if (selector < pctrl->ngroups)
|
||||||
return pctrl->groups[selector].name;
|
return pctrl->groups[selector].name;
|
||||||
|
|
||||||
|
return zynqmp_desc.pins[selector - pctrl->ngroups].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||||
@ -115,8 +119,13 @@ static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
|||||||
{
|
{
|
||||||
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
|
if (selector < pctrl->ngroups) {
|
||||||
*pins = pctrl->groups[selector].pins;
|
*pins = pctrl->groups[selector].pins;
|
||||||
*npins = pctrl->groups[selector].npins;
|
*npins = pctrl->groups[selector].npins;
|
||||||
|
} else {
|
||||||
|
*pins = &zynqmp_desc.pins[selector - pctrl->ngroups].number;
|
||||||
|
*npins = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -197,17 +206,16 @@ static int zynqmp_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|||||||
unsigned int function,
|
unsigned int function,
|
||||||
unsigned int group)
|
unsigned int group)
|
||||||
{
|
{
|
||||||
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
const unsigned int *pins;
|
||||||
const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[group];
|
unsigned int npins;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
for (i = 0; i < pgrp->npins; i++) {
|
zynqmp_pctrl_get_group_pins(pctldev, group, &pins, &npins);
|
||||||
unsigned int pin = pgrp->pins[i];
|
for (i = 0; i < npins; i++) {
|
||||||
|
ret = zynqmp_pm_pinctrl_set_function(pins[i], function);
|
||||||
ret = zynqmp_pm_pinctrl_set_function(pin, function);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(pctldev->dev, "set mux failed for pin %u\n",
|
dev_err(pctldev->dev, "set mux failed for pin %u\n",
|
||||||
pin);
|
pins[i]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,12 +475,13 @@ static int zynqmp_pinconf_group_set(struct pinctrl_dev *pctldev,
|
|||||||
unsigned long *configs,
|
unsigned long *configs,
|
||||||
unsigned int num_configs)
|
unsigned int num_configs)
|
||||||
{
|
{
|
||||||
|
const unsigned int *pins;
|
||||||
|
unsigned int npins;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[selector];
|
|
||||||
|
|
||||||
for (i = 0; i < pgrp->npins; i++) {
|
zynqmp_pctrl_get_group_pins(pctldev, selector, &pins, &npins);
|
||||||
ret = zynqmp_pinconf_cfg_set(pctldev, pgrp->pins[i], configs,
|
for (i = 0; i < npins; i++) {
|
||||||
|
ret = zynqmp_pinconf_cfg_set(pctldev, pins[i], configs,
|
||||||
num_configs);
|
num_configs);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -560,10 +569,12 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
|
|||||||
{
|
{
|
||||||
u16 resp[NUM_GROUPS_PER_RESP] = {0};
|
u16 resp[NUM_GROUPS_PER_RESP] = {0};
|
||||||
const char **fgroups;
|
const char **fgroups;
|
||||||
int ret, index, i;
|
int ret, index, i, pin;
|
||||||
|
unsigned int npins;
|
||||||
|
unsigned long *used_pins __free(bitmap) =
|
||||||
|
bitmap_zalloc(zynqmp_desc.npins, GFP_KERNEL);
|
||||||
|
|
||||||
fgroups = devm_kcalloc(dev, func->ngroups, sizeof(*fgroups), GFP_KERNEL);
|
if (!used_pins)
|
||||||
if (!fgroups)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (index = 0; index < func->ngroups; index += NUM_GROUPS_PER_RESP) {
|
for (index = 0; index < func->ngroups; index += NUM_GROUPS_PER_RESP) {
|
||||||
@ -578,23 +589,37 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
|
|||||||
if (resp[i] == RESERVED_GROUP)
|
if (resp[i] == RESERVED_GROUP)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fgroups[index + i] = devm_kasprintf(dev, GFP_KERNEL,
|
|
||||||
"%s_%d_grp",
|
|
||||||
func->name,
|
|
||||||
index + i);
|
|
||||||
if (!fgroups[index + i])
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
groups[resp[i]].name = devm_kasprintf(dev, GFP_KERNEL,
|
groups[resp[i]].name = devm_kasprintf(dev, GFP_KERNEL,
|
||||||
"%s_%d_grp",
|
"%s_%d_grp",
|
||||||
func->name,
|
func->name,
|
||||||
index + i);
|
index + i);
|
||||||
if (!groups[resp[i]].name)
|
if (!groups[resp[i]].name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (pin = 0; pin < groups[resp[i]].npins; pin++)
|
||||||
|
__set_bit(groups[resp[i]].pins[pin], used_pins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
npins = bitmap_weight(used_pins, zynqmp_desc.npins);
|
||||||
|
fgroups = devm_kcalloc(dev, size_add(func->ngroups, npins),
|
||||||
|
sizeof(*fgroups), GFP_KERNEL);
|
||||||
|
if (!fgroups)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < func->ngroups; i++) {
|
||||||
|
fgroups[i] = devm_kasprintf(dev, GFP_KERNEL, "%s_%d_grp",
|
||||||
|
func->name, i);
|
||||||
|
if (!fgroups[i])
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pin = 0;
|
||||||
|
for_each_set_bit(pin, used_pins, zynqmp_desc.npins)
|
||||||
|
fgroups[i++] = zynqmp_desc.pins[pin].name;
|
||||||
|
|
||||||
func->groups = fgroups;
|
func->groups = fgroups;
|
||||||
|
func->ngroups += npins;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -772,6 +797,10 @@ static int zynqmp_pinctrl_prepare_function_info(struct device *dev,
|
|||||||
if (!groups)
|
if (!groups)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl->ngroups);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
for (i = 0; i < pctrl->nfuncs; i++) {
|
for (i = 0; i < pctrl->nfuncs; i++) {
|
||||||
ret = zynqmp_pinctrl_prepare_func_groups(dev, i, &funcs[i],
|
ret = zynqmp_pinctrl_prepare_func_groups(dev, i, &funcs[i],
|
||||||
groups);
|
groups);
|
||||||
@ -779,10 +808,6 @@ static int zynqmp_pinctrl_prepare_function_info(struct device *dev,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl->ngroups);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
pctrl->funcs = funcs;
|
pctrl->funcs = funcs;
|
||||||
pctrl->groups = groups;
|
pctrl->groups = groups;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user