summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-nomadik.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 11:21:33 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 11:21:33 -0800
commit505cbedab9c7c565957e64af6348e5d84acd510e (patch)
tree4855caf82c434629432e22f03c96892d73383ba2 /drivers/pinctrl/pinctrl-nomadik.c
parenta8936db7c2d9ef7f8e080d629301e448291f3b75 (diff)
parent7c8f86a451fe8c010eb93c62d4d69727ccdbe435 (diff)
Merge tag 'pinctrl-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl changes from Linus Walleij: "These are the first and major pinctrl changes for the v3.8 merge cycle. Some of this is used as merge base for other trees so I better be early on the trigger. As can be seen from the diffstat the major changes are: - A big conversion of the AT91 pinctrl driver and the associated ACKed platform changes under arch/arm/max-at91 and its device trees. This has been coordinated with the AT91 maintainers to go in through the pinctrl tree. - A larger chunk of changes to the SPEAr drivers and the addition of the "plgpio" driver for the SPEAr as well. - The removal of the remnants of the Nomadik driver from the arch/arm tree and fusion of that into the Nomadik driver and platform data header files. - Some local movement in the Marvell MVEBU drivers, these now have their own subdirectory. - The addition of a chunk of code to gpiolib under drivers/gpio to register gpio-to-pin range mappings from the GPIO side of things. This has been requested by Grant Likely and is now implemented, it is particularly useful for device tree work. Then we have incremental updates all over the place, many of these are cleanups and fixes from Axel Lin who has done a great job of removing minor mistakes and compilation annoyances." * tag 'pinctrl-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (114 commits) ARM: mmp: select PINCTRL for ARCH_MMP pinctrl: Drop selecting PINCONF for MMP2, PXA168 and PXA910 pinctrl: pinctrl-single: Fix error check condition pinctrl: SPEAr: Update error check for unsigned variables gpiolib: Fix use after free in gpiochip_add_pin_range gpiolib: rename pin range arguments pinctrl: single: support gpio request and free pinctrl: generic: add input schmitt disable parameter pinctrl/u300/coh901: stop spawning pinctrl from GPIO pinctrl/u300/coh901: let the gpio_chip register the range pinctrl: add function to retrieve range from pin gpiolib: return any error code from range creation pinctrl: make range registration defer properly gpiolib: rename find_pinctrl_* gpiolib: let gpiochip_add_pin_range() specify offset ARM: at91: pm9g45: add mmc support ARM: at91: Animeo IP: add mmc support ARM: at91: dt: add mmc pinctrl for Atmel reference boards ARM: at91: dt: at91sam9: add mmc pinctrl support ARM: at91/dts: add nodes for atmel hsmci controllers for atmel boards ...
Diffstat (limited to 'drivers/pinctrl/pinctrl-nomadik.c')
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c152
1 files changed, 104 insertions, 48 deletions
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index cf82d9ce4dee..8ef3e85cb011 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -30,26 +30,10 @@
#include <linux/pinctrl/pinconf.h>
/* Since we request GPIOs from ourself */
#include <linux/pinctrl/consumer.h>
-/*
- * For the U8500 archs, use the PRCMU register interface, for the older
- * Nomadik, provide some stubs. The functions using these will only be
- * called on the U8500 series.
- */
-#ifdef CONFIG_ARCH_U8500
-#include <linux/mfd/dbx500-prcmu.h>
-#else
-static inline u32 prcmu_read(unsigned int reg) {
- return 0;
-}
-static inline void prcmu_write(unsigned int reg, u32 value) {}
-static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
-#endif
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach/irq.h>
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-
#include "pinctrl-nomadik.h"
/*
@@ -60,8 +44,6 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
-#define NMK_GPIO_PER_CHIP 32
-
struct nmk_gpio_chip {
struct gpio_chip chip;
struct irq_domain *domain;
@@ -86,10 +68,18 @@ struct nmk_gpio_chip {
u32 lowemi;
};
+/**
+ * struct nmk_pinctrl - state container for the Nomadik pin controller
+ * @dev: containing device pointer
+ * @pctl: corresponding pin controller device
+ * @soc: SoC data for this specific chip
+ * @prcm_base: PRCM register range virtual base
+ */
struct nmk_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
const struct nmk_pinctrl_soc_data *soc;
+ void __iomem *prcm_base;
};
static struct nmk_gpio_chip *
@@ -251,6 +241,15 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
}
+static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
+{
+ u32 val;
+
+ val = readl(reg);
+ val = ((val & ~mask) | (value & mask));
+ writel(val, reg);
+}
+
static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
unsigned offset, unsigned alt_num)
{
@@ -289,8 +288,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -318,8 +317,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -331,7 +330,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
bit = pin_desc->altcx[alt_index].control_bit;
dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n",
offset, alt_index+1);
- prcmu_write_masked(reg, BIT(bit), BIT(bit));
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit));
}
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
@@ -536,7 +535,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
* and its sleep mode based on the specified configuration. The @cfg is
* usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
* are constructed using, and can be further enhanced with, the macros in
- * plat/pincfg.h.
+ * <linux/platform_data/pinctrl-nomadik.h>
*
* If a pin's mode is set to GPIO, it is configured as an input to avoid
* side-effects. The gpio can be manipulated later using standard GPIO API
@@ -675,6 +674,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
}
EXPORT_SYMBOL(nmk_gpio_set_mode);
+static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
+{
+ int i;
+ u16 reg;
+ u8 bit;
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
+ const u16 *gpiocr_regs;
+
+ for (i = 0; i < npct->soc->npins_altcx; i++) {
+ if (npct->soc->altcx_pins[i].pin == gpio)
+ break;
+ }
+ if (i == npct->soc->npins_altcx)
+ return NMK_GPIO_ALT_C;
+
+ pin_desc = npct->soc->altcx_pins + i;
+ gpiocr_regs = npct->soc->prcm_gpiocr_registers;
+ for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) {
+ if (pin_desc->altcx[i].used == true) {
+ reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
+ bit = pin_desc->altcx[i].control_bit;
+ if (readl(npct->prcm_base + reg) & BIT(bit))
+ return NMK_GPIO_ALT_C+i+1;
+ }
+ }
+ return NMK_GPIO_ALT_C;
+}
+
int nmk_gpio_get_mode(int gpio)
{
struct nmk_gpio_chip *nmk_chip;
@@ -1063,8 +1091,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
- unsigned offset, unsigned gpio)
+static void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
@@ -1078,12 +1107,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
[NMK_GPIO_ALT_A] = "altA",
[NMK_GPIO_ALT_B] = "altB",
[NMK_GPIO_ALT_C] = "altC",
+ [NMK_GPIO_ALT_C+1] = "altC1",
+ [NMK_GPIO_ALT_C+2] = "altC2",
+ [NMK_GPIO_ALT_C+3] = "altC3",
+ [NMK_GPIO_ALT_C+4] = "altC4",
};
clk_enable(nmk_chip->clk);
is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
mode = nmk_gpio_get_mode(gpio);
+ if ((mode == NMK_GPIO_ALT_C) && pctldev)
+ mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
gpio, label ?: "(none)",
@@ -1127,13 +1162,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
for (i = 0; i < chip->ngpio; i++, gpio++) {
- nmk_gpio_dbg_show_one(s, chip, i, gpio);
+ nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio);
seq_printf(s, "\n");
}
}
#else
static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
@@ -1250,8 +1286,8 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
-int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct nmk_gpio_chip *nmk_chip = d->host_data;
@@ -1464,7 +1500,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
return;
}
chip = range->gc;
- nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+ nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
}
static struct pinctrl_ops nmk_pinctrl_ops = {
@@ -1635,9 +1671,9 @@ static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
}
-int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
struct nmk_gpio_chip *nmk_chip;
@@ -1666,9 +1702,9 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
@@ -1686,17 +1722,15 @@ static struct pinmux_ops nmk_pinmux_ops = {
.gpio_disable_free = nmk_gpio_disable_free,
};
-int nmk_pin_config_get(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long *config)
+static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
{
/* Not implemented */
return -EINVAL;
}
-int nmk_pin_config_set(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long config)
+static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
{
static const char *pullnames[] = {
[NMK_GPIO_PULL_NONE] = "none",
@@ -1818,6 +1852,7 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device_node *np = pdev->dev.of_node;
struct nmk_pinctrl *npct;
+ struct resource *res;
unsigned int version = 0;
int i;
@@ -1827,9 +1862,14 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (platid)
version = platid->driver_data;
- else if (np)
- version = (unsigned int)
- of_match_device(nmk_pinctrl_match, &pdev->dev)->data;
+ else if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_device(nmk_pinctrl_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+ version = (unsigned int) match->data;
+ }
/* Poke in other ASIC variants here */
if (version == PINCTRL_NMK_STN8815)
@@ -1839,22 +1879,37 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (version == PINCTRL_NMK_DB8540)
nmk_pinctrl_db8540_init(&npct->soc);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ npct->prcm_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!npct->prcm_base) {
+ dev_err(&pdev->dev,
+ "failed to ioremap PRCM registers\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_info(&pdev->dev,
+ "No PRCM base, assume no ALT-Cx control is available\n");
+ }
+
/*
* We need all the GPIO drivers to probe FIRST, or we will not be able
* to obtain references to the struct gpio_chip * for them, and we
* need this to proceed.
*/
for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
- if (!nmk_gpio_chips[i]) {
+ if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) {
dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
return -EPROBE_DEFER;
}
- npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+ npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip;
}
nmk_pinctrl_desc.pins = npct->soc->pins;
nmk_pinctrl_desc.npins = npct->soc->npins;
npct->dev = &pdev->dev;
+
npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
if (!npct->pctl) {
dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
@@ -1889,6 +1944,7 @@ static const struct platform_device_id nmk_pinctrl_id[] = {
{ "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
{ "pinctrl-db8500", PINCTRL_NMK_DB8500 },
{ "pinctrl-db8540", PINCTRL_NMK_DB8540 },
+ { }
};
static struct platform_driver nmk_pinctrl_driver = {