Commit d530ef9b authored by Robert Jarzmik's avatar Robert Jarzmik Committed by Linus Walleij

pinctrl: pxa: pxa2xx: add pin muxing

The driver is inspired from the sunxi driver. The pxa architecture
specificities leading to the driver are :
 - each pin has 8 possible alternate functions
 - 4 of these are output kind
 - 4 of these are input kind
 - there is always a "gpio input" and "gpio output" function
 - the function matrix is very scattered :
   - some functions can be found on 5 different pads
   - the number of functions is greater than the number of pins
   - there is no "topology" grouping of pins (such as all SPI in one
     corner of the die)
Signed-off-by: default avatarRobert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 73317712
......@@ -64,8 +64,129 @@ static const struct pinctrl_ops pxa2xx_pctl_ops = {
.get_group_pins = pxa2xx_pctrl_get_group_pins,
};
static struct pxa_desc_function *
pxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name,
const char *func_name)
{
int i;
struct pxa_desc_function *df;
for (i = 0; i < pctl->npins; i++) {
const struct pxa_desc_pin *pin = pctl->ppins + i;
if (!strcmp(pin->pin.name, pin_name))
for (df = pin->functions; df->name; df++)
if (!strcmp(df->name, func_name))
return df;
}
return NULL;
}
static int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned pin,
bool input)
{
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
unsigned long flags;
uint32_t val;
void __iomem *gpdr;
gpdr = pctl->base_gpdr[pin / 32];
dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n",
pin, !input);
spin_lock_irqsave(&pctl->lock, flags);
val = readl_relaxed(gpdr);
val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32));
writel_relaxed(val, gpdr);
spin_unlock_irqrestore(&pctl->lock, flags);
return 0;
}
static const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
unsigned function)
{
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct pxa_pinctrl_function *pf = pctl->functions + function;
return pf->name;
}
static int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev)
{
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
return pctl->nfuncs;
}
static int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
unsigned function,
const char * const **groups,
unsigned * const num_groups)
{
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct pxa_pinctrl_function *pf = pctl->functions + function;
*groups = pf->groups;
*num_groups = pf->ngroups;
return 0;
}
static int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function,
unsigned tgroup)
{
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct pxa_pinctrl_group *group = pctl->groups + tgroup;
struct pxa_desc_function *df;
int pin, shift;
unsigned long flags;
void __iomem *gafr, *gpdr;
u32 val;
df = pxa_desc_by_func_group(pctl, group->name,
(pctl->functions + function)->name);
if (!df)
return -EINVAL;
pin = group->pin;
gafr = pctl->base_gafr[pin / 16];
gpdr = pctl->base_gpdr[pin / 32];
shift = (pin % 16) << 1;
dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n",
pin, df->muxval >> 1, df->muxval & 0x1);
spin_lock_irqsave(&pctl->lock, flags);
val = readl_relaxed(gafr);
val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift);
writel_relaxed(val, gafr);
val = readl_relaxed(gpdr);
val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0);
writel_relaxed(val, gpdr);
spin_unlock_irqrestore(&pctl->lock, flags);
return 0;
}
static const struct pinmux_ops pxa2xx_pinmux_ops = {
.get_functions_count = pxa2xx_get_functions_count,
.get_function_name = pxa2xx_pmx_get_func_name,
.get_function_groups = pxa2xx_pmx_get_func_groups,
.set_mux = pxa2xx_pmx_set_mux,
.gpio_set_direction = pxa2xx_pmx_gpio_set_direction,
};
static struct pinctrl_desc pxa2xx_pinctrl_desc = {
.pctlops = &pxa2xx_pctl_ops,
.pmxops = &pxa2xx_pinmux_ops,
};
static const struct pxa_pinctrl_function *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment