diff options
Diffstat (limited to 'drivers/pinctrl')
49 files changed, 4486 insertions, 386 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 011133772d2..c31aeb01bb0 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -26,6 +26,15 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. +config PINCTRL_AT91 + bool "AT91 pinctrl driver" + depends on OF + depends on ARCH_AT91 + select PINMUX + select PINCONF + help + Say Y here to enable the at91 pinctrl driver + config PINCTRL_BCM2835 bool select PINMUX @@ -87,21 +96,18 @@ config PINCTRL_MMP2 bool "MMP2 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_MXS bool + select PINMUX + select PINCONF config PINCTRL_IMX23 bool - select PINMUX - select PINCONF select PINCTRL_MXS config PINCTRL_IMX28 bool - select PINMUX - select PINCONF select PINCTRL_MXS config PINCTRL_NOMADIK @@ -126,13 +132,11 @@ config PINCTRL_PXA168 bool "PXA168 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_PXA910 bool "PXA910 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" @@ -143,23 +147,21 @@ config PINCTRL_SINGLE This selects the device tree based generic pinctrl driver. config PINCTRL_SIRF - bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_PRIMA2 + bool "CSR SiRFprimaII/SiRFmarco pin controller driver" + depends on ARCH_SIRF select PINMUX config PINCTRL_TEGRA bool + select PINMUX + select PINCONF config PINCTRL_TEGRA20 bool - select PINMUX - select PINCONF select PINCTRL_TEGRA config PINCTRL_TEGRA30 bool - select PINMUX - select PINCONF select PINCTRL_TEGRA config PINCTRL_U300 @@ -178,7 +180,7 @@ config PINCTRL_COH901 ports of 8 GPIO pins each. config PINCTRL_SAMSUNG - bool "Samsung pinctrl driver" + bool depends on OF && GPIOLIB select PINMUX select PINCONF @@ -188,6 +190,11 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG +config PINCTRL_EXYNOS5440 + bool "Samsung EXYNOS5440 SoC pinctrl driver" + select PINMUX + select PINCONF + source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 3cb6a0a668a..fc4606f27dc 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y) obj-$(CONFIG_PINCTRL) += devicetree.o endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o +obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o @@ -36,6 +37,7 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o +obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index cec6072cd7c..5cdee8669ea 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,62 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname); + + /* + * If we can't find this device, let's assume that is because + * it has not probed yet, so the driver trying to register this + * range need to defer probing. + */ + if (!pctldev) + return ERR_PTR(-EPROBE_DEFER); + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} +EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range); + +/** + * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin + * @pctldev: the pin controller device to look in + * @pin: a controller-local number to find the range for + */ +struct pinctrl_gpio_range * +pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + struct pinctrl_gpio_range *range = NULL; + + /* Loop over the ranges */ + list_for_each_entry(range, &pctldev->gpio_ranges, node) { + /* Check if we're in the valid range */ + if (pin >= range->pin_base && + pin < range->pin_base + range->npins) { + return range; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin); + +/** + * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller + * @pctldev: pin controller device to remove the range from + * @range: the GPIO range to remove + */ +void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range) +{ + mutex_lock(&pinctrl_mutex); + list_del(&range->node); + mutex_unlock(&pinctrl_mutex); +} +EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); + /** * pinctrl_get_group_selector() - returns the group selector for a group * @pctldev: the pin controller handling the group diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index fcb1de45473..fe2d1af7cfa 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) +{ + struct pinctrl_dev *pctldev; + + pctldev = find_pinctrl_by_of_node(np); + if (!pctldev) + return NULL; + + return pctldev; +} + static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config) { diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 33fbaeaa65d..833a3645815 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -41,6 +41,7 @@ struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), + PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c new file mode 100644 index 00000000000..c5e75715718 --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91.c @@ -0,0 +1,1634 @@ +/* + * at91 pinctrl driver based on at91 pinmux core + * + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * Under GPLv2 only + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +/* Since we request GPIOs from ourself */ +#include <linux/pinctrl/consumer.h> + +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/at91_pio.h> + +#include "core.h" + +#define MAX_NB_GPIO_PER_BANK 32 + +struct at91_pinctrl_mux_ops; + +struct at91_gpio_chip { + struct gpio_chip chip; + struct pinctrl_gpio_range range; + struct at91_gpio_chip *next; /* Bank sharing same clock */ + int pioc_hwirq; /* PIO bank interrupt identifier on AIC */ + int pioc_virq; /* PIO bank Linux virtual interrupt */ + int pioc_idx; /* PIO bank index */ + void __iomem *regbase; /* PIO bank virtual address */ + struct clk *clock; /* associated clock */ + struct irq_domain *domain; /* associated irq domain */ + struct at91_pinctrl_mux_ops *ops; /* ops */ +}; + +#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip) + +static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS]; + +static int gpio_banks; + +#define PULL_UP (1 << 0) +#define MULTI_DRIVE (1 << 1) +#define DEGLITCH (1 << 2) +#define PULL_DOWN (1 << 3) +#define DIS_SCHMIT (1 << 4) +#define DEBOUNCE (1 << 16) +#define DEBOUNCE_VAL_SHIFT 17 +#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) + +/** + * struct at91_pmx_func - describes AT91 pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @ngroups: the number of groups + */ +struct at91_pmx_func { + const char *name; + const char **groups; + unsigned ngroups; +}; + +enum at91_mux { + AT91_MUX_GPIO = 0, + AT91_MUX_PERIPH_A = 1, + AT91_MUX_PERIPH_B = 2, + AT91_MUX_PERIPH_C = 3, + AT91_MUX_PERIPH_D = 4, +}; + +/** + * struct at91_pmx_pin - describes an At91 pin mux + * @bank: the bank of the pin + * @pin: the pin number in the @bank + * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function. + * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc... + */ +struct at91_pmx_pin { + uint32_t bank; + uint32_t pin; + enum at91_mux mux; + unsigned long conf; +}; + +/** + * struct at91_pin_group - describes an At91 pin group + * @name: the name of this specific pin group + * @pins_conf: the mux mode for each pin in this group. The size of this + * array is the same as pins. + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + */ +struct at91_pin_group { + const char *name; + struct at91_pmx_pin *pins_conf; + unsigned int *pins; + unsigned npins; +}; + +/** + * struct at91_pinctrl_mux_ops - describes an At91 mux ops group + * on new IP with support for periph C and D the way to mux in + * periph A and B has changed + * So provide the right call back + * if not present means the IP does not support it + * @get_periph: return the periph mode configured + * @mux_A_periph: mux as periph A + * @mux_B_periph: mux as periph B + * @mux_C_periph: mux as periph C + * @mux_D_periph: mux as periph D + * @get_deglitch: get deglitch status + * @set_deglitch: enable/disable deglitch + * @get_debounce: get debounce status + * @set_debounce: enable/disable debounce + * @get_pulldown: get pulldown status + * @set_pulldown: enable/disable pulldown + * @get_schmitt_trig: get schmitt trigger status + * @disable_schmitt_trig: disable schmitt trigger + * @irq_type: return irq type + */ +struct at91_pinctrl_mux_ops { + enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask); + void (*mux_A_periph)(void __iomem *pio, unsigned mask); + void (*mux_B_periph)(void __iomem *pio, unsigned mask); + void (*mux_C_periph)(void __iomem *pio, unsigned mask); + void (*mux_D_periph)(void __iomem *pio, unsigned mask); + bool (*get_deglitch)(void __iomem *pio, unsigned pin); + void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on); + bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); + void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div); + bool (*get_pulldown)(void __iomem *pio, unsigned pin); + void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on); + bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); + void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask); + /* irq */ + int (*irq_type)(struct irq_data *d, unsigned type); +}; + +static int gpio_irq_type(struct irq_data *d, unsigned type); +static int alt_gpio_irq_type(struct irq_data *d, unsigned type); + +struct at91_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + + int nbanks; + + uint32_t *mux_mask; + int nmux; + + struct at91_pmx_func *functions; + int nfunctions; + + struct at91_pin_group *groups; + int ngroups; + + struct at91_pinctrl_mux_ops *ops; +}; + +static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name( + const struct at91_pinctrl *info, + const char *name) +{ + const struct at91_pin_group *grp = NULL; + int i; + + for (i = 0; i < info->ngroups; i++) { + if (strcmp(info->groups[i].name, name)) + continue; + + grp = &info->groups[i]; + dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]); + break; + } + + return grp; +} + +static int at91_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *at91_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *npins) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = at91_pinctrl_find_group_by_name(info, np->name); + if (!grp) { + dev_err(info->dev, "unable to find group for node %s\n", + np->name); + return -EINVAL; + } + + map_num += grp->npins; + new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create mux map */ + parent = of_get_parent(np); + if (!parent) { + kfree(new_map); + return -EINVAL; + } + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = 0; i < grp->npins; i++) { + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[i]); + new_map[i].data.configs.configs = &grp->pins_conf[i].conf; + new_map[i].data.configs.num_configs = 1; + } + + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, (*map)->data.mux.group, map_num); + + return 0; +} + +static void at91_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ +} + +static struct pinctrl_ops at91_pctrl_ops = { + .get_groups_count = at91_get_groups_count, + .get_group_name = at91_get_group_name, + .get_group_pins = at91_get_group_pins, + .pin_dbg_show = at91_pin_dbg_show, + .dt_node_to_map = at91_dt_node_to_map, + .dt_free_map = at91_dt_free_map, +}; + +static void __iomem * pin_to_controller(struct at91_pinctrl *info, + unsigned int bank) +{ + return gpio_chips[bank]->regbase; +} + +static inline int pin_to_bank(unsigned pin) +{ + return pin /= MAX_NB_GPIO_PER_BANK; +} + +static unsigned pin_to_mask(unsigned int pin) +{ + return 1 << pin; +} + +static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_IDR); +} + +static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1; +} + +static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR)); +} + +static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1; +} + +static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR)); +} + +static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_ASR); +} + +static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_BSR); +} + +static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask) +{ + + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask); + select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1); + + return select + 1; +} + +static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = readl_relaxed(pio + PIO_ABSR) & mask; + + return select + 1; +} + +static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1; +} + +static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) +{ + __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); +} + +static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) +{ + if (is_on) + __raw_writel(mask, pio + PIO_IFSCDR); + at91_mux_set_deglitch(pio, mask, is_on); +} + +static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div) +{ + *div = __raw_readl(pio + PIO_SCDR); + + return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1; +} + +static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, + bool is_on, u32 div) +{ + if (is_on) { + __raw_writel(mask, pio + PIO_IFSCER); + __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); + __raw_writel(mask, pio + PIO_IFER); + } else { + __raw_writel(mask, pio + PIO_IFDR); + } +} + +static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1; +} + +static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on) +{ + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); +} + +static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask) +{ + __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); +} + +static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1; +} + +static struct at91_pinctrl_mux_ops at91rm9200_ops = { + .get_periph = at91_mux_get_periph, + .mux_A_periph = at91_mux_set_A_periph, + .mux_B_periph = at91_mux_set_B_periph, + .get_deglitch = at91_mux_get_deglitch, + .set_deglitch = at91_mux_set_deglitch, + .irq_type = gpio_irq_type, +}; + +static struct at91_pinctrl_mux_ops at91sam9x5_ops = { + .get_periph = at91_mux_pio3_get_periph, + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .get_deglitch = at91_mux_get_deglitch, + .set_deglitch = at91_mux_pio3_set_deglitch, + .get_debounce = at91_mux_pio3_get_debounce, + .set_debounce = at91_mux_pio3_set_debounce, + .get_pulldown = at91_mux_pio3_get_pulldown, + .set_pulldown = at91_mux_pio3_set_pulldown, + .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .irq_type = alt_gpio_irq_type, +}; + +static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin) +{ + if (pin->mux) { + dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf); + } else { + dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->conf); + } +} + +static int pin_check_config(struct at91_pinctrl *info, const char* name, + int index, const struct at91_pmx_pin *pin) +{ + int mux; + + /* check if it's a valid config */ + if (pin->bank >= info->nbanks) { + dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n", + name, index, pin->bank, info->nbanks); + return -EINVAL; + } + + if (pin->pin >= MAX_NB_GPIO_PER_BANK) { + dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n", + name, index, pin->pin, MAX_NB_GPIO_PER_BANK); + return -EINVAL; + } + + if (!pin->mux) + return 0; + + mux = pin->mux - 1; + + if (mux >= info->nmux) { + dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n", + name, index, mux, info->nmux); + return -EINVAL; + } + + if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) { + dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n", + name, index, mux, pin->bank + 'A', pin->pin); + return -EINVAL; + } + + return 0; +} + +static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_PDR); +} + +static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input) +{ + writel_relaxed(mask, pio + PIO_PER); + writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER)); +} + +static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i, ret; + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + /* first check that all the pins of the group are valid with a valid + * paramter */ + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + ret = pin_check_config(info, info->groups[group].name, i, pin); + if (ret) + return ret; + } + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_disable_interrupt(pio, mask); + switch(pin->mux) { + case AT91_MUX_GPIO: + at91_mux_gpio_enable(pio, mask, 1); + break; + case AT91_MUX_PERIPH_A: + info->ops->mux_A_periph(pio, mask); + break; + case AT91_MUX_PERIPH_B: + info->ops->mux_B_periph(pio, mask); + break; + case AT91_MUX_PERIPH_C: + if (!info->ops->mux_C_periph) + return -EINVAL; + info->ops->mux_C_periph(pio, mask); + break; + case AT91_MUX_PERIPH_D: + if (!info->ops->mux_D_periph) + return -EINVAL; + info->ops->mux_D_periph(pio, mask); + break; + } + if (pin->mux) + at91_mux_gpio_disable(pio, mask); + } + + return 0; +} + +static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i; + unsigned mask; + void __iomem *pio; + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_gpio_enable(pio, mask, 1); + } +} + +static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +static int at91_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct at91_gpio_chip *at91_chip; + struct gpio_chip *chip; + unsigned mask; + + if (!range) { + dev_err(npct->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "missing GPIO chip in range\n"); + return -EINVAL; + } + chip = range->gc; + at91_chip = container_of(chip, struct at91_gpio_chip, chip); + + dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); + + mask = 1 << (offset - chip->base); + + dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n", + offset, 'A' + range->id, offset - chip->base, mask); + + writel_relaxed(mask, at91_chip->regbase + PIO_PER); + + return 0; +} + +static void at91_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); + /* Set the pin to some default state, GPIO is usually default */ +} + +static struct pinmux_ops at91_pmx_ops = { + .get_functions_count = at91_pmx_get_funcs_count, + .get_function_name = at91_pmx_get_func_name, + .get_function_groups = at91_pmx_get_groups, + .enable = at91_pmx_enable, + .disable = at91_pmx_disable, + .gpio_request_enable = at91_gpio_request_enable, + .gpio_disable_free = at91_gpio_disable_free, +}; + +static int at91_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + void __iomem *pio; + unsigned pin; + int div; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + pin = pin_id % MAX_NB_GPIO_PER_BANK; + + if (at91_mux_get_multidrive(pio, pin)) + *config |= MULTI_DRIVE; + + if (at91_mux_get_pullup(pio, pin)) + *config |= PULL_UP; + + if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin)) + *config |= DEGLITCH; + if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div)) + *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT); + if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin)) + *config |= PULL_DOWN; + if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin)) + *config |= DIS_SCHMIT; + + return 0; +} + +static int at91_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + + if (config & PULL_UP && config & PULL_DOWN) + return -EINVAL; + + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + if (info->ops->set_deglitch) + info->ops->set_deglitch(pio, mask, config & DEGLITCH); + if (info->ops->set_debounce) + info->ops->set_debounce(pio, mask, config & DEBOUNCE, + (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); + if (info->ops->set_pulldown) + info->ops->set_pulldown(pio, mask, config & PULL_DOWN); + if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) + info->ops->disable_schmitt_trig(pio, mask); + + return 0; +} + +static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + +} + +static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ +} + +static struct pinconf_ops at91_pinconf_ops = { + .pin_config_get = at91_pinconf_get, + .pin_config_set = at91_pinconf_set, + .pin_config_dbg_show = at91_pinconf_dbg_show, + .pin_config_group_dbg_show = at91_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc at91_pinctrl_desc = { + .pctlops = &at91_pctrl_ops, + .pmxops = &at91_pmx_ops, + .confops = &at91_pinconf_ops, + .owner = THIS_MODULE, +}; + +static const char *gpio_compat = "atmel,at91rm9200-gpio"; + +static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info, + struct device_node *np) +{ + int ret = 0; + int size; + const const __be32 *list; + + list = of_get_property(np, "atmel,mux-mask", &size); + if (!list) { + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return -EINVAL; + } + + size /= sizeof(*list); + if (!size || size % info->nbanks) { + dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks); + return -EINVAL; + } + info->nmux = size / info->nbanks; + + info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); + if (!info->mux_mask) { + dev_err(info->dev, "could not alloc mux_mask\n"); + return -ENOMEM; + } + + ret = of_property_read_u32_array(np, "atmel,mux-mask", + info->mux_mask, size); + if (ret) + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return ret; +} + +static int __devinit at91_pinctrl_parse_groups(struct device_node *np, + struct at91_pin_group *grp, + struct at91_pinctrl *info, + u32 index) +{ + struct at91_pmx_pin *pin; + int size; + const const __be32 *list; + int i, j; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is atmel,pins = <bank pin mux CONFIG ...>, + * do sanity check and calculate pins number + */ + list = of_get_property(np, "atmel,pins", &size); + /* we do not check return since it's safe node passed down */ + size /= sizeof(*list); + if (!size || size % 4) { + dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n"); + return -EINVAL; + } + + grp->npins = size / 4; + pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin), + GFP_KERNEL); + grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + if (!grp->pins_conf || !grp->pins) + return -ENOMEM; + + for (i = 0, j = 0; i < size; i += 4, j++) { + pin->bank = be32_to_cpu(*list++); + pin->pin = be32_to_cpu(*list++); + grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin; + pin->mux = be32_to_cpu(*list++); + pin->conf = be32_to_cpu(*list++); + + at91_pin_dbg(info->dev, pin); + pin++; + } + + return 0; +} + +static int __devinit at91_pinctrl_parse_functions(struct device_node *np, + struct at91_pinctrl *info, u32 index) +{ + struct device_node *child; + struct at91_pmx_func *func; + struct at91_pin_group *grp; + int ret; + static u32 grp_index; + u32 i = 0; + + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups <= 0) { + dev_err(info->dev, "no groups defined\n"); + return -EINVAL; + } + func->groups = devm_kzalloc(info->dev, + func->ngroups * sizeof(char *), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[grp_index++]; + ret = at91_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static struct of_device_id at91_pinctrl_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops }, + { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev, + struct at91_pinctrl *info) +{ + int ret = 0; + int i, j; + uint32_t *tmp; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + + if (!np) + return -ENODEV; + + info->dev = &pdev->dev; + info->ops = (struct at91_pinctrl_mux_ops*) + of_match_device(at91_pinctrl_of_match, &pdev->dev)->data; + at91_pinctrl_child_count(info, np); + + if (info->nbanks < 1) { + dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n"); + return -EINVAL; + } + + ret = at91_pinctrl_mux_mask(info, np); + if (ret) + return ret; + + dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux); + + dev_dbg(&pdev->dev, "mux-mask\n"); + tmp = info->mux_mask; + for (i = 0; i < info->nbanks; i++) { + for (j = 0; j < info->nmux; j++, tmp++) { + dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]); + } + } + + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func), + GFP_KERNEL); + if (!info->functions) + return -ENOMEM; + + info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group), + GFP_KERNEL); + if (!info->groups) + return -ENOMEM; + + dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks); + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + + i = 0; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + ret = at91_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +static int __devinit at91_pinctrl_probe(struct platform_device *pdev) +{ + struct at91_pinctrl *info; + struct pinctrl_pin_desc *pdesc; + int ret, i, j ,k; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = at91_pinctrl_probe_dt(pdev, info); + if (ret) + return ret; + + /* + * 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 < info->nbanks; i++) { + if (!gpio_chips[i]) { + dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); + devm_kfree(&pdev->dev, info); + return -EPROBE_DEFER; + } + } + + at91_pinctrl_desc.name = dev_name(&pdev->dev); + at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK; + at91_pinctrl_desc.pins = pdesc = + devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL); + + if (!at91_pinctrl_desc.pins) + return -ENOMEM; + + for (i = 0 , k = 0; i < info->nbanks; i++) { + for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) { + pdesc->number = k; + pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j); + pdesc++; + } + } + + platform_set_drvdata(pdev, info); + info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info); + + if (!info->pctl) { + dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n"); + ret = -EINVAL; + goto err; + } + + /* We will handle a range of GPIO pins */ + for (i = 0; i < info->nbanks; i++) + pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); + + dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n"); + + return 0; + +err: + return ret; +} + +static int __devexit at91_pinctrl_remove(struct platform_device *pdev) +{ + struct at91_pinctrl *info = platform_get_drvdata(pdev); + + pinctrl_unregister(info->pctl); + + return 0; +} + +static int at91_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + /* + * Map back to global GPIO space and request muxing, the direction + * parameter does not matter for this controller. + */ + int gpio = chip->base + offset; + int bank = chip->base / chip->ngpio; + + dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__, + 'A' + bank, offset, gpio); + + return pinctrl_request_gpio(gpio); +} + +static void at91_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + int gpio = chip->base + offset; + + pinctrl_free_gpio(gpio); +} + +static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + PIO_ODR); + return 0; +} + +static int at91_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + u32 pdsr; + + pdsr = readl_relaxed(pio + PIO_PDSR); + return (pdsr & mask) != 0; +} + +static void at91_gpio_set(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); +} + +static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); + writel_relaxed(mask, pio + PIO_OER); + + return 0; +} + +static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + int virq; + + if (offset < chip->ngpio) + virq = irq_create_mapping(at91_gpio->domain, offset); + else + virq = -ENXIO; + + dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", + chip->label, offset + chip->base, virq); + return virq; +} + +#ifdef CONFIG_DEBUG_FS +static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + enum at91_mux mode; + int i; + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + unsigned mask = pin_to_mask(pin); + const char *gpio_label; + u32 pdsr; + + gpio_label = gpiochip_is_requested(chip, i); + if (!gpio_label) + continue; + mode = at91_gpio->ops->get_periph(pio, mask); + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + if (mode == AT91_MUX_GPIO) { + pdsr = readl_relaxed(pio + PIO_PDSR); + + seq_printf(s, "[gpio] %s\n", + pdsr & mask ? + "set" : "clear"); + } else { + seq_printf(s, "[periph %c]\n", + mode + 'A' - 1); + } + } +} +#else +#define at91_gpio_dbg_show NULL +#endif + +/* Several AIC controller irqs are dispatched through this GPIO handler. + * To use any AT91_PIN_* as an externally triggered IRQ, first call + * at91_set_gpio_input() then maybe enable its glitch filter. + * Then just request_irq() with the pin ID; it works like any ARM IRQ + * handler. + * First implementation always triggers on rising and falling edges + * whereas the newer PIO3 can be additionally configured to trigger on + * level, edge with any polarity. + * + * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after + * configuring them with at91_set_a_periph() or at91_set_b_periph(). + * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering. + */ + +static void gpio_irq_mask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IDR); +} + +static void gpio_irq_unmask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IER); +} + +static int gpio_irq_type(struct irq_data *d, unsigned type) +{ + switch (type) { + case IRQ_TYPE_NONE: + case IRQ_TYPE_EDGE_BOTH: + return 0; + default: + return -EINVAL; + } +} + +/* Alternate irq type for PIO3 support */ +static int alt_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_FALLING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_LOW: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_HIGH: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_BOTH: + /* + * disable additional interrupt modes: + * fall back to default behavior + */ + writel_relaxed(mask, pio + PIO_AIMDR); + return 0; + case IRQ_TYPE_NONE: + default: + pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); + return -EINVAL; + } + + /* enable additional interrupt modes */ + writel_relaxed(mask, pio + PIO_AIMER); + + return 0; +} + +#ifdef CONFIG_PM +static int gpio_irq_set_wake(struct irq_data *d, unsigned state) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + unsigned bank = at91_gpio->pioc_idx; + + if (unlikely(bank >= MAX_GPIO_BANKS)) + return -EINVAL; + + irq_set_irq_wake(at91_gpio->pioc_virq, state); + + return 0; +} +#else +#define gpio_irq_set_wake NULL +#endif + +static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .irq_disable = gpio_irq_mask, + .irq_mask = gpio_irq_mask, + .irq_unmask = gpio_irq_unmask, + /* .irq_set_type is set dynamically */ + .irq_set_wake = gpio_irq_set_wake, +}; + +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *idata = irq_desc_get_irq_data(desc); + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata); + void __iomem *pio = at91_gpio->regbase; + unsigned long isr; + int n; + + chained_irq_enter(chip, desc); + for (;;) { + /* Reading ISR acks pending (edge triggered) GPIO interrupts. + * When there none are pending, we're finished unless we need + * to process multiple banks (like ID_PIOCDE on sam9263). + */ + isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR); + if (!isr) { + if (!at91_gpio->next) + break; + at91_gpio = at91_gpio->next; + pio = at91_gpio->regbase; + continue; + } + + for_each_set_bit(n, &isr, BITS_PER_LONG) { + generic_handle_irq(irq_find_mapping(at91_gpio->domain, n)); + } + } + chained_irq_exit(chip, desc); + /* now it may re-trigger */ +} + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct at91_gpio_chip *at91_gpio = h->host_data; + + irq_set_lockdep_class(virq, &gpio_lock_class); + + /* + * Can use the "simple" and not "edge" handler since it's + * shorter, and the AIC handles interrupts sanely. + */ + irq_set_chip_and_handler(virq, &gpio_irqchip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, at91_gpio); + + return 0; +} + +static int at91_gpio_irq_domain_xlate(struct irq_domain *d, + struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_type) +{ + struct at91_gpio_chip *at91_gpio = d->host_data; + int ret; + int pin = at91_gpio->chip.base + intspec[0]; + + if (WARN_ON(intsize < 2)) + return -EINVAL; + *out_hwirq = intspec[0]; + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + + ret = gpio_request(pin, ctrlr->full_name); + if (ret) + return ret; + + ret = gpio_direction_input(pin); + if (ret) + return ret; + + return 0; +} + +static struct irq_domain_ops at91_gpio_ops = { + .map = at91_gpio_irq_map, + .xlate = at91_gpio_irq_domain_xlate, +}; + +static int at91_gpio_of_irq_setup(struct device_node *node, + struct at91_gpio_chip *at91_gpio) +{ + struct at91_gpio_chip *prev = NULL; + struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + + at91_gpio->pioc_hwirq = irqd_to_hwirq(d); + + /* Setup proper .irq_set_type function */ + gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + + /* Disable irqs of this PIO controller */ + writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); + + /* Setup irq domain */ + at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, + &at91_gpio_ops, at91_gpio); + if (!at91_gpio->domain) + panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", + at91_gpio->pioc_idx); + + /* Setup chained handler */ + if (at91_gpio->pioc_idx) + prev = gpio_chips[at91_gpio->pioc_idx - 1]; + + /* The toplevel handler handles one bank of GPIOs, except + * on some SoC it can handles up to three... + * We only set up the handler for the first of the list. + */ + if (prev && prev->next == at91_gpio) + return 0; + + irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); + irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); + + return 0; +} + +/* This structure is replicated for each GPIO block allocated at probe time */ +static struct gpio_chip at91_gpio_template = { + .request = at91_gpio_request, + .free = at91_gpio_free, + .direction_input = at91_gpio_direction_input, + .get = at91_gpio_get, + .direction_output = at91_gpio_direction_output, + .set = at91_gpio_set, + .to_irq = at91_gpio_to_irq, + .dbg_show = at91_gpio_dbg_show, + .can_sleep = 0, + .ngpio = MAX_NB_GPIO_PER_BANK, +}; + +static void __devinit at91_gpio_probe_fixup(void) +{ + unsigned i; + struct at91_gpio_chip *at91_gpio, *last = NULL; + + for (i = 0; i < gpio_banks; i++) { + at91_gpio = gpio_chips[i]; + + /* + * GPIO controller are grouped on some SoC: + * PIOC, PIOD and PIOE can share the same IRQ line + */ + if (last && last->pioc_virq == at91_gpio->pioc_virq) + last->next = at91_gpio; + last = at91_gpio; + } +} + +static struct of_device_id at91_gpio_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, + { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + struct at91_gpio_chip *at91_chip = NULL; + struct gpio_chip *chip; + struct pinctrl_gpio_range *range; + int ret = 0; + int irq, i; + int alias_idx = of_alias_get_id(np, "gpio"); + uint32_t ngpio; + char **names; + + BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips)); + if (gpio_chips[alias_idx]) { + ret = -EBUSY; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto err; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err; + } + + at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL); + if (!at91_chip) { + ret = -ENOMEM; + goto err; + } + + at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res); + if (!at91_chip->regbase) { + dev_err(&pdev->dev, "failed to map registers, ignoring.\n"); + ret = -EBUSY; + goto err; + } + + at91_chip->ops = (struct at91_pinctrl_mux_ops*) + of_match_device(at91_gpio_of_match, &pdev->dev)->data; + at91_chip->pioc_virq = irq; + at91_chip->pioc_idx = alias_idx; + + at91_chip->clock = clk_get(&pdev->dev, NULL); + if (IS_ERR(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to get clock, ignoring.\n"); + goto err; + } + + if (clk_prepare(at91_chip->clock)) + goto clk_prep_err; + + /* enable PIO controller's clock */ + if (clk_enable(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to enable clock, ignoring.\n"); + goto clk_err; + } + + at91_chip->chip = at91_gpio_template; + + chip = &at91_chip->chip; + chip->of_node = np; + chip->label = dev_name(&pdev->dev); + chip->dev = &pdev->dev; + chip->owner = THIS_MODULE; + chip->base = alias_idx * MAX_NB_GPIO_PER_BANK; + + if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) { + if (ngpio >= MAX_NB_GPIO_PER_BANK) + pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n", + alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); + else + chip->ngpio = ngpio; + } + + names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL); + + if (!names) { + ret = -ENOMEM; + goto clk_err; + } + + for (i = 0; i < chip->ngpio; i++) + names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i); + + chip->names = (const char*const*)names; + + range = &at91_chip->range; + range->name = chip->label; + range->id = alias_idx; + range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK; + + range->npins = chip->ngpio; + range->gc = chip; + + ret = gpiochip_add(chip); + if (ret) + goto clk_err; + + gpio_chips[alias_idx] = at91_chip; + gpio_banks = max(gpio_banks, alias_idx + 1); + + at91_gpio_probe_fixup(); + + at91_gpio_of_irq_setup(np, at91_chip); + + dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase); + + return 0; + +clk_err: + clk_unprepare(at91_chip->clock); +clk_prep_err: + clk_put(at91_chip->clock); +err: + dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx); + + return ret; +} + +static struct platform_driver at91_gpio_driver = { + .driver = { + .name = "gpio-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_gpio_of_match), + }, + .probe = at91_gpio_probe, +}; + +static struct platform_driver at91_pinctrl_driver = { + .driver = { + .name = "pinctrl-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_pinctrl_of_match), + }, + .probe = at91_pinctrl_probe, + .remove = __devexit_p(at91_pinctrl_remove), +}; + +static int __init at91_pinctrl_init(void) +{ + int ret; + + ret = platform_driver_register(&at91_gpio_driver); + if (ret) + return ret; + return platform_driver_register(&at91_pinctrl_driver); +} +arch_initcall(at91_pinctrl_init); + +static void __exit at91_pinctrl_exit(void) +{ + platform_driver_unregister(&at91_pinctrl_driver); +} + +module_exit(at91_pinctrl_exit); +MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>"); +MODULE_DESCRIPTION("Atmel AT91 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index 7e9be18ec2d..0b0e9b49a1b 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -372,7 +372,7 @@ static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_linear_revmap(pc->irq_domain, offset); } -static struct gpio_chip bcm2835_gpio_chip __devinitconst = { +static struct gpio_chip bcm2835_gpio_chip = { .label = MODULE_NAME, .owner = THIS_MODULE, .request = bcm2835_gpio_request, @@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev, return 0; } -struct pinconf_ops bcm2835_pinconf_ops = { +static struct pinconf_ops bcm2835_pinconf_ops = { .pin_config_get = bcm2835_pinconf_get, .pin_config_set = bcm2835_pinconf_set, }; @@ -931,7 +931,7 @@ static struct pinctrl_desc bcm2835_pinctrl_desc = { .owner = THIS_MODULE, }; -static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range __devinitconst = { +static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = { .name = MODULE_NAME, .npins = BCM2835_NUM_GPIOS, }; @@ -1042,7 +1042,7 @@ static int __devinit bcm2835_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit bcm2835_pinctrl_remove(struct platform_device *pdev) +static int bcm2835_pinctrl_remove(struct platform_device *pdev) { struct bcm2835_pinctrl *pc = platform_get_drvdata(pdev); @@ -1052,7 +1052,7 @@ static int __devexit bcm2835_pinctrl_remove(struct platform_device *pdev) return 0; } -static struct of_device_id bcm2835_pinctrl_match[] __devinitconst = { +static struct of_device_id bcm2835_pinctrl_match[] = { { .compatible = "brcm,bcm2835-gpio" }, {} }; diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index b446c964121..fbb37154471 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> @@ -64,10 +65,8 @@ struct u300_gpio { struct gpio_chip chip; struct list_head port_list; struct clk *clk; - struct resource *memres; void __iomem *base; struct device *dev; - int irq_base; u32 stride; /* Register offsets */ u32 pcr; @@ -83,6 +82,7 @@ struct u300_gpio_port { struct list_head node; struct u300_gpio *gpio; char name[8]; + struct irq_domain *domain; int irq; int number; u8 toggle_edge_mode; @@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct u300_gpio *gpio = to_u300_gpio(chip); - int retirq = gpio->irq_base + offset; + int portno = offset >> 3; + struct u300_gpio_port *port = NULL; + struct list_head *p; + int retirq; - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, - retirq); + list_for_each(p, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + if (port->number == portno) + break; + } + if (port == NULL) { + dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", + offset); + return -EINVAL; + } + + /* + * The local hwirqs on the port are the lower three bits, there + * are exactly 8 IRQs per port since they are 8-bit + */ + retirq = irq_find_mapping(port->domain, (offset & 0x7)); + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", + offset, retirq, port->number); return retirq; } @@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; + dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", + d->hwirq, port->name, offset); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; @@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = gpio->irq_base + (port->number << 3) - + irqoffset; + int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", @@ -631,64 +652,86 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio) list_for_each_safe(p, n, &gpio->port_list) { port = list_entry(p, struct u300_gpio_port, node); list_del(&port->node); + if (port->domain) + irq_domain_remove(port->domain); kfree(port); } } +/* + * Here we map a GPIO in the local gpio_chip pin space to a pin in + * the local pinctrl pin space. The pin controller used is + * pinctrl-u300. + */ +struct coh901_pinpair { + unsigned int offset; + unsigned int pin_base; +}; + +#define COH901_PINRANGE(a, b) { .offset = a, .pin_base = b } + +static struct coh901_pinpair coh901_pintable[] = { + COH901_PINRANGE(10, 426), + COH901_PINRANGE(11, 180), + COH901_PINRANGE(12, 165), /* MS/MMC card insertion */ + COH901_PINRANGE(13, 179), + COH901_PINRANGE(14, 178), + COH901_PINRANGE(16, 194), + COH901_PINRANGE(17, 193), + COH901_PINRANGE(18, 192), + COH901_PINRANGE(19, 191), + COH901_PINRANGE(20, 186), + COH901_PINRANGE(21, 185), + COH901_PINRANGE(22, 184), + COH901_PINRANGE(23, 183), + COH901_PINRANGE(24, 182), + COH901_PINRANGE(25, 181), +}; + static int __init u300_gpio_probe(struct platform_device *pdev) { struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); struct u300_gpio *gpio; + struct resource *memres; int err = 0; int portno; u32 val; u32 ifr; int i; - gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); - if (gpio == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) return -ENOMEM; - } gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; - gpio->irq_base = plat->gpio_irq_base; gpio->chip.dev = &pdev->dev; gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; - /* Get GPIO clock */ - gpio->clk = clk_get(gpio->dev, NULL); + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + return -ENODEV; + } + + gpio->base = devm_request_and_ioremap(&pdev->dev, memres); + if (!gpio->base) { + dev_err(gpio->dev, "could not get remap memory\n"); + return -ENOMEM; + } + + gpio->clk = devm_clk_get(gpio->dev, NULL); if (IS_ERR(gpio->clk)) { err = PTR_ERR(gpio->clk); dev_err(gpio->dev, "could not get GPIO clock\n"); - goto err_no_clk; + return err; } + err = clk_prepare_enable(gpio->clk); if (err) { dev_err(gpio->dev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!gpio->memres) { - dev_err(gpio->dev, "could not get GPIO memory resource\n"); - err = -ENODEV; - goto err_no_resource; - } - - if (!request_mem_region(gpio->memres->start, - resource_size(gpio->memres), - "GPIO Controller")) { - err = -ENODEV; - goto err_no_ioregion; - } - - gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); - if (!gpio->base) { - err = -ENOMEM; - goto err_no_ioremap; + return err; } dev_info(gpio->dev, @@ -732,18 +775,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq_byname(pdev, port->name); - dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, port->name); + port->domain = irq_domain_add_linear(pdev->dev.of_node, + U300_GPIO_PINS_PER_PORT, + &irq_domain_simple_ops, + port); + if (!port->domain) { + err = -ENOMEM; + goto err_no_domain; + } + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); irq_set_handler_data(port->irq, port); /* For each GPIO pin set the unique IRQ handler */ for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = gpio->irq_base + (portno << 3) + i; + int irqno = irq_create_mapping(port->domain, i); - dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", - irqno, port->name); + dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", + gpio->chip.base + (port->number << 3) + i, + port->name, irqno); irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, handle_simple_irq); set_irq_flags(irqno, IRQF_VALID); @@ -763,32 +816,31 @@ static int __init u300_gpio_probe(struct platform_device *pdev) goto err_no_chip; } - /* Spawn pin controller device as child of the GPIO, pass gpio chip */ - plat->pinctrl_device->dev.platform_data = &gpio->chip; - err = platform_device_register(plat->pinctrl_device); - if (err) - goto err_no_pinctrl; + /* + * Add pinctrl pin ranges, the pin controller must be registered + * at this point + */ + for (i = 0; i < ARRAY_SIZE(coh901_pintable); i++) { + struct coh901_pinpair *p = &coh901_pintable[i]; + + err = gpiochip_add_pin_range(&gpio->chip, "pinctrl-u300", + p->offset, p->pin_base, 1); + if (err) + goto err_no_range; + } platform_set_drvdata(pdev, gpio); return 0; -err_no_pinctrl: +err_no_range: err = gpiochip_remove(&gpio->chip); err_no_chip: +err_no_domain: err_no_port: u300_gpio_free_ports(gpio); - iounmap(gpio->base); -err_no_ioremap: - release_mem_region(gpio->memres->start, resource_size(gpio->memres)); -err_no_ioregion: -err_no_resource: clk_disable_unprepare(gpio->clk); -err_no_clk_enable: - clk_put(gpio->clk); -err_no_clk: - kfree(gpio); - dev_info(&pdev->dev, "module ERROR:%d\n", err); + dev_err(&pdev->dev, "module ERROR:%d\n", err); return err; } @@ -806,13 +858,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) return err; } u300_gpio_free_ports(gpio); - iounmap(gpio->base); - release_mem_region(gpio->memres->start, - resource_size(gpio->memres)); clk_disable_unprepare(gpio->clk); - clk_put(gpio->clk); platform_set_drvdata(pdev, NULL); - kfree(gpio); return 0; } diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 19fab68a9fb..538b9ddaadf 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -36,6 +36,7 @@ /* list of external wakeup controllers supported */ static const struct of_device_id exynos_wkup_irq_ids[] = { { .compatible = "samsung,exynos4210-wakeup-eint", }, + { } }; static void exynos_gpio_irq_unmask(struct irq_data *irqd) diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c new file mode 100644 index 00000000000..b8635f634e9 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos5440.c @@ -0,0 +1,919 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include "core.h" + +/* EXYNOS5440 GPIO and Pinctrl register offsets */ +#define GPIO_MUX 0x00 +#define GPIO_IE 0x04 +#define GPIO_INT 0x08 +#define GPIO_TYPE 0x0C +#define GPIO_VAL 0x10 +#define GPIO_OE 0x14 +#define GPIO_IN 0x18 +#define GPIO_PE 0x1C +#define GPIO_PS 0x20 +#define GPIO_SR 0x24 +#define GPIO_DS0 0x28 +#define GPIO_DS1 0x2C + +#define EXYNOS5440_MAX_PINS 23 +#define PIN_NAME_LENGTH 10 + +#define GROUP_SUFFIX "-grp" +#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) +#define FUNCTION_SUFFIX "-mux" +#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) + +/* + * pin configuration type and its value are packed together into a 16-bits. + * The upper 8-bits represent the configuration type and the lower 8-bits + * hold the value of the configuration type. + */ +#define PINCFG_TYPE_MASK 0xFF +#define PINCFG_VALUE_SHIFT 8 +#define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) +#define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) +#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) +#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ + PINCFG_VALUE_SHIFT) + +/** + * enum pincfg_type - possible pin configuration types supported. + * @PINCFG_TYPE_PUD: Pull up/down configuration. + * @PINCFG_TYPE_DRV: Drive strength configuration. + * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration. + * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration. + */ +enum pincfg_type { + PINCFG_TYPE_PUD, + PINCFG_TYPE_DRV, + PINCFG_TYPE_SKEW_RATE, + PINCFG_TYPE_INPUT_TYPE +}; + +/** + * struct exynos5440_pin_group: represent group of pins for pincfg setting. + * @name: name of the pin group, used to lookup the group. + * @pins: the pins included in this group. + * @num_pins: number of pins included in this group. + */ +struct exynos5440_pin_group { + const char *name; + const unsigned int *pins; + u8 num_pins; +}; + +/** + * struct exynos5440_pmx_func: represent a pin function. + * @name: name of the pin function, used to lookup the function. + * @groups: one or more names of pin groups that provide this function. + * @num_groups: number of groups included in @groups. + * @function: the function number to be programmed when selected. + */ +struct exynos5440_pmx_func { + const char *name; + const char **groups; + u8 num_groups; + unsigned long function; +}; + +/** + * struct exynos5440_pinctrl_priv_data: driver's private runtime data. + * @reg_base: ioremapped based address of the register space. + * @gc: gpio chip registered with gpiolib. + * @pin_groups: list of pin groups parsed from device tree. + * @nr_groups: number of pin groups available. + * @pmx_functions: list of pin functions parsed from device tree. + * @nr_functions: number of pin functions available. + */ +struct exynos5440_pinctrl_priv_data { + void __iomem *reg_base; + struct gpio_chip *gc; + + const struct exynos5440_pin_group *pin_groups; + unsigned int nr_groups; + const struct exynos5440_pmx_func *pmx_functions; + unsigned int nr_functions; +}; + +/* list of all possible config options supported */ +struct pin_config { + char *prop_cfg; + unsigned int cfg_type; +} pcfgs[] = { + { "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD }, + { "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV }, + { "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE }, + { "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE }, +}; + +/* check if the selector is a valid pin group selector */ +static int exynos5440_get_group_count(struct pinctrl_dev *pctldev) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + return priv->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + return priv->pin_groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int exynos5440_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, unsigned *num_pins) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + *pins = priv->pin_groups[selector].pins; + *num_pins = priv->pin_groups[selector].num_pins; + return 0; +} + +/* create pinctrl_map entries by parsing device tree nodes */ +static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **maps, + unsigned *nmaps) +{ + struct device *dev = pctldev->dev; + struct pinctrl_map *map; + unsigned long *cfg = NULL; + char *gname, *fname; + int cfg_cnt = 0, map_cnt = 0, idx = 0; + + /* count the number of config options specfied in the node */ + for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) + if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) + cfg_cnt++; + + /* + * Find out the number of map entries to create. All the config options + * can be accomadated into a single config map entry. + */ + if (cfg_cnt) + map_cnt = 1; + if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) + map_cnt++; + if (!map_cnt) { + dev_err(dev, "node %s does not have either config or function " + "configurations\n", np->name); + return -EINVAL; + } + + /* Allocate memory for pin-map entries */ + map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); + if (!map) { + dev_err(dev, "could not alloc memory for pin-maps\n"); + return -ENOMEM; + } + *nmaps = 0; + + /* + * Allocate memory for pin group name. The pin group name is derived + * from the node name from which these map entries are be created. + */ + gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + goto free_map; + } + sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); + + /* + * don't have config options? then skip over to creating function + * map entries. + */ + if (!cfg_cnt) + goto skip_cfgs; + + /* Allocate memory for config entries */ + cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); + if (!cfg) { + dev_err(dev, "failed to alloc memory for configs\n"); + goto free_gname; + } + + /* Prepare a list of config settings */ + for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { + u32 value; + if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) + cfg[cfg_cnt++] = + PINCFG_PACK(pcfgs[idx].cfg_type, value); + } + + /* create the config map entry */ + map[*nmaps].data.configs.group_or_pin = gname; + map[*nmaps].data.configs.configs = cfg; + map[*nmaps].data.configs.num_configs = cfg_cnt; + map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + *nmaps += 1; + +skip_cfgs: + /* create the function map entry */ + if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { + fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + goto free_cfg; + } + sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); + + map[*nmaps].data.mux.group = gname; + map[*nmaps].data.mux.function = fname; + map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + *nmaps += 1; + } + + *maps = map; + return 0; + +free_cfg: + kfree(cfg); +free_gname: + kfree(gname); +free_map: + kfree(map); + return -ENOMEM; +} + +/* free the memory allocated to hold the pin-map table */ +static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int idx; + + for (idx = 0; idx < num_maps; idx++) { + if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { + kfree(map[idx].data.mux.function); + if (!idx) + kfree(map[idx].data.mux.group); + } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { + kfree(map[idx].data.configs.configs); + if (!idx) + kfree(map[idx].data.configs.group_or_pin); + } + }; + + kfree(map); +} + +/* list of pinctrl callbacks for the pinctrl core */ +static struct pinctrl_ops exynos5440_pctrl_ops = { + .get_groups_count = exynos5440_get_group_count, + .get_group_name = exynos5440_get_group_name, + .get_group_pins = exynos5440_get_group_pins, + .dt_node_to_map = exynos5440_dt_node_to_map, + .dt_free_map = exynos5440_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int exynos5440_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + return priv->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + return priv->pmx_functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, const char * const **groups, + unsigned * const num_groups) +{ + struct exynos5440_pinctrl_priv_data *priv; + + priv = pinctrl_dev_get_drvdata(pctldev); + *groups = priv->pmx_functions[selector].groups; + *num_groups = priv->pmx_functions[selector].num_groups; + return 0; +} + +/* enable or disable a pinmux function */ +static void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group, bool enable) +{ + struct exynos5440_pinctrl_priv_data *priv; + void __iomem *base; + u32 function; + u32 data; + + priv = pinctrl_dev_get_drvdata(pctldev); + base = priv->reg_base; + function = priv->pmx_functions[selector].function; + + data = readl(base + GPIO_MUX); + if (enable) + data |= (1 << function); + else + data &= ~(1 << function); + writel(data, base + GPIO_MUX); +} + +/* enable a specified pinmux by writing to registers */ +static int exynos5440_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + exynos5440_pinmux_setup(pctldev, selector, group, true); + return 0; +} + +/* disable a specified pinmux by writing to registers */ +static void exynos5440_pinmux_disable(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + exynos5440_pinmux_setup(pctldev, selector, group, false); +} + +/* + * The calls to gpio_direction_output() and gpio_direction_input() + * leads to this function call (via the pinctrl_gpio_direction_{input|output}() + * function called from the gpiolib interface). + */ +static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + return 0; +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static struct pinmux_ops exynos5440_pinmux_ops = { + .get_functions_count = exynos5440_get_functions_count, + .get_function_name = exynos5440_pinmux_get_fname, + .get_function_groups = exynos5440_pinmux_get_groups, + .enable = exynos5440_pinmux_enable, + .disable = exynos5440_pinmux_disable, + .gpio_set_direction = exynos5440_pinmux_gpio_set_direction, +}; + +/* set the pin config settings for a specified pin */ +static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long config) +{ + struct exynos5440_pinctrl_priv_data *priv; + void __iomem *base; + enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(config); + u32 cfg_value = PINCFG_UNPACK_VALUE(config); + u32 data; + + priv = pinctrl_dev_get_drvdata(pctldev); + base = priv->reg_base; + + switch (cfg_type) { + case PINCFG_TYPE_PUD: + /* first set pull enable/disable bit */ + data = readl(base + GPIO_PE); + data &= ~(1 << pin); + if (cfg_value) + data |= (1 << pin); + writel(data, base + GPIO_PE); + + /* then set pull up/down bit */ + data = readl(base + GPIO_PS); + data &= ~(1 << pin); + if (cfg_value == 2) + data |= (1 << pin); + writel(data, base + GPIO_PS); + break; + + case PINCFG_TYPE_DRV: + /* set the first bit of the drive strength */ + data = readl(base + GPIO_DS0); + data &= ~(1 << pin); + data |= ((cfg_value & 1) << pin); + writel(data, base + GPIO_DS0); + cfg_value >>= 1; + + /* set the second bit of the driver strength */ + data = readl(base + GPIO_DS1); + data &= ~(1 << pin); + data |= ((cfg_value & 1) << pin); + writel(data, base + GPIO_DS1); + break; + case PINCFG_TYPE_SKEW_RATE: + data = readl(base + GPIO_SR); + data &= ~(1 << pin); + data |= ((cfg_value & 1) << pin); + writel(data, base + GPIO_SR); + break; + case PINCFG_TYPE_INPUT_TYPE: + data = readl(base + GPIO_TYPE); + data &= ~(1 << pin); + data |= ((cfg_value & 1) << pin); + writel(data, base + GPIO_TYPE); + break; + default: + WARN_ON(1); + return -EINVAL; + } + + return 0; +} + +/* get the pin config settings for a specified pin */ +static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct exynos5440_pinctrl_priv_data *priv; + void __iomem *base; + enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); + u32 data; + + priv = pinctrl_dev_get_drvdata(pctldev); + base = priv->reg_base; + + switch (cfg_type) { + case PINCFG_TYPE_PUD: + data = readl(base + GPIO_PE); + data = (data >> pin) & 1; + if (!data) + *config = 0; + else + *config = ((readl(base + GPIO_PS) >> pin) & 1) + 1; + break; + case PINCFG_TYPE_DRV: + data = readl(base + GPIO_DS0); + data = (data >> pin) & 1; + *config = data; + data = readl(base + GPIO_DS1); + data = (data >> pin) & 1; + *config |= (data << 1); + break; + case PINCFG_TYPE_SKEW_RATE: + data = readl(base + GPIO_SR); + *config = (data >> pin) & 1; + break; + case PINCFG_TYPE_INPUT_TYPE: + data = readl(base + GPIO_TYPE); + *config = (data >> pin) & 1; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + return 0; +} + +/* set the pin config settings for a specified pin group */ +static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned group, unsigned long config) +{ + struct exynos5440_pinctrl_priv_data *priv; + const unsigned int *pins; + unsigned int cnt; + + priv = pinctrl_dev_get_drvdata(pctldev); + pins = priv->pin_groups[group].pins; + + for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++) + exynos5440_pinconf_set(pctldev, pins[cnt], config); + + return 0; +} + +/* get the pin config settings for a specified pin group */ +static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *config) +{ + struct exynos5440_pinctrl_priv_data *priv; + const unsigned int *pins; + + priv = pinctrl_dev_get_drvdata(pctldev); + pins = priv->pin_groups[group].pins; + exynos5440_pinconf_get(pctldev, pins[0], config); + return 0; +} + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ +static struct pinconf_ops exynos5440_pinconf_ops = { + .pin_config_get = exynos5440_pinconf_get, + .pin_config_set = exynos5440_pinconf_set, + .pin_config_group_get = exynos5440_pinconf_group_get, + .pin_config_group_set = exynos5440_pinconf_group_set, +}; + +/* gpiolib gpio_set callback function */ +static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); + void __iomem *base = priv->reg_base; + u32 data; + + data = readl(base + GPIO_VAL); + data &= ~(1 << offset); + if (value) + data |= 1 << offset; + writel(data, base + GPIO_VAL); +} + +/* gpiolib gpio_get callback function */ +static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); + void __iomem *base = priv->reg_base; + u32 data; + + data = readl(base + GPIO_IN); + data >>= offset; + data &= 1; + return data; +} + +/* gpiolib gpio_direction_input callback function */ +static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); + void __iomem *base = priv->reg_base; + u32 data; + + /* first disable the data output enable on this pin */ + data = readl(base + GPIO_OE); + data &= ~(1 << offset); + writel(data, base + GPIO_OE); + + /* now enable input on this pin */ + data = readl(base + GPIO_IE); + data |= 1 << offset; + writel(data, base + GPIO_IE); + return 0; +} + +/* gpiolib gpio_direction_output callback function */ +static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); + void __iomem *base = priv->reg_base; + u32 data; + + exynos5440_gpio_set(gc, offset, value); + + /* first disable the data input enable on this pin */ + data = readl(base + GPIO_IE); + data &= ~(1 << offset); + writel(data, base + GPIO_IE); + + /* now enable output on this pin */ + data = readl(base + GPIO_OE); + data |= 1 << offset; + writel(data, base + GPIO_OE); + return 0; +} + +/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ +static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, + struct device_node *cfg_np, unsigned int **pin_list, + unsigned int *npins) +{ + struct device *dev = &pdev->dev; + struct property *prop; + + prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL); + if (!prop) + return -ENOENT; + + *npins = prop->length / sizeof(unsigned long); + if (!*npins) { + dev_err(dev, "invalid pin list in %s node", cfg_np->name); + return -EINVAL; + } + + *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); + if (!*pin_list) { + dev_err(dev, "failed to allocate memory for pin list\n"); + return -ENOMEM; + } + + return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins", + *pin_list, *npins); +} + +/* + * Parse the information about all the available pin groups and pin functions + * from device node of the pin-controller. + */ +static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev, + struct exynos5440_pinctrl_priv_data *priv) +{ + struct device *dev = &pdev->dev; + struct device_node *dev_np = dev->of_node; + struct device_node *cfg_np; + struct exynos5440_pin_group *groups, *grp; + struct exynos5440_pmx_func *functions, *func; + unsigned *pin_list; + unsigned int npins, grp_cnt, func_idx = 0; + char *gname, *fname; + int ret; + + grp_cnt = of_get_child_count(dev_np); + if (!grp_cnt) + return -EINVAL; + + groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); + if (!groups) { + dev_err(dev, "failed allocate memory for ping group list\n"); + return -EINVAL; + } + grp = groups; + + functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); + if (!functions) { + dev_err(dev, "failed to allocate memory for function list\n"); + return -EINVAL; + } + func = functions; + + /* + * Iterate over all the child nodes of the pin controller node + * and create pin groups and pin function lists. + */ + for_each_child_of_node(dev_np, cfg_np) { + u32 function; + + ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np, + &pin_list, &npins); + if (ret) + return ret; + + /* derive pin group name from the node name */ + gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, + GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + return -ENOMEM; + } + sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); + + grp->name = gname; + grp->pins = pin_list; + grp->num_pins = npins; + grp++; + + ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function", + &function); + if (ret) + continue; + + /* derive function name from the node name */ + fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, + GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + return -ENOMEM; + } + sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); + + func->name = fname; + func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); + if (!func->groups) { + dev_err(dev, "failed to alloc memory for group list " + "in pin function"); + return -ENOMEM; + } + func->groups[0] = gname; + func->num_groups = 1; + func->function = function; + func++; + func_idx++; + } + + priv->pin_groups = groups; + priv->nr_groups = grp_cnt; + priv->pmx_functions = functions; + priv->nr_functions = func_idx; + return 0; +} + +/* register the pinctrl interface with the pinctrl subsystem */ +static int __init exynos5440_pinctrl_register(struct platform_device *pdev, + struct exynos5440_pinctrl_priv_data *priv) +{ + struct device *dev = &pdev->dev; + struct pinctrl_desc *ctrldesc; + struct pinctrl_dev *pctl_dev; + struct pinctrl_pin_desc *pindesc, *pdesc; + struct pinctrl_gpio_range grange; + char *pin_names; + int pin, ret; + + ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL); + if (!ctrldesc) { + dev_err(dev, "could not allocate memory for pinctrl desc\n"); + return -ENOMEM; + } + + ctrldesc->name = "exynos5440-pinctrl"; + ctrldesc->owner = THIS_MODULE; + ctrldesc->pctlops = &exynos5440_pctrl_ops; + ctrldesc->pmxops = &exynos5440_pinmux_ops; + ctrldesc->confops = &exynos5440_pinconf_ops; + + pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * + EXYNOS5440_MAX_PINS, GFP_KERNEL); + if (!pindesc) { + dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + return -ENOMEM; + } + ctrldesc->pins = pindesc; + ctrldesc->npins = EXYNOS5440_MAX_PINS; + + /* dynamically populate the pin number and pin name for pindesc */ + for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) + pdesc->number = pin; + + /* + * allocate space for storing the dynamically generated names for all + * the pins which belong to this pin-controller. + */ + pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * + ctrldesc->npins, GFP_KERNEL); + if (!pin_names) { + dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + return -ENOMEM; + } + + /* for each pin, set the name of the pin */ + for (pin = 0; pin < ctrldesc->npins; pin++) { + sprintf(pin_names, "gpio%02d", pin); + pdesc = pindesc + pin; + pdesc->name = pin_names; + pin_names += PIN_NAME_LENGTH; + } + + ret = exynos5440_pinctrl_parse_dt(pdev, priv); + if (ret) + return ret; + + pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv); + if (!pctl_dev) { + dev_err(&pdev->dev, "could not register pinctrl driver\n"); + return -EINVAL; + } + + grange.name = "exynos5440-pctrl-gpio-range"; + grange.id = 0; + grange.base = 0; + grange.npins = EXYNOS5440_MAX_PINS; + grange.gc = priv->gc; + pinctrl_add_gpio_range(pctl_dev, &grange); + return 0; +} + +/* register the gpiolib interface with the gpiolib subsystem */ +static int __init exynos5440_gpiolib_register(struct platform_device *pdev, + struct exynos5440_pinctrl_priv_data *priv) +{ + struct gpio_chip *gc; + int ret; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) { + dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); + return -ENOMEM; + } + + priv->gc = gc; + gc->base = 0; + gc->ngpio = EXYNOS5440_MAX_PINS; + gc->dev = &pdev->dev; + gc->set = exynos5440_gpio_set; + gc->get = exynos5440_gpio_get; + gc->direction_input = exynos5440_gpio_direction_input; + gc->direction_output = exynos5440_gpio_direction_output; + gc->label = "gpiolib-exynos5440"; + gc->owner = THIS_MODULE; + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error " + "code: %d\n", gc->label, ret); + return ret; + } + + return 0; +} + +/* unregister the gpiolib interface with the gpiolib subsystem */ +static int __init exynos5440_gpiolib_unregister(struct platform_device *pdev, + struct exynos5440_pinctrl_priv_data *priv) +{ + int ret = gpiochip_remove(priv->gc); + if (ret) { + dev_err(&pdev->dev, "gpio chip remove failed\n"); + return ret; + } + return 0; +} + +static int __devinit exynos5440_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos5440_pinctrl_priv_data *priv; + struct resource *res; + int ret; + + if (!dev->of_node) { + dev_err(dev, "device tree node not found\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, sizeof(priv), GFP_KERNEL); + if (!priv) { + dev_err(dev, "could not allocate memory for private data\n"); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find IO resource\n"); + return -ENOENT; + } + + priv->reg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!priv->reg_base) { + dev_err(dev, "ioremap failed\n"); + return -ENODEV; + } + + ret = exynos5440_gpiolib_register(pdev, priv); + if (ret) + return ret; + + ret = exynos5440_pinctrl_register(pdev, priv); + if (ret) { + exynos5440_gpiolib_unregister(pdev, priv); + return ret; + } + + platform_set_drvdata(pdev, priv); + dev_info(dev, "EXYNOS5440 pinctrl driver registered\n"); + return 0; +} + +static const struct of_device_id exynos5440_pinctrl_dt_match[] = { + { .compatible = "samsung,exynos5440-pinctrl" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match); + +static struct platform_driver exynos5440_pinctrl_driver = { + .probe = exynos5440_pinctrl_probe, + .driver = { + .name = "exynos5440-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(exynos5440_pinctrl_dt_match), + }, +}; + +static int __init exynos5440_pinctrl_drv_register(void) +{ + return platform_driver_register(&exynos5440_pinctrl_driver); +} +postcore_initcall(exynos5440_pinctrl_drv_register); + +static void __exit exynos5440_pinctrl_drv_unregister(void) +{ + platform_driver_unregister(&exynos5440_pinctrl_driver); +} +module_exit(exynos5440_pinctrl_drv_unregister); + +MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); +MODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index ee730590347..8ed20e84cb0 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -322,7 +322,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev, { } -struct pinconf_ops falcon_pinconf_ops = { +static struct pinconf_ops falcon_pinconf_ops = { .pin_config_get = falcon_pinconf_get, .pin_config_set = falcon_pinconf_set, .pin_config_group_get = falcon_pinconf_group_get, diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index 63866d95357..131d86d7c2a 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -71,7 +71,7 @@ static const struct imx_pin_reg *imx_find_pin_reg( break; } - if (!pin_reg) { + if (i == info->npin_regs) { dev_err(info->dev, "Pin(%s): unable to find pin reg map\n", info->pins[pin].name); return NULL; @@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, } } -struct pinconf_ops imx_pinconf_ops = { +static struct pinconf_ops imx_pinconf_ops = { .pin_config_get = imx_pinconf_get, .pin_config_set = imx_pinconf_set, .pin_config_dbg_show = imx_pinconf_dbg_show, @@ -611,7 +611,7 @@ int __devinit imx_pinctrl_probe(struct platform_device *pdev, return 0; } -int __devexit imx_pinctrl_remove(struct platform_device *pdev) +int imx_pinctrl_remove(struct platform_device *pdev) { struct imx_pinctrl *ipctl = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-imx23.c b/drivers/pinctrl/pinctrl-imx23.c index 3674d877ed7..04364f7822b 100644 --- a/drivers/pinctrl/pinctrl-imx23.c +++ b/drivers/pinctrl/pinctrl-imx23.c @@ -272,7 +272,7 @@ static int __devinit imx23_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data); } -static struct of_device_id imx23_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx23_pinctrl_of_match[] = { { .compatible = "fsl,imx23-pinctrl", }, { /* sentinel */ } }; @@ -285,7 +285,7 @@ static struct platform_driver imx23_pinctrl_driver = { .of_match_table = imx23_pinctrl_of_match, }, .probe = imx23_pinctrl_probe, - .remove = __devexit_p(mxs_pinctrl_remove), + .remove = mxs_pinctrl_remove, }; static int __init imx23_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx28.c b/drivers/pinctrl/pinctrl-imx28.c index 0f5b2122b1b..e1af2ba8900 100644 --- a/drivers/pinctrl/pinctrl-imx28.c +++ b/drivers/pinctrl/pinctrl-imx28.c @@ -388,7 +388,7 @@ static int __devinit imx28_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data); } -static struct of_device_id imx28_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx28_pinctrl_of_match[] = { { .compatible = "fsl,imx28-pinctrl", }, { /* sentinel */ } }; @@ -401,7 +401,7 @@ static struct platform_driver imx28_pinctrl_driver = { .of_match_table = imx28_pinctrl_of_match, }, .probe = imx28_pinctrl_probe, - .remove = __devexit_p(mxs_pinctrl_remove), + .remove = mxs_pinctrl_remove, }; static int __init imx28_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/pinctrl-imx35.c index 82f109e26f2..1dbf5278ace 100644 --- a/drivers/pinctrl/pinctrl-imx35.c +++ b/drivers/pinctrl/pinctrl-imx35.c @@ -1559,7 +1559,7 @@ static struct imx_pinctrl_soc_info imx35_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx35_pin_regs), }; -static struct of_device_id imx35_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx35_pinctrl_of_match[] = { { .compatible = "fsl,imx35-iomuxc", }, { /* sentinel */ } }; @@ -1576,7 +1576,7 @@ static struct platform_driver imx35_pinctrl_driver = { .of_match_table = of_match_ptr(imx35_pinctrl_of_match), }, .probe = imx35_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx35_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx51.c b/drivers/pinctrl/pinctrl-imx51.c index fb846896677..131216558a7 100644 --- a/drivers/pinctrl/pinctrl-imx51.c +++ b/drivers/pinctrl/pinctrl-imx51.c @@ -1286,7 +1286,7 @@ static struct imx_pinctrl_soc_info imx51_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx51_pin_regs), }; -static struct of_device_id imx51_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx51_pinctrl_of_match[] = { { .compatible = "fsl,imx51-iomuxc", }, { /* sentinel */ } }; @@ -1303,7 +1303,7 @@ static struct platform_driver imx51_pinctrl_driver = { .of_match_table = of_match_ptr(imx51_pinctrl_of_match), }, .probe = imx51_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx51_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/pinctrl-imx53.c index 783feb1ce06..ec404869177 100644 --- a/drivers/pinctrl/pinctrl-imx53.c +++ b/drivers/pinctrl/pinctrl-imx53.c @@ -1613,7 +1613,7 @@ static struct imx_pinctrl_soc_info imx53_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx53_pin_regs), }; -static struct of_device_id imx53_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx53_pinctrl_of_match[] = { { .compatible = "fsl,imx53-iomuxc", }, { /* sentinel */ } }; @@ -1630,7 +1630,7 @@ static struct platform_driver imx53_pinctrl_driver = { .of_match_table = of_match_ptr(imx53_pinctrl_of_match), }, .probe = imx53_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx53_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c index e9bf71fbedc..844ab13c93a 100644 --- a/drivers/pinctrl/pinctrl-imx6q.c +++ b/drivers/pinctrl/pinctrl-imx6q.c @@ -2297,7 +2297,7 @@ static struct imx_pinctrl_soc_info imx6q_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx6q_pin_regs), }; -static struct of_device_id imx6q_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx6q_pinctrl_of_match[] = { { .compatible = "fsl,imx6q-iomuxc", }, { /* sentinel */ } }; @@ -2314,7 +2314,7 @@ static struct platform_driver imx6q_pinctrl_driver = { .of_match_table = of_match_ptr(imx6q_pinctrl_of_match), }, .probe = imx6q_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx6q_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index 07ba7682cf2..15f501d8902 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -46,8 +46,8 @@ static int ltq_get_group_pins(struct pinctrl_dev *pctrldev, return 0; } -void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) { int i; @@ -128,10 +128,10 @@ static int ltq_pinctrl_dt_subnode_size(struct device_node *np) return ret; } -int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, - unsigned *num_maps) +static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { struct pinctrl_map *tmp; struct device_node *np; @@ -275,16 +275,6 @@ static int ltq_pmx_enable(struct pinctrl_dev *pctrldev, return 0; } -static void ltq_pmx_disable(struct pinctrl_dev *pctrldev, - unsigned func, - unsigned group) -{ - /* - * Nothing to do here. However, pinconf_check_ops() requires this - * callback to be defined. - */ -} - static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -312,7 +302,6 @@ static struct pinmux_ops ltq_pmx_ops = { .get_function_name = ltq_pmx_func_name, .get_function_groups = ltq_pmx_get_groups, .enable = ltq_pmx_enable, - .disable = ltq_pmx_disable, .gpio_request_enable = ltq_pmx_gpio_request_enable, }; diff --git a/drivers/pinctrl/pinctrl-mmp2.c b/drivers/pinctrl/pinctrl-mmp2.c index 2cfed552bbe..4fbb3db3f1c 100644 --- a/drivers/pinctrl/pinctrl-mmp2.c +++ b/drivers/pinctrl/pinctrl-mmp2.c @@ -691,7 +691,7 @@ static int __devinit mmp2_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &mmp2_info); } -static int __devexit mmp2_pinmux_remove(struct platform_device *pdev) +static int mmp2_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -702,7 +702,7 @@ static struct platform_driver mmp2_pinmux_driver = { .owner = THIS_MODULE, }, .probe = mmp2_pinmux_probe, - .remove = __devexit_p(mmp2_pinmux_remove), + .remove = mmp2_pinmux_remove, }; static int __init mmp2_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c index 4ba4636b6a4..180f16379ec 100644 --- a/drivers/pinctrl/pinctrl-mxs.c +++ b/drivers/pinctrl/pinctrl-mxs.c @@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, "0x%lx", config); } -struct pinconf_ops mxs_pinconf_ops = { +static struct pinconf_ops mxs_pinconf_ops = { .pin_config_get = mxs_pinconf_get, .pin_config_set = mxs_pinconf_set, .pin_config_group_get = mxs_pinconf_group_get, @@ -522,7 +522,7 @@ err: } EXPORT_SYMBOL_GPL(mxs_pinctrl_probe); -int __devexit mxs_pinctrl_remove(struct platform_device *pdev) +int mxs_pinctrl_remove(struct platform_device *pdev) { struct mxs_pinctrl_data *d = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index debaa75b055..7d88ae35211 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -475,8 +475,10 @@ static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8 }; -static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 }; -static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; +static const unsigned clkout1_a_1_pins[] = { DB8500_PIN_AH7 }; +static const unsigned clkout1_a_2_pins[] = { DB8500_PIN_AG7 }; +static const unsigned clkout2_a_1_pins[] = { DB8500_PIN_AJ6 }; +static const unsigned clkout2_a_2_pins[] = { DB8500_PIN_AF7 }; static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29, DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26, DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27, @@ -592,7 +594,8 @@ static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 }; static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 }; static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 }; -static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 }; +static const unsigned clkout1_c_1_pins[] = { DB8500_PIN_AH13 }; +static const unsigned clkout2_c_1_pins[] = { DB8500_PIN_AH12 }; static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 }; static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8 }; @@ -600,14 +603,66 @@ static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 }; static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; /* Other C1 column */ +static const unsigned u2rx_oc1_1_pins[] = { DB8500_PIN_AB2 }; +static const unsigned stmape_oc1_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4, + DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned remap0_oc1_1_pins[] = { DB8500_PIN_E1 }; +static const unsigned remap1_oc1_1_pins[] = { DB8500_PIN_E2 }; +static const unsigned ptma9_oc1_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned rf_oc1_1_pins[] = { DB8500_PIN_D8, DB8500_PIN_D9 }; +static const unsigned hxclk_oc1_1_pins[] = { DB8500_PIN_D16 }; +static const unsigned uartmodrx_oc1_1_pins[] = { DB8500_PIN_B17 }; +static const unsigned uartmodtx_oc1_1_pins[] = { DB8500_PIN_C16 }; +static const unsigned stmmod_oc1_1_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 }; +static const unsigned hxgpio_oc1_1_pins[] = { DB8500_PIN_D21, DB8500_PIN_D20, + DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22, + DB8500_PIN_B24, DB8500_PIN_C22 }; +static const unsigned rf_oc1_2_pins[] = { DB8500_PIN_C23, DB8500_PIN_D23 }; static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, DB8500_PIN_AH12, DB8500_PIN_AH11 }; static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12, DB8500_PIN_AH11 }; +/* Other C2 column */ +static const unsigned sbag_oc2_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned etmr4_oc2_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; +static const unsigned ptma9_oc2_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C3 column */ +static const unsigned stmmod_oc3_1_pins[] = { DB8500_PIN_AB2, DB8500_PIN_W2, + DB8500_PIN_W3, DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned stmmod_oc3_2_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 }; +static const unsigned uartmodrx_oc3_1_pins[] = { DB8500_PIN_H2 }; +static const unsigned uartmodtx_oc3_1_pins[] = { DB8500_PIN_J2 }; +static const unsigned etmr4_oc3_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C4 column */ +static const unsigned sbag_oc4_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H1 }; +static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + #define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \ .npins = ARRAY_SIZE(a##_pins), .altsetting = b } @@ -639,6 +694,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(kp_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A), @@ -647,8 +703,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), - DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), - DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), /* Altfunction B column */ DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B), @@ -720,15 +778,41 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout2_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), /* Other alt C1 column */ + DB8500_PIN_GROUP(u2rx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(ptma9_oc1_1, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxclk_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodrx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodtx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmmod_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxgpio_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_2, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1), + /* Other alt C2 column */ + DB8500_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(etmr4_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(ptma9_oc2_1, NMK_GPIO_ALT_C2), + /* Other alt C3 column */ + DB8500_PIN_GROUP(stmmod_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(stmmod_oc3_2, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodrx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodtx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(etmr4_oc3_1, NMK_GPIO_ALT_C3), + /* Other alt C4 column */ + DB8500_PIN_GROUP(sbag_oc4_1, NMK_GPIO_ALT_C4), + DB8500_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4), }; /* We use this macro to define the groups applicable to a function */ @@ -742,7 +826,7 @@ DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1"); * only available on two pins in alternative function C */ DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1", - "u2rxtx_c_2", "u2rxtx_c_3"); + "u2rxtx_c_2", "u2rxtx_c_3", "u2rx_oc1_1"); DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2"); /* * MSP0 can only be on a certain set of pins, but the TX/RX pins can be @@ -757,7 +841,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1"); DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1"); DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1", "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1"); -DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1"); +DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_a_2", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1"); DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1"); DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1"); DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1"); @@ -773,7 +857,8 @@ DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2", "mc1dir_a_1"); DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); -DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1"); +DB8500_FUNC_GROUPS(clkout, "clkout1_a_1", "clkout1_a_2", "clkout1_c_1", + "clkout2_a_1", "clkout2_a_2", "clkout2_c_1"); DB8500_FUNC_GROUPS(usb, "usb_a_1"); DB8500_FUNC_GROUPS(trig, "trig_b_1"); DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1"); @@ -784,8 +869,10 @@ DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2"); * so select one of each. */ DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2", - "uartmodrx_c_1", "uartmod_tx_c_1"); -DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1"); + "uartmodrx_c_1", "uartmod_tx_c_1", "uartmodrx_oc1_1", + "uartmodtx_oc1_1", "uartmodrx_oc3_1", "uartmodtx_oc3_1"); +DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1", "stmmod_oc1_1", + "stmmod_oc3_1", "stmmod_oc3_2"); DB8500_FUNC_GROUPS(spi3, "spi3_b_1"); /* Select between CS0 on alt B or PS1 on alt C */ DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1", @@ -799,13 +886,19 @@ DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1"); DB8500_FUNC_GROUPS(slim0, "slim0_c_1"); DB8500_FUNC_GROUPS(ms, "ms_c_1"); DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1"); -DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2"); +DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2", "stmape_oc1_1"); DB8500_FUNC_GROUPS(mc5, "mc5_c_1"); DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2"); DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2"); DB8500_FUNC_GROUPS(spi0, "spi0_c_1"); DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2"); - +DB8500_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1"); +DB8500_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc4_1"); +DB8500_FUNC_GROUPS(ptm, "ptma9_oc1_1", "ptma9_oc2_1"); +DB8500_FUNC_GROUPS(rf, "rf_oc1_1", "rf_oc1_2"); +DB8500_FUNC_GROUPS(hx, "hxclk_oc1_1", "hxgpio_oc1_1"); +DB8500_FUNC_GROUPS(etm, "etmr4_oc2_1", "etmr4_oc3_1"); +DB8500_FUNC_GROUPS(hwobs, "hwobs_oc4_1"); #define FUNCTION(fname) \ { \ .name = #fname, \ @@ -858,6 +951,12 @@ static const struct nmk_function nmk_db8500_functions[] = { FUNCTION(i2c3), FUNCTION(spi0), FUNCTION(spi2), + FUNCTION(remap), + FUNCTION(ptm), + FUNCTION(rf), + FUNCTION(hx), + FUNCTION(etm), + FUNCTION(hwobs), }; static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = { diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c index 52fc30181f7..bb6a4016322 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c @@ -460,8 +460,10 @@ static const unsigned hsit_a_1_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10, DB8540_PIN_E10, DB8540_PIN_B12, DB8540_PIN_D10 }; static const unsigned hsit_a_2_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10, DB8540_PIN_E10, DB8540_PIN_B12 }; -static const unsigned clkout_a_1_pins[] = { DB8540_PIN_D11, DB8540_PIN_AJ6 }; -static const unsigned clkout_a_2_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 }; +static const unsigned clkout1_a_1_pins[] = { DB8540_PIN_D11 }; +static const unsigned clkout1_a_2_pins[] = { DB8540_PIN_B13 }; +static const unsigned clkout2_a_1_pins[] = { DB8540_PIN_AJ6 }; +static const unsigned clkout2_a_2_pins[] = { DB8540_PIN_C12 }; static const unsigned msp4_a_1_pins[] = { DB8540_PIN_B14, DB8540_PIN_E11 }; static const unsigned usb_a_1_pins[] = { DB8540_PIN_D12, DB8540_PIN_D15, DB8540_PIN_C13, DB8540_PIN_C14, DB8540_PIN_C18, DB8540_PIN_C16, @@ -698,8 +700,10 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), - DB8540_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), - DB8540_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(msp4_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), /* Altfunction B column */ @@ -822,6 +826,7 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4), DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4), DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduartstmmux_oc4_1, NMK_GPIO_ALT_C4), }; @@ -830,7 +835,8 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { static const char * const a##_groups[] = { b }; DB8540_FUNC_GROUPS(apetrig, "apetrig_b_1"); -DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout_a_1", "clkout_a_2"); +DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout1_a_1", "clkout1_a_2", + "clkout2_a_1", "clkout2_a_2"); DB8540_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1"); DB8540_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); DB8540_FUNC_GROUPS(hwobs, "hwobs_oc4_1"); diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index cf82d9ce4de..8ef3e85cb01 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 = { diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h index eef316e979a..bcd4191e10e 100644 --- a/drivers/pinctrl/pinctrl-nomadik.h +++ b/drivers/pinctrl/pinctrl-nomadik.h @@ -1,7 +1,7 @@ #ifndef PINCTRL_PINCTRL_NOMADIK_H #define PINCTRL_PINCTRL_NOMADIK_H -#include <plat/gpio-nomadik.h> +#include <linux/platform_data/pinctrl-nomadik.h> /* Package definitions */ #define PINCTRL_NMK_STN8815 0 diff --git a/drivers/pinctrl/pinctrl-pxa168.c b/drivers/pinctrl/pinctrl-pxa168.c index c1997fa7f28..cb771e4a635 100644 --- a/drivers/pinctrl/pinctrl-pxa168.c +++ b/drivers/pinctrl/pinctrl-pxa168.c @@ -620,7 +620,7 @@ static int __devinit pxa168_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &pxa168_info); } -static int __devexit pxa168_pinmux_remove(struct platform_device *pdev) +static int pxa168_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -631,7 +631,7 @@ static struct platform_driver pxa168_pinmux_driver = { .owner = THIS_MODULE, }, .probe = pxa168_pinmux_probe, - .remove = __devexit_p(pxa168_pinmux_remove), + .remove = pxa168_pinmux_remove, }; static int __init pxa168_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c index f14cd6ba4c0..51f8a388b91 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.c +++ b/drivers/pinctrl/pinctrl-pxa3xx.c @@ -173,7 +173,6 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, { struct pinctrl_desc *desc; struct resource *res; - int ret = 0; if (!info || !info->cputype) return -EINVAL; @@ -188,23 +187,17 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - info->phy_base = res->start; - info->phy_size = resource_size(res); - info->virt_base = ioremap(info->phy_base, info->phy_size); + info->virt_base = devm_request_and_ioremap(&pdev->dev, res); if (!info->virt_base) return -ENOMEM; info->pctrl = pinctrl_register(desc, &pdev->dev, info); if (!info->pctrl) { dev_err(&pdev->dev, "failed to register PXA pinmux driver\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range); platform_set_drvdata(pdev, info); return 0; -err: - iounmap(info->virt_base); - return ret; } int pxa3xx_pinctrl_unregister(struct platform_device *pdev) @@ -212,7 +205,6 @@ int pxa3xx_pinctrl_unregister(struct platform_device *pdev) struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev); pinctrl_unregister(info->pctrl); - iounmap(info->virt_base); platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h index 8135744d659..92fad088083 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.h +++ b/drivers/pinctrl/pinctrl-pxa3xx.h @@ -60,8 +60,6 @@ struct pxa3xx_pinmux_info { struct device *dev; struct pinctrl_dev *pctrl; enum pxa_cpu_type cputype; - unsigned int phy_base; - unsigned int phy_size; void __iomem *virt_base; struct pxa3xx_mfp_pin *mfp; diff --git a/drivers/pinctrl/pinctrl-pxa910.c b/drivers/pinctrl/pinctrl-pxa910.c index c72ab4b9cc8..5fecd221b83 100644 --- a/drivers/pinctrl/pinctrl-pxa910.c +++ b/drivers/pinctrl/pinctrl-pxa910.c @@ -976,7 +976,7 @@ static int __devinit pxa910_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &pxa910_info); } -static int __devexit pxa910_pinmux_remove(struct platform_device *pdev) +static int pxa910_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -987,7 +987,7 @@ static struct platform_driver pxa910_pinmux_driver = { .owner = THIS_MODULE, }, .probe = pxa910_pinmux_probe, - .remove = __devexit_p(pxa910_pinmux_remove), + .remove = pxa910_pinmux_remove, }; static int __init pxa910_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 81c9896d4f6..8f31b656c4e 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -47,7 +47,7 @@ struct pin_config { { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, }; -static unsigned int pin_base = 0; +static unsigned int pin_base; static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) { @@ -560,7 +560,7 @@ static int __devinit samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, const char *pin_name; *npins = of_property_count_strings(cfg_np, "samsung,pins"); - if (*npins < 0) { + if (IS_ERR_VALUE(*npins)) { dev_err(dev, "invalid pin list in %s node", cfg_np->name); return -EINVAL; } diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 726a729a2ec..79642831bba 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -30,6 +30,7 @@ #define PCS_MUX_BITS_NAME "pinctrl-single,bits" #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) #define PCS_OFF_DISABLED ~0U +#define PCS_MAX_GPIO_VALUES 2 /** * struct pcs_pingroup - pingroups for a function @@ -77,6 +78,16 @@ struct pcs_function { }; /** + * struct pcs_gpio_range - pinctrl gpio range + * @range: subrange of the GPIO number space + * @gpio_func: gpio function value in the pinmux register + */ +struct pcs_gpio_range { + struct pinctrl_gpio_range range; + int gpio_func; +}; + +/** * struct pcs_data - wrapper for data needed by pinctrl framework * @pa: pindesc array * @cur: index to current element @@ -244,15 +255,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev, static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) + unsigned pin) { struct pcs_device *pcs; - unsigned val; + unsigned val, mux_bytes; pcs = pinctrl_dev_get_drvdata(pctldev); - val = pcs->read(pcs->base + offset); - val &= pcs->fmask; + mux_bytes = pcs->width / BITS_PER_BYTE; + val = pcs->read(pcs->base + pin * mux_bytes); seq_printf(s, "%08x %s " , val, DRIVER_NAME); } @@ -403,9 +414,26 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, } static int pcs_request_gpio(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, unsigned offset) + struct pinctrl_gpio_range *range, unsigned pin) { - return -ENOTSUPP; + struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); + struct pcs_gpio_range *gpio = NULL; + int end, mux_bytes; + unsigned data; + + gpio = container_of(range, struct pcs_gpio_range, range); + end = range->pin_base + range->npins - 1; + if (pin < range->pin_base || pin > end) { + dev_err(pctldev->dev, + "pin %d isn't in the range of %d to %d\n", + pin, range->pin_base, end); + return -EINVAL; + } + mux_bytes = pcs->width / BITS_PER_BYTE; + data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask; + data |= gpio->gpio_func; + pcs->write(data, pcs->base + pin * mux_bytes); + return 0; } static struct pinmux_ops pcs_pinmux_ops = { @@ -772,7 +800,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, pcs = pinctrl_dev_get_drvdata(pctldev); *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL); - if (!map) + if (!*map) return -ENOMEM; *num_maps = 0; @@ -879,6 +907,50 @@ static void pcs_free_resources(struct pcs_device *pcs) static struct of_device_id pcs_of_match[]; +static int __devinit pcs_add_gpio_range(struct device_node *node, + struct pcs_device *pcs) +{ + struct pcs_gpio_range *gpio; + struct device_node *child; + struct resource r; + const char name[] = "pinctrl-single"; + u32 gpiores[PCS_MAX_GPIO_VALUES]; + int ret, i = 0, mux_bytes = 0; + + for_each_child_of_node(node, child) { + ret = of_address_to_resource(child, 0, &r); + if (ret < 0) + continue; + memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES); + ret = of_property_read_u32_array(child, "pinctrl-single,gpio", + gpiores, PCS_MAX_GPIO_VALUES); + if (ret < 0) + continue; + gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(pcs->dev, "failed to allocate pcs gpio\n"); + return -ENOMEM; + } + gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name), + GFP_KERNEL); + if (!gpio->range.name) { + dev_err(pcs->dev, "failed to allocate range name\n"); + return -ENOMEM; + } + memcpy((char *)gpio->range.name, name, sizeof(name)); + + gpio->range.id = i++; + gpio->range.base = gpiores[0]; + gpio->gpio_func = gpiores[1]; + mux_bytes = pcs->width / BITS_PER_BYTE; + gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes; + gpio->range.npins = (r.end - r.start) / mux_bytes + 1; + + pinctrl_add_gpio_range(pcs->pctl, &gpio->range); + } + return 0; +} + static int __devinit pcs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -975,6 +1047,10 @@ static int __devinit pcs_probe(struct platform_device *pdev) goto free; } + ret = pcs_add_gpio_range(np, pcs); + if (ret < 0) + goto free; + dev_info(pcs->dev, "%i pins at pa %p size %u\n", pcs->desc.npins, pcs->base, pcs->size); @@ -986,7 +1062,7 @@ free: return ret; } -static int __devexit pcs_remove(struct platform_device *pdev) +static int pcs_remove(struct platform_device *pdev) { struct pcs_device *pcs = platform_get_drvdata(pdev); @@ -998,7 +1074,7 @@ static int __devexit pcs_remove(struct platform_device *pdev) return 0; } -static struct of_device_id pcs_of_match[] __devinitdata = { +static struct of_device_id pcs_of_match[] = { { .compatible = DRIVER_NAME, }, { }, }; @@ -1006,7 +1082,7 @@ MODULE_DEVICE_TABLE(of, pcs_of_match); static struct platform_driver pcs_driver = { .probe = pcs_probe, - .remove = __devexit_p(pcs_remove), + .remove = pcs_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 9ecacf3d0a7..a4f0c5e487d 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -32,10 +32,10 @@ #define SIRFSOC_NUM_PADS 622 #define SIRFSOC_RSC_PIN_MUX 0x4 -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90) #define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) #define SIRFSOC_GPIO_DSP_EN0 (0x80) -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) #define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 @@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank { int id; int parent_irq; spinlock_t lock; + bool is_marco; /* for marco, some registers are different with prima2 */ }; static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -191,6 +192,7 @@ struct sirfsoc_pmx { struct pinctrl_dev *pmx; void __iomem *gpio_virtbase; void __iomem *rsc_virtbase; + bool is_marco; }; /* SIRFSOC_GPIO_PAD_EN set */ @@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); - if (enable) - muxval = muxval & ~mask[i].mask; - else - muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (enable) + muxval = muxval & ~mask[i].mask; + else + muxval = muxval | mask[i].mask; + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } else { + if (enable) + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group)); + else + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } } if (mux->funcmask && enable) { @@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); - muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + muxval = muxval | (1 << (offset - range->pin_base)); + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + } else { + writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); + } return 0; } @@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) { const struct of_device_id rsc_ids[] = { { .compatible = "sirf,prima2-rsc" }, + { .compatible = "sirf,marco-rsc" }, {} }; struct device_node *np; @@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_rsc_remap; } + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + spmx->is_marco = 1; + /* Now register the pin controller and all pins it handles */ spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx); if (!spmx->pmx) { @@ -1285,8 +1305,9 @@ out_no_gpio_remap: return ret; } -static const struct of_device_id pinmux_ids[] __devinitconst = { +static const struct of_device_id pinmux_ids[] = { { .compatible = "sirf,prima2-pinctrl" }, + { .compatible = "sirf,marco-pinctrl" }, {} }; @@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&bank->lock, flags); } -int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct sirfsoc_gpio_bank *bank = d->host_data; @@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void *regs; struct platform_device *pdev; + bool is_marco = false; pdev = of_find_device_by_node(np); if (!pdev) @@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) if (!regs) return -ENOMEM; + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + is_marco = 1; + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { bank = &sgpio_bank[i]; spin_lock_init(&bank->lock); @@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.of_node = np; bank->chip.regs = regs; bank->id = i; + bank->is_marco = is_marco; bank->parent_irq = platform_get_irq(pdev, i); if (bank->parent_irq < 0) { err = bank->parent_irq; diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 7da0b371fd6..e356b0380fa 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -178,8 +178,9 @@ static int add_config(struct device *dev, unsigned long **configs, return 0; } -void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned num_maps) { int i; @@ -209,11 +210,11 @@ static const struct cfg_param { {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, }; -int tegra_pinctrl_dt_subnode_to_map(struct device *dev, - struct device_node *np, - struct pinctrl_map **map, - unsigned *reserved_maps, - unsigned *num_maps) +static int tegra_pinctrl_dt_subnode_to_map(struct device *dev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) { int ret, i; const char *function; @@ -288,9 +289,10 @@ exit: return ret; } -int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *num_maps) +static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { unsigned reserved_maps; struct device_node *np; @@ -660,7 +662,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev, } #endif -struct pinconf_ops tegra_pinconf_ops = { +static struct pinconf_ops tegra_pinconf_ops = { .pin_config_get = tegra_pinconf_get, .pin_config_set = tegra_pinconf_set, .pin_config_group_get = tegra_pinconf_group_get, @@ -758,7 +760,7 @@ int __devinit tegra_pinctrl_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(tegra_pinctrl_probe); -int __devexit tegra_pinctrl_remove(struct platform_device *pdev) +int tegra_pinctrl_remove(struct platform_device *pdev) { struct tegra_pmx *pmx = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c index a74f9a56853..1524bfd6660 100644 --- a/drivers/pinctrl/pinctrl-tegra20.c +++ b/drivers/pinctrl/pinctrl-tegra20.c @@ -2861,7 +2861,7 @@ static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra20_pinctrl); } -static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = { +static struct of_device_id tegra20_pinctrl_of_match[] = { { .compatible = "nvidia,tegra20-pinmux", }, { }, }; @@ -2873,7 +2873,7 @@ static struct platform_driver tegra20_pinctrl_driver = { .of_match_table = tegra20_pinctrl_of_match, }, .probe = tegra20_pinctrl_probe, - .remove = __devexit_p(tegra_pinctrl_remove), + .remove = tegra_pinctrl_remove, }; static int __init tegra20_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index 7894f14c705..cf579ebf346 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -3727,7 +3727,7 @@ static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra30_pinctrl); } -static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = { +static struct of_device_id tegra30_pinctrl_of_match[] = { { .compatible = "nvidia,tegra30-pinmux", }, { }, }; @@ -3739,7 +3739,7 @@ static struct platform_driver tegra30_pinctrl_driver = { .of_match_table = tegra30_pinctrl_of_match, }, .probe = tegra30_pinctrl_probe, - .remove = __devexit_p(tegra_pinctrl_remove), + .remove = tegra_pinctrl_remove, }; static int __init tegra30_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 309f5b9a70e..8c039ad22ba 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = { struct u300_pmx { struct device *dev; struct pinctrl_dev *pctl; - u32 phybase; - u32 physize; void __iomem *virtbase; }; @@ -1013,52 +1011,11 @@ static struct pinmux_ops u300_pmx_ops = { .disable = u300_pmx_disable, }; -/* - * GPIO ranges handled by the application-side COH901XXX GPIO controller - * Very many pins can be converted into GPIO pins, but we only list those - * that are useful in practice to cut down on tables. - */ -#define U300_GPIO_RANGE(a, b, c) { .name = "COH901XXX", .id = a, .base= a, \ - .pin_base = b, .npins = c } - -static struct pinctrl_gpio_range u300_gpio_ranges[] = { - U300_GPIO_RANGE(10, 426, 1), - U300_GPIO_RANGE(11, 180, 1), - U300_GPIO_RANGE(12, 165, 1), /* MS/MMC card insertion */ - U300_GPIO_RANGE(13, 179, 1), - U300_GPIO_RANGE(14, 178, 1), - U300_GPIO_RANGE(16, 194, 1), - U300_GPIO_RANGE(17, 193, 1), - U300_GPIO_RANGE(18, 192, 1), - U300_GPIO_RANGE(19, 191, 1), - U300_GPIO_RANGE(20, 186, 1), - U300_GPIO_RANGE(21, 185, 1), - U300_GPIO_RANGE(22, 184, 1), - U300_GPIO_RANGE(23, 183, 1), - U300_GPIO_RANGE(24, 182, 1), - U300_GPIO_RANGE(25, 181, 1), -}; - -static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) { - struct pinctrl_gpio_range *range; - - range = &u300_gpio_ranges[i]; - if (pin >= range->pin_base && - pin <= (range->pin_base + range->npins - 1)) - return range; - } - return NULL; -} - -int u300_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { - struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctldev, pin); /* We get config for those pins we CAN get it for and that's it */ if (!range) @@ -1069,11 +1026,11 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev, config); } -int u300_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { - struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctldev, pin); int ret; if (!range) @@ -1109,9 +1066,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) { struct u300_pmx *upmx; struct resource *res; - struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev); - int ret; - int i; /* Create state holders etc for this driver */ upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL); @@ -1123,32 +1077,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - upmx->phybase = res->start; - upmx->physize = resource_size(res); - - if (request_mem_region(upmx->phybase, upmx->physize, - DRIVER_NAME) == NULL) { - ret = -ENOMEM; - goto out_no_memregion; - } - upmx->virtbase = ioremap(upmx->phybase, upmx->physize); - if (!upmx->virtbase) { - ret = -ENOMEM; - goto out_no_remap; - } + upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res); + if (!upmx->virtbase) + return -ENOMEM; upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx); if (!upmx->pctl) { dev_err(&pdev->dev, "could not register U300 pinmux driver\n"); - ret = -EINVAL; - goto out_no_pmx; - } - - /* We will handle a range of GPIO pins */ - for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) { - u300_gpio_ranges[i].gc = gpio_chip; - pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]); + return -EINVAL; } platform_set_drvdata(pdev, upmx); @@ -1156,23 +1093,13 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) dev_info(&pdev->dev, "initialized U300 pin control driver\n"); return 0; - -out_no_pmx: - iounmap(upmx->virtbase); -out_no_remap: - platform_set_drvdata(pdev, NULL); -out_no_memregion: - release_mem_region(upmx->phybase, upmx->physize); - return ret; } -static int __devexit u300_pmx_remove(struct platform_device *pdev) +static int u300_pmx_remove(struct platform_device *pdev) { struct u300_pmx *upmx = platform_get_drvdata(pdev); pinctrl_unregister(upmx->pctl); - iounmap(upmx->virtbase); - release_mem_region(upmx->phybase, upmx->physize); platform_set_drvdata(pdev, NULL); return 0; @@ -1184,7 +1111,7 @@ static struct platform_driver u300_pmx_driver = { .owner = THIS_MODULE, }, .probe = u300_pmx_probe, - .remove = __devexit_p(u300_pmx_remove), + .remove = u300_pmx_remove, }; static int __init u300_pmx_init(void) diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index b9bcaec6622..ad90984ec50 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -522,7 +522,7 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev, return 0; } -struct pinconf_ops xway_pinconf_ops = { +static struct pinconf_ops xway_pinconf_ops = { .pin_config_get = xway_pinconf_get, .pin_config_set = xway_pinconf_set, }; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 0ef01ee2835..1a00658b3ea 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -409,11 +409,7 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) dev_err(pctldev->dev, "could not request pin %d on device %s\n", pins[i], pinctrl_dev_get_name(pctldev)); - /* On error release all taken pins */ - i--; /* this pin just failed */ - for (; i >= 0; i--) - pin_free(pctldev, pins[i], NULL); - return -ENODEV; + goto err_pin_request; } } @@ -429,8 +425,26 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) desc->mux_setting = &(setting->data.mux); } - return ops->enable(pctldev, setting->data.mux.func, - setting->data.mux.group); + ret = ops->enable(pctldev, setting->data.mux.func, + setting->data.mux.group); + + if (ret) + goto err_enable; + + return 0; + +err_enable: + for (i = 0; i < num_pins; i++) { + desc = pin_desc_get(pctldev, pins[i]); + if (desc) + desc->mux_setting = NULL; + } +err_pin_request: + /* On error release all taken pins */ + while (--i >= 0) + pin_free(pctldev, pins[i], NULL); + + return ret; } void pinmux_disable_setting(struct pinctrl_setting const *setting) diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 91558791e76..04d93e60267 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -25,20 +25,31 @@ config PINCTRL_SPEAR310 bool "ST Microelectronics SPEAr310 SoC pin controller driver" depends on MACH_SPEAR310 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR320 bool "ST Microelectronics SPEAr320 SoC pin controller driver" depends on MACH_SPEAR320 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1310 bool "ST Microelectronics SPEAr1310 SoC pin controller driver" depends on MACH_SPEAR1310 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1340 bool "ST Microelectronics SPEAr1340 SoC pin controller driver" depends on MACH_SPEAR1340 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO + +config PINCTRL_SPEAR_PLGPIO + bool "SPEAr SoC PLGPIO Controller" + depends on GPIOLIB && PINCTRL_SPEAR + help + Say yes here to support PLGPIO controller on ST Microelectronics SPEAr + SoCs. endif diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile index b28a7ba2244..0e400ebeb8f 100644 --- a/drivers/pinctrl/spear/Makefile +++ b/drivers/pinctrl/spear/Makefile @@ -1,5 +1,6 @@ # SPEAr pinmux support +obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c new file mode 100644 index 00000000000..4c045053bbd --- /dev/null +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -0,0 +1,758 @@ +/* + * SPEAr platform PLGPIO driver + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@linaro.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/spinlock.h> +#include <asm/mach/irq.h> + +#define MAX_GPIO_PER_REG 32 +#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG) +#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \ + * sizeof(int *)) + +/* + * plgpio pins in all machines are not one to one mapped, bitwise with registers + * bits. These set of macros define register masks for which below functions + * (pin_to_offset and offset_to_pin) are required to be called. + */ +#define PTO_ENB_REG 0x001 +#define PTO_WDATA_REG 0x002 +#define PTO_DIR_REG 0x004 +#define PTO_IE_REG 0x008 +#define PTO_RDATA_REG 0x010 +#define PTO_MIS_REG 0x020 + +struct plgpio_regs { + u32 enb; /* enable register */ + u32 wdata; /* write data register */ + u32 dir; /* direction set register */ + u32 rdata; /* read data register */ + u32 ie; /* interrupt enable register */ + u32 mis; /* mask interrupt status register */ + u32 eit; /* edge interrupt type */ +}; + +/* + * struct plgpio: plgpio driver specific structure + * + * lock: lock for guarding gpio registers + * base: base address of plgpio block + * irq_base: irq number of plgpio0 + * chip: gpio framework specific chip information structure + * p2o: function ptr for pin to offset conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * o2p: function ptr for offset to pin conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * p2o_regs: mask of registers for which p2o and o2p are applicable + * regs: register offsets + * csave_regs: context save registers for standby/sleep/hibernate cases + */ +struct plgpio { + spinlock_t lock; + void __iomem *base; + struct clk *clk; + unsigned irq_base; + struct irq_domain *irq_domain; + struct gpio_chip chip; + int (*p2o)(int pin); /* pin_to_offset */ + int (*o2p)(int offset); /* offset_to_pin */ + u32 p2o_regs; + struct plgpio_regs regs; +#ifdef CONFIG_PM + struct plgpio_regs *csave_regs; +#endif +}; + +/* register manipulation inline functions */ +static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + return !!(val & (1 << offset)); +} + +static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val | (1 << offset), reg_off); +} + +static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val & ~(1 << offset), reg_off); +} + +/* gpio framework specific routines */ +static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + unsigned dir_offset = offset, wdata_offset = offset, tmp; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) { + tmp = plgpio->p2o(offset); + if (tmp == -1) + return -EINVAL; + + if (plgpio->p2o_regs & PTO_DIR_REG) + dir_offset = tmp; + if (plgpio->p2o_regs & PTO_WDATA_REG) + wdata_offset = tmp; + } + + spin_lock_irqsave(&plgpio->lock, flags); + if (value) + plgpio_reg_set(plgpio->base, wdata_offset, + plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, wdata_offset, + plgpio->regs.wdata); + + plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return -EINVAL; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata); +} + +static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + if (value) + plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata); +} + +static int plgpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + int ret = 0; + + if (offset >= chip->ngpio) + return -EINVAL; + + ret = pinctrl_request_gpio(gpio); + if (ret) + return ret; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_enable(plgpio->clk); + if (ret) + goto err0; + } + + if (plgpio->regs.enb == -1) + return 0; + + /* + * put gpio in IN mode before enabling it. This make enabling gpio safe + */ + ret = plgpio_direction_input(chip, offset); + if (ret) + goto err1; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) { + ret = -EINVAL; + goto err1; + } + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + return 0; + +err1: + if (!IS_ERR(plgpio->clk)) + clk_disable(plgpio->clk); +err0: + pinctrl_free_gpio(gpio); + return ret; +} + +static void plgpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + + if (offset >= chip->ngpio) + return; + + if (plgpio->regs.enb == -1) + goto disable_clk; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + +disable_clk: + if (!IS_ERR(plgpio->clk)) + clk_disable(plgpio->clk); + + pinctrl_free_gpio(gpio); +} + +static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (IS_ERR_VALUE(plgpio->irq_base)) + return -EINVAL; + + return irq_find_mapping(plgpio->irq_domain, offset); +} + +/* PLGPIO IRQ */ +static void plgpio_irq_disable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static void plgpio_irq_enable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + void __iomem *reg_off; + unsigned int supported_type = 0, val; + + if (offset >= plgpio->chip.ngpio) + return -EINVAL; + + if (plgpio->regs.eit == -1) + supported_type = IRQ_TYPE_LEVEL_HIGH; + else + supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + if (!(trigger & supported_type)) + return -EINVAL; + + if (plgpio->regs.eit == -1) + return 0; + + reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset); + val = readl_relaxed(reg_off); + + offset = PIN_OFFSET(offset); + if (trigger & IRQ_TYPE_EDGE_RISING) + writel_relaxed(val | (1 << offset), reg_off); + else + writel_relaxed(val & ~(1 << offset), reg_off); + + return 0; +} + +static struct irq_chip plgpio_irqchip = { + .name = "PLGPIO", + .irq_enable = plgpio_irq_enable, + .irq_disable = plgpio_irq_disable, + .irq_set_type = plgpio_irq_set_type, +}; + +static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct plgpio *plgpio = irq_get_handler_data(irq); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int regs_count, count, pin, offset, i = 0; + unsigned long pending; + + count = plgpio->chip.ngpio; + regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG); + + chained_irq_enter(irqchip, desc); + /* check all plgpio MIS registers for a possible interrupt */ + for (; i < regs_count; i++) { + pending = readl_relaxed(plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + if (!pending) + continue; + + /* clear interrupts */ + writel_relaxed(~pending, plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + /* + * clear extra bits in last register having gpios < MAX/REG + * ex: Suppose there are max 102 plgpios. then last register + * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits + * so, we must not take other 28 bits into consideration for + * checking interrupt. so clear those bits. + */ + count = count - i * MAX_GPIO_PER_REG; + if (count < MAX_GPIO_PER_REG) + pending &= (1 << count) - 1; + + for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) { + /* get correct pin for "offset" */ + if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) { + pin = plgpio->o2p(offset); + if (pin == -1) + continue; + } else + pin = offset; + + /* get correct irq line number */ + pin = i * MAX_GPIO_PER_REG + pin; + generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin)); + } + } + chained_irq_exit(irqchip, desc); +} + +/* + * pin to offset and offset to pin converter functions + * + * In spear310 there is inconsistency among bit positions in plgpio regiseters, + * for different plgpio pins. For example: for pin 27, bit offset is 23, pin + * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1 + */ +static int spear310_p2o(int pin) +{ + int offset = pin; + + if (pin <= 27) + offset += 4; + else if (pin <= 33) + offset = -1; + else if (pin <= 97) + offset -= 2; + else if (pin <= 101) + offset = 101 - pin; + else + offset = -1; + + return offset; +} + +int spear310_o2p(int offset) +{ + if (offset <= 3) + return 101 - offset; + else if (offset <= 31) + return offset - 4; + else + return offset + 2; +} + +static int __devinit plgpio_probe_dt(struct platform_device *pdev, + struct plgpio *plgpio) +{ + struct device_node *np = pdev->dev.of_node; + int ret = -EINVAL; + u32 val; + + if (of_machine_is_compatible("st,spear310")) { + plgpio->p2o = spear310_p2o; + plgpio->o2p = spear310_o2p; + plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG | + PTO_RDATA_REG | PTO_MIS_REG; + } + + if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) { + plgpio->chip.ngpio = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ngpio field\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val)) + plgpio->regs.enb = val; + else + plgpio->regs.enb = -1; + + if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) { + plgpio->regs.wdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid wdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) { + plgpio->regs.dir = val; + } else { + dev_err(&pdev->dev, "DT: Invalid dir reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) { + plgpio->regs.ie = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ie reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) { + plgpio->regs.rdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid rdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) { + plgpio->regs.mis = val; + } else { + dev_err(&pdev->dev, "DT: Invalid mis reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val)) + plgpio->regs.eit = val; + else + plgpio->regs.eit = -1; + + return 0; + +end: + return ret; +} +static int __devinit plgpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct plgpio *plgpio; + struct resource *res; + int ret, irq, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL); + if (!plgpio) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + plgpio->base = devm_request_and_ioremap(&pdev->dev, res); + if (!plgpio->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + ret = plgpio_probe_dt(pdev, plgpio); + if (ret) { + dev_err(&pdev->dev, "DT probe failed\n"); + return ret; + } + + plgpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(plgpio->clk)) + dev_warn(&pdev->dev, "clk_get() failed, work without it\n"); + +#ifdef CONFIG_PM + plgpio->csave_regs = devm_kzalloc(&pdev->dev, + sizeof(*plgpio->csave_regs) * + DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), + GFP_KERNEL); + if (!plgpio->csave_regs) { + dev_err(&pdev->dev, "csave registers memory allocation fail\n"); + return -ENOMEM; + } +#endif + + platform_set_drvdata(pdev, plgpio); + spin_lock_init(&plgpio->lock); + + plgpio->irq_base = -1; + plgpio->chip.base = -1; + plgpio->chip.request = plgpio_request; + plgpio->chip.free = plgpio_free; + plgpio->chip.direction_input = plgpio_direction_input; + plgpio->chip.direction_output = plgpio_direction_output; + plgpio->chip.get = plgpio_get_value; + plgpio->chip.set = plgpio_set_value; + plgpio->chip.to_irq = plgpio_to_irq; + plgpio->chip.label = dev_name(&pdev->dev); + plgpio->chip.dev = &pdev->dev; + plgpio->chip.owner = THIS_MODULE; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_prepare(plgpio->clk); + if (ret) { + dev_err(&pdev->dev, "clk prepare failed\n"); + return ret; + } + } + + ret = gpiochip_add(&plgpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + goto unprepare_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_info(&pdev->dev, "irqs not supported\n"); + return 0; + } + + plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0); + if (IS_ERR_VALUE(plgpio->irq_base)) { + /* we would not support irq for gpio */ + dev_warn(&pdev->dev, "couldn't allocate irq base\n"); + return 0; + } + + plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio, + plgpio->irq_base, 0, &irq_domain_simple_ops, NULL); + if (WARN_ON(!plgpio->irq_domain)) { + dev_err(&pdev->dev, "irq domain init failed\n"); + irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio); + ret = -ENXIO; + goto remove_gpiochip; + } + + irq_set_chained_handler(irq, plgpio_irq_handler); + for (i = 0; i < plgpio->chip.ngpio; i++) { + irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip, + handle_simple_irq); + set_irq_flags(i + plgpio->irq_base, IRQF_VALID); + irq_set_chip_data(i + plgpio->irq_base, plgpio); + } + + irq_set_handler_data(irq, plgpio); + dev_info(&pdev->dev, "PLGPIO registered with IRQs\n"); + + return 0; + +remove_gpiochip: + dev_info(&pdev->dev, "Remove gpiochip\n"); + if (gpiochip_remove(&plgpio->chip)) + dev_err(&pdev->dev, "unable to remove gpiochip\n"); +unprepare_clk: + if (!IS_ERR(plgpio->clk)) + clk_unprepare(plgpio->clk); + + return ret; +} + +#ifdef CONFIG_PM +static int plgpio_suspend(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (plgpio->regs.enb != -1) + plgpio->csave_regs[i].enb = + readl_relaxed(plgpio->regs.enb + off); + if (plgpio->regs.eit != -1) + plgpio->csave_regs[i].eit = + readl_relaxed(plgpio->regs.eit + off); + plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata + + off); + plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir + + off); + plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off); + } + + return 0; +} + +/* + * This is used to correct the values in end registers. End registers contain + * extra bits that might be used for other purpose in platform. So, we shouldn't + * overwrite these bits. This macro, reads given register again, preserves other + * bit values (non-plgpio bits), and retain captured value (plgpio bits). + */ +#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \ +{ \ + _tmp = readl_relaxed(plgpio->regs.__reg + _off); \ + _tmp &= ~_mask; \ + plgpio->csave_regs[i].__reg = \ + _tmp | (plgpio->csave_regs[i].__reg & _mask); \ +} + +static int plgpio_resume(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + u32 mask, tmp; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (i == reg_count - 1) { + mask = (1 << (plgpio->chip.ngpio - i * + MAX_GPIO_PER_REG)) - 1; + + if (plgpio->regs.enb != -1) + plgpio_prepare_reg(enb, off, mask, tmp); + + if (plgpio->regs.eit != -1) + plgpio_prepare_reg(eit, off, mask, tmp); + + plgpio_prepare_reg(wdata, off, mask, tmp); + plgpio_prepare_reg(dir, off, mask, tmp); + plgpio_prepare_reg(ie, off, mask, tmp); + } + + writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata + + off); + writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir + + off); + + if (plgpio->regs.eit != -1) + writel_relaxed(plgpio->csave_regs[i].eit, + plgpio->regs.eit + off); + + writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off); + + if (plgpio->regs.enb != -1) + writel_relaxed(plgpio->csave_regs[i].enb, + plgpio->regs.enb + off); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume); + +static const struct of_device_id plgpio_of_match[] = { + { .compatible = "st,spear-plgpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, plgpio_of_match); + +static struct platform_driver plgpio_driver = { + .probe = plgpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-plgpio", + .pm = &plgpio_dev_pm_ops, + .of_match_table = of_match_ptr(plgpio_of_match), + }, +}; + +static int __init plgpio_init(void) +{ + return platform_driver_register(&plgpio_driver); +} +subsys_initcall(plgpio_init); + +MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); +MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b1fd6ee33c6..922c057521a 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -14,10 +14,10 @@ */ #include <linux/err.h> -#include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_gpio.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> @@ -28,14 +28,26 @@ #define DRIVER_NAME "spear-pinmux" -static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg) +static void muxregs_endisable(struct spear_pmx *pmx, + struct spear_muxreg *muxregs, u8 count, bool enable) { - return readl_relaxed(pmx->vbase + reg); -} + struct spear_muxreg *muxreg; + u32 val, temp, j; -static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) -{ - writel_relaxed(val, pmx->vbase + reg); + for (j = 0; j < count; j++) { + muxreg = &muxregs[j]; + + val = pmx_readl(pmx, muxreg->reg); + val &= ~muxreg->mask; + + if (enable) + temp = muxreg->val; + else + temp = ~muxreg->val; + + val |= muxreg->mask & temp; + pmx_writel(pmx, val, muxreg->reg); + } } static int set_mode(struct spear_pmx *pmx, int mode) @@ -70,6 +82,17 @@ static int set_mode(struct spear_pmx *pmx, int mode) return 0; } +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg) +{ + int i, j; + + for (i = 0; i < count; i++) + for (j = 0; j < gpio_pingroup[i].nmuxregs; j++) + gpio_pingroup[i].muxregs[j].reg = reg; +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) { struct spear_pingroup *pgroup; @@ -121,9 +144,10 @@ static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " " DRIVER_NAME); } -int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *num_maps) +static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct device_node *np; @@ -168,8 +192,9 @@ int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, return 0; } -void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned num_maps) { kfree(map); } @@ -216,9 +241,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct spear_pingroup *pgroup; const struct spear_modemux *modemux; - struct spear_muxreg *muxreg; - u32 val, temp; - int i, j; + int i; bool found = false; pgroup = pmx->machdata->groups[group]; @@ -233,20 +256,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, } found = true; - for (j = 0; j < modemux->nmuxregs; j++) { - muxreg = &modemux->muxregs[j]; - - val = pmx_readl(pmx, muxreg->reg); - val &= ~muxreg->mask; - - if (enable) - temp = muxreg->val; - else - temp = ~muxreg->val; - - val |= muxreg->mask & temp; - pmx_writel(pmx, val, muxreg->reg); - } + muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs, + enable); } if (!found) { @@ -270,12 +281,74 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev, spear_pinctrl_endisable(pctldev, function, group, false); } +/* gpio with pinmux */ +static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx, + unsigned pin) +{ + struct spear_gpio_pingroup *gpio_pingroup; + int i, j; + + if (!pmx->machdata->gpio_pingroups) + return NULL; + + for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) { + gpio_pingroup = &pmx->machdata->gpio_pingroups[i]; + + for (j = 0; j < gpio_pingroup->npins; j++) { + if (gpio_pingroup->pins[j] == pin) + return gpio_pingroup; + } + } + + return NULL; +} + +static int gpio_request_endisable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool enable) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct spear_pinctrl_machdata *machdata = pmx->machdata; + struct spear_gpio_pingroup *gpio_pingroup; + + /* + * Some SoC have configuration options applicable to group of pins, + * rather than a single pin. + */ + gpio_pingroup = get_gpio_pingroup(pmx, offset); + if (gpio_pingroup) + muxregs_endisable(pmx, gpio_pingroup->muxregs, + gpio_pingroup->nmuxregs, enable); + + /* + * SoC may need some extra configurations, or configurations for single + * pin + */ + if (machdata->gpio_request_endisable) + machdata->gpio_request_endisable(pmx, offset, enable); + + return 0; +} + +static int gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + return gpio_request_endisable(pctldev, range, offset, true); +} + +static void gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + gpio_request_endisable(pctldev, range, offset, false); +} + static struct pinmux_ops spear_pinmux_ops = { .get_functions_count = spear_pinctrl_get_funcs_count, .get_function_name = spear_pinctrl_get_func_name, .get_function_groups = spear_pinctrl_get_func_groups, .enable = spear_pinctrl_enable, .disable = spear_pinctrl_disable, + .gpio_request_enable = gpio_request_enable, + .gpio_disable_free = gpio_disable_free, }; static struct pinctrl_desc spear_pinctrl_desc = { @@ -344,7 +417,7 @@ int __devinit spear_pinctrl_probe(struct platform_device *pdev, return 0; } -int __devexit spear_pinctrl_remove(struct platform_device *pdev) +int spear_pinctrl_remove(struct platform_device *pdev) { struct spear_pmx *pmx = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h index d950eb78d93..1be46ecc6d9 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.h +++ b/drivers/pinctrl/spear/pinctrl-spear.h @@ -12,11 +12,14 @@ #ifndef __PINMUX_SPEAR_H__ #define __PINMUX_SPEAR_H__ +#include <linux/gpio.h> +#include <linux/io.h> #include <linux/pinctrl/pinctrl.h> #include <linux/types.h> struct platform_device; struct device; +struct spear_pmx; /** * struct spear_pmx_mode - SPEAr pmx mode @@ -46,6 +49,44 @@ struct spear_muxreg { u32 val; }; +struct spear_gpio_pingroup { + const unsigned *pins; + unsigned npins; + struct spear_muxreg *muxregs; + u8 nmuxregs; +}; + +/* ste: set to enable */ +#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg, \ + .mask = __mask, \ + .val = __ste ? __mask : 0, \ + }, \ +} + +#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg1, \ + .mask = __mask, \ + .val = __ste1 ? __mask : 0, \ + }, { \ + .reg = __muxreg2, \ + .mask = __mask, \ + .val = __ste2 ? __mask : 0, \ + }, \ +} + +#define GPIO_PINGROUP(__pins) \ + { \ + .pins = __pins, \ + .npins = ARRAY_SIZE(__pins), \ + .muxregs = __pins##_muxregs, \ + .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \ + } + /** * struct spear_modemux - SPEAr mode mux configuration * @modes: mode ids supported by this group of muxregs @@ -100,6 +141,8 @@ struct spear_function { * @nfunctions: The numbmer of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The numbmer of entries in @groups. + * @gpio_pingroups: gpio pingroups + * @ngpio_pingroups: gpio pingroups count * * @modes_supported: Does SoC support modes * @mode: mode configured from probe @@ -113,6 +156,10 @@ struct spear_pinctrl_machdata { unsigned nfunctions; struct spear_pingroup **groups; unsigned ngroups; + struct spear_gpio_pingroup *gpio_pingroups; + void (*gpio_request_endisable)(struct spear_pmx *pmx, int offset, + bool enable); + unsigned ngpio_pingroups; bool modes_supported; u16 mode; @@ -135,10 +182,23 @@ struct spear_pmx { }; /* exported routines */ +static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg) +{ + return readl_relaxed(pmx->vbase + reg); +} + +static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) +{ + writel_relaxed(val, pmx->vbase + reg); +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg); +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg); int __devinit spear_pinctrl_probe(struct platform_device *pdev, struct spear_pinctrl_machdata *machdata); -int __devexit spear_pinctrl_remove(struct platform_device *pdev); +int spear_pinctrl_remove(struct platform_device *pdev); #define SPEAR_PIN_0_TO_101 \ PINCTRL_PIN(0, "PLGPIO0"), \ diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index 0436fc7895d..e40d785a3fc 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = { &gpt64_function, }; +static const unsigned pin18[] = { 18, }; +static const unsigned pin19[] = { 19, }; +static const unsigned pin20[] = { 20, }; +static const unsigned pin21[] = { 21, }; +static const unsigned pin22[] = { 22, }; +static const unsigned pin23[] = { 23, }; +static const unsigned pin54[] = { 54, }; +static const unsigned pin55[] = { 55, }; +static const unsigned pin56[] = { 56, }; +static const unsigned pin57[] = { 57, }; +static const unsigned pin58[] = { 58, }; +static const unsigned pin59[] = { 59, }; +static const unsigned pin60[] = { 60, }; +static const unsigned pin61[] = { 61, }; +static const unsigned pin62[] = { 62, }; +static const unsigned pin63[] = { 63, }; +static const unsigned pin143[] = { 143, }; +static const unsigned pin144[] = { 144, }; +static const unsigned pin145[] = { 145, }; +static const unsigned pin146[] = { 146, }; +static const unsigned pin147[] = { 147, }; +static const unsigned pin148[] = { 148, }; +static const unsigned pin149[] = { 149, }; +static const unsigned pin150[] = { 150, }; +static const unsigned pin151[] = { 151, }; +static const unsigned pin152[] = { 152, }; +static const unsigned pin205[] = { 205, }; +static const unsigned pin206[] = { 206, }; +static const unsigned pin211[] = { 211, }; +static const unsigned pin212[] = { 212, }; +static const unsigned pin213[] = { 213, }; +static const unsigned pin214[] = { 214, }; +static const unsigned pin215[] = { 215, }; +static const unsigned pin216[] = { 216, }; +static const unsigned pin217[] = { 217, }; +static const unsigned pin218[] = { 218, }; +static const unsigned pin219[] = { 219, }; +static const unsigned pin220[] = { 220, }; +static const unsigned pin221[] = { 221, }; +static const unsigned pin222[] = { 222, }; +static const unsigned pin223[] = { 223, }; +static const unsigned pin224[] = { 224, }; +static const unsigned pin225[] = { 225, }; +static const unsigned pin226[] = { 226, }; +static const unsigned pin227[] = { 227, }; +static const unsigned pin228[] = { 228, }; +static const unsigned pin229[] = { 229, }; +static const unsigned pin230[] = { 230, }; +static const unsigned pin231[] = { 231, }; +static const unsigned pin232[] = { 232, }; +static const unsigned pin233[] = { 233, }; +static const unsigned pin234[] = { 234, }; +static const unsigned pin235[] = { 235, }; +static const unsigned pin236[] = { 236, }; +static const unsigned pin237[] = { 237, }; +static const unsigned pin238[] = { 238, }; +static const unsigned pin239[] = { 239, }; +static const unsigned pin240[] = { 240, }; +static const unsigned pin241[] = { 241, }; +static const unsigned pin242[] = { 242, }; +static const unsigned pin243[] = { 243, }; +static const unsigned pin244[] = { 244, }; +static const unsigned pin245[] = { 245, }; + +static const unsigned pin_grp0[] = { 173, 174, }; +static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, }; +static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189, + 190, 191, 192, }; +static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, }; +static const unsigned pin_grp4[] = { 199, 200, }; +static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, }; +static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, }; +static const unsigned pin_grp7[] = { 98, 99, }; +static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, }; + +/* Define muxreg arrays */ +DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1); +DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1); +DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1); +DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1); +DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1); +DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1); +DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1); +DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1); +DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1); +DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1); +DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1); +DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1); +DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1); +DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1); +DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1); +DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1); +DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1); +DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1); +DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1); +DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1); +DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1); +DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1); +DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1); +DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1); +DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1); +DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1); +DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1); +DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1); +DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1); +DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1); +DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1); +DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1); +DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1); +DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1); +DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1); +DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1); +DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1); +DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1); +DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1); +DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1); +DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1); +DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1); +DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1); +DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1); +DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1); +DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1); +DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1); +DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1); +DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1); +DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1); +DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1); +DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1); +DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1); +DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1); +DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1); +DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1); +DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1); +DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1); +DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1); +DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1); + +static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = { + GPIO_PINGROUP(i2c0_pins), + GPIO_PINGROUP(ssp0_pins), + GPIO_PINGROUP(ssp0_cs0_pins), + GPIO_PINGROUP(ssp0_cs1_2_pins), + GPIO_PINGROUP(i2s0_pins), + GPIO_PINGROUP(i2s1_pins), + GPIO_PINGROUP(clcd_pins), + GPIO_PINGROUP(clcd_high_res_pins), + GPIO_PINGROUP(pin18), + GPIO_PINGROUP(pin19), + GPIO_PINGROUP(pin20), + GPIO_PINGROUP(pin21), + GPIO_PINGROUP(pin22), + GPIO_PINGROUP(pin23), + GPIO_PINGROUP(pin143), + GPIO_PINGROUP(pin144), + GPIO_PINGROUP(pin145), + GPIO_PINGROUP(pin146), + GPIO_PINGROUP(pin147), + GPIO_PINGROUP(pin148), + GPIO_PINGROUP(pin149), + GPIO_PINGROUP(pin150), + GPIO_PINGROUP(pin151), + GPIO_PINGROUP(pin152), + GPIO_PINGROUP(smi_2_chips_pins), + GPIO_PINGROUP(pin54), + GPIO_PINGROUP(pin55), + GPIO_PINGROUP(pin56), + GPIO_PINGROUP(pin57), + GPIO_PINGROUP(pin58), + GPIO_PINGROUP(pin59), + GPIO_PINGROUP(pin60), + GPIO_PINGROUP(pin61), + GPIO_PINGROUP(pin62), + GPIO_PINGROUP(pin63), + GPIO_PINGROUP(pin_grp0), + GPIO_PINGROUP(pin_grp1), + GPIO_PINGROUP(pin_grp2), + GPIO_PINGROUP(pin_grp3), + GPIO_PINGROUP(pin_grp4), + GPIO_PINGROUP(pin_grp5), + GPIO_PINGROUP(pin_grp6), + GPIO_PINGROUP(pin_grp7), + GPIO_PINGROUP(pin_grp8), + GPIO_PINGROUP(nand_16bit_pins), + GPIO_PINGROUP(pin205), + GPIO_PINGROUP(pin206), + GPIO_PINGROUP(pin211), + GPIO_PINGROUP(pin212), + GPIO_PINGROUP(pin213), + GPIO_PINGROUP(pin214), + GPIO_PINGROUP(pin215), + GPIO_PINGROUP(pin216), + GPIO_PINGROUP(pin217), + GPIO_PINGROUP(pin218), + GPIO_PINGROUP(pin219), + GPIO_PINGROUP(pin220), + GPIO_PINGROUP(pin221), + GPIO_PINGROUP(pin222), + GPIO_PINGROUP(pin223), + GPIO_PINGROUP(pin224), + GPIO_PINGROUP(pin225), + GPIO_PINGROUP(pin226), + GPIO_PINGROUP(pin227), + GPIO_PINGROUP(pin228), + GPIO_PINGROUP(pin229), + GPIO_PINGROUP(pin230), + GPIO_PINGROUP(pin231), + GPIO_PINGROUP(pin232), + GPIO_PINGROUP(pin233), + GPIO_PINGROUP(pin234), + GPIO_PINGROUP(pin235), + GPIO_PINGROUP(pin236), + GPIO_PINGROUP(pin237), + GPIO_PINGROUP(pin238), + GPIO_PINGROUP(pin239), + GPIO_PINGROUP(pin240), + GPIO_PINGROUP(pin241), + GPIO_PINGROUP(pin242), + GPIO_PINGROUP(pin243), + GPIO_PINGROUP(pin244), + GPIO_PINGROUP(pin245), + GPIO_PINGROUP(keyboard_rowcol6_8_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(uart0_modem_pins), + GPIO_PINGROUP(gpt0_tmr0_pins), + GPIO_PINGROUP(gpt0_tmr1_pins), + GPIO_PINGROUP(gpt1_tmr0_pins), + GPIO_PINGROUP(gpt1_tmr1_pins), + GPIO_PINGROUP(touch_xy_pins), +}; + static struct spear_pinctrl_machdata spear1310_machdata = { .pins = spear1310_pins, .npins = ARRAY_SIZE(spear1310_pins), @@ -2425,10 +2687,12 @@ static struct spear_pinctrl_machdata spear1310_machdata = { .ngroups = ARRAY_SIZE(spear1310_pingroups), .functions = spear1310_functions, .nfunctions = ARRAY_SIZE(spear1310_functions), + .gpio_pingroups = spear1310_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup), .modes_supported = false, }; -static struct of_device_id spear1310_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear1310_pinctrl_of_match[] = { { .compatible = "st,spear1310-pinmux", }, @@ -2440,7 +2704,7 @@ static int __devinit spear1310_pinctrl_probe(struct platform_device *pdev) return spear_pinctrl_probe(pdev, &spear1310_machdata); } -static int __devexit spear1310_pinctrl_remove(struct platform_device *pdev) +static int spear1310_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -2452,7 +2716,7 @@ static struct platform_driver spear1310_pinctrl_driver = { .of_match_table = spear1310_pinctrl_of_match, }, .probe = spear1310_pinctrl_probe, - .remove = __devexit_p(spear1310_pinctrl_remove), + .remove = spear1310_pinctrl_remove, }; static int __init spear1310_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c index 0606b8cf3f2..8deaaff3156 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1340.c +++ b/drivers/pinctrl/spear/pinctrl-spear1340.c @@ -1971,6 +1971,32 @@ static struct spear_function *spear1340_functions[] = { &sata_function, }; +static void gpio_request_endisable(struct spear_pmx *pmx, int pin, + bool enable) +{ + unsigned int regoffset, regindex, bitoffset; + unsigned int val; + + /* pin++ as gpio configuration starts from 2nd bit of base register */ + pin++; + + regindex = pin / 32; + bitoffset = pin % 32; + + if (regindex <= 3) + regoffset = PAD_FUNCTION_EN_1 + regindex * sizeof(int *); + else + regoffset = PAD_FUNCTION_EN_5 + (regindex - 4) * sizeof(int *); + + val = pmx_readl(pmx, regoffset); + if (enable) + val &= ~(0x1 << bitoffset); + else + val |= 0x1 << bitoffset; + + pmx_writel(pmx, val, regoffset); +} + static struct spear_pinctrl_machdata spear1340_machdata = { .pins = spear1340_pins, .npins = ARRAY_SIZE(spear1340_pins), @@ -1978,10 +2004,11 @@ static struct spear_pinctrl_machdata spear1340_machdata = { .ngroups = ARRAY_SIZE(spear1340_pingroups), .functions = spear1340_functions, .nfunctions = ARRAY_SIZE(spear1340_functions), + .gpio_request_endisable = gpio_request_endisable, .modes_supported = false, }; -static struct of_device_id spear1340_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear1340_pinctrl_of_match[] = { { .compatible = "st,spear1340-pinmux", }, @@ -1993,7 +2020,7 @@ static int __devinit spear1340_pinctrl_probe(struct platform_device *pdev) return spear_pinctrl_probe(pdev, &spear1340_machdata); } -static int __devexit spear1340_pinctrl_remove(struct platform_device *pdev) +static int spear1340_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -2005,7 +2032,7 @@ static struct platform_driver spear1340_pinctrl_driver = { .of_match_table = spear1340_pinctrl_of_match, }, .probe = spear1340_pinctrl_probe, - .remove = __devexit_p(spear1340_pinctrl_remove), + .remove = spear1340_pinctrl_remove, }; static int __init spear1340_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 4dfc2849b17..f48e466e605 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -646,7 +646,7 @@ static struct spear_function *spear300_functions[] = { &gpio1_function, }; -static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear300_pinctrl_of_match[] = { { .compatible = "st,spear300-pinmux", }, @@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups); spear3xx_machdata.functions = spear300_functions; spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions); + spear3xx_machdata.gpio_pingroups = NULL; + spear3xx_machdata.ngpio_pingroups = 0; spear3xx_machdata.modes_supported = true; spear3xx_machdata.pmx_modes = spear300_pmx_modes; @@ -675,7 +677,7 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear300_pinctrl_remove(struct platform_device *pdev) +static int spear300_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -687,7 +689,7 @@ static struct platform_driver spear300_pinctrl_driver = { .of_match_table = spear300_pinctrl_of_match, }, .probe = spear300_pinctrl_probe, - .remove = __devexit_p(spear300_pinctrl_remove), + .remove = spear300_pinctrl_remove, }; static int __init spear300_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index 96883693fb7..5b954c19a6d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -371,7 +371,7 @@ static struct spear_function *spear310_functions[] = { &tdm_function, }; -static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear310_pinctrl_of_match[] = { { .compatible = "st,spear310-pinmux", }, @@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); spear3xx_machdata.modes_supported = false; @@ -398,7 +400,7 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear310_pinctrl_remove(struct platform_device *pdev) +static int spear310_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -410,7 +412,7 @@ static struct platform_driver spear310_pinctrl_driver = { .of_match_table = spear310_pinctrl_of_match, }, .probe = spear310_pinctrl_probe, - .remove = __devexit_p(spear310_pinctrl_remove), + .remove = spear310_pinctrl_remove, }; static int __init spear310_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index ca47b0e5078..e9a5e6d3924 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -3410,7 +3410,7 @@ static struct spear_function *spear320_functions[] = { &i2c2_function, }; -static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear320_pinctrl_of_match[] = { { .compatible = "st,spear320-pinmux", }, @@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); if (ret) @@ -3439,7 +3441,7 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear320_pinctrl_remove(struct platform_device *pdev) +static int spear320_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -3451,7 +3453,7 @@ static struct platform_driver spear320_pinctrl_driver = { .of_match_table = spear320_pinctrl_of_match, }, .probe = spear320_pinctrl_probe, - .remove = __devexit_p(spear320_pinctrl_remove), + .remove = spear320_pinctrl_remove, }; static int __init spear320_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c index 0242378f7cb..12ee21af766 100644 --- a/drivers/pinctrl/spear/pinctrl-spear3xx.c +++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c @@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = { .ngroups = ARRAY_SIZE(timer_2_3_grps), }; +/* Define muxreg arrays */ +DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0); +DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0); +DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0); +DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0); +DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0); +DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0); +DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0); +DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0); +DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0); +DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0); +DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0); +DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0); +DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0); +DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0); +DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0); + +static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = { + GPIO_PINGROUP(firda_pins), + GPIO_PINGROUP(i2c_pins), + GPIO_PINGROUP(ssp_cs_pins), + GPIO_PINGROUP(ssp_pins), + GPIO_PINGROUP(mii_pins), + GPIO_PINGROUP(gpio0_pin0_pins), + GPIO_PINGROUP(gpio0_pin1_pins), + GPIO_PINGROUP(gpio0_pin2_pins), + GPIO_PINGROUP(gpio0_pin3_pins), + GPIO_PINGROUP(gpio0_pin4_pins), + GPIO_PINGROUP(gpio0_pin5_pins), + GPIO_PINGROUP(uart0_ext_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(timer_0_1_pins), + GPIO_PINGROUP(timer_2_3_pins), +}; + struct spear_pinctrl_machdata spear3xx_machdata = { .pins = spear3xx_pins, .npins = ARRAY_SIZE(spear3xx_pins), + .gpio_pingroups = spear3xx_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup), }; |