pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
/*
|
|
|
|
* Marvell PXA2xx family pin control
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 Robert Jarzmik
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/pinctrl/pinconf.h>
|
|
|
|
#include <linux/pinctrl/pinconf-generic.h>
|
|
|
|
#include <linux/pinctrl/pinmux.h>
|
|
|
|
#include <linux/pinctrl/pinctrl.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
|
|
#include "../pinctrl-utils.h"
|
|
|
|
#include "pinctrl-pxa2xx.h"
|
|
|
|
|
|
|
|
static int pxa2xx_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
return pctl->ngroups;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *pxa2xx_pctrl_get_group_name(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned tgroup)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct pxa_pinctrl_group *group = pctl->groups + tgroup;
|
|
|
|
|
|
|
|
return group->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pxa2xx_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned tgroup,
|
|
|
|
const unsigned **pins,
|
|
|
|
unsigned *num_pins)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct pxa_pinctrl_group *group = pctl->groups + tgroup;
|
|
|
|
|
|
|
|
*pins = (unsigned *)&group->pin;
|
|
|
|
*num_pins = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct pinctrl_ops pxa2xx_pctl_ops = {
|
|
|
|
#ifdef CONFIG_OF
|
|
|
|
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
|
|
|
.dt_free_map = pinctrl_utils_dt_free_map,
|
|
|
|
#endif
|
|
|
|
.get_groups_count = pxa2xx_pctrl_get_groups_count,
|
|
|
|
.get_group_name = pxa2xx_pctrl_get_group_name,
|
|
|
|
.get_group_pins = pxa2xx_pctrl_get_group_pins,
|
|
|
|
};
|
|
|
|
|
2015-11-21 18:04:50 +00:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2015-11-21 18:04:51 +00:00
|
|
|
static int pxa2xx_pconf_group_get(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned group,
|
|
|
|
unsigned long *config)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct pxa_pinctrl_group *g = pctl->groups + group;
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned pin = g->pin;
|
|
|
|
void __iomem *pgsr = pctl->base_pgsr[pin / 32];
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&pctl->lock, flags);
|
|
|
|
val = readl_relaxed(pgsr) & BIT(pin % 32);
|
|
|
|
*config = val ? PIN_CONFIG_LOW_POWER_MODE : 0;
|
|
|
|
spin_unlock_irqrestore(&pctl->lock, flags);
|
|
|
|
|
|
|
|
dev_dbg(pctl->dev, "get sleep gpio state(pin=%d) %d\n",
|
|
|
|
pin, !!val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pxa2xx_pconf_group_set(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned group,
|
|
|
|
unsigned long *configs,
|
|
|
|
unsigned num_configs)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct pxa_pinctrl_group *g = pctl->groups + group;
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned pin = g->pin;
|
|
|
|
void __iomem *pgsr = pctl->base_pgsr[pin / 32];
|
|
|
|
int i, is_set = 0;
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
for (i = 0; i < num_configs; i++) {
|
|
|
|
switch (pinconf_to_config_param(configs[i])) {
|
|
|
|
case PIN_CONFIG_LOW_POWER_MODE:
|
|
|
|
is_set = pinconf_to_config_argument(configs[i]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_dbg(pctl->dev, "set sleep gpio state(pin=%d) %d\n",
|
|
|
|
pin, is_set);
|
|
|
|
|
|
|
|
spin_lock_irqsave(&pctl->lock, flags);
|
|
|
|
val = readl_relaxed(pgsr);
|
|
|
|
val = (val & ~BIT(pin % 32)) | (is_set ? BIT(pin % 32) : 0);
|
|
|
|
writel_relaxed(val, pgsr);
|
|
|
|
spin_unlock_irqrestore(&pctl->lock, flags);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct pinconf_ops pxa2xx_pconf_ops = {
|
|
|
|
.pin_config_group_get = pxa2xx_pconf_group_get,
|
|
|
|
.pin_config_group_set = pxa2xx_pconf_group_set,
|
|
|
|
.is_generic = true,
|
|
|
|
};
|
|
|
|
|
pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
static struct pinctrl_desc pxa2xx_pinctrl_desc = {
|
2015-11-21 18:04:51 +00:00
|
|
|
.confops = &pxa2xx_pconf_ops,
|
pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
.pctlops = &pxa2xx_pctl_ops,
|
2015-11-21 18:04:50 +00:00
|
|
|
.pmxops = &pxa2xx_pinmux_ops,
|
pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct pxa_pinctrl_function *
|
|
|
|
pxa2xx_find_function(struct pxa_pinctrl *pctl, const char *fname,
|
|
|
|
const struct pxa_pinctrl_function *functions)
|
|
|
|
{
|
|
|
|
const struct pxa_pinctrl_function *func;
|
|
|
|
|
|
|
|
for (func = functions; func->name; func++)
|
|
|
|
if (!strcmp(fname, func->name))
|
|
|
|
return func;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pxa2xx_build_functions(struct pxa_pinctrl *pctl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct pxa_pinctrl_function *functions;
|
|
|
|
struct pxa_desc_function *df;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each pin can have at most 6 alternate functions, and 2 gpio functions
|
|
|
|
* which are common to each pin. As there are more than 2 pins without
|
|
|
|
* alternate function, 6 * npins is an absolute high limit of the number
|
|
|
|
* of functions.
|
|
|
|
*/
|
|
|
|
functions = devm_kcalloc(pctl->dev, pctl->npins * 6,
|
|
|
|
sizeof(*functions), GFP_KERNEL);
|
|
|
|
if (!functions)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->npins; i++)
|
|
|
|
for (df = pctl->ppins[i].functions; df->name; df++)
|
|
|
|
if (!pxa2xx_find_function(pctl, df->name, functions))
|
|
|
|
(functions + pctl->nfuncs++)->name = df->name;
|
|
|
|
pctl->functions = devm_kmemdup(pctl->dev, functions,
|
|
|
|
pctl->nfuncs * sizeof(*functions),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pctl->functions)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2015-12-12 21:43:05 +00:00
|
|
|
devm_kfree(pctl->dev, functions);
|
pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pxa2xx_build_groups(struct pxa_pinctrl *pctl)
|
|
|
|
{
|
|
|
|
int i, j, ngroups;
|
|
|
|
struct pxa_pinctrl_function *func;
|
|
|
|
struct pxa_desc_function *df;
|
|
|
|
char **gtmp;
|
|
|
|
|
|
|
|
gtmp = devm_kmalloc_array(pctl->dev, pctl->npins, sizeof(*gtmp),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!gtmp)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->nfuncs; i++) {
|
|
|
|
ngroups = 0;
|
|
|
|
for (j = 0; j < pctl->npins; j++)
|
|
|
|
for (df = pctl->ppins[j].functions; df->name;
|
|
|
|
df++)
|
|
|
|
if (!strcmp(pctl->functions[i].name,
|
|
|
|
df->name))
|
|
|
|
gtmp[ngroups++] = (char *)
|
|
|
|
pctl->ppins[j].pin.name;
|
|
|
|
func = pctl->functions + i;
|
|
|
|
func->ngroups = ngroups;
|
|
|
|
func->groups =
|
|
|
|
devm_kmalloc_array(pctl->dev, ngroups,
|
|
|
|
sizeof(char *), GFP_KERNEL);
|
|
|
|
if (!func->groups)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(func->groups, gtmp, ngroups * sizeof(*gtmp));
|
|
|
|
}
|
|
|
|
|
2015-12-12 21:43:05 +00:00
|
|
|
devm_kfree(pctl->dev, gtmp);
|
pinctrl: pxa: pxa2xx: add pin control skeleton
Add a pincontrol driver for pxa2xx architecture, encompassing all pxa25x
and pxa27x variants. This is only the pin muxing part of the driver.
One specific consideration is also the memory space (MMIO), which is
intertwined with the GPIO registers. To make things worse, the GPIO
direction register also affect pin muxing, as it chooses the "kind" of
pin, ie. the 4 output functions or 4 input functions.
The mapping between pinctrl notions and PXA Technical Reference Manual
is as follows :
- a pin is obviously a pin
- a group is also a pin, ie. group P101 is the pin 101
- a mux function is an alternate function
(ie. gpio-in, gpio-out, MMCLK, BTRTS, etc ...)
The individual architecture (pxa27x, pxa25x) instantiate a pin control
by providing a table of pins, each pin being provided a list of
PXA_FUNCTION (alternate functions).
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2015-11-21 18:04:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pxa2xx_build_state(struct pxa_pinctrl *pctl,
|
|
|
|
const struct pxa_desc_pin *ppins, int npins)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl_group *group;
|
|
|
|
struct pinctrl_pin_desc *pins;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
pctl->npins = npins;
|
|
|
|
pctl->ppins = ppins;
|
|
|
|
pctl->ngroups = npins;
|
|
|
|
|
|
|
|
pctl->desc.npins = npins;
|
|
|
|
pins = devm_kcalloc(pctl->dev, npins, sizeof(*pins), GFP_KERNEL);
|
|
|
|
if (!pins)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
pctl->desc.pins = pins;
|
|
|
|
for (i = 0; i < npins; i++)
|
|
|
|
pins[i] = ppins[i].pin;
|
|
|
|
|
|
|
|
pctl->groups = devm_kmalloc_array(pctl->dev, pctl->ngroups,
|
|
|
|
sizeof(*pctl->groups), GFP_KERNEL);
|
|
|
|
if (!pctl->groups)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < npins; i++) {
|
|
|
|
group = pctl->groups + i;
|
|
|
|
group->name = ppins[i].pin.name;
|
|
|
|
group->pin = ppins[i].pin.number;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = pxa2xx_build_functions(pctl);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = pxa2xx_build_groups(pctl);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pxa2xx_pinctrl_init(struct platform_device *pdev,
|
|
|
|
const struct pxa_desc_pin *ppins, int npins,
|
|
|
|
void __iomem *base_gafr[], void __iomem *base_gpdr[],
|
|
|
|
void __iomem *base_pgsr[])
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl;
|
|
|
|
int ret, i, maxpin = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < npins; i++)
|
|
|
|
maxpin = max_t(int, ppins[i].pin.number, maxpin);
|
|
|
|
|
|
|
|
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
|
|
|
|
if (!pctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
pctl->base_gafr = devm_kcalloc(&pdev->dev, roundup(maxpin, 16),
|
|
|
|
sizeof(*pctl->base_gafr), GFP_KERNEL);
|
|
|
|
pctl->base_gpdr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
|
|
|
|
sizeof(*pctl->base_gpdr), GFP_KERNEL);
|
|
|
|
pctl->base_pgsr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
|
|
|
|
sizeof(*pctl->base_pgsr), GFP_KERNEL);
|
|
|
|
if (!pctl->base_gafr || !pctl->base_gpdr || !pctl->base_pgsr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
platform_set_drvdata(pdev, pctl);
|
|
|
|
spin_lock_init(&pctl->lock);
|
|
|
|
|
|
|
|
pctl->dev = &pdev->dev;
|
|
|
|
pctl->desc = pxa2xx_pinctrl_desc;
|
|
|
|
pctl->desc.name = dev_name(&pdev->dev);
|
|
|
|
pctl->desc.owner = THIS_MODULE;
|
|
|
|
|
|
|
|
for (i = 0; i < roundup(maxpin, 16); i += 16)
|
|
|
|
pctl->base_gafr[i / 16] = base_gafr[i / 16];
|
|
|
|
for (i = 0; i < roundup(maxpin, 32); i += 32) {
|
|
|
|
pctl->base_gpdr[i / 32] = base_gpdr[i / 32];
|
|
|
|
pctl->base_pgsr[i / 32] = base_pgsr[i / 32];
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = pxa2xx_build_state(pctl, ppins, npins);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
pctl->pctl_dev = pinctrl_register(&pctl->desc, &pdev->dev, pctl);
|
|
|
|
if (IS_ERR(pctl->pctl_dev)) {
|
|
|
|
dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
|
|
|
|
return PTR_ERR(pctl->pctl_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_info(&pdev->dev, "initialized pxa2xx pinctrl driver\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pxa2xx_pinctrl_exit(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct pxa_pinctrl *pctl = platform_get_drvdata(pdev);
|
|
|
|
|
|
|
|
pinctrl_unregister(pctl->pctl_dev);
|
|
|
|
return 0;
|
|
|
|
}
|