diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 12:34:42 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 12:34:42 +0200 |
commit | f2006e27396f55276f24434f56e208d86e7f9908 (patch) | |
tree | 71896db916d33888b4286f80117d3cac0da40e6d /drivers/pinctrl | |
parent | e399eb56a6110e13f97e644658648602e2b08de7 (diff) | |
parent | 9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e (diff) |
Merge branch 'linus' into timers/urgent
Get upstream changes so we can apply fixes against them
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/pinctrl')
38 files changed, 12587 insertions, 2683 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 901a388dbea..5a8ad513931 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -58,6 +58,18 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver +config PINCTRL_BAYTRAIL + bool "Intel Baytrail GPIO pin control" + depends on GPIOLIB && ACPI && X86 + select IRQ_DOMAIN + help + driver for memory mapped GPIO functionality on Intel Baytrail + platforms. Supports 3 banks with 102, 28 and 44 gpios. + Most pins are usually muxed to some other functionality by firmware, + so only a small amount is available for gpio use. + + Requires ACPI device enumeration code to set up a platform device. + config PINCTRL_BCM2835 bool select PINMUX @@ -108,6 +120,14 @@ config PINCTRL_IMX6SL help Say Y here to enable the imx6sl pinctrl driver +config PINCTRL_VF610 + bool "Freescale Vybrid VF610 pinctrl driver" + depends on OF + depends on SOC_VF610 + select PINCTRL_IMX + help + Say Y here to enable the Freescale Vybrid VF610 pinctrl driver + config PINCTRL_LANTIQ bool depends on LANTIQ @@ -150,6 +170,12 @@ config PINCTRL_DB8540 bool "DB8540 pin controller driver" depends on PINCTRL_NOMADIK && ARCH_U8500 +config PINCTRL_ROCKCHIP + bool + select PINMUX + select GENERIC_PINCONF + select GENERIC_IRQ_CHIP + config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" depends on OF @@ -169,6 +195,12 @@ config PINCTRL_SUNXI select PINMUX select GENERIC_PINCONF +config PINCTRL_ST + bool + depends on OF + select PINMUX + select PINCONF + config PINCTRL_TEGRA bool select PINMUX @@ -186,6 +218,18 @@ config PINCTRL_TEGRA114 bool select PINCTRL_TEGRA +config PINCTRL_TZ1090 + bool "Toumaz Xenif TZ1090 pin control driver" + depends on SOC_TZ1090 + select PINMUX + select GENERIC_PINCONF + +config PINCTRL_TZ1090_PDC + bool "Toumaz Xenif TZ1090 PDC pin control driver" + depends on SOC_TZ1090 + select PINMUX + select PINCONF + config PINCTRL_U300 bool "U300 pin controller driver" depends on ARCH_U300 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f90b645fb60..d64563bf6fb 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,12 +16,14 @@ obj-$(CONFIG_PINCTRL_AB9540) += pinctrl-ab9540.o obj-$(CONFIG_PINCTRL_AB8505) += pinctrl-ab8505.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o +obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o @@ -30,13 +32,16 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o +obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o -obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o +obj-$(CONFIG_PINCTRL_SIRF) += sirf/ obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o +obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o +obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o @@ -46,6 +51,8 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o +obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 5327f35d9b5..5b272bfd261 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -41,13 +41,13 @@ static bool pinctrl_dummy_state; /* Mutex taken to protect pinctrl_list */ -DEFINE_MUTEX(pinctrl_list_mutex); +static DEFINE_MUTEX(pinctrl_list_mutex); /* Mutex taken to protect pinctrl_maps */ DEFINE_MUTEX(pinctrl_maps_mutex); /* Mutex taken to protect pinctrldev_list */ -DEFINE_MUTEX(pinctrldev_list_mutex); +static DEFINE_MUTEX(pinctrldev_list_mutex); /* Global list of pin control devices (struct pinctrl_dev) */ static LIST_HEAD(pinctrldev_list); @@ -101,20 +101,23 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata); struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname) { struct pinctrl_dev *pctldev = NULL; - bool found = false; if (!devname) return NULL; + mutex_lock(&pinctrldev_list_mutex); + list_for_each_entry(pctldev, &pinctrldev_list, node) { if (!strcmp(dev_name(pctldev->dev), devname)) { /* Matched on device name */ - found = true; - break; + mutex_unlock(&pinctrldev_list_mutex); + return pctldev; } } - return found ? pctldev : NULL; + mutex_unlock(&pinctrldev_list_mutex); + + return NULL; } struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np) @@ -280,6 +283,29 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev, } /** + * gpio_to_pin() - GPIO range GPIO number to pin number translation + * @range: GPIO range used for the translation + * @gpio: gpio pin to translate to a pin number + * + * Finds the pin number for a given GPIO using the specified GPIO range + * as a base for translation. The distinction between linear GPIO ranges + * and pin list based GPIO ranges is managed correctly by this function. + * + * This function assumes the gpio is part of the specified GPIO range, use + * only after making sure this is the case (e.g. by calling it on the + * result of successful pinctrl_get_device_gpio_range calls)! + */ +static inline int gpio_to_pin(struct pinctrl_gpio_range *range, + unsigned int gpio) +{ + unsigned int offset = gpio - range->base; + if (range->pins) + return range->pins[offset]; + else + return range->pin_base + offset; +} + +/** * pinctrl_match_gpio_range() - check if a certain GPIO pin is in range * @pctldev: pin controller device to check * @gpio: gpio pin to check taken from the global GPIO pin space @@ -326,6 +352,8 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio) struct pinctrl_gpio_range *range = NULL; struct gpio_chip *chip = gpio_to_chip(gpio); + mutex_lock(&pinctrldev_list_mutex); + /* Loop over the pin controllers */ list_for_each_entry(pctldev, &pinctrldev_list, node) { /* Loop over the ranges */ @@ -334,9 +362,13 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio) if (range->base + range->npins - 1 < chip->base || range->base > chip->base + chip->ngpio - 1) continue; + mutex_unlock(&pinctrldev_list_mutex); return true; } } + + mutex_unlock(&pinctrldev_list_mutex); + return false; } #else @@ -408,8 +440,6 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname, { struct pinctrl_dev *pctldev; - mutex_lock(&pinctrldev_list_mutex); - pctldev = get_pinctrl_dev_from_devname(devname); /* @@ -418,13 +448,10 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname, * range need to defer probing. */ if (!pctldev) { - mutex_unlock(&pinctrldev_list_mutex); return ERR_PTR(-EPROBE_DEFER); } pinctrl_add_gpio_range(pctldev, range); - mutex_unlock(&pinctrldev_list_mutex); - return pctldev; } EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range); @@ -438,21 +465,26 @@ struct pinctrl_gpio_range * pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev, unsigned int pin) { - struct pinctrl_gpio_range *range = NULL; + struct pinctrl_gpio_range *range; mutex_lock(&pctldev->mutex); /* 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) { - mutex_unlock(&pctldev->mutex); - return range; - } + if (range->pins) { + int a; + for (a = 0; a < range->npins; a++) { + if (range->pins[a] == pin) + goto out; + } + } else if (pin >= range->pin_base && + pin < range->pin_base + range->npins) + goto out; } + range = NULL; +out: mutex_unlock(&pctldev->mutex); - - return NULL; + return range; } EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin); @@ -517,22 +549,18 @@ int pinctrl_request_gpio(unsigned gpio) int ret; int pin; - mutex_lock(&pinctrldev_list_mutex); - ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { if (pinctrl_ready_for_gpio_range(gpio)) ret = 0; - mutex_unlock(&pinctrldev_list_mutex); return ret; } /* Convert to the pin controllers number space */ - pin = gpio - range->base + range->pin_base; + pin = gpio_to_pin(range, gpio); ret = pinmux_request_gpio(pctldev, range, pin, gpio); - mutex_unlock(&pinctrldev_list_mutex); return ret; } EXPORT_SYMBOL_GPL(pinctrl_request_gpio); @@ -552,22 +580,18 @@ void pinctrl_free_gpio(unsigned gpio) int ret; int pin; - mutex_lock(&pinctrldev_list_mutex); - ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { - mutex_unlock(&pinctrldev_list_mutex); return; } mutex_lock(&pctldev->mutex); /* Convert to the pin controllers number space */ - pin = gpio - range->base + range->pin_base; + pin = gpio_to_pin(range, gpio); pinmux_free_gpio(pctldev, pin, range); mutex_unlock(&pctldev->mutex); - mutex_unlock(&pinctrldev_list_mutex); } EXPORT_SYMBOL_GPL(pinctrl_free_gpio); @@ -578,22 +602,18 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input) int ret; int pin; - mutex_lock(&pinctrldev_list_mutex); - ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { - mutex_unlock(&pinctrldev_list_mutex); return ret; } mutex_lock(&pctldev->mutex); /* Convert to the pin controllers number space */ - pin = gpio - range->base + range->pin_base; + pin = gpio_to_pin(range, gpio); ret = pinmux_gpio_direction(pctldev, range, pin, input); mutex_unlock(&pctldev->mutex); - mutex_unlock(&pinctrldev_list_mutex); return ret; } @@ -1204,6 +1224,69 @@ int pinctrl_force_default(struct pinctrl_dev *pctldev) } EXPORT_SYMBOL_GPL(pinctrl_force_default); +#ifdef CONFIG_PM + +/** + * pinctrl_pm_select_default_state() - select default pinctrl state for PM + * @dev: device to select default state for + */ +int pinctrl_pm_select_default_state(struct device *dev) +{ + struct dev_pin_info *pins = dev->pins; + int ret; + + if (!pins) + return 0; + if (IS_ERR(pins->default_state)) + return 0; /* No default state */ + ret = pinctrl_select_state(pins->p, pins->default_state); + if (ret) + dev_err(dev, "failed to activate default pinctrl state\n"); + return ret; +} +EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state); + +/** + * pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM + * @dev: device to select sleep state for + */ +int pinctrl_pm_select_sleep_state(struct device *dev) +{ + struct dev_pin_info *pins = dev->pins; + int ret; + + if (!pins) + return 0; + if (IS_ERR(pins->sleep_state)) + return 0; /* No sleep state */ + ret = pinctrl_select_state(pins->p, pins->sleep_state); + if (ret) + dev_err(dev, "failed to activate pinctrl sleep state\n"); + return ret; +} +EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state); + +/** + * pinctrl_pm_select_idle_state() - select idle pinctrl state for PM + * @dev: device to select idle state for + */ +int pinctrl_pm_select_idle_state(struct device *dev) +{ + struct dev_pin_info *pins = dev->pins; + int ret; + + if (!pins) + return 0; + if (IS_ERR(pins->idle_state)) + return 0; /* No idle state */ + ret = pinctrl_select_state(pins->p, pins->idle_state); + if (ret) + dev_err(dev, "failed to activate pinctrl idle state\n"); + return ret; +} +EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state); +#endif + #ifdef CONFIG_DEBUG_FS static int pinctrl_pins_show(struct seq_file *s, void *what) @@ -1296,11 +1379,21 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what) /* Loop over the ranges */ list_for_each_entry(range, &pctldev->gpio_ranges, node) { - seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n", - range->id, range->name, - range->base, (range->base + range->npins - 1), - range->pin_base, - (range->pin_base + range->npins - 1)); + if (range->pins) { + int a; + seq_printf(s, "%u: %s GPIOS [%u - %u] PINS {", + range->id, range->name, + range->base, (range->base + range->npins - 1)); + for (a = 0; a < range->npins - 1; a++) + seq_printf(s, "%u, ", range->pins[a]); + seq_printf(s, "%u}\n", range->pins[a]); + } + else + seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n", + range->id, range->name, + range->base, (range->base + range->npins - 1), + range->pin_base, + (range->pin_base + range->npins - 1)); } mutex_unlock(&pctldev->mutex); diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index 428ea96a94d..048ae80adab 100644 --- a/drivers/pinctrl/mvebu/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -26,6 +26,9 @@ #define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0200) #define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10) #define DOVE_AU0_AC97_SEL BIT(16) +#define DOVE_PMU_SIGNAL_SELECT_0 (DOVE_SB_REGS_VIRT_BASE + 0xd802C) +#define DOVE_PMU_SIGNAL_SELECT_1 (DOVE_SB_REGS_VIRT_BASE + 0xd8030) +#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C) #define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C) #define DOVE_TWSI_ENABLE_OPTION1 BIT(7) #define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE + 0xe8030) @@ -58,12 +61,16 @@ static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl, unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS; unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS; unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL); - unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off); - - if (pmu & (1 << ctrl->pid)) - *config = CONFIG_PMU; - else - *config = (mpp >> shift) & MPP_MASK; + unsigned long func; + + if (pmu & (1 << ctrl->pid)) { + func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off); + *config = (func >> shift) & MPP_MASK; + *config |= CONFIG_PMU; + } else { + func = readl(DOVE_MPP_VIRT_BASE + off); + *config = (func >> shift) & MPP_MASK; + } return 0; } @@ -73,15 +80,20 @@ static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl, unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS; unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS; unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL); - unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off); + unsigned long func; - if (config == CONFIG_PMU) + if (config & CONFIG_PMU) { writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL); - else { + func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off); + func &= ~(MPP_MASK << shift); + func |= (config & MPP_MASK) << shift; + writel(func, DOVE_PMU_SIGNAL_SELECT_0 + off); + } else { writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL); - mpp &= ~(MPP_MASK << shift); - mpp |= config << shift; - writel(mpp, DOVE_MPP_VIRT_BASE + off); + func = readl(DOVE_MPP_VIRT_BASE + off); + func &= ~(MPP_MASK << shift); + func |= (config & MPP_MASK) << shift; + writel(func, DOVE_MPP_VIRT_BASE + off); } return 0; } @@ -378,20 +390,53 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = { MPP_FUNCTION(0x02, "uart2", "rts"), MPP_FUNCTION(0x03, "sdio0", "cd"), MPP_FUNCTION(0x0f, "lcd0", "pwm"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(1, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart2", "cts"), MPP_FUNCTION(0x03, "sdio0", "wp"), MPP_FUNCTION(0x0f, "lcd1", "pwm"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(2, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x01, "sata", "prsnt"), MPP_FUNCTION(0x02, "uart2", "txd"), MPP_FUNCTION(0x03, "sdio0", "buspwr"), MPP_FUNCTION(0x04, "uart1", "rts"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(3, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x01, "sata", "act"), @@ -399,43 +444,131 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = { MPP_FUNCTION(0x03, "sdio0", "ledctrl"), MPP_FUNCTION(0x04, "uart1", "cts"), MPP_FUNCTION(0x0f, "lcd-spi", "cs1"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(4, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart3", "rts"), MPP_FUNCTION(0x03, "sdio1", "cd"), MPP_FUNCTION(0x04, "spi1", "miso"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(5, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart3", "cts"), MPP_FUNCTION(0x03, "sdio1", "wp"), MPP_FUNCTION(0x04, "spi1", "cs"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(6, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart3", "txd"), MPP_FUNCTION(0x03, "sdio1", "buspwr"), MPP_FUNCTION(0x04, "spi1", "mosi"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(7, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart3", "rxd"), MPP_FUNCTION(0x03, "sdio1", "ledctrl"), MPP_FUNCTION(0x04, "spi1", "sck"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(8, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x01, "watchdog", "rstout"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(9, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x05, "pex1", "clkreq"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(10, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x05, "ssp", "sclk"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(11, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x01, "sata", "prsnt"), @@ -443,33 +576,88 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = { MPP_FUNCTION(0x03, "sdio0", "ledctrl"), MPP_FUNCTION(0x04, "sdio1", "ledctrl"), MPP_FUNCTION(0x05, "pex0", "clkreq"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(12, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x01, "sata", "act"), MPP_FUNCTION(0x02, "uart2", "rts"), MPP_FUNCTION(0x03, "audio0", "extclk"), MPP_FUNCTION(0x04, "sdio1", "cd"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(13, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart2", "cts"), MPP_FUNCTION(0x03, "audio1", "extclk"), MPP_FUNCTION(0x04, "sdio1", "wp"), MPP_FUNCTION(0x05, "ssp", "extclk"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(14, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart2", "txd"), MPP_FUNCTION(0x04, "sdio1", "buspwr"), MPP_FUNCTION(0x05, "ssp", "rxd"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(15, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart2", "rxd"), MPP_FUNCTION(0x04, "sdio1", "ledctrl"), MPP_FUNCTION(0x05, "ssp", "sfrm"), - MPP_FUNCTION(0x10, "pmu", NULL)), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), MPP_MODE(16, MPP_FUNCTION(0x00, "gpio", NULL), MPP_FUNCTION(0x02, "uart3", "rts"), diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 2ad5a8d337b..8594f033ac2 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -21,6 +21,7 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> +#include <linux/of.h> #include "core.h" #include "pinconf.h" @@ -37,14 +38,18 @@ struct pin_config_item { static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL), + PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, + "input bias pull to pin specific state", NULL), 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_DRIVE_STRENGTH, "output drive strength", "mA"), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), - PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), + PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL), PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"), @@ -135,3 +140,100 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); #endif + +#ifdef CONFIG_OF +struct pinconf_generic_dt_params { + const char * const property; + enum pin_config_param param; + u32 default_value; +}; + +static struct pinconf_generic_dt_params dt_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, + { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, + { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 }, + { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, + { "output-low", PIN_CONFIG_OUTPUT, 0, }, + { "output-high", PIN_CONFIG_OUTPUT, 1, }, +}; + +/** + * pinconf_generic_parse_dt_config() + * parse the config properties into generic pinconfig values. + * @np: node containing the pinconfig properties + * @configs: array with nconfigs entries containing the generic pinconf values + * @nconfigs: umber of configurations + */ +int pinconf_generic_parse_dt_config(struct device_node *np, + unsigned long **configs, + unsigned int *nconfigs) +{ + unsigned long *cfg; + unsigned int ncfg = 0; + int ret; + int i; + u32 val; + + if (!np) + return -EINVAL; + + /* allocate a temporary array big enough to hold one of each option */ + cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(dt_params); i++) { + struct pinconf_generic_dt_params *par = &dt_params[i]; + ret = of_property_read_u32(np, par->property, &val); + + /* property not found */ + if (ret == -EINVAL) + continue; + + /* use default value, when no value is specified */ + if (ret) + val = par->default_value; + + pr_debug("found %s with value %u\n", par->property, val); + cfg[ncfg] = pinconf_to_config_packed(par->param, val); + ncfg++; + } + + ret = 0; + + /* no configs found at all */ + if (ncfg == 0) { + *configs = NULL; + *nconfigs = 0; + goto out; + } + + /* + * Now limit the number of configs to the real number of + * found properties. + */ + *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL); + if (!*configs) { + ret = -ENOMEM; + goto out; + } + + memcpy(*configs, cfg, ncfg * sizeof(unsigned long)); + *nconfigs = ncfg; + +out: + kfree(cfg); + return ret; +} +#endif diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 694c3ace452..e875f21a590 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -75,98 +75,6 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, return ops->pin_config_get(pctldev, pin, config); } -/** - * pin_config_get() - get the configuration of a single pin parameter - * @dev_name: name of the pin controller device for this pin - * @name: name of the pin to get the config for - * @config: the config pointed to by this argument will be filled in with the - * current pin state, it can be used directly by drivers as a numeral, or - * it can be dereferenced to any struct. - */ -int pin_config_get(const char *dev_name, const char *name, - unsigned long *config) -{ - struct pinctrl_dev *pctldev; - int pin; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - pin = -EINVAL; - return pin; - } - - mutex_lock(&pctldev->mutex); - - pin = pin_get_from_name(pctldev, name); - if (pin < 0) - goto unlock; - - pin = pin_config_get_for_pin(pctldev, pin, config); - -unlock: - mutex_unlock(&pctldev->mutex); - return pin; -} -EXPORT_SYMBOL(pin_config_get); - -static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin, - unsigned long config) -{ - const struct pinconf_ops *ops = pctldev->desc->confops; - int ret; - - if (!ops || !ops->pin_config_set) { - dev_err(pctldev->dev, "cannot configure pin, missing " - "config function in driver\n"); - return -EINVAL; - } - - ret = ops->pin_config_set(pctldev, pin, config); - if (ret) { - dev_err(pctldev->dev, - "unable to set pin configuration on pin %d\n", pin); - return ret; - } - - return 0; -} - -/** - * pin_config_set() - set the configuration of a single pin parameter - * @dev_name: name of pin controller device for this pin - * @name: name of the pin to set the config for - * @config: the config in this argument will contain the desired pin state, it - * can be used directly by drivers as a numeral, or it can be dereferenced - * to any struct. - */ -int pin_config_set(const char *dev_name, const char *name, - unsigned long config) -{ - struct pinctrl_dev *pctldev; - int pin, ret; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - ret = -EINVAL; - return ret; - } - - mutex_lock(&pctldev->mutex); - - pin = pin_get_from_name(pctldev, name); - if (pin < 0) { - ret = pin; - goto unlock; - } - - ret = pin_config_set_for_pin(pctldev, pin, config); - -unlock: - mutex_unlock(&pctldev->mutex); - return ret; -} -EXPORT_SYMBOL(pin_config_set); - int pin_config_group_get(const char *dev_name, const char *pin_group, unsigned long *config) { @@ -204,88 +112,6 @@ unlock: mutex_unlock(&pctldev->mutex); return ret; } -EXPORT_SYMBOL(pin_config_group_get); - -int pin_config_group_set(const char *dev_name, const char *pin_group, - unsigned long config) -{ - struct pinctrl_dev *pctldev; - const struct pinconf_ops *ops; - const struct pinctrl_ops *pctlops; - int selector; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - ret = -EINVAL; - return ret; - } - - mutex_lock(&pctldev->mutex); - - ops = pctldev->desc->confops; - pctlops = pctldev->desc->pctlops; - - if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) { - dev_err(pctldev->dev, "cannot configure pin group, missing " - "config function in driver\n"); - ret = -EINVAL; - goto unlock; - } - - selector = pinctrl_get_group_selector(pctldev, pin_group); - if (selector < 0) { - ret = selector; - goto unlock; - } - - ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, "cannot configure pin group, error " - "getting pins\n"); - goto unlock; - } - - /* - * If the pin controller supports handling entire groups we use that - * capability. - */ - if (ops->pin_config_group_set) { - ret = ops->pin_config_group_set(pctldev, selector, config); - /* - * If the pin controller prefer that a certain group be handled - * pin-by-pin as well, it returns -EAGAIN. - */ - if (ret != -EAGAIN) - goto unlock; - } - - /* - * If the controller cannot handle entire groups, we configure each pin - * individually. - */ - if (!ops->pin_config_set) { - ret = 0; - goto unlock; - } - - for (i = 0; i < num_pins; i++) { - ret = ops->pin_config_set(pctldev, pins[i], config); - if (ret < 0) - goto unlock; - } - - ret = 0; - -unlock: - mutex_unlock(&pctldev->mutex); - - return ret; -} -EXPORT_SYMBOL(pin_config_group_set); int pinconf_map_to_setting(struct pinctrl_map const *map, struct pinctrl_setting *setting) diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 92c7267244d..a4a5417e141 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -123,3 +123,9 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, return; } #endif + +#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF) +int pinconf_generic_parse_dt_config(struct device_node *np, + unsigned long **configs, + unsigned int *nconfigs); +#endif diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c index 6d4532702f8..1d3f988c2c8 100644 --- a/drivers/pinctrl/pinctrl-abx500.c +++ b/drivers/pinctrl/pinctrl-abx500.c @@ -30,8 +30,11 @@ #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/machine.h> #include "pinctrl-abx500.h" +#include "core.h" +#include "pinconf.h" /* * The AB9540 and AB8540 GPIO support are extended versions @@ -93,13 +96,15 @@ #define AB8540_GPIOX_VBAT_START 51 #define AB8540_GPIOX_VBAT_END 54 +#define ABX500_GPIO_INPUT 0 +#define ABX500_GPIO_OUTPUT 1 + struct abx500_pinctrl { struct device *dev; struct pinctrl_dev *pctldev; struct abx500_pinctrl_soc_data *soc; struct gpio_chip chip; struct ab8500 *parent; - struct mutex lock; struct abx500_gpio_irq_cluster *irq_cluster; int irq_cluster_size; }; @@ -129,8 +134,8 @@ static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg, if (ret < 0) dev_err(pct->dev, - "%s read reg =%x, offset=%x failed\n", - __func__, reg, offset); + "%s read reg =%x, offset=%x failed (%d)\n", + __func__, reg, offset, ret); return ret; } @@ -146,7 +151,8 @@ static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg, ret = abx500_mask_and_set_register_interruptible(pct->dev, AB8500_MISC, reg, BIT(pos), val << pos); if (ret < 0) - dev_err(pct->dev, "%s write failed\n", __func__); + dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n", + __func__, reg, offset, ret); return ret; } @@ -160,12 +166,24 @@ static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset) { struct abx500_pinctrl *pct = to_abx500_pinctrl(chip); bool bit; + bool is_out; + u8 gpio_offset = offset - 1; int ret; - ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG, - offset, &bit); + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, + gpio_offset, &is_out); + if (ret < 0) + goto out; + + if (is_out) + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG, + gpio_offset, &bit); + else + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG, + gpio_offset, &bit); +out: if (ret < 0) { - dev_err(pct->dev, "%s failed\n", __func__); + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); return ret; } @@ -179,13 +197,14 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); if (ret < 0) - dev_err(pct->dev, "%s write failed\n", __func__); + dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret); } -static int abx500_config_pull_updown(struct abx500_pinctrl *pct, - int offset, enum abx500_gpio_pull_updown val) +static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset, + enum abx500_gpio_pull_updown *pull_updown) { u8 pos; + u8 val; int ret; struct pullud *pullud; @@ -204,7 +223,41 @@ static int abx500_config_pull_updown(struct abx500_pinctrl *pct, goto out; } - pos = offset << 1; + ret = abx500_get_register_interruptible(pct->dev, + AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG, &val); + + pos = (offset - pullud->first_pin) << 1; + *pull_updown = (val >> pos) & AB8540_GPIO_PULL_UPDOWN_MASK; + +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + + return ret; +} + +static int abx500_set_pull_updown(struct abx500_pinctrl *pct, + int offset, enum abx500_gpio_pull_updown val) +{ + u8 pos; + int ret; + struct pullud *pullud; + + if (!pct->soc->pullud) { + dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature", + __func__); + ret = -EPERM; + goto out; + } + + pullud = pct->soc->pullud; + + if ((offset < pullud->first_pin) + || (offset > pullud->last_pin)) { + ret = -EINVAL; + goto out; + } + pos = (offset - pullud->first_pin) << 1; ret = abx500_mask_and_set_register_interruptible(pct->dev, AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG, @@ -217,33 +270,51 @@ out: return ret; } +static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio) +{ + struct abx500_pinctrl *pct = to_abx500_pinctrl(chip); + struct pullud *pullud = pct->soc->pullud; + + return (pullud && + gpio >= pullud->first_pin && + gpio <= pullud->last_pin); +} + static int abx500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int val) { struct abx500_pinctrl *pct = to_abx500_pinctrl(chip); - struct pullud *pullud = pct->soc->pullud; unsigned gpio; int ret; /* set direction as output */ - ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_DIR1_REG, + offset, + ABX500_GPIO_OUTPUT); if (ret < 0) - return ret; + goto out; /* disable pull down */ - ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); + ret = abx500_gpio_set_bits(chip, + AB8500_GPIO_PUD1_REG, + offset, + ABX500_GPIO_PULL_NONE); if (ret < 0) - return ret; + goto out; /* if supported, disable both pull down and pull up */ gpio = offset + 1; - if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) { - ret = abx500_config_pull_updown(pct, + if (abx500_pullud_supported(chip, gpio)) { + ret = abx500_set_pull_updown(pct, gpio, ABX500_GPIO_PULL_NONE); - if (ret < 0) - return ret; + } +out: + if (ret < 0) { + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; } /* set the output as 1 or 0 */ @@ -253,7 +324,10 @@ static int abx500_gpio_direction_output(struct gpio_chip *chip, static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { /* set the register as input */ - return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); + return abx500_gpio_set_bits(chip, + AB8500_GPIO_DIR1_REG, + offset, + ABX500_GPIO_INPUT); } static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) @@ -338,10 +412,16 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, if (af.alt_bit1 != UNUSED) { ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, offset, 0); + if (ret < 0) + goto out; + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit1, !!(af.alta_val && BIT(0))); + if (ret < 0) + goto out; + if (af.alt_bit2 != UNUSED) ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, @@ -355,8 +435,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, case ABX500_ALT_B: ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, offset, 0); + if (ret < 0) + goto out; + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit1, !!(af.altb_val && BIT(0))); + if (ret < 0) + goto out; + if (af.alt_bit2 != UNUSED) ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, @@ -367,8 +453,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, case ABX500_ALT_C: ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG, offset, 0); + if (ret < 0) + goto out; + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2, !!(af.altc_val && BIT(0))); + if (ret < 0) + goto out; + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2, !!(af.altc_val && BIT(1))); break; @@ -378,11 +470,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, return -EINVAL; } +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); return ret; } -static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, +static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned gpio) { u8 mode; @@ -393,6 +488,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, struct alternate_functions af = pct->soc->alternate_functions[gpio]; /* on ABx5xx, there is no GPIO0, so adjust the offset */ unsigned offset = gpio - 1; + int ret; /* * if gpiosel_bit is set to unused, @@ -402,8 +498,11 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, return ABX500_DEFAULT; /* read GpioSelx register */ - abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8), + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8), af.gpiosel_bit, &bit_mode); + if (ret < 0) + goto out; + mode = bit_mode; /* sanity check */ @@ -435,14 +534,19 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, * pin use the AlternatFunction register * read alt_bit1 value */ - abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit1, &alt_bit1); + if (ret < 0) + goto out; - if (af.alt_bit2 != UNUSED) + if (af.alt_bit2 != UNUSED) { /* read alt_bit2 value */ - abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2, + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, + af.alt_bit2, &alt_bit2); - else + if (ret < 0) + goto out; + } else alt_bit2 = 0; mode = (alt_bit2 << 1) + alt_bit1; @@ -452,6 +556,10 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, return ABX500_ALT_B; else return ABX500_ALT_C; + +out: + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; } #ifdef CONFIG_DEBUG_FS @@ -463,11 +571,14 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, unsigned offset, unsigned gpio) { + struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); const char *label = gpiochip_is_requested(chip, offset - 1); u8 gpio_offset = offset - 1; int mode = -1; bool is_out; - bool pull; + bool pd; + enum abx500_gpio_pull_updown pud = 0; + int ret; const char *modes[] = { [ABX500_DEFAULT] = "default", @@ -476,21 +587,48 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s, [ABX500_ALT_C] = "altC", }; - abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out); - abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull); + const char *pull_up_down[] = { + [ABX500_GPIO_PULL_DOWN] = "pull down", + [ABX500_GPIO_PULL_NONE] = "pull none", + [ABX500_GPIO_PULL_NONE + 1] = "pull none", + [ABX500_GPIO_PULL_UP] = "pull up", + }; + + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, + gpio_offset, &is_out); + if (ret < 0) + goto out; + + seq_printf(s, " gpio-%-3d (%-20.20s) %-3s", + gpio, label ?: "(none)", + is_out ? "out" : "in "); + + if (!is_out) { + if (abx500_pullud_supported(chip, offset)) { + ret = abx500_get_pull_updown(pct, offset, &pud); + if (ret < 0) + goto out; + + seq_printf(s, " %-9s", pull_up_down[pud]); + } else { + ret = abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, + gpio_offset, &pd); + if (ret < 0) + goto out; + + seq_printf(s, " %-9s", pull_up_down[pd]); + } + } else + seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo"); if (pctldev) mode = abx500_get_mode(pctldev, chip, offset); - seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s", - gpio, label ?: "(none)", - is_out ? "out" : "in ", - is_out ? - (chip->get - ? (chip->get(chip, offset) ? "hi" : "lo") - : "? ") - : (pull ? "pull up" : "pull down"), - (mode < 0) ? "unknown" : modes[mode]); + seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]); + +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); } static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -594,6 +732,9 @@ static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting); } + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); + return ret; } @@ -642,10 +783,8 @@ static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev, ret = abx500_set_mode(pct->pctldev, &pct->chip, offset, p->altfunc); - if (ret < 0) { + if (ret < 0) dev_err(pct->dev, "%s setting altfunc failed\n", __func__); - return ret; - } return ret; } @@ -704,11 +843,193 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev, chip->base + offset - 1); } +static void abx500_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) + kfree(map[i].data.configs.configs); + kfree(map); +} + +static int abx500_dt_reserve_map(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, + unsigned reserve) +{ + unsigned old_num = *reserved_maps; + unsigned new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + + return 0; +} + +static int abx500_dt_add_map_mux(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int abx500_dt_add_map_configs(struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs) +{ + unsigned long *dup_configs; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) + return -ENOMEM; + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN; + + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static const char *abx500_find_pin_name(struct pinctrl_dev *pctldev, + const char *pin_name) +{ + int i, pin_number; + struct abx500_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1) + for (i = 0; i < npct->soc->npins; i++) + if (npct->soc->pins[i].number == pin_number) + return npct->soc->pins[i].name; + return NULL; +} + +static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + int ret; + const char *function = NULL; + unsigned long *configs; + unsigned int nconfigs = 0; + bool has_config = 0; + unsigned reserve = 0; + struct property *prop; + const char *group, *gpio_name; + struct device_node *np_config; + + ret = of_property_read_string(np, "ste,function", &function); + if (ret >= 0) + reserve = 1; + + ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs); + if (nconfigs) + has_config = 1; + + np_config = of_parse_phandle(np, "ste,config", 0); + if (np_config) { + ret = pinconf_generic_parse_dt_config(np_config, &configs, + &nconfigs); + if (ret) + goto exit; + has_config |= nconfigs; + } + + ret = of_property_count_strings(np, "ste,pins"); + if (ret < 0) + goto exit; + + if (has_config) + reserve++; + + reserve *= ret; + + ret = abx500_dt_reserve_map(map, reserved_maps, num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "ste,pins", prop, group) { + if (function) { + ret = abx500_dt_add_map_mux(map, reserved_maps, + num_maps, group, function); + if (ret < 0) + goto exit; + } + if (has_config) { + gpio_name = abx500_find_pin_name(pctldev, group); + + ret = abx500_dt_add_map_configs(map, reserved_maps, + num_maps, gpio_name, configs, 1); + if (ret < 0) + goto exit; + } + + } +exit: + return ret; +} + +static int abx500_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; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = abx500_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + abx500_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + static const struct pinctrl_ops abx500_pinctrl_ops = { .get_groups_count = abx500_get_groups_cnt, .get_group_name = abx500_get_group_name, .get_group_pins = abx500_get_group_pins, .pin_dbg_show = abx500_pin_dbg_show, + .dt_node_to_map = abx500_dt_node_to_map, + .dt_free_map = abx500_dt_free_map, }; static int abx500_pin_config_get(struct pinctrl_dev *pctldev, @@ -723,10 +1044,9 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, unsigned long config) { struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); - struct pullud *pullud = pct->soc->pullud; struct gpio_chip *chip = &pct->chip; unsigned offset; - int ret; + int ret = -EINVAL; enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param argument = pinconf_to_config_argument(config); @@ -739,41 +1059,83 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, offset = pin - 1; switch (param) { - case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_DISABLE: + ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; /* - * if argument = 1 set the pull down - * else clear the pull down + * Some chips only support pull down, while some actually + * support both pull up and pull down. Such chips have + * a "pullud" range specified for the pins that support + * both features. If the pin is not within that range, we + * fall back to the old bit set that only support pull down. */ + if (abx500_pullud_supported(chip, pin)) + ret = abx500_set_pull_updown(pct, + pin, + ABX500_GPIO_PULL_NONE); + else + /* Chip only supports pull down */ + ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, + offset, ABX500_GPIO_PULL_NONE); + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; /* + * if argument = 1 set the pull down + * else clear the pull down * Some chips only support pull down, while some actually * support both pull up and pull down. Such chips have * a "pullud" range specified for the pins that support * both features. If the pin is not within that range, we * fall back to the old bit set that only support pull down. */ - if (pullud && - pin >= pullud->first_pin && - pin <= pullud->last_pin) - ret = abx500_config_pull_updown(pct, + if (abx500_pullud_supported(chip, pin)) + ret = abx500_set_pull_updown(pct, pin, argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE); else /* Chip only supports pull down */ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, - offset, argument ? 0 : 1); + offset, + argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + ret = abx500_gpio_direction_input(chip, offset); + if (ret < 0) + goto out; + /* + * if argument = 1 set the pull up + * else clear the pull up + */ + ret = abx500_gpio_direction_input(chip, offset); + /* + * Some chips only support pull down, while some actually + * support both pull up and pull down. Such chips have + * a "pullud" range specified for the pins that support + * both features. If the pin is not within that range, do + * nothing + */ + if (abx500_pullud_supported(chip, pin)) + ret = abx500_set_pull_updown(pct, + pin, + argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE); break; case PIN_CONFIG_OUTPUT: ret = abx500_gpio_direction_output(chip, offset, argument); - break; default: dev_err(chip->dev, "illegal configuration requested\n"); - - return -EINVAL; } +out: + if (ret < 0) + dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); return ret; } @@ -881,9 +1243,6 @@ static int abx500_gpio_probe(struct platform_device *pdev) id = (unsigned long)match->data; } - /* initialize the lock */ - mutex_init(&pct->lock); - /* Poke in other ASIC variants here */ switch (id) { case PINCTRL_AB8500: @@ -900,13 +1259,11 @@ static int abx500_gpio_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id); - mutex_destroy(&pct->lock); return -EINVAL; } if (!pct->soc) { dev_err(&pdev->dev, "Invalid SOC data\n"); - mutex_destroy(&pct->lock); return -EINVAL; } @@ -917,7 +1274,6 @@ static int abx500_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(&pct->chip); if (ret) { dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - mutex_destroy(&pct->lock); return ret; } dev_info(&pdev->dev, "added gpiochip\n"); @@ -954,7 +1310,6 @@ out_rem_chip: if (err) dev_info(&pdev->dev, "failed to remove gpiochip\n"); - mutex_destroy(&pct->lock); return ret; } @@ -974,8 +1329,6 @@ static int abx500_gpio_remove(struct platform_device *pdev) return ret; } - mutex_destroy(&pct->lock); - return 0; } diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 5d7529ed539..b90a3a0ac53 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1543,12 +1543,6 @@ static int at91_gpio_probe(struct platform_device *pdev) 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; @@ -1561,6 +1555,7 @@ static int at91_gpio_probe(struct platform_device *pdev) goto err; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); at91_chip->regbase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(at91_chip->regbase)) { ret = PTR_ERR(at91_chip->regbase); diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c new file mode 100644 index 00000000000..e9d735dcebf --- /dev/null +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -0,0 +1,543 @@ +/* + * Pinctrl GPIO driver for Intel Baytrail + * Copyright (c) 2012-2013, Intel Corporation. + * + * Author: Mathias Nyman <mathias.nyman@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/irqdomain.h> +#include <linux/acpi.h> +#include <linux/acpi_gpio.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <linux/pinctrl/pinctrl.h> + +/* memory mapped register offsets */ +#define BYT_CONF0_REG 0x000 +#define BYT_CONF1_REG 0x004 +#define BYT_VAL_REG 0x008 +#define BYT_DFT_REG 0x00c +#define BYT_INT_STAT_REG 0x800 + +/* BYT_CONF0_REG register bits */ +#define BYT_TRIG_NEG BIT(26) +#define BYT_TRIG_POS BIT(25) +#define BYT_TRIG_LVL BIT(24) +#define BYT_PIN_MUX 0x07 + +/* BYT_VAL_REG register bits */ +#define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/ +#define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/ +#define BYT_LEVEL BIT(0) + +#define BYT_DIR_MASK (BIT(1) | BIT(2)) +#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) + +#define BYT_NGPIO_SCORE 102 +#define BYT_NGPIO_NCORE 28 +#define BYT_NGPIO_SUS 44 + +/* + * Baytrail gpio controller consist of three separate sub-controllers called + * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID. + * + * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does + * _not_ correspond to the first gpio register at controller's gpio base. + * There is no logic or pattern in mapping gpio numbers to registers (pads) so + * each sub-controller needs to have its own mapping table + */ + +/* score_pins[gpio_nr] = pad_nr */ + +static unsigned const score_pins[BYT_NGPIO_SCORE] = { + 85, 89, 93, 96, 99, 102, 98, 101, 34, 37, + 36, 38, 39, 35, 40, 84, 62, 61, 64, 59, + 54, 56, 60, 55, 63, 57, 51, 50, 53, 47, + 52, 49, 48, 43, 46, 41, 45, 42, 58, 44, + 95, 105, 70, 68, 67, 66, 69, 71, 65, 72, + 86, 90, 88, 92, 103, 77, 79, 83, 78, 81, + 80, 82, 13, 12, 15, 14, 17, 18, 19, 16, + 2, 1, 0, 4, 6, 7, 9, 8, 33, 32, + 31, 30, 29, 27, 25, 28, 26, 23, 21, 20, + 24, 22, 5, 3, 10, 11, 106, 87, 91, 104, + 97, 100, +}; + +static unsigned const ncore_pins[BYT_NGPIO_NCORE] = { + 19, 18, 17, 20, 21, 22, 24, 25, 23, 16, + 14, 15, 12, 26, 27, 1, 4, 8, 11, 0, + 3, 6, 10, 13, 2, 5, 9, 7, +}; + +static unsigned const sus_pins[BYT_NGPIO_SUS] = { + 29, 33, 30, 31, 32, 34, 36, 35, 38, 37, + 18, 7, 11, 20, 17, 1, 8, 10, 19, 12, + 0, 2, 23, 39, 28, 27, 22, 21, 24, 25, + 26, 51, 56, 54, 49, 55, 48, 57, 50, 58, + 52, 53, 59, 40, +}; + +static struct pinctrl_gpio_range byt_ranges[] = { + { + .name = "1", /* match with acpi _UID in probe */ + .npins = BYT_NGPIO_SCORE, + .pins = score_pins, + }, + { + .name = "2", + .npins = BYT_NGPIO_NCORE, + .pins = ncore_pins, + }, + { + .name = "3", + .npins = BYT_NGPIO_SUS, + .pins = sus_pins, + }, + { + }, +}; + +struct byt_gpio { + struct gpio_chip chip; + struct irq_domain *domain; + struct platform_device *pdev; + spinlock_t lock; + void __iomem *reg_base; + struct pinctrl_gpio_range *range; +}; + +static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset, + int reg) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + u32 reg_offset; + void __iomem *ptr; + + if (reg == BYT_INT_STAT_REG) + reg_offset = (offset / 32) * 4; + else + reg_offset = vg->range->pins[offset] * 16; + + ptr = (void __iomem *) (vg->reg_base + reg_offset + reg); + return ptr; +} + +static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + + pm_runtime_get(&vg->pdev->dev); + + return 0; +} + +static void byt_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + u32 value; + + /* clear interrupt triggering */ + value = readl(reg); + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + writel(value, reg); + + pm_runtime_put(&vg->pdev->dev); +} + +static int byt_irq_type(struct irq_data *d, unsigned type) +{ + struct byt_gpio *vg = irq_data_get_irq_chip_data(d); + u32 offset = irqd_to_hwirq(d); + u32 value; + unsigned long flags; + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + + if (offset >= vg->chip.ngpio) + return -EINVAL; + + spin_lock_irqsave(&vg->lock, flags); + value = readl(reg); + + /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits + * are used to indicate high and low level triggering + */ + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_RISING: + value |= BYT_TRIG_POS; + break; + case IRQ_TYPE_LEVEL_LOW: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_FALLING: + value |= BYT_TRIG_NEG; + break; + case IRQ_TYPE_EDGE_BOTH: + value |= (BYT_TRIG_NEG | BYT_TRIG_POS); + break; + } + writel(value, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + return readl(reg) & BYT_LEVEL; +} + +static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + unsigned long flags; + u32 old_val; + + spin_lock_irqsave(&vg->lock, flags); + + old_val = readl(reg); + + if (value) + writel(old_val | BYT_LEVEL, reg); + else + writel(old_val & ~BYT_LEVEL, reg); + + spin_unlock_irqrestore(&vg->lock, flags); +} + +static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + unsigned long flags; + u32 value; + + spin_lock_irqsave(&vg->lock, flags); + + value = readl(reg) | BYT_DIR_MASK; + value = value & (~BYT_INPUT_EN); /* active low */ + writel(value, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static int byt_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG); + unsigned long flags; + u32 reg_val; + + spin_lock_irqsave(&vg->lock, flags); + + reg_val = readl(reg) | (BYT_DIR_MASK | !!value); + reg_val &= ~(BYT_OUTPUT_EN | !value); + writel(reg_val, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + int i; + unsigned long flags; + u32 conf0, val, offs; + + spin_lock_irqsave(&vg->lock, flags); + + for (i = 0; i < vg->chip.ngpio; i++) { + offs = vg->range->pins[i] * 16; + conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG); + val = readl(vg->reg_base + offs + BYT_VAL_REG); + + seq_printf(s, + " gpio-%-3d %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s\n", + i, + val & BYT_INPUT_EN ? " " : "in", + val & BYT_OUTPUT_EN ? " " : "out", + val & BYT_LEVEL ? "hi" : "lo", + vg->range->pins[i], offs, + conf0 & 0x7, + conf0 & BYT_TRIG_NEG ? "fall " : "", + conf0 & BYT_TRIG_POS ? "rise " : "", + conf0 & BYT_TRIG_LVL ? "lvl " : ""); + } + spin_unlock_irqrestore(&vg->lock, flags); +} + +static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip); + return irq_create_mapping(vg->domain, offset); +} + +static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct byt_gpio *vg = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, pin, mask; + void __iomem *reg; + u32 pending; + unsigned virq; + int looplimit = 0; + + /* check from GPIO controller which pin triggered the interrupt */ + for (base = 0; base < vg->chip.ngpio; base += 32) { + + reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); + + while ((pending = readl(reg))) { + pin = __ffs(pending); + mask = BIT(pin); + /* Clear before handling so we can't lose an edge */ + writel(mask, reg); + + virq = irq_find_mapping(vg->domain, base + pin); + generic_handle_irq(virq); + + /* In case bios or user sets triggering incorretly a pin + * might remain in "interrupt triggered" state. + */ + if (looplimit++ > 32) { + dev_err(&vg->pdev->dev, + "Gpio %d interrupt flood, disabling\n", + base + pin); + + reg = byt_gpio_reg(&vg->chip, base + pin, + BYT_CONF0_REG); + mask = readl(reg); + mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS | + BYT_TRIG_LVL); + writel(mask, reg); + mask = readl(reg); /* flush */ + break; + } + } + } + chip->irq_eoi(data); +} + +static void byt_irq_unmask(struct irq_data *d) +{ +} + +static void byt_irq_mask(struct irq_data *d) +{ +} + +static struct irq_chip byt_irqchip = { + .name = "BYT-GPIO", + .irq_mask = byt_irq_mask, + .irq_unmask = byt_irq_unmask, + .irq_set_type = byt_irq_type, +}; + +static void byt_gpio_irq_init_hw(struct byt_gpio *vg) +{ + void __iomem *reg; + u32 base, value; + + /* clear interrupt status trigger registers */ + for (base = 0; base < vg->chip.ngpio; base += 32) { + reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); + writel(0xffffffff, reg); + /* make sure trigger bits are cleared, if not then a pin + might be misconfigured in bios */ + value = readl(reg); + if (value) + dev_err(&vg->pdev->dev, + "GPIO interrupt error, pins misconfigured\n"); + } +} + +static int byt_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct byt_gpio *vg = d->host_data; + + irq_set_chip_and_handler_name(virq, &byt_irqchip, handle_simple_irq, + "demux"); + irq_set_chip_data(virq, vg); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops byt_gpio_irq_ops = { + .map = byt_gpio_irq_map, +}; + +static int byt_gpio_probe(struct platform_device *pdev) +{ + struct byt_gpio *vg; + struct gpio_chip *gc; + struct resource *mem_rc, *irq_rc; + struct device *dev = &pdev->dev; + struct acpi_device *acpi_dev; + struct pinctrl_gpio_range *range; + acpi_handle handle = ACPI_HANDLE(dev); + unsigned hwirq; + int ret; + + if (acpi_bus_get_device(handle, &acpi_dev)) + return -ENODEV; + + vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL); + if (!vg) { + dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n"); + return -ENOMEM; + } + + for (range = byt_ranges; range->name; range++) { + if (!strcmp(acpi_dev->pnp.unique_id, range->name)) { + vg->chip.ngpio = range->npins; + vg->range = range; + break; + } + } + + if (!vg->chip.ngpio || !vg->range) + return -ENODEV; + + vg->pdev = pdev; + platform_set_drvdata(pdev, vg); + + mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + vg->reg_base = devm_ioremap_resource(dev, mem_rc); + if (IS_ERR(vg->reg_base)) + return PTR_ERR(vg->reg_base); + + spin_lock_init(&vg->lock); + + gc = &vg->chip; + gc->label = dev_name(&pdev->dev); + gc->owner = THIS_MODULE; + gc->request = byt_gpio_request; + gc->free = byt_gpio_free; + gc->direction_input = byt_gpio_direction_input; + gc->direction_output = byt_gpio_direction_output; + gc->get = byt_gpio_get; + gc->set = byt_gpio_set; + gc->dbg_show = byt_gpio_dbg_show; + gc->base = -1; + gc->can_sleep = 0; + gc->dev = dev; + + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed adding byt-gpio chip\n"); + return ret; + } + + /* set up interrupts */ + irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq_rc && irq_rc->start) { + hwirq = irq_rc->start; + gc->to_irq = byt_gpio_to_irq; + + vg->domain = irq_domain_add_linear(NULL, gc->ngpio, + &byt_gpio_irq_ops, vg); + if (!vg->domain) + return -ENXIO; + + byt_gpio_irq_init_hw(vg); + + irq_set_handler_data(hwirq, vg); + irq_set_chained_handler(hwirq, byt_gpio_irq_handler); + + /* Register interrupt handlers for gpio signaled acpi events */ + acpi_gpiochip_request_interrupts(gc); + } + + pm_runtime_enable(dev); + + return 0; +} + +static int byt_gpio_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int byt_gpio_runtime_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops byt_gpio_pm_ops = { + .runtime_suspend = byt_gpio_runtime_suspend, + .runtime_resume = byt_gpio_runtime_resume, +}; + +static const struct acpi_device_id byt_gpio_acpi_match[] = { + { "INT33B2", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match); + +static int byt_gpio_remove(struct platform_device *pdev) +{ + struct byt_gpio *vg = platform_get_drvdata(pdev); + int err; + pm_runtime_disable(&pdev->dev); + err = gpiochip_remove(&vg->chip); + if (err) + dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); + + return 0; +} + +static struct platform_driver byt_gpio_driver = { + .probe = byt_gpio_probe, + .remove = byt_gpio_remove, + .driver = { + .name = "byt_gpio", + .owner = THIS_MODULE, + .pm = &byt_gpio_pm_ops, + .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match), + }, +}; + +static int __init byt_gpio_init(void) +{ + return platform_driver_register(&byt_gpio_driver); +} + +subsys_initcall(byt_gpio_init); diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index c8f20a3d8f8..a1c88b30f71 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -113,7 +113,7 @@ static struct lock_class_key gpio_lock_class; /* pins are just named GPIO0..GPIO53 */ #define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) -struct pinctrl_pin_desc bcm2835_gpio_pins[] = { +static struct pinctrl_pin_desc bcm2835_gpio_pins[] = { BCM2835_GPIO_PIN(0), BCM2835_GPIO_PIN(1), BCM2835_GPIO_PIN(2), diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index eeff7f7fc92..f22a2193d94 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -853,7 +853,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) } u300_gpio_free_ports(gpio); clk_disable_unprepare(gpio->clk); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 5f58cf0e96e..a74b3cbd745 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -50,37 +50,58 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { { } }; -static void exynos_gpio_irq_unmask(struct irq_data *irqd) +static void exynos_gpio_irq_mask(struct irq_data *irqd) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; + unsigned long flags; + + spin_lock_irqsave(&bank->slock, flags); mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << irqd->hwirq); + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); + + spin_unlock_irqrestore(&bank->slock, flags); } -static void exynos_gpio_irq_mask(struct irq_data *irqd) +static void exynos_gpio_irq_ack(struct irq_data *irqd) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; - unsigned long mask; + unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; - mask = readl(d->virt_base + reg_mask); - mask |= 1 << irqd->hwirq; - writel(mask, d->virt_base + reg_mask); + writel(1 << irqd->hwirq, d->virt_base + reg_pend); } -static void exynos_gpio_irq_ack(struct irq_data *irqd) +static void exynos_gpio_irq_unmask(struct irq_data *irqd) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; + unsigned long mask; + unsigned long flags; - writel(1 << irqd->hwirq, d->virt_base + reg_pend); + /* + * Ack level interrupts right before unmask + * + * If we don't do this we'll get a double-interrupt. Level triggered + * interrupts must not fire an interrupt if the level is not + * _currently_ active, even if it was active while the interrupt was + * masked. + */ + if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK) + exynos_gpio_irq_ack(irqd); + + spin_lock_irqsave(&bank->slock, flags); + + mask = readl(d->virt_base + reg_mask); + mask &= ~(1 << irqd->hwirq); + writel(mask, d->virt_base + reg_mask); + + spin_unlock_irqrestore(&bank->slock, flags); } static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) @@ -258,37 +279,58 @@ err_domains: return ret; } -static void exynos_wkup_irq_unmask(struct irq_data *irqd) +static void exynos_wkup_irq_mask(struct irq_data *irqd) { struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = b->drvdata; unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; unsigned long mask; + unsigned long flags; + + spin_lock_irqsave(&b->slock, flags); mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << irqd->hwirq); + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); + + spin_unlock_irqrestore(&b->slock, flags); } -static void exynos_wkup_irq_mask(struct irq_data *irqd) +static void exynos_wkup_irq_ack(struct irq_data *irqd) { struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = b->drvdata; - unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; - unsigned long mask; + unsigned long pend = d->ctrl->weint_pend + b->eint_offset; - mask = readl(d->virt_base + reg_mask); - mask |= 1 << irqd->hwirq; - writel(mask, d->virt_base + reg_mask); + writel(1 << irqd->hwirq, d->virt_base + pend); } -static void exynos_wkup_irq_ack(struct irq_data *irqd) +static void exynos_wkup_irq_unmask(struct irq_data *irqd) { struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = b->drvdata; - unsigned long pend = d->ctrl->weint_pend + b->eint_offset; + unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; + unsigned long mask; + unsigned long flags; - writel(1 << irqd->hwirq, d->virt_base + pend); + /* + * Ack level interrupts right before unmask + * + * If we don't do this we'll get a double-interrupt. Level triggered + * interrupts must not fire an interrupt if the level is not + * _currently_ active, even if it was active while the interrupt was + * masked. + */ + if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK) + exynos_wkup_irq_ack(irqd); + + spin_lock_irqsave(&b->slock, flags); + + mask = readl(d->virt_base + reg_mask); + mask &= ~(1 << irqd->hwirq); + writel(mask, d->virt_base + reg_mask); + + spin_unlock_irqrestore(&b->slock, flags); } static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c index 32a48f44f57..3b283fd898f 100644 --- a/drivers/pinctrl/pinctrl-exynos5440.c +++ b/drivers/pinctrl/pinctrl-exynos5440.c @@ -220,7 +220,7 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, dev_err(dev, "failed to alloc memory for group name\n"); goto free_map; } - sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); + snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX); /* * don't have config options? then skip over to creating function @@ -259,7 +259,8 @@ skip_cfgs: dev_err(dev, "failed to alloc memory for func name\n"); goto free_cfg; } - sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); + snprintf(fname, strlen(np->name) + 4, "%s%s", np->name, + FUNCTION_SUFFIX); map[*nmaps].data.mux.group = gname; map[*nmaps].data.mux.function = fname; @@ -713,7 +714,8 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, dev_err(dev, "failed to alloc memory for group name\n"); return -ENOMEM; } - sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); + snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, + GROUP_SUFFIX); grp->name = gname; grp->pins = pin_list; @@ -733,7 +735,8 @@ skip_to_pin_function: dev_err(dev, "failed to alloc memory for func name\n"); return -ENOMEM; } - sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); + snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, + FUNCTION_SUFFIX); func->name = fname; func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); @@ -806,7 +809,7 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, /* for each pin, set the name of the pin */ for (pin = 0; pin < ctrldesc->npins; pin++) { - sprintf(pin_names, "gpio%02d", pin); + snprintf(pin_names, 6, "gpio%02d", pin); pdesc = pindesc + pin; pdesc->name = pin_names; pin_names += PIN_NAME_LENGTH; diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index 4fcfff9243b..57a4eb0add2 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -221,13 +221,21 @@ static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, pin_id = pins[i]; pin_reg = &info->pin_regs[pin_id]; - if (!pin_reg->mux_reg) { + if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->mux_reg) { dev_err(ipctl->dev, "Pin(%s) does not support mux function\n", info->pins[pin_id].name); return -EINVAL; } - writel(mux[i], ipctl->base + pin_reg->mux_reg); + if (info->flags & SHARE_MUX_CONF_REG) { + u32 reg; + reg = readl(ipctl->base + pin_reg->mux_reg); + reg &= ~(0x7 << 20); + reg |= (mux[i] << 20); + writel(reg, ipctl->base + pin_reg->mux_reg); + } else { + writel(mux[i], ipctl->base + pin_reg->mux_reg); + } dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", pin_reg->mux_reg, mux[i]); @@ -287,7 +295,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, const struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; - if (!pin_reg->conf_reg) { + if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) { dev_err(info->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; @@ -295,6 +303,9 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, *config = readl(ipctl->base + pin_reg->conf_reg); + if (info->flags & SHARE_MUX_CONF_REG) + *config &= 0xffff; + return 0; } @@ -305,7 +316,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, const struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; - if (!pin_reg->conf_reg) { + if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) { dev_err(info->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; @@ -314,7 +325,15 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, dev_dbg(ipctl->dev, "pinconf set pin %s\n", info->pins[pin_id].name); - writel(config, ipctl->base + pin_reg->conf_reg); + if (info->flags & SHARE_MUX_CONF_REG) { + u32 reg; + reg = readl(ipctl->base + pin_reg->conf_reg); + reg &= ~0xffff; + reg |= config; + writel(reg, ipctl->base + pin_reg->conf_reg); + } else { + writel(config, ipctl->base + pin_reg->conf_reg); + } dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", pin_reg->conf_reg, config); @@ -381,19 +400,24 @@ static struct pinctrl_desc imx_pinctrl_desc = { * 1 u32 CONFIG, so 24 types in total for each pin. */ #define FSL_PIN_SIZE 24 +#define SHARE_FSL_PIN_SIZE 20 static int imx_pinctrl_parse_groups(struct device_node *np, struct imx_pin_group *grp, struct imx_pinctrl_soc_info *info, u32 index) { - int size; + int size, pin_size; const __be32 *list; int i; u32 config; dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + if (info->flags & SHARE_MUX_CONF_REG) + pin_size = SHARE_FSL_PIN_SIZE; + else + pin_size = FSL_PIN_SIZE; /* Initialise group */ grp->name = np->name; @@ -403,12 +427,12 @@ static int imx_pinctrl_parse_groups(struct device_node *np, */ list = of_get_property(np, "fsl,pins", &size); /* we do not check return since it's safe node passed down */ - if (!size || size % FSL_PIN_SIZE) { + if (!size || size % pin_size) { dev_err(info->dev, "Invalid fsl,pins property\n"); return -EINVAL; } - grp->npins = size / FSL_PIN_SIZE; + grp->npins = size / pin_size; grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), GFP_KERNEL); grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), @@ -421,10 +445,17 @@ static int imx_pinctrl_parse_groups(struct device_node *np, GFP_KERNEL); for (i = 0; i < grp->npins; i++) { u32 mux_reg = be32_to_cpu(*list++); - u32 conf_reg = be32_to_cpu(*list++); - unsigned int pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4; - struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; + u32 conf_reg; + unsigned int pin_id; + struct imx_pin_reg *pin_reg; + if (info->flags & SHARE_MUX_CONF_REG) + conf_reg = mux_reg; + else + conf_reg = be32_to_cpu(*list++); + + pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4; + pin_reg = &info->pin_regs[pin_id]; grp->pins[i] = pin_id; pin_reg->mux_reg = mux_reg; pin_reg->conf_reg = conf_reg; diff --git a/drivers/pinctrl/pinctrl-imx.h b/drivers/pinctrl/pinctrl-imx.h index 607ef549755..bcedd991c9f 100644 --- a/drivers/pinctrl/pinctrl-imx.h +++ b/drivers/pinctrl/pinctrl-imx.h @@ -74,8 +74,12 @@ struct imx_pinctrl_soc_info { unsigned int ngroups; struct imx_pmx_func *functions; unsigned int nfunctions; + unsigned int flags; }; +#define ZERO_OFFSET_VALID 0x1 +#define SHARE_MUX_CONF_REG 0x2 + #define NO_MUX 0x0 #define NO_PAD 0x0 diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c index b45c4eb3579..f5d56436ba7 100644 --- a/drivers/pinctrl/pinctrl-mxs.c +++ b/drivers/pinctrl/pinctrl-mxs.c @@ -515,7 +515,6 @@ int mxs_pinctrl_probe(struct platform_device *pdev, return 0; err: - platform_set_drvdata(pdev, NULL); iounmap(d->base); return ret; } @@ -525,7 +524,6 @@ int mxs_pinctrl_remove(struct platform_device *pdev) { struct mxs_pinctrl_data *d = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); pinctrl_unregister(d->pctl); iounmap(d->base); diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 8a4f9c5c0b8..4a1cfdce223 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -1309,7 +1309,7 @@ static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, return 0; } -const struct irq_domain_ops nmk_gpio_irq_simple_ops = { +static const struct irq_domain_ops nmk_gpio_irq_simple_ops = { .map = nmk_gpio_irq_map, .xlate = irq_domain_xlate_twocell, }; @@ -1681,7 +1681,7 @@ static bool nmk_pinctrl_dt_get_config(struct device_node *np, return has_config; } -int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, +static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned *reserved_maps, @@ -1740,7 +1740,7 @@ exit: return ret; } -int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, +static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps) { diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c new file mode 100644 index 00000000000..1eb5a2e43b0 --- /dev/null +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -0,0 +1,1394 @@ +/* + * Pinctrl driver for Rockchip SoCs + * + * Copyright (c) 2013 MundoReader S.L. + * Author: Heiko Stuebner <heiko@sntech.de> + * + * With some ideas taken from pinctrl-samsung: + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * and pinctrl-at91: + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/clk-provider.h> +#include <dt-bindings/pinctrl/rockchip.h> + +#include "core.h" +#include "pinconf.h" + +/* GPIO control registers */ +#define GPIO_SWPORT_DR 0x00 +#define GPIO_SWPORT_DDR 0x04 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3c +#define GPIO_INT_STATUS 0x40 +#define GPIO_INT_RAWSTATUS 0x44 +#define GPIO_DEBOUNCE 0x48 +#define GPIO_PORTS_EOI 0x4c +#define GPIO_EXT_PORT 0x50 +#define GPIO_LS_SYNC 0x60 + +/** + * @reg_base: register base of the gpio bank + * @clk: clock of the gpio bank + * @irq: interrupt of the gpio bank + * @pin_base: first pin number + * @nr_pins: number of pins in this bank + * @name: name of the bank + * @bank_num: number of the bank, to account for holes + * @valid: are all necessary informations present + * @of_node: dt node of this bank + * @drvdata: common pinctrl basedata + * @domain: irqdomain of the gpio bank + * @gpio_chip: gpiolib chip + * @grange: gpio range + * @slock: spinlock for the gpio bank + */ +struct rockchip_pin_bank { + void __iomem *reg_base; + struct clk *clk; + int irq; + u32 pin_base; + u8 nr_pins; + char *name; + u8 bank_num; + bool valid; + struct device_node *of_node; + struct rockchip_pinctrl *drvdata; + struct irq_domain *domain; + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range grange; + spinlock_t slock; + +}; + +#define PIN_BANK(id, pins, label) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + } + +/** + * @pull_auto: some SoCs don't allow pulls to be specified as up or down, but + * instead decide this automatically based on the pad-type. + */ +struct rockchip_pin_ctrl { + struct rockchip_pin_bank *pin_banks; + u32 nr_banks; + u32 nr_pins; + char *label; + int mux_offset; + int pull_offset; + bool pull_auto; + int pull_bank_stride; +}; + +struct rockchip_pin_config { + unsigned int func; + unsigned long *configs; + unsigned int nconfigs; +}; + +/** + * struct rockchip_pin_group: represent group of pins of a pinmux function. + * @name: name of the pin group, used to lookup the group. + * @pins: the pins included in this group. + * @npins: number of pins included in this group. + * @func: the mux function number to be programmed when selected. + * @configs: the config values to be set for each pin + * @nconfigs: number of configs for each pin + */ +struct rockchip_pin_group { + const char *name; + unsigned int npins; + unsigned int *pins; + struct rockchip_pin_config *data; +}; + +/** + * struct rockchip_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. + */ +struct rockchip_pmx_func { + const char *name; + const char **groups; + u8 ngroups; +}; + +struct rockchip_pinctrl { + void __iomem *reg_base; + struct device *dev; + struct rockchip_pin_ctrl *ctrl; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + struct rockchip_pin_group *groups; + unsigned int ngroups; + struct rockchip_pmx_func *functions; + unsigned int nfunctions; +}; + +static inline struct rockchip_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) +{ + return container_of(gc, struct rockchip_pin_bank, gpio_chip); +} + +static const inline struct rockchip_pin_group *pinctrl_name_to_group( + const struct rockchip_pinctrl *info, + const char *name) +{ + const struct rockchip_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]; + break; + } + + return grp; +} + +/* + * given a pin number that is local to a pin controller, find out the pin bank + * and the register base of the pin bank. + */ +static struct rockchip_pin_bank *pin_to_bank(struct rockchip_pinctrl *info, + unsigned pin) +{ + struct rockchip_pin_bank *b = info->ctrl->pin_banks; + + while ((pin >= b->pin_base) && + ((b->pin_base + b->nr_pins - 1) < pin)) + b++; + + return b; +} + +static struct rockchip_pin_bank *bank_num_to_bank( + struct rockchip_pinctrl *info, + unsigned num) +{ + struct rockchip_pin_bank *b = info->ctrl->pin_banks; + int i; + + for (i = 0; i < info->ctrl->nr_banks; i++) { + if (b->bank_num == num) + break; + + b++; + } + + if (b->bank_num != num) + return ERR_PTR(-EINVAL); + + return b; +} + +/* + * Pinctrl_ops handling + */ + +static int rockchip_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *rockchip_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int rockchip_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, + unsigned *npins) +{ + struct rockchip_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 int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct rockchip_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 to create + * config maps for pins + */ + grp = pinctrl_name_to_group(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) { + devm_kfree(pctldev->dev, 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->data[i].configs; + new_map[i].data.configs.num_configs = grp->data[i].nconfigs; + } + + 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 rockchip_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ +} + +static const struct pinctrl_ops rockchip_pctrl_ops = { + .get_groups_count = rockchip_get_groups_count, + .get_group_name = rockchip_get_group_name, + .get_group_pins = rockchip_get_group_pins, + .dt_node_to_map = rockchip_dt_node_to_map, + .dt_free_map = rockchip_dt_free_map, +}; + +/* + * Hardware access + */ + +/* + * Set a new mux function for a pin. + * + * The register is divided into the upper and lower 16 bit. When changing + * a value, the previous register value is not read and changed. Instead + * it seems the changed bits are marked in the upper 16 bit, while the + * changed value gets set in the same offset in the lower 16 bit. + * All pin settings seem to be 2 bit wide in both the upper and lower + * parts. + * @bank: pin bank to change + * @pin: pin to change + * @mux: new mux function to set + */ +static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) +{ + struct rockchip_pinctrl *info = bank->drvdata; + void __iomem *reg = info->reg_base + info->ctrl->mux_offset; + unsigned long flags; + u8 bit; + u32 data; + + dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n", + bank->bank_num, pin, mux); + + /* get basic quadrupel of mux registers and the correct reg inside */ + reg += bank->bank_num * 0x10; + reg += (pin / 8) * 4; + bit = (pin % 8) * 2; + + spin_lock_irqsave(&bank->slock, flags); + + data = (3 << (bit + 16)); + data |= (mux & 3) << bit; + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); +} + +static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) +{ + struct rockchip_pinctrl *info = bank->drvdata; + struct rockchip_pin_ctrl *ctrl = info->ctrl; + void __iomem *reg; + u8 bit; + + /* rk3066b does support any pulls */ + if (!ctrl->pull_offset) + return PIN_CONFIG_BIAS_DISABLE; + + reg = info->reg_base + ctrl->pull_offset; + + if (ctrl->pull_auto) { + reg += bank->bank_num * ctrl->pull_bank_stride; + reg += (pin_num / 16) * 4; + bit = pin_num % 16; + + return !(readl_relaxed(reg) & BIT(bit)) + ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT + : PIN_CONFIG_BIAS_DISABLE; + } else { + dev_err(info->dev, "pull support for rk31xx not implemented\n"); + return -EIO; + } +} + +static int rockchip_set_pull(struct rockchip_pin_bank *bank, + int pin_num, int pull) +{ + struct rockchip_pinctrl *info = bank->drvdata; + struct rockchip_pin_ctrl *ctrl = info->ctrl; + void __iomem *reg; + unsigned long flags; + u8 bit; + u32 data; + + dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n", + bank->bank_num, pin_num, pull); + + /* rk3066b does support any pulls */ + if (!ctrl->pull_offset) + return pull ? -EINVAL : 0; + + reg = info->reg_base + ctrl->pull_offset; + + if (ctrl->pull_auto) { + if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && + pull != PIN_CONFIG_BIAS_DISABLE) { + dev_err(info->dev, "only PIN_DEFAULT and DISABLE allowed\n"); + return -EINVAL; + } + + reg += bank->bank_num * ctrl->pull_bank_stride; + reg += (pin_num / 16) * 4; + bit = pin_num % 16; + + spin_lock_irqsave(&bank->slock, flags); + + data = BIT(bit + 16); + if (pull == PIN_CONFIG_BIAS_DISABLE) + data |= BIT(bit); + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + } else { + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) { + dev_err(info->dev, "pull direction (up/down) needs to be specified\n"); + return -EINVAL; + } + + dev_err(info->dev, "pull support for rk31xx not implemented\n"); + return -EIO; + } + + return 0; +} + +/* + * Pinmux_ops handling + */ + +static int rockchip_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *rockchip_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, const char * const **groups, + unsigned * const num_groups) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const unsigned int *pins = info->groups[group].pins; + const struct rockchip_pin_config *data = info->groups[group].data; + struct rockchip_pin_bank *bank; + int cnt; + + dev_dbg(info->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + /* + * for each pin in the pin group selected, program the correspoding pin + * pin function number in the config register. + */ + for (cnt = 0; cnt < info->groups[group].npins; cnt++) { + bank = pin_to_bank(info, pins[cnt]); + rockchip_set_mux(bank, pins[cnt] - bank->pin_base, + data[cnt].func); + } + + return 0; +} + +static void rockchip_pmx_disable(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const unsigned int *pins = info->groups[group].pins; + struct rockchip_pin_bank *bank; + int cnt; + + dev_dbg(info->dev, "disable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + for (cnt = 0; cnt < info->groups[group].npins; cnt++) { + bank = pin_to_bank(info, pins[cnt]); + rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0); + } +} + +/* + * 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 rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset, bool input) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct rockchip_pin_bank *bank; + struct gpio_chip *chip; + int pin; + u32 data; + + chip = range->gc; + bank = gc_to_pin_bank(chip); + pin = offset - chip->base; + + dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", + offset, range->name, pin, input ? "input" : "output"); + + rockchip_set_mux(bank, pin, RK_FUNC_GPIO); + + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + /* set bit to 1 for output, 0 for input */ + if (!input) + data |= BIT(pin); + else + data &= ~BIT(pin); + writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + + return 0; +} + +static const struct pinmux_ops rockchip_pmx_ops = { + .get_functions_count = rockchip_pmx_get_funcs_count, + .get_function_name = rockchip_pmx_get_func_name, + .get_function_groups = rockchip_pmx_get_groups, + .enable = rockchip_pmx_enable, + .disable = rockchip_pmx_disable, + .gpio_set_direction = rockchip_pmx_gpio_set_direction, +}; + +/* + * Pinconf_ops handling + */ + +static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, + enum pin_config_param pull) +{ + /* rk3066b does support any pulls */ + if (!ctrl->pull_offset) + return pull ? false : true; + + if (ctrl->pull_auto) { + if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && + pull != PIN_CONFIG_BIAS_DISABLE) + return false; + } else { + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + return false; + } + + return true; +} + +/* set the pin config settings for a specified pin */ +static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long config) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct rockchip_pin_bank *bank = pin_to_bank(info, pin); + enum pin_config_param param = pinconf_to_config_param(config); + u16 arg = pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + return rockchip_set_pull(bank, pin - bank->pin_base, param); + break; + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (!rockchip_pinconf_pull_valid(info->ctrl, param)) + return -ENOTSUPP; + + if (!arg) + return -EINVAL; + + return rockchip_set_pull(bank, pin - bank->pin_base, param); + break; + default: + return -ENOTSUPP; + break; + } + + return 0; +} + +/* get the pin config settings for a specified pin */ +static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct rockchip_pin_bank *bank = pin_to_bank(info, pin); + enum pin_config_param param = pinconf_to_config_param(*config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (rockchip_get_pull(bank, pin - bank->pin_base) != param) + return -EINVAL; + + *config = 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (!rockchip_pinconf_pull_valid(info->ctrl, param)) + return -ENOTSUPP; + + if (rockchip_get_pull(bank, pin - bank->pin_base) != param) + return -EINVAL; + + *config = 1; + break; + default: + return -ENOTSUPP; + break; + } + + return 0; +} + +static const struct pinconf_ops rockchip_pinconf_ops = { + .pin_config_get = rockchip_pinconf_get, + .pin_config_set = rockchip_pinconf_set, +}; + +static const char *gpio_compat = "rockchip,gpio-bank"; + +static void rockchip_pinctrl_child_count(struct rockchip_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)) + continue; + + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } +} + +static int rockchip_pinctrl_parse_groups(struct device_node *np, + struct rockchip_pin_group *grp, + struct rockchip_pinctrl *info, + u32 index) +{ + struct rockchip_pin_bank *bank; + int size; + const __be32 *list; + int num; + int i, j; + int ret; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is rockchip,pins = <bank pin mux CONFIG>, + * do sanity check and calculate pins number + */ + list = of_get_property(np, "rockchip,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; + + grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + grp->data = devm_kzalloc(info->dev, grp->npins * + sizeof(struct rockchip_pin_config), + GFP_KERNEL); + if (!grp->pins || !grp->data) + return -ENOMEM; + + for (i = 0, j = 0; i < size; i += 4, j++) { + const __be32 *phandle; + struct device_node *np_config; + + num = be32_to_cpu(*list++); + bank = bank_num_to_bank(info, num); + if (IS_ERR(bank)) + return PTR_ERR(bank); + + grp->pins[j] = bank->pin_base + be32_to_cpu(*list++); + grp->data[j].func = be32_to_cpu(*list++); + + phandle = list++; + if (!phandle) + return -EINVAL; + + np_config = of_find_node_by_phandle(be32_to_cpup(phandle)); + ret = pinconf_generic_parse_dt_config(np_config, + &grp->data[j].configs, &grp->data[j].nconfigs); + if (ret) + return ret; + } + + return 0; +} + +static int rockchip_pinctrl_parse_functions(struct device_node *np, + struct rockchip_pinctrl *info, + u32 index) +{ + struct device_node *child; + struct rockchip_pmx_func *func; + struct rockchip_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) + return 0; + + 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 = rockchip_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, + struct rockchip_pinctrl *info) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + int ret; + int i; + + rockchip_pinctrl_child_count(info, np); + + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + + info->functions = devm_kzalloc(dev, info->nfunctions * + sizeof(struct rockchip_pmx_func), + GFP_KERNEL); + if (!info->functions) { + dev_err(dev, "failed to allocate memory for function list\n"); + return -EINVAL; + } + + info->groups = devm_kzalloc(dev, info->ngroups * + sizeof(struct rockchip_pin_group), + GFP_KERNEL); + if (!info->groups) { + dev_err(dev, "failed allocate memory for ping group list\n"); + return -EINVAL; + } + + i = 0; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + ret = rockchip_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +static int rockchip_pinctrl_register(struct platform_device *pdev, + struct rockchip_pinctrl *info) +{ + struct pinctrl_desc *ctrldesc = &info->pctl; + struct pinctrl_pin_desc *pindesc, *pdesc; + struct rockchip_pin_bank *pin_bank; + int pin, bank, ret; + int k; + + ctrldesc->name = "rockchip-pinctrl"; + ctrldesc->owner = THIS_MODULE; + ctrldesc->pctlops = &rockchip_pctrl_ops; + ctrldesc->pmxops = &rockchip_pmx_ops; + ctrldesc->confops = &rockchip_pinconf_ops; + + pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * + info->ctrl->nr_pins, GFP_KERNEL); + if (!pindesc) { + dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + return -ENOMEM; + } + ctrldesc->pins = pindesc; + ctrldesc->npins = info->ctrl->nr_pins; + + pdesc = pindesc; + for (bank = 0 , k = 0; bank < info->ctrl->nr_banks; bank++) { + pin_bank = &info->ctrl->pin_banks[bank]; + for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) { + pdesc->number = k; + pdesc->name = kasprintf(GFP_KERNEL, "%s-%d", + pin_bank->name, pin); + pdesc++; + } + } + + info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info); + if (!info->pctl_dev) { + dev_err(&pdev->dev, "could not register pinctrl driver\n"); + return -EINVAL; + } + + for (bank = 0; bank < info->ctrl->nr_banks; ++bank) { + pin_bank = &info->ctrl->pin_banks[bank]; + pin_bank->grange.name = pin_bank->name; + pin_bank->grange.id = bank; + pin_bank->grange.pin_base = pin_bank->pin_base; + pin_bank->grange.base = pin_bank->gpio_chip.base; + pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; + pin_bank->grange.gc = &pin_bank->gpio_chip; + pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange); + } + + ret = rockchip_pinctrl_parse_dt(pdev, info); + if (ret) { + pinctrl_unregister(info->pctl_dev); + return ret; + } + + return 0; +} + +/* + * GPIO handling + */ + +static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct rockchip_pin_bank *bank = gc_to_pin_bank(gc); + void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR; + unsigned long flags; + u32 data; + + spin_lock_irqsave(&bank->slock, flags); + + data = readl(reg); + data &= ~BIT(offset); + if (value) + data |= BIT(offset); + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); +} + +/* + * Returns the level of the pin for input direction and setting of the DR + * register for output gpios. + */ +static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct rockchip_pin_bank *bank = gc_to_pin_bank(gc); + u32 data; + + data = readl(bank->reg_base + GPIO_EXT_PORT); + data >>= offset; + data &= 1; + return data; +} + +/* + * gpiolib gpio_direction_input callback function. The setting of the pin + * mux function as 'gpio input' will be handled by the pinctrl susbsystem + * interface. + */ +static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + return pinctrl_gpio_direction_input(gc->base + offset); +} + +/* + * gpiolib gpio_direction_output callback function. The setting of the pin + * mux function as 'gpio output' will be handled by the pinctrl susbsystem + * interface. + */ +static int rockchip_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + rockchip_gpio_set(gc, offset, value); + return pinctrl_gpio_direction_output(gc->base + offset); +} + +/* + * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin + * and a virtual IRQ, if not already present. + */ +static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct rockchip_pin_bank *bank = gc_to_pin_bank(gc); + unsigned int virq; + + if (!bank->domain) + return -ENXIO; + + virq = irq_create_mapping(bank->domain, offset); + + return (virq) ? : -ENXIO; +} + +static const struct gpio_chip rockchip_gpiolib_chip = { + .set = rockchip_gpio_set, + .get = rockchip_gpio_get, + .direction_input = rockchip_gpio_direction_input, + .direction_output = rockchip_gpio_direction_output, + .to_irq = rockchip_gpio_to_irq, + .owner = THIS_MODULE, +}; + +/* + * Interrupt handling + */ + +static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_get_chip(irq); + struct rockchip_pin_bank *bank = irq_get_handler_data(irq); + u32 pend; + + dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); + + chained_irq_enter(chip, desc); + + pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); + + while (pend) { + unsigned int virq; + + irq = __ffs(pend); + pend &= ~BIT(irq); + virq = irq_linear_revmap(bank->domain, irq); + + if (!virq) { + dev_err(bank->drvdata->dev, "unmapped irq %d\n", irq); + continue; + } + + dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq); + + generic_handle_irq(virq); + } + + chained_irq_exit(chip, desc); +} + +static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct rockchip_pin_bank *bank = gc->private; + u32 mask = BIT(d->hwirq); + u32 polarity; + u32 level; + u32 data; + + if (type & IRQ_TYPE_EDGE_BOTH) + __irq_set_handler_locked(d->irq, handle_edge_irq); + else + __irq_set_handler_locked(d->irq, handle_level_irq); + + irq_gc_lock(gc); + + level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL); + polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + level |= mask; + polarity |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + level |= mask; + polarity &= ~mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + level &= ~mask; + polarity |= mask; + break; + case IRQ_TYPE_LEVEL_LOW: + level &= ~mask; + polarity &= ~mask; + break; + default: + irq_gc_unlock(gc); + return -EINVAL; + } + + writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL); + writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY); + + irq_gc_unlock(gc); + + /* make sure the pin is configured as gpio input */ + rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + data &= ~mask; + writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + + return 0; +} + +static int rockchip_interrupts_register(struct platform_device *pdev, + struct rockchip_pinctrl *info) +{ + struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct rockchip_pin_bank *bank = ctrl->pin_banks; + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct irq_chip_generic *gc; + int ret; + int i; + + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + if (!bank->valid) { + dev_warn(&pdev->dev, "bank %s is not valid\n", + bank->name); + continue; + } + + bank->domain = irq_domain_add_linear(bank->of_node, 32, + &irq_generic_chip_ops, NULL); + if (!bank->domain) { + dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n", + bank->name); + continue; + } + + ret = irq_alloc_domain_generic_chips(bank->domain, 32, 1, + "rockchip_gpio_irq", handle_level_irq, + clr, 0, IRQ_GC_INIT_MASK_CACHE); + if (ret) { + dev_err(&pdev->dev, "could not alloc generic chips for bank %s\n", + bank->name); + irq_domain_remove(bank->domain); + continue; + } + + gc = irq_get_domain_generic_chip(bank->domain, 0); + gc->reg_base = bank->reg_base; + gc->private = bank; + gc->chip_types[0].regs.mask = GPIO_INTEN; + gc->chip_types[0].regs.ack = GPIO_PORTS_EOI; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; + gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; + + irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler(bank->irq, rockchip_irq_demux); + } + + return 0; +} + +static int rockchip_gpiolib_register(struct platform_device *pdev, + struct rockchip_pinctrl *info) +{ + struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct rockchip_pin_bank *bank = ctrl->pin_banks; + struct gpio_chip *gc; + int ret; + int i; + + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + if (!bank->valid) { + dev_warn(&pdev->dev, "bank %s is not valid\n", + bank->name); + continue; + } + + bank->gpio_chip = rockchip_gpiolib_chip; + + gc = &bank->gpio_chip; + gc->base = bank->pin_base; + gc->ngpio = bank->nr_pins; + gc->dev = &pdev->dev; + gc->of_node = bank->of_node; + gc->label = bank->name; + + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", + gc->label, ret); + goto fail; + } + } + + rockchip_interrupts_register(pdev, info); + + return 0; + +fail: + for (--i, --bank; i >= 0; --i, --bank) { + if (!bank->valid) + continue; + + if (gpiochip_remove(&bank->gpio_chip)) + dev_err(&pdev->dev, "gpio chip %s remove failed\n", + bank->gpio_chip.label); + } + return ret; +} + +static int rockchip_gpiolib_unregister(struct platform_device *pdev, + struct rockchip_pinctrl *info) +{ + struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct rockchip_pin_bank *bank = ctrl->pin_banks; + int ret = 0; + int i; + + for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) { + if (!bank->valid) + continue; + + ret = gpiochip_remove(&bank->gpio_chip); + } + + if (ret) + dev_err(&pdev->dev, "gpio chip remove failed\n"); + + return ret; +} + +static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, + struct device *dev) +{ + struct resource res; + + if (of_address_to_resource(bank->of_node, 0, &res)) { + dev_err(dev, "cannot find IO resource for bank\n"); + return -ENOENT; + } + + bank->reg_base = devm_ioremap_resource(dev, &res); + if (IS_ERR(bank->reg_base)) + return PTR_ERR(bank->reg_base); + + bank->irq = irq_of_parse_and_map(bank->of_node, 0); + + bank->clk = of_clk_get(bank->of_node, 0); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + + return clk_prepare_enable(bank->clk); +} + +static const struct of_device_id rockchip_pinctrl_dt_match[]; + +/* retrieve the soc specific data */ +static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( + struct rockchip_pinctrl *d, + struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device_node *node = pdev->dev.of_node; + struct device_node *np; + struct rockchip_pin_ctrl *ctrl; + struct rockchip_pin_bank *bank; + int i; + + match = of_match_node(rockchip_pinctrl_dt_match, node); + ctrl = (struct rockchip_pin_ctrl *)match->data; + + for_each_child_of_node(node, np) { + if (!of_find_property(np, "gpio-controller", NULL)) + continue; + + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + if (!strcmp(bank->name, np->name)) { + bank->of_node = np; + + if (!rockchip_get_bank_data(bank, &pdev->dev)) + bank->valid = true; + + break; + } + } + } + + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + spin_lock_init(&bank->slock); + bank->drvdata = d; + bank->pin_base = ctrl->nr_pins; + ctrl->nr_pins += bank->nr_pins; + } + + return ctrl; +} + +static int rockchip_pinctrl_probe(struct platform_device *pdev) +{ + struct rockchip_pinctrl *info; + struct device *dev = &pdev->dev; + struct rockchip_pin_ctrl *ctrl; + struct resource *res; + int ret; + + if (!dev->of_node) { + dev_err(dev, "device tree node not found\n"); + return -ENODEV; + } + + info = devm_kzalloc(dev, sizeof(struct rockchip_pinctrl), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ctrl = rockchip_pinctrl_get_soc_data(info, pdev); + if (!ctrl) { + dev_err(dev, "driver data not available\n"); + return -EINVAL; + } + info->ctrl = ctrl; + info->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find IO resource\n"); + return -ENOENT; + } + + info->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->reg_base)) + return PTR_ERR(info->reg_base); + + ret = rockchip_gpiolib_register(pdev, info); + if (ret) + return ret; + + ret = rockchip_pinctrl_register(pdev, info); + if (ret) { + rockchip_gpiolib_unregister(pdev, info); + return ret; + } + + platform_set_drvdata(pdev, info); + + return 0; +} + +static struct rockchip_pin_bank rk2928_pin_banks[] = { + PIN_BANK(0, 32, "gpio0"), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), +}; + +static struct rockchip_pin_ctrl rk2928_pin_ctrl = { + .pin_banks = rk2928_pin_banks, + .nr_banks = ARRAY_SIZE(rk2928_pin_banks), + .label = "RK2928-GPIO", + .mux_offset = 0xa8, + .pull_offset = 0x118, + .pull_auto = 1, + .pull_bank_stride = 8, +}; + +static struct rockchip_pin_bank rk3066a_pin_banks[] = { + PIN_BANK(0, 32, "gpio0"), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), + PIN_BANK(4, 32, "gpio4"), + PIN_BANK(6, 16, "gpio6"), +}; + +static struct rockchip_pin_ctrl rk3066a_pin_ctrl = { + .pin_banks = rk3066a_pin_banks, + .nr_banks = ARRAY_SIZE(rk3066a_pin_banks), + .label = "RK3066a-GPIO", + .mux_offset = 0xa8, + .pull_offset = 0x118, + .pull_auto = 1, + .pull_bank_stride = 8, +}; + +static struct rockchip_pin_bank rk3066b_pin_banks[] = { + PIN_BANK(0, 32, "gpio0"), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), +}; + +static struct rockchip_pin_ctrl rk3066b_pin_ctrl = { + .pin_banks = rk3066b_pin_banks, + .nr_banks = ARRAY_SIZE(rk3066b_pin_banks), + .label = "RK3066b-GPIO", + .mux_offset = 0x60, + .pull_offset = -EINVAL, +}; + +static struct rockchip_pin_bank rk3188_pin_banks[] = { + PIN_BANK(0, 32, "gpio0"), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), +}; + +static struct rockchip_pin_ctrl rk3188_pin_ctrl = { + .pin_banks = rk3188_pin_banks, + .nr_banks = ARRAY_SIZE(rk3188_pin_banks), + .label = "RK3188-GPIO", + .mux_offset = 0x68, + .pull_offset = 0x164, + .pull_bank_stride = 16, +}; + +static const struct of_device_id rockchip_pinctrl_dt_match[] = { + { .compatible = "rockchip,rk2928-pinctrl", + .data = (void *)&rk2928_pin_ctrl }, + { .compatible = "rockchip,rk3066a-pinctrl", + .data = (void *)&rk3066a_pin_ctrl }, + { .compatible = "rockchip,rk3066b-pinctrl", + .data = (void *)&rk3066b_pin_ctrl }, + { .compatible = "rockchip,rk3188-pinctrl", + .data = (void *)&rk3188_pin_ctrl }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match); + +static struct platform_driver rockchip_pinctrl_driver = { + .probe = rockchip_pinctrl_probe, + .driver = { + .name = "rockchip-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rockchip_pinctrl_dt_match), + }, +}; + +static int __init rockchip_pinctrl_drv_register(void) +{ + return platform_driver_register(&rockchip_pinctrl_driver); +} +postcore_initcall(rockchip_pinctrl_drv_register); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("Rockchip pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 0a6c720b665..a7fa9e2d475 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -50,7 +50,7 @@ static struct pin_config { }; /* Global list of devices (struct samsung_pinctrl_drv_data) */ -LIST_HEAD(drvdata_list); +static LIST_HEAD(drvdata_list); static unsigned int pin_base; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b9fa0461860..6866548fab3 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -30,7 +30,7 @@ #define DRIVER_NAME "pinctrl-single" #define PCS_MUX_PINS_NAME "pinctrl-single,pins" #define PCS_MUX_BITS_NAME "pinctrl-single,bits" -#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) +#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 3) #define PCS_OFF_DISABLED ~0U /** @@ -163,6 +163,7 @@ struct pcs_name { * @foff: value to turn mux off * @fmax: max number of functions in fmask * @is_pinconf: whether supports pinconf + * @bits_per_pin:number of bits per pin * @names: array of register names for pins * @pins: physical pins on the SoC * @pgtree: pingroup index radix tree @@ -190,6 +191,7 @@ struct pcs_device { unsigned fmax; bool bits_per_mux; bool is_pinconf; + unsigned bits_per_pin; struct pcs_name *names; struct pcs_data pins; struct radix_tree_root pgtree; @@ -431,10 +433,11 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, vals = &func->vals[i]; val = pcs->read(vals->reg); - if (!vals->mask) - mask = pcs->fmask; + + if (pcs->bits_per_mux) + mask = vals->mask; else - mask = pcs->fmask & vals->mask; + mask = pcs->fmask; val &= ~mask; val |= (vals->val & mask); @@ -741,7 +744,8 @@ static const struct pinconf_ops pcs_pinconf_ops = { * @pcs: pcs driver instance * @offset: register offset from base */ -static int pcs_add_pin(struct pcs_device *pcs, unsigned offset) +static int pcs_add_pin(struct pcs_device *pcs, unsigned offset, + unsigned pin_pos) { struct pinctrl_pin_desc *pin; struct pcs_name *pn; @@ -756,8 +760,8 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset) pin = &pcs->pins.pa[i]; pn = &pcs->names[i]; - sprintf(pn->name, "%lx", - (unsigned long)pcs->res->start + offset); + sprintf(pn->name, "%lx.%d", + (unsigned long)pcs->res->start + offset, pin_pos); pin->name = pn->name; pin->number = i; pcs->pins.cur++; @@ -777,9 +781,17 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset) static int pcs_allocate_pin_table(struct pcs_device *pcs) { int mux_bytes, nr_pins, i; + int num_pins_in_register = 0; mux_bytes = pcs->width / BITS_PER_BYTE; - nr_pins = pcs->size / mux_bytes; + + if (pcs->bits_per_mux) { + pcs->bits_per_pin = fls(pcs->fmask); + nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin; + num_pins_in_register = pcs->width / pcs->bits_per_pin; + } else { + nr_pins = pcs->size / mux_bytes; + } dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins); pcs->pins.pa = devm_kzalloc(pcs->dev, @@ -800,9 +812,17 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs) for (i = 0; i < pcs->desc.npins; i++) { unsigned offset; int res; - - offset = i * mux_bytes; - res = pcs_add_pin(pcs, offset); + int byte_num; + int pin_pos = 0; + + if (pcs->bits_per_mux) { + byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE; + offset = (byte_num / mux_bytes) * mux_bytes; + pin_pos = i % num_pins_in_register; + } else { + offset = i * mux_bytes; + } + res = pcs_add_pin(pcs, offset, pin_pos); if (res < 0) { dev_err(pcs->dev, "error adding pins: %i\n", res); return res; @@ -919,7 +939,10 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) return -EINVAL; } - index = offset / (pcs->width / BITS_PER_BYTE); + if (pcs->bits_per_mux) + index = (offset * BITS_PER_BYTE) / pcs->bits_per_pin; + else + index = offset / (pcs->width / BITS_PER_BYTE); return index; } @@ -1097,29 +1120,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, { struct pcs_func_vals *vals; const __be32 *mux; - int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM; + int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; struct pcs_function *function; - if (pcs->bits_per_mux) { - params = 3; - mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); - } else { - params = 2; - mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); - } - - if (!mux) { - dev_err(pcs->dev, "no valid property for %s\n", np->name); - return -EINVAL; - } - - if (size < (sizeof(*mux) * params)) { - dev_err(pcs->dev, "bad data for %s\n", np->name); + mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); + if ((!mux) || (size < sizeof(*mux) * 2)) { + dev_err(pcs->dev, "bad data for mux %s\n", + np->name); return -EINVAL; } size /= sizeof(*mux); /* Number of elements in array */ - rows = size / params; + rows = size / 2; vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); if (!vals) @@ -1137,10 +1149,6 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, val = be32_to_cpup(mux + index++); vals[found].reg = pcs->base + offset; vals[found].val = val; - if (params == 3) { - val = be32_to_cpup(mux + index++); - vals[found].mask = val; - } pin = pcs_get_pin_by_offset(pcs, offset); if (pin < 0) { @@ -1189,6 +1197,125 @@ free_vals: return res; } + +#define PARAMS_FOR_BITS_PER_MUX 3 + +static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, + struct device_node *np, + struct pinctrl_map **map, + unsigned *num_maps, + const char **pgnames) +{ + struct pcs_func_vals *vals; + const __be32 *mux; + int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; + int npins_in_row; + struct pcs_function *function; + + mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); + + if (!mux) { + dev_err(pcs->dev, "no valid property for %s\n", np->name); + return -EINVAL; + } + + if (size < (sizeof(*mux) * PARAMS_FOR_BITS_PER_MUX)) { + dev_err(pcs->dev, "bad data for %s\n", np->name); + return -EINVAL; + } + + /* Number of elements in array */ + size /= sizeof(*mux); + + rows = size / PARAMS_FOR_BITS_PER_MUX; + npins_in_row = pcs->width / pcs->bits_per_pin; + + vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row, + GFP_KERNEL); + if (!vals) + return -ENOMEM; + + pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row, + GFP_KERNEL); + if (!pins) + goto free_vals; + + while (index < size) { + unsigned offset, val; + unsigned mask, bit_pos, val_pos, mask_pos, submask; + unsigned pin_num_from_lsb; + int pin; + + offset = be32_to_cpup(mux + index++); + val = be32_to_cpup(mux + index++); + mask = be32_to_cpup(mux + index++); + + /* Parse pins in each row from LSB */ + while (mask) { + bit_pos = ffs(mask); + pin_num_from_lsb = bit_pos / pcs->bits_per_pin; + mask_pos = ((pcs->fmask) << (bit_pos - 1)); + val_pos = val & mask_pos; + submask = mask & mask_pos; + mask &= ~mask_pos; + + if (submask != mask_pos) { + dev_warn(pcs->dev, + "Invalid submask 0x%x for %s at 0x%x\n", + submask, np->name, offset); + continue; + } + + vals[found].mask = submask; + vals[found].reg = pcs->base + offset; + vals[found].val = val_pos; + + pin = pcs_get_pin_by_offset(pcs, offset); + if (pin < 0) { + dev_err(pcs->dev, + "could not add functions for %s %ux\n", + np->name, offset); + break; + } + pins[found++] = pin + pin_num_from_lsb; + } + } + + pgnames[0] = np->name; + function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1); + if (!function) + goto free_pins; + + res = pcs_add_pingroup(pcs, np, np->name, pins, found); + if (res < 0) + goto free_function; + + (*map)->type = PIN_MAP_TYPE_MUX_GROUP; + (*map)->data.mux.group = np->name; + (*map)->data.mux.function = np->name; + + if (pcs->is_pinconf) { + dev_err(pcs->dev, "pinconf not supported\n"); + goto free_pingroups; + } + + *num_maps = 1; + return 0; + +free_pingroups: + pcs_free_pingroups(pcs); + *num_maps = 1; +free_function: + pcs_remove_function(pcs, function); + +free_pins: + devm_kfree(pcs->dev, pins); + +free_vals: + devm_kfree(pcs->dev, vals); + + return res; +} /** * pcs_dt_node_to_map() - allocates and parses pinctrl maps * @pctldev: pinctrl instance @@ -1219,12 +1346,22 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, goto free_map; } - ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps, - pgnames); - if (ret < 0) { - dev_err(pcs->dev, "no pins entries for %s\n", - np_config->name); - goto free_pgnames; + if (pcs->bits_per_mux) { + ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map, + num_maps, pgnames); + if (ret < 0) { + dev_err(pcs->dev, "no pins entries for %s\n", + np_config->name); + goto free_pgnames; + } + } else { + ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, + num_maps, pgnames); + if (ret < 0) { + dev_err(pcs->dev, "no pins entries for %s\n", + np_config->name); + goto free_pgnames; + } } return 0; @@ -1346,6 +1483,29 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) return ret; } +static int pinctrl_single_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct pcs_device *pcs; + + pcs = platform_get_drvdata(pdev); + if (!pcs) + return -EINVAL; + + return pinctrl_force_sleep(pcs->pctl); +} + +static int pinctrl_single_resume(struct platform_device *pdev) +{ + struct pcs_device *pcs; + + pcs = platform_get_drvdata(pdev); + if (!pcs) + return -EINVAL; + + return pinctrl_force_default(pcs->pctl); +} + static int pcs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1494,6 +1654,10 @@ static struct platform_driver pcs_driver = { .name = DRIVER_NAME, .of_match_table = pcs_of_match, }, +#ifdef CONFIG_PM + .suspend = pinctrl_single_suspend, + .resume = pinctrl_single_resume, +#endif }; module_platform_driver(pcs_driver); diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c new file mode 100644 index 00000000000..04d4506ae18 --- /dev/null +++ b/drivers/pinctrl/pinctrl-st.c @@ -0,0 +1,1403 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited. + * Authors: + * Srinivas Kandagatla <srinivas.kandagatla@st.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/platform_device.h> +#include "core.h" + +/* PIO Block registers */ +/* PIO output */ +#define REG_PIO_POUT 0x00 +/* Set bits of POUT */ +#define REG_PIO_SET_POUT 0x04 +/* Clear bits of POUT */ +#define REG_PIO_CLR_POUT 0x08 +/* PIO input */ +#define REG_PIO_PIN 0x10 +/* PIO configuration */ +#define REG_PIO_PC(n) (0x20 + (n) * 0x10) +/* Set bits of PC[2:0] */ +#define REG_PIO_SET_PC(n) (0x24 + (n) * 0x10) +/* Clear bits of PC[2:0] */ +#define REG_PIO_CLR_PC(n) (0x28 + (n) * 0x10) +/* PIO input comparison */ +#define REG_PIO_PCOMP 0x50 +/* Set bits of PCOMP */ +#define REG_PIO_SET_PCOMP 0x54 +/* Clear bits of PCOMP */ +#define REG_PIO_CLR_PCOMP 0x58 +/* PIO input comparison mask */ +#define REG_PIO_PMASK 0x60 +/* Set bits of PMASK */ +#define REG_PIO_SET_PMASK 0x64 +/* Clear bits of PMASK */ +#define REG_PIO_CLR_PMASK 0x68 + +#define ST_GPIO_DIRECTION_BIDIR 0x1 +#define ST_GPIO_DIRECTION_OUT 0x2 +#define ST_GPIO_DIRECTION_IN 0x4 + +/** + * Packed style retime configuration. + * There are two registers cfg0 and cfg1 in this style for each bank. + * Each field in this register is 8 bit corresponding to 8 pins in the bank. + */ +#define RT_P_CFGS_PER_BANK 2 +#define RT_P_CFG0_CLK1NOTCLK0_FIELD(reg) REG_FIELD(reg, 0, 7) +#define RT_P_CFG0_DELAY_0_FIELD(reg) REG_FIELD(reg, 16, 23) +#define RT_P_CFG0_DELAY_1_FIELD(reg) REG_FIELD(reg, 24, 31) +#define RT_P_CFG1_INVERTCLK_FIELD(reg) REG_FIELD(reg, 0, 7) +#define RT_P_CFG1_RETIME_FIELD(reg) REG_FIELD(reg, 8, 15) +#define RT_P_CFG1_CLKNOTDATA_FIELD(reg) REG_FIELD(reg, 16, 23) +#define RT_P_CFG1_DOUBLE_EDGE_FIELD(reg) REG_FIELD(reg, 24, 31) + +/** + * Dedicated style retime Configuration register + * each register is dedicated per pin. + */ +#define RT_D_CFGS_PER_BANK 8 +#define RT_D_CFG_CLK_SHIFT 0 +#define RT_D_CFG_CLK_MASK (0x3 << 0) +#define RT_D_CFG_CLKNOTDATA_SHIFT 2 +#define RT_D_CFG_CLKNOTDATA_MASK BIT(2) +#define RT_D_CFG_DELAY_SHIFT 3 +#define RT_D_CFG_DELAY_MASK (0xf << 3) +#define RT_D_CFG_DELAY_INNOTOUT_SHIFT 7 +#define RT_D_CFG_DELAY_INNOTOUT_MASK BIT(7) +#define RT_D_CFG_DOUBLE_EDGE_SHIFT 8 +#define RT_D_CFG_DOUBLE_EDGE_MASK BIT(8) +#define RT_D_CFG_INVERTCLK_SHIFT 9 +#define RT_D_CFG_INVERTCLK_MASK BIT(9) +#define RT_D_CFG_RETIME_SHIFT 10 +#define RT_D_CFG_RETIME_MASK BIT(10) + +/* + * Pinconf is represented in an opaque unsigned long variable. + * Below is the bit allocation details for each possible configuration. + * All the bit fields can be encapsulated into four variables + * (direction, retime-type, retime-clk, retime-delay) + * + * +----------------+ + *[31:28]| reserved-3 | + * +----------------+------------- + *[27] | oe | | + * +----------------+ v + *[26] | pu | [Direction ] + * +----------------+ ^ + *[25] | od | | + * +----------------+------------- + *[24] | reserved-2 | + * +----------------+------------- + *[23] | retime | | + * +----------------+ | + *[22] | retime-invclk | | + * +----------------+ v + *[21] |retime-clknotdat| [Retime-type ] + * +----------------+ ^ + *[20] | retime-de | | + * +----------------+------------- + *[19:18]| retime-clk |------>[Retime-Clk ] + * +----------------+ + *[17:16]| reserved-1 | + * +----------------+ + *[15..0]| retime-delay |------>[Retime Delay] + * +----------------+ + */ + +#define ST_PINCONF_UNPACK(conf, param)\ + ((conf >> ST_PINCONF_ ##param ##_SHIFT) \ + & ST_PINCONF_ ##param ##_MASK) + +#define ST_PINCONF_PACK(conf, val, param) (conf |=\ + ((val & ST_PINCONF_ ##param ##_MASK) << \ + ST_PINCONF_ ##param ##_SHIFT)) + +/* Output enable */ +#define ST_PINCONF_OE_MASK 0x1 +#define ST_PINCONF_OE_SHIFT 27 +#define ST_PINCONF_OE BIT(27) +#define ST_PINCONF_UNPACK_OE(conf) ST_PINCONF_UNPACK(conf, OE) +#define ST_PINCONF_PACK_OE(conf) ST_PINCONF_PACK(conf, 1, OE) + +/* Pull Up */ +#define ST_PINCONF_PU_MASK 0x1 +#define ST_PINCONF_PU_SHIFT 26 +#define ST_PINCONF_PU BIT(26) +#define ST_PINCONF_UNPACK_PU(conf) ST_PINCONF_UNPACK(conf, PU) +#define ST_PINCONF_PACK_PU(conf) ST_PINCONF_PACK(conf, 1, PU) + +/* Open Drain */ +#define ST_PINCONF_OD_MASK 0x1 +#define ST_PINCONF_OD_SHIFT 25 +#define ST_PINCONF_OD BIT(25) +#define ST_PINCONF_UNPACK_OD(conf) ST_PINCONF_UNPACK(conf, OD) +#define ST_PINCONF_PACK_OD(conf) ST_PINCONF_PACK(conf, 1, OD) + +#define ST_PINCONF_RT_MASK 0x1 +#define ST_PINCONF_RT_SHIFT 23 +#define ST_PINCONF_RT BIT(23) +#define ST_PINCONF_UNPACK_RT(conf) ST_PINCONF_UNPACK(conf, RT) +#define ST_PINCONF_PACK_RT(conf) ST_PINCONF_PACK(conf, 1, RT) + +#define ST_PINCONF_RT_INVERTCLK_MASK 0x1 +#define ST_PINCONF_RT_INVERTCLK_SHIFT 22 +#define ST_PINCONF_RT_INVERTCLK BIT(22) +#define ST_PINCONF_UNPACK_RT_INVERTCLK(conf) \ + ST_PINCONF_UNPACK(conf, RT_INVERTCLK) +#define ST_PINCONF_PACK_RT_INVERTCLK(conf) \ + ST_PINCONF_PACK(conf, 1, RT_INVERTCLK) + +#define ST_PINCONF_RT_CLKNOTDATA_MASK 0x1 +#define ST_PINCONF_RT_CLKNOTDATA_SHIFT 21 +#define ST_PINCONF_RT_CLKNOTDATA BIT(21) +#define ST_PINCONF_UNPACK_RT_CLKNOTDATA(conf) \ + ST_PINCONF_UNPACK(conf, RT_CLKNOTDATA) +#define ST_PINCONF_PACK_RT_CLKNOTDATA(conf) \ + ST_PINCONF_PACK(conf, 1, RT_CLKNOTDATA) + +#define ST_PINCONF_RT_DOUBLE_EDGE_MASK 0x1 +#define ST_PINCONF_RT_DOUBLE_EDGE_SHIFT 20 +#define ST_PINCONF_RT_DOUBLE_EDGE BIT(20) +#define ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \ + ST_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE) +#define ST_PINCONF_PACK_RT_DOUBLE_EDGE(conf) \ + ST_PINCONF_PACK(conf, 1, RT_DOUBLE_EDGE) + +#define ST_PINCONF_RT_CLK_MASK 0x3 +#define ST_PINCONF_RT_CLK_SHIFT 18 +#define ST_PINCONF_RT_CLK BIT(18) +#define ST_PINCONF_UNPACK_RT_CLK(conf) ST_PINCONF_UNPACK(conf, RT_CLK) +#define ST_PINCONF_PACK_RT_CLK(conf, val) ST_PINCONF_PACK(conf, val, RT_CLK) + +/* RETIME_DELAY in Pico Secs */ +#define ST_PINCONF_RT_DELAY_MASK 0xffff +#define ST_PINCONF_RT_DELAY_SHIFT 0 +#define ST_PINCONF_UNPACK_RT_DELAY(conf) ST_PINCONF_UNPACK(conf, RT_DELAY) +#define ST_PINCONF_PACK_RT_DELAY(conf, val) \ + ST_PINCONF_PACK(conf, val, RT_DELAY) + +#define ST_GPIO_PINS_PER_BANK (8) +#define OF_GPIO_ARGS_MIN (4) +#define OF_RT_ARGS_MIN (2) + +#define gpio_range_to_bank(chip) \ + container_of(chip, struct st_gpio_bank, range) + +#define gpio_chip_to_bank(chip) \ + container_of(chip, struct st_gpio_bank, gpio_chip) + + +enum st_retime_style { + st_retime_style_none, + st_retime_style_packed, + st_retime_style_dedicated, +}; + +struct st_retime_dedicated { + struct regmap_field *rt[ST_GPIO_PINS_PER_BANK]; +}; + +struct st_retime_packed { + struct regmap_field *clk1notclk0; + struct regmap_field *delay_0; + struct regmap_field *delay_1; + struct regmap_field *invertclk; + struct regmap_field *retime; + struct regmap_field *clknotdata; + struct regmap_field *double_edge; +}; + +struct st_pio_control { + u32 rt_pin_mask; + struct regmap_field *alt, *oe, *pu, *od; + /* retiming */ + union { + struct st_retime_packed rt_p; + struct st_retime_dedicated rt_d; + } rt; +}; + +struct st_pctl_data { + enum st_retime_style rt_style; + unsigned int *input_delays; + int ninput_delays; + unsigned int *output_delays; + int noutput_delays; + /* register offset information */ + int alt, oe, pu, od, rt; +}; + +struct st_pinconf { + int pin; + const char *name; + unsigned long config; + int altfunc; +}; + +struct st_pmx_func { + const char *name; + const char **groups; + unsigned ngroups; +}; + +struct st_pctl_group { + const char *name; + unsigned int *pins; + unsigned npins; + struct st_pinconf *pin_conf; +}; + +struct st_gpio_bank { + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range range; + void __iomem *base; + struct st_pio_control pc; +}; + +struct st_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + struct st_gpio_bank *banks; + int nbanks; + struct st_pmx_func *functions; + int nfunctions; + struct st_pctl_group *groups; + int ngroups; + struct regmap *regmap; + const struct st_pctl_data *data; +}; + +/* SOC specific data */ +/* STiH415 data */ +unsigned int stih415_input_delays[] = {0, 500, 1000, 1500}; +unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000}; + +#define STIH415_PCTRL_COMMON_DATA \ + .rt_style = st_retime_style_packed, \ + .input_delays = stih415_input_delays, \ + .ninput_delays = 4, \ + .output_delays = stih415_output_delays, \ + .noutput_delays = 4 + +static const struct st_pctl_data stih415_sbc_data = { + STIH415_PCTRL_COMMON_DATA, + .alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 16, +}; + +static const struct st_pctl_data stih415_front_data = { + STIH415_PCTRL_COMMON_DATA, + .alt = 0, .oe = 8, .pu = 10, .od = 12, .rt = 16, +}; + +static const struct st_pctl_data stih415_rear_data = { + STIH415_PCTRL_COMMON_DATA, + .alt = 0, .oe = 6, .pu = 8, .od = 10, .rt = 38, +}; + +static const struct st_pctl_data stih415_left_data = { + STIH415_PCTRL_COMMON_DATA, + .alt = 0, .oe = 3, .pu = 4, .od = 5, .rt = 6, +}; + +static const struct st_pctl_data stih415_right_data = { + STIH415_PCTRL_COMMON_DATA, + .alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 11, +}; + +/* STiH416 data */ +unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500, + 1750, 2000, 2250, 2500, 2750, 3000, 3250 }; + +static const struct st_pctl_data stih416_data = { + .rt_style = st_retime_style_dedicated, + .input_delays = stih416_delays, + .ninput_delays = 14, + .output_delays = stih416_delays, + .noutput_delays = 14, + .alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100, +}; + +/* Low level functions.. */ +static inline int st_gpio_bank(int gpio) +{ + return gpio/ST_GPIO_PINS_PER_BANK; +} + +static inline int st_gpio_pin(int gpio) +{ + return gpio%ST_GPIO_PINS_PER_BANK; +} + +static void st_pinconf_set_config(struct st_pio_control *pc, + int pin, unsigned long config) +{ + struct regmap_field *output_enable = pc->oe; + struct regmap_field *pull_up = pc->pu; + struct regmap_field *open_drain = pc->od; + unsigned int oe_value, pu_value, od_value; + unsigned long mask = BIT(pin); + + regmap_field_read(output_enable, &oe_value); + regmap_field_read(pull_up, &pu_value); + regmap_field_read(open_drain, &od_value); + + /* Clear old values */ + oe_value &= ~mask; + pu_value &= ~mask; + od_value &= ~mask; + + if (config & ST_PINCONF_OE) + oe_value |= mask; + if (config & ST_PINCONF_PU) + pu_value |= mask; + if (config & ST_PINCONF_OD) + od_value |= mask; + + regmap_field_write(output_enable, oe_value); + regmap_field_write(pull_up, pu_value); + regmap_field_write(open_drain, od_value); +} + +static void st_pctl_set_function(struct st_pio_control *pc, + int pin_id, int function) +{ + struct regmap_field *alt = pc->alt; + unsigned int val; + int pin = st_gpio_pin(pin_id); + int offset = pin * 4; + + regmap_field_read(alt, &val); + val &= ~(0xf << offset); + val |= function << offset; + regmap_field_write(alt, val); +} + +static unsigned long st_pinconf_delay_to_bit(unsigned int delay, + const struct st_pctl_data *data, unsigned long config) +{ + unsigned int *delay_times; + int num_delay_times, i, closest_index = -1; + unsigned int closest_divergence = UINT_MAX; + + if (ST_PINCONF_UNPACK_OE(config)) { + delay_times = data->output_delays; + num_delay_times = data->noutput_delays; + } else { + delay_times = data->input_delays; + num_delay_times = data->ninput_delays; + } + + for (i = 0; i < num_delay_times; i++) { + unsigned int divergence = abs(delay - delay_times[i]); + + if (divergence == 0) + return i; + + if (divergence < closest_divergence) { + closest_divergence = divergence; + closest_index = i; + } + } + + pr_warn("Attempt to set delay %d, closest available %d\n", + delay, delay_times[closest_index]); + + return closest_index; +} + +static unsigned long st_pinconf_bit_to_delay(unsigned int index, + const struct st_pctl_data *data, unsigned long output) +{ + unsigned int *delay_times; + int num_delay_times; + + if (output) { + delay_times = data->output_delays; + num_delay_times = data->noutput_delays; + } else { + delay_times = data->input_delays; + num_delay_times = data->ninput_delays; + } + + if (index < num_delay_times) { + return delay_times[index]; + } else { + pr_warn("Delay not found in/out delay list\n"); + return 0; + } +} + +static void st_regmap_field_bit_set_clear_pin(struct regmap_field *field, + int enable, int pin) +{ + unsigned int val = 0; + + regmap_field_read(field, &val); + if (enable) + val |= BIT(pin); + else + val &= ~BIT(pin); + regmap_field_write(field, val); +} + +static void st_pinconf_set_retime_packed(struct st_pinctrl *info, + struct st_pio_control *pc, unsigned long config, int pin) +{ + const struct st_pctl_data *data = info->data; + struct st_retime_packed *rt_p = &pc->rt.rt_p; + unsigned int delay; + + st_regmap_field_bit_set_clear_pin(rt_p->clk1notclk0, + ST_PINCONF_UNPACK_RT_CLK(config), pin); + + st_regmap_field_bit_set_clear_pin(rt_p->clknotdata, + ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), pin); + + st_regmap_field_bit_set_clear_pin(rt_p->double_edge, + ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), pin); + + st_regmap_field_bit_set_clear_pin(rt_p->invertclk, + ST_PINCONF_UNPACK_RT_INVERTCLK(config), pin); + + st_regmap_field_bit_set_clear_pin(rt_p->retime, + ST_PINCONF_UNPACK_RT(config), pin); + + delay = st_pinconf_delay_to_bit(ST_PINCONF_UNPACK_RT_DELAY(config), + data, config); + /* 2 bit delay, lsb */ + st_regmap_field_bit_set_clear_pin(rt_p->delay_0, delay & 0x1, pin); + /* 2 bit delay, msb */ + st_regmap_field_bit_set_clear_pin(rt_p->delay_1, delay & 0x2, pin); + +} + +static void st_pinconf_set_retime_dedicated(struct st_pinctrl *info, + struct st_pio_control *pc, unsigned long config, int pin) +{ + int input = ST_PINCONF_UNPACK_OE(config) ? 0 : 1; + int clk = ST_PINCONF_UNPACK_RT_CLK(config); + int clknotdata = ST_PINCONF_UNPACK_RT_CLKNOTDATA(config); + int double_edge = ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config); + int invertclk = ST_PINCONF_UNPACK_RT_INVERTCLK(config); + int retime = ST_PINCONF_UNPACK_RT(config); + + unsigned long delay = st_pinconf_delay_to_bit( + ST_PINCONF_UNPACK_RT_DELAY(config), + info->data, config); + struct st_retime_dedicated *rt_d = &pc->rt.rt_d; + + unsigned long retime_config = + ((clk) << RT_D_CFG_CLK_SHIFT) | + ((delay) << RT_D_CFG_DELAY_SHIFT) | + ((input) << RT_D_CFG_DELAY_INNOTOUT_SHIFT) | + ((retime) << RT_D_CFG_RETIME_SHIFT) | + ((clknotdata) << RT_D_CFG_CLKNOTDATA_SHIFT) | + ((invertclk) << RT_D_CFG_INVERTCLK_SHIFT) | + ((double_edge) << RT_D_CFG_DOUBLE_EDGE_SHIFT); + + regmap_field_write(rt_d->rt[pin], retime_config); +} + +static void st_pinconf_get_direction(struct st_pio_control *pc, + int pin, unsigned long *config) +{ + unsigned int oe_value, pu_value, od_value; + + regmap_field_read(pc->oe, &oe_value); + regmap_field_read(pc->pu, &pu_value); + regmap_field_read(pc->od, &od_value); + + if (oe_value & BIT(pin)) + ST_PINCONF_PACK_OE(*config); + if (pu_value & BIT(pin)) + ST_PINCONF_PACK_PU(*config); + if (od_value & BIT(pin)) + ST_PINCONF_PACK_OD(*config); + +} + +static int st_pinconf_get_retime_packed(struct st_pinctrl *info, + struct st_pio_control *pc, int pin, unsigned long *config) +{ + const struct st_pctl_data *data = info->data; + struct st_retime_packed *rt_p = &pc->rt.rt_p; + unsigned int delay_bits, delay, delay0, delay1, val; + int output = ST_PINCONF_UNPACK_OE(*config); + + if (!regmap_field_read(rt_p->retime, &val) && (val & BIT(pin))) + ST_PINCONF_PACK_RT(*config); + + if (!regmap_field_read(rt_p->clk1notclk0, &val) && (val & BIT(pin))) + ST_PINCONF_PACK_RT_CLK(*config, 1); + + if (!regmap_field_read(rt_p->clknotdata, &val) && (val & BIT(pin))) + ST_PINCONF_PACK_RT_CLKNOTDATA(*config); + + if (!regmap_field_read(rt_p->double_edge, &val) && (val & BIT(pin))) + ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config); + + if (!regmap_field_read(rt_p->invertclk, &val) && (val & BIT(pin))) + ST_PINCONF_PACK_RT_INVERTCLK(*config); + + regmap_field_read(rt_p->delay_0, &delay0); + regmap_field_read(rt_p->delay_1, &delay1); + delay_bits = (((delay1 & BIT(pin)) ? 1 : 0) << 1) | + (((delay0 & BIT(pin)) ? 1 : 0)); + delay = st_pinconf_bit_to_delay(delay_bits, data, output); + ST_PINCONF_PACK_RT_DELAY(*config, delay); + + return 0; +} + +static int st_pinconf_get_retime_dedicated(struct st_pinctrl *info, + struct st_pio_control *pc, int pin, unsigned long *config) +{ + unsigned int value; + unsigned long delay_bits, delay, rt_clk; + int output = ST_PINCONF_UNPACK_OE(*config); + struct st_retime_dedicated *rt_d = &pc->rt.rt_d; + + regmap_field_read(rt_d->rt[pin], &value); + + rt_clk = (value & RT_D_CFG_CLK_MASK) >> RT_D_CFG_CLK_SHIFT; + ST_PINCONF_PACK_RT_CLK(*config, rt_clk); + + delay_bits = (value & RT_D_CFG_DELAY_MASK) >> RT_D_CFG_DELAY_SHIFT; + delay = st_pinconf_bit_to_delay(delay_bits, info->data, output); + ST_PINCONF_PACK_RT_DELAY(*config, delay); + + if (value & RT_D_CFG_CLKNOTDATA_MASK) + ST_PINCONF_PACK_RT_CLKNOTDATA(*config); + + if (value & RT_D_CFG_DOUBLE_EDGE_MASK) + ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config); + + if (value & RT_D_CFG_INVERTCLK_MASK) + ST_PINCONF_PACK_RT_INVERTCLK(*config); + + if (value & RT_D_CFG_RETIME_MASK) + ST_PINCONF_PACK_RT(*config); + + return 0; +} + +/* GPIO related functions */ + +static inline void __st_gpio_set(struct st_gpio_bank *bank, + unsigned offset, int value) +{ + if (value) + writel(BIT(offset), bank->base + REG_PIO_SET_POUT); + else + writel(BIT(offset), bank->base + REG_PIO_CLR_POUT); +} + +static void st_gpio_direction(struct st_gpio_bank *bank, + unsigned int gpio, unsigned int direction) +{ + int offset = st_gpio_pin(gpio); + int i = 0; + /** + * There are three configuration registers (PIOn_PC0, PIOn_PC1 + * and PIOn_PC2) for each port. These are used to configure the + * PIO port pins. Each pin can be configured as an input, output, + * bidirectional, or alternative function pin. Three bits, one bit + * from each of the three registers, configure the corresponding bit of + * the port. Valid bit settings is: + * + * PC2 PC1 PC0 Direction. + * 0 0 0 [Input Weak pull-up] + * 0 0 or 1 1 [Bidirection] + * 0 1 0 [Output] + * 1 0 0 [Input] + * + * PIOn_SET_PC and PIOn_CLR_PC registers are used to set and clear bits + * individually. + */ + for (i = 0; i <= 2; i++) { + if (direction & BIT(i)) + writel(BIT(offset), bank->base + REG_PIO_SET_PC(i)); + else + writel(BIT(offset), bank->base + REG_PIO_CLR_PC(i)); + } +} + +static int st_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void st_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int st_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct st_gpio_bank *bank = gpio_chip_to_bank(chip); + + return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset)); +} + +static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct st_gpio_bank *bank = gpio_chip_to_bank(chip); + __st_gpio_set(bank, offset, value); +} + +static int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_gpio_direction_input(chip->base + offset); + + return 0; +} + +static int st_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct st_gpio_bank *bank = gpio_chip_to_bank(chip); + + __st_gpio_set(bank, offset, value); + pinctrl_gpio_direction_output(chip->base + offset); + + return 0; +} + +static int st_gpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + if (WARN_ON(gc->of_gpio_n_cells < 1)) + return -EINVAL; + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] > gc->ngpio) + return -EINVAL; + + return gpiospec->args[0]; +} + +/* Pinctrl Groups */ +static int st_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *st_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int st_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, unsigned *npins) +{ + struct st_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 const inline struct st_pctl_group *st_pctl_find_group_by_name( + const struct st_pinctrl *info, const char *name) +{ + int i; + + for (i = 0; i < info->ngroups; i++) { + if (!strcmp(info->groups[i].name, name)) + return &info->groups[i]; + } + + return NULL; +} + +static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, unsigned *num_maps) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct st_pctl_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num, i; + + grp = st_pctl_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 + 1; + new_map = devm_kzalloc(pctldev->dev, + sizeof(*new_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + parent = of_get_parent(np); + if (!parent) { + devm_kfree(pctldev->dev, new_map); + return -EINVAL; + } + + *map = new_map; + *num_maps = map_num; + 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 per pin */ + 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->pin_conf[i].config; + new_map[i].data.configs.num_configs = 1; + } + dev_info(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, grp->name, map_num); + + return 0; +} + +static void st_pctl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ +} + +static struct pinctrl_ops st_pctlops = { + .get_groups_count = st_pctl_get_groups_count, + .get_group_pins = st_pctl_get_group_pins, + .get_group_name = st_pctl_get_group_name, + .dt_node_to_map = st_pctl_dt_node_to_map, + .dt_free_map = st_pctl_dt_free_map, +}; + +/* Pinmux */ +static int st_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +const char *st_pmx_get_fname(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int st_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, const char * const **grps, unsigned * const ngrps) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + *grps = info->functions[selector].groups; + *ngrps = info->functions[selector].ngroups; + + return 0; +} + +static struct st_pio_control *st_get_pio_control( + struct pinctrl_dev *pctldev, int pin) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctldev, pin); + struct st_gpio_bank *bank = gpio_range_to_bank(range); + + return &bank->pc; +} + +static int st_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector, + unsigned group) +{ + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct st_pinconf *conf = info->groups[group].pin_conf; + struct st_pio_control *pc; + int i; + + for (i = 0; i < info->groups[group].npins; i++) { + pc = st_get_pio_control(pctldev, conf[i].pin); + st_pctl_set_function(pc, conf[i].pin, conf[i].altfunc); + } + + return 0; +} + +static void st_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ +} + +static int st_pmx_set_gpio_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned gpio, + bool input) +{ + struct st_gpio_bank *bank = gpio_range_to_bank(range); + /* + * When a PIO bank is used in its primary function mode (altfunc = 0) + * Output Enable (OE), Open Drain(OD), and Pull Up (PU) + * for the primary PIO functions are driven by the related PIO block + */ + st_pctl_set_function(&bank->pc, gpio, 0); + st_gpio_direction(bank, gpio, input ? + ST_GPIO_DIRECTION_IN : ST_GPIO_DIRECTION_OUT); + + return 0; +} + +static struct pinmux_ops st_pmxops = { + .get_functions_count = st_pmx_get_funcs_count, + .get_function_name = st_pmx_get_fname, + .get_function_groups = st_pmx_get_groups, + .enable = st_pmx_enable, + .disable = st_pmx_disable, + .gpio_set_direction = st_pmx_set_gpio_direction, +}; + +/* Pinconf */ +static void st_pinconf_get_retime(struct st_pinctrl *info, + struct st_pio_control *pc, int pin, unsigned long *config) +{ + if (info->data->rt_style == st_retime_style_packed) + st_pinconf_get_retime_packed(info, pc, pin, config); + else if (info->data->rt_style == st_retime_style_dedicated) + if ((BIT(pin) & pc->rt_pin_mask)) + st_pinconf_get_retime_dedicated(info, pc, + pin, config); +} + +static void st_pinconf_set_retime(struct st_pinctrl *info, + struct st_pio_control *pc, int pin, unsigned long config) +{ + if (info->data->rt_style == st_retime_style_packed) + st_pinconf_set_retime_packed(info, pc, config, pin); + else if (info->data->rt_style == st_retime_style_dedicated) + if ((BIT(pin) & pc->rt_pin_mask)) + st_pinconf_set_retime_dedicated(info, pc, + config, pin); +} + +static int st_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long config) +{ + int pin = st_gpio_pin(pin_id); + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id); + + st_pinconf_set_config(pc, pin, config); + st_pinconf_set_retime(info, pc, pin, config); + + return 0; +} + +static int st_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + int pin = st_gpio_pin(pin_id); + struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id); + + *config = 0; + st_pinconf_get_direction(pc, pin, config); + st_pinconf_get_retime(info, pc, pin, config); + + return 0; +} + +static void st_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + unsigned long config; + st_pinconf_get(pctldev, pin_id, &config); + + seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n" + "\t\t[retime:%ld,invclk:%ld,clknotdat:%ld," + "de:%ld,rt-clk:%ld,rt-delay:%ld]", + ST_PINCONF_UNPACK_OE(config), + ST_PINCONF_UNPACK_PU(config), + ST_PINCONF_UNPACK_OD(config), + ST_PINCONF_UNPACK_RT(config), + ST_PINCONF_UNPACK_RT_INVERTCLK(config), + ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), + ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), + ST_PINCONF_UNPACK_RT_CLK(config), + ST_PINCONF_UNPACK_RT_DELAY(config)); +} + +static struct pinconf_ops st_confops = { + .pin_config_get = st_pinconf_get, + .pin_config_set = st_pinconf_set, + .pin_config_dbg_show = st_pinconf_dbg_show, +}; + +static void st_pctl_dt_child_count(struct st_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static int st_pctl_dt_setup_retime_packed(struct st_pinctrl *info, + int bank, struct st_pio_control *pc) +{ + struct device *dev = info->dev; + struct regmap *rm = info->regmap; + const struct st_pctl_data *data = info->data; + /* 2 registers per bank */ + int reg = (data->rt + bank * RT_P_CFGS_PER_BANK) * 4; + struct st_retime_packed *rt_p = &pc->rt.rt_p; + /* cfg0 */ + struct reg_field clk1notclk0 = RT_P_CFG0_CLK1NOTCLK0_FIELD(reg); + struct reg_field delay_0 = RT_P_CFG0_DELAY_0_FIELD(reg); + struct reg_field delay_1 = RT_P_CFG0_DELAY_1_FIELD(reg); + /* cfg1 */ + struct reg_field invertclk = RT_P_CFG1_INVERTCLK_FIELD(reg + 4); + struct reg_field retime = RT_P_CFG1_RETIME_FIELD(reg + 4); + struct reg_field clknotdata = RT_P_CFG1_CLKNOTDATA_FIELD(reg + 4); + struct reg_field double_edge = RT_P_CFG1_DOUBLE_EDGE_FIELD(reg + 4); + + rt_p->clk1notclk0 = devm_regmap_field_alloc(dev, rm, clk1notclk0); + rt_p->delay_0 = devm_regmap_field_alloc(dev, rm, delay_0); + rt_p->delay_1 = devm_regmap_field_alloc(dev, rm, delay_1); + rt_p->invertclk = devm_regmap_field_alloc(dev, rm, invertclk); + rt_p->retime = devm_regmap_field_alloc(dev, rm, retime); + rt_p->clknotdata = devm_regmap_field_alloc(dev, rm, clknotdata); + rt_p->double_edge = devm_regmap_field_alloc(dev, rm, double_edge); + + if (IS_ERR(rt_p->clk1notclk0) || IS_ERR(rt_p->delay_0) || + IS_ERR(rt_p->delay_1) || IS_ERR(rt_p->invertclk) || + IS_ERR(rt_p->retime) || IS_ERR(rt_p->clknotdata) || + IS_ERR(rt_p->double_edge)) + return -EINVAL; + + return 0; +} + +static int st_pctl_dt_setup_retime_dedicated(struct st_pinctrl *info, + int bank, struct st_pio_control *pc) +{ + struct device *dev = info->dev; + struct regmap *rm = info->regmap; + const struct st_pctl_data *data = info->data; + /* 8 registers per bank */ + int reg_offset = (data->rt + bank * RT_D_CFGS_PER_BANK) * 4; + struct st_retime_dedicated *rt_d = &pc->rt.rt_d; + unsigned int j; + u32 pin_mask = pc->rt_pin_mask; + + for (j = 0; j < RT_D_CFGS_PER_BANK; j++) { + if (BIT(j) & pin_mask) { + struct reg_field reg = REG_FIELD(reg_offset, 0, 31); + rt_d->rt[j] = devm_regmap_field_alloc(dev, rm, reg); + if (IS_ERR(rt_d->rt[j])) + return -EINVAL; + reg_offset += 4; + } + } + return 0; +} + +static int st_pctl_dt_setup_retime(struct st_pinctrl *info, + int bank, struct st_pio_control *pc) +{ + const struct st_pctl_data *data = info->data; + if (data->rt_style == st_retime_style_packed) + return st_pctl_dt_setup_retime_packed(info, bank, pc); + else if (data->rt_style == st_retime_style_dedicated) + return st_pctl_dt_setup_retime_dedicated(info, bank, pc); + + return -EINVAL; +} + +static int st_parse_syscfgs(struct st_pinctrl *info, + int bank, struct device_node *np) +{ + const struct st_pctl_data *data = info->data; + /** + * For a given shared register like OE/PU/OD, there are 8 bits per bank + * 0:7 belongs to bank0, 8:15 belongs to bank1 ... + * So each register is shared across 4 banks. + */ + int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK; + int msb = lsb + ST_GPIO_PINS_PER_BANK - 1; + struct reg_field alt_reg = REG_FIELD((data->alt + bank) * 4, 0, 31); + struct reg_field oe_reg = REG_FIELD((data->oe + bank/4) * 4, lsb, msb); + struct reg_field pu_reg = REG_FIELD((data->pu + bank/4) * 4, lsb, msb); + struct reg_field od_reg = REG_FIELD((data->od + bank/4) * 4, lsb, msb); + struct st_pio_control *pc = &info->banks[bank].pc; + struct device *dev = info->dev; + struct regmap *regmap = info->regmap; + + pc->alt = devm_regmap_field_alloc(dev, regmap, alt_reg); + pc->oe = devm_regmap_field_alloc(dev, regmap, oe_reg); + pc->pu = devm_regmap_field_alloc(dev, regmap, pu_reg); + pc->od = devm_regmap_field_alloc(dev, regmap, od_reg); + + if (IS_ERR(pc->alt) || IS_ERR(pc->oe) || + IS_ERR(pc->pu) || IS_ERR(pc->od)) + return -EINVAL; + + /* retime avaiable for all pins by default */ + pc->rt_pin_mask = 0xff; + of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask); + st_pctl_dt_setup_retime(info, bank, pc); + + return 0; +} + +/* + * Each pin is represented in of the below forms. + * <bank offset mux direction rt_type rt_delay rt_clk> + */ +static int st_pctl_dt_parse_groups(struct device_node *np, + struct st_pctl_group *grp, struct st_pinctrl *info, int idx) +{ + /* bank pad direction val altfunction */ + const __be32 *list; + struct property *pp; + struct st_pinconf *conf; + phandle phandle; + struct device_node *pins; + u32 pin; + int i = 0, npins = 0, nr_props; + + pins = of_get_child_by_name(np, "st,pins"); + if (!pins) + return -ENODATA; + + for_each_property_of_node(pins, pp) { + /* Skip those we do not want to proceed */ + if (!strcmp(pp->name, "name")) + continue; + + if (pp && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) { + npins++; + } else { + pr_warn("Invalid st,pins in %s node\n", np->name); + return -EINVAL; + } + } + + grp->npins = npins; + grp->name = np->name; + grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL); + grp->pin_conf = devm_kzalloc(info->dev, + npins * sizeof(*conf), GFP_KERNEL); + + if (!grp->pins || !grp->pin_conf) + return -ENOMEM; + + /* <bank offset mux direction rt_type rt_delay rt_clk> */ + for_each_property_of_node(pins, pp) { + if (!strcmp(pp->name, "name")) + continue; + nr_props = pp->length/sizeof(u32); + list = pp->value; + conf = &grp->pin_conf[i]; + + /* bank & offset */ + phandle = be32_to_cpup(list++); + pin = be32_to_cpup(list++); + conf->pin = of_get_named_gpio(pins, pp->name, 0); + conf->name = pp->name; + grp->pins[i] = conf->pin; + /* mux */ + conf->altfunc = be32_to_cpup(list++); + conf->config = 0; + /* direction */ + conf->config |= be32_to_cpup(list++); + /* rt_type rt_delay rt_clk */ + if (nr_props >= OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) { + /* rt_type */ + conf->config |= be32_to_cpup(list++); + /* rt_delay */ + conf->config |= be32_to_cpup(list++); + /* rt_clk */ + if (nr_props > OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) + conf->config |= be32_to_cpup(list++); + } + i++; + } + of_node_put(pins); + + return 0; +} + +static int st_pctl_parse_functions(struct device_node *np, + struct st_pinctrl *info, u32 index, int *grp_index) +{ + struct device_node *child; + struct st_pmx_func *func; + struct st_pctl_group *grp; + int ret, i; + + func = &info->functions[index]; + 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; + + i = 0; + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[*grp_index]; + *grp_index += 1; + ret = st_pctl_dt_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n", + index, func->name, func->ngroups); + + return 0; +} + +static struct gpio_chip st_gpio_template = { + .request = st_gpio_request, + .free = st_gpio_free, + .get = st_gpio_get, + .set = st_gpio_set, + .direction_input = st_gpio_direction_input, + .direction_output = st_gpio_direction_output, + .ngpio = ST_GPIO_PINS_PER_BANK, + .of_gpio_n_cells = 1, + .of_xlate = st_gpio_xlate, +}; + +static int st_gpiolib_register_bank(struct st_pinctrl *info, + int bank_nr, struct device_node *np) +{ + struct st_gpio_bank *bank = &info->banks[bank_nr]; + struct pinctrl_gpio_range *range = &bank->range; + struct device *dev = info->dev; + int bank_num = of_alias_get_id(np, "gpio"); + struct resource res; + int err; + + if (of_address_to_resource(np, 0, &res)) + return -ENODEV; + + bank->base = devm_request_and_ioremap(dev, &res); + if (!bank->base) { + dev_err(dev, "Can't get IO memory mapping!\n"); + return -ENODEV; + } + + bank->gpio_chip = st_gpio_template; + bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK; + bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK; + bank->gpio_chip.of_node = np; + + of_property_read_string(np, "st,bank-name", &range->name); + bank->gpio_chip.label = range->name; + + range->id = bank_num; + range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK; + range->npins = bank->gpio_chip.ngpio; + range->gc = &bank->gpio_chip; + err = gpiochip_add(&bank->gpio_chip); + if (err) { + dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num); + return err; + } + dev_info(dev, "%s bank added.\n", range->name); + + return 0; +} + +static struct of_device_id st_pctl_of_match[] = { + { .compatible = "st,stih415-sbc-pinctrl", .data = &stih415_sbc_data }, + { .compatible = "st,stih415-rear-pinctrl", .data = &stih415_rear_data }, + { .compatible = "st,stih415-left-pinctrl", .data = &stih415_left_data }, + { .compatible = "st,stih415-right-pinctrl", + .data = &stih415_right_data }, + { .compatible = "st,stih415-front-pinctrl", + .data = &stih415_front_data }, + { .compatible = "st,stih416-sbc-pinctrl", .data = &stih416_data}, + { .compatible = "st,stih416-front-pinctrl", .data = &stih416_data}, + { .compatible = "st,stih416-rear-pinctrl", .data = &stih416_data}, + { .compatible = "st,stih416-fvdp-fe-pinctrl", .data = &stih416_data}, + { .compatible = "st,stih416-fvdp-lite-pinctrl", .data = &stih416_data}, + { /* sentinel */ } +}; + +static int st_pctl_probe_dt(struct platform_device *pdev, + struct pinctrl_desc *pctl_desc, struct st_pinctrl *info) +{ + int ret = 0; + int i = 0, j = 0, k = 0, bank; + struct pinctrl_pin_desc *pdesc; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + int grp_index = 0; + + st_pctl_dt_child_count(info, np); + if (!info->nbanks) { + dev_err(&pdev->dev, "you need atleast one gpio bank\n"); + return -EINVAL; + } + + dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks); + dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups); + + info->functions = devm_kzalloc(&pdev->dev, + info->nfunctions * sizeof(*info->functions), GFP_KERNEL); + + info->groups = devm_kzalloc(&pdev->dev, + info->ngroups * sizeof(*info->groups) , GFP_KERNEL); + + info->banks = devm_kzalloc(&pdev->dev, + info->nbanks * sizeof(*info->banks), GFP_KERNEL); + + if (!info->functions || !info->groups || !info->banks) + return -ENOMEM; + + info->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(info->regmap)) { + dev_err(info->dev, "No syscfg phandle specified\n"); + return PTR_ERR(info->regmap); + } + info->data = of_match_node(st_pctl_of_match, np)->data; + + pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK; + pdesc = devm_kzalloc(&pdev->dev, + sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL); + if (!pdesc) + return -ENOMEM; + + pctl_desc->pins = pdesc; + + bank = 0; + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + const char *bank_name = NULL; + ret = st_gpiolib_register_bank(info, bank, child); + if (ret) + return ret; + + k = info->banks[bank].range.pin_base; + bank_name = info->banks[bank].range.name; + for (j = 0; j < ST_GPIO_PINS_PER_BANK; j++, k++) { + pdesc->number = k; + pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]", + bank_name, j); + pdesc++; + } + st_parse_syscfgs(info, bank, child); + bank++; + } else { + ret = st_pctl_parse_functions(child, info, + i++, &grp_index); + if (ret) { + dev_err(&pdev->dev, "No functions found.\n"); + return ret; + } + } + } + + return 0; +} + +static int st_pctl_probe(struct platform_device *pdev) +{ + struct st_pinctrl *info; + struct pinctrl_desc *pctl_desc; + int ret, i; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "device node not found.\n"); + return -EINVAL; + } + + pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + platform_set_drvdata(pdev, info); + ret = st_pctl_probe_dt(pdev, pctl_desc, info); + if (ret) + return ret; + + pctl_desc->owner = THIS_MODULE, + pctl_desc->pctlops = &st_pctlops, + pctl_desc->pmxops = &st_pmxops, + pctl_desc->confops = &st_confops, + pctl_desc->name = dev_name(&pdev->dev); + + info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info); + if (!info->pctl) { + dev_err(&pdev->dev, "Failed pinctrl registration\n"); + return -EINVAL; + } + + for (i = 0; i < info->nbanks; i++) + pinctrl_add_gpio_range(info->pctl, &info->banks[i].range); + + return 0; +} + +static struct platform_driver st_pctl_driver = { + .driver = { + .name = "st-pinctrl", + .owner = THIS_MODULE, + .of_match_table = st_pctl_of_match, + }, + .probe = st_pctl_probe, +}; + +static int __init st_pctl_init(void) +{ + return platform_driver_register(&st_pctl_driver); +} +arch_initcall(st_pctl_init); diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h new file mode 100644 index 00000000000..2eeae0c066c --- /dev/null +++ b/drivers/pinctrl/pinctrl-sunxi-pins.h @@ -0,0 +1,2023 @@ +/* + * Allwinner A1X SoCs pinctrl driver. + * + * Copyright (C) 2012 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * 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. + */ + +#ifndef __PINCTRL_SUNXI_PINS_H +#define __PINCTRL_SUNXI_PINS_H + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin sun4i_a10_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */ + SUNXI_FUNCTION(0x3, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x4, "uart2")), /* RTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */ + SUNXI_FUNCTION(0x3, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart2")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */ + SUNXI_FUNCTION(0x3, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x4, "uart2")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */ + SUNXI_FUNCTION(0x3, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x4, "uart2")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */ + SUNXI_FUNCTION(0x3, "spi1")), /* CS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */ + SUNXI_FUNCTION(0x3, "spi3")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */ + SUNXI_FUNCTION(0x3, "spi3")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */ + SUNXI_FUNCTION(0x3, "spi3")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */ + SUNXI_FUNCTION(0x3, "spi3")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */ + SUNXI_FUNCTION(0x3, "spi3")), /* CS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */ + SUNXI_FUNCTION(0x4, "uart1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDC */ + SUNXI_FUNCTION(0x4, "uart1")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */ + SUNXI_FUNCTION(0x3, "uart6"), /* TX */ + SUNXI_FUNCTION(0x4, "uart1")), /* RTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */ + SUNXI_FUNCTION(0x3, "uart6"), /* RX */ + SUNXI_FUNCTION(0x4, "uart1")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */ + SUNXI_FUNCTION(0x3, "uart7"), /* TX */ + SUNXI_FUNCTION(0x4, "uart1")), /* DTR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECRS */ + SUNXI_FUNCTION(0x3, "uart7"), /* RX */ + SUNXI_FUNCTION(0x4, "uart1")), /* DSR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECOL */ + SUNXI_FUNCTION(0x3, "can"), /* TX */ + SUNXI_FUNCTION(0x4, "uart1")), /* DCD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */ + SUNXI_FUNCTION(0x3, "can"), /* RX */ + SUNXI_FUNCTION(0x4, "uart1")), /* RING */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm")), /* PWM0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */ + SUNXI_FUNCTION(0x3, "ac97")), /* MCLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */ + SUNXI_FUNCTION(0x3, "ac97")), /* BCLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */ + SUNXI_FUNCTION(0x3, "ac97")), /* SYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DO0 */ + SUNXI_FUNCTION(0x3, "ac97")), /* DO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s")), /* DO2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s")), /* DO3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DI */ + SUNXI_FUNCTION(0x3, "ac97")), /* DI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2")), /* CS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ + SUNXI_FUNCTION(0x3, "jtag")), /* MS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ + SUNXI_FUNCTION(0x3, "jtag")), /* CK0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ + SUNXI_FUNCTION(0x3, "jtag")), /* DO0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ + SUNXI_FUNCTION(0x3, "jtag")), /* DI0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* TX */ + SUNXI_FUNCTION(0x3, "ir1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* RX */ + SUNXI_FUNCTION(0x3, "ir1")), /* RX */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NRE# */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NDQ4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NDQ5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NDQ6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NDQ7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NWP */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */ + SUNXI_FUNCTION(0x3, "spi2")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE5 */ + SUNXI_FUNCTION(0x3, "spi2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE6 */ + SUNXI_FUNCTION(0x3, "spi2")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE7 */ + SUNXI_FUNCTION(0x3, "spi2")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NDQS */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VM3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VPC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ + SUNXI_FUNCTION(0x3, "csi1")), /* MCLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ + SUNXI_FUNCTION(0x3, "sim")), /* VPPEN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ + SUNXI_FUNCTION(0x3, "sim")), /* VPPPP */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ + SUNXI_FUNCTION(0x3, "sim")), /* DET */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ + SUNXI_FUNCTION(0x3, "sim")), /* VCCEN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ + SUNXI_FUNCTION(0x3, "sim")), /* RST */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "sim")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "sim")), /* SDA */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ + SUNXI_FUNCTION(0x3, "csi0")), /* PCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ + SUNXI_FUNCTION(0x3, "csi0")), /* CK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ + SUNXI_FUNCTION(0x3, "csi0")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ + SUNXI_FUNCTION(0x3, "csi0")), /* VSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ + SUNXI_FUNCTION(0x4, "sim")), /* VPPEN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ + SUNXI_FUNCTION(0x3, "csi0")), /* D7 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x4, "jtag")), /* MSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* CLK */ + SUNXI_FUNCTION(0x3, "csi1"), /* PCK */ + SUNXI_FUNCTION(0x4, "mmc1")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* ERR */ + SUNXI_FUNCTION(0x3, "csi1"), /* CK */ + SUNXI_FUNCTION(0x4, "mmc1")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* SYNC */ + SUNXI_FUNCTION(0x3, "csi1"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "mmc1")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* DVLD */ + SUNXI_FUNCTION(0x3, "csi1"), /* VSYNC */ + SUNXI_FUNCTION(0x4, "mmc1")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D0 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D0 */ + SUNXI_FUNCTION(0x4, "mmc1"), /* D2 */ + SUNXI_FUNCTION(0x5, "csi0")), /* D8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D1 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D1 */ + SUNXI_FUNCTION(0x4, "mmc1"), /* D3 */ + SUNXI_FUNCTION(0x5, "csi0")), /* D9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D2 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D2 */ + SUNXI_FUNCTION(0x4, "uart3"), /* TX */ + SUNXI_FUNCTION(0x5, "csi0")), /* D10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D3 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart3"), /* RX */ + SUNXI_FUNCTION(0x5, "csi0")), /* D11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D4 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D4 */ + SUNXI_FUNCTION(0x4, "uart3"), /* RTS */ + SUNXI_FUNCTION(0x5, "csi0")), /* D12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D5 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D5 */ + SUNXI_FUNCTION(0x4, "uart3"), /* CTS */ + SUNXI_FUNCTION(0x5, "csi0")), /* D13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D6 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart4"), /* TX */ + SUNXI_FUNCTION(0x5, "csi0")), /* D14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts1"), /* D7 */ + SUNXI_FUNCTION(0x3, "csi1"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart4"), /* RX */ + SUNXI_FUNCTION(0x5, "csi0")), /* D15 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D0 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAA0 */ + SUNXI_FUNCTION(0x4, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 0), /* EINT0 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D1 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAA1 */ + SUNXI_FUNCTION(0x4, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 1), /* EINT1 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D2 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAA2 */ + SUNXI_FUNCTION(0x4, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 2), /* EINT2 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D3 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAIRQ */ + SUNXI_FUNCTION(0x4, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 3), /* EINT3 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D4 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD0 */ + SUNXI_FUNCTION(0x4, "uart4"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 4), /* EINT4 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D5 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD1 */ + SUNXI_FUNCTION(0x4, "uart4"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 5), /* EINT5 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D6 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD2 */ + SUNXI_FUNCTION(0x4, "uart5"), /* TX */ + SUNXI_FUNCTION(0x5, "ms"), /* BS */ + SUNXI_FUNCTION_IRQ(0x6, 6), /* EINT6 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D7 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD3 */ + SUNXI_FUNCTION(0x4, "uart5"), /* RX */ + SUNXI_FUNCTION(0x5, "ms"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 7), /* EINT7 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D8 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD4 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN0 */ + SUNXI_FUNCTION(0x5, "ms"), /* D0 */ + SUNXI_FUNCTION_IRQ(0x6, 8), /* EINT8 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D9 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD5 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN1 */ + SUNXI_FUNCTION(0x5, "ms"), /* D1 */ + SUNXI_FUNCTION_IRQ(0x6, 9), /* EINT9 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D10 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD6 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN2 */ + SUNXI_FUNCTION(0x5, "ms"), /* D2 */ + SUNXI_FUNCTION_IRQ(0x6, 10), /* EINT10 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D11 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD7 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN3 */ + SUNXI_FUNCTION(0x5, "ms"), /* D3 */ + SUNXI_FUNCTION_IRQ(0x6, 11), /* EINT11 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D12 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD8 */ + SUNXI_FUNCTION(0x4, "ps2"), /* SCK1 */ + SUNXI_FUNCTION_IRQ(0x6, 12), /* EINT12 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D13 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD9 */ + SUNXI_FUNCTION(0x4, "ps2"), /* SDA1 */ + SUNXI_FUNCTION(0x5, "sim"), /* RST */ + SUNXI_FUNCTION_IRQ(0x6, 13), /* EINT13 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D14 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD10 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN4 */ + SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */ + SUNXI_FUNCTION_IRQ(0x6, 14), /* EINT14 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D15 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD11 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN5 */ + SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */ + SUNXI_FUNCTION_IRQ(0x6, 15), /* EINT15 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D16 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD12 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN6 */ + SUNXI_FUNCTION_IRQ(0x6, 16), /* EINT16 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D17 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD13 */ + SUNXI_FUNCTION(0x4, "keypad"), /* IN7 */ + SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */ + SUNXI_FUNCTION_IRQ(0x6, 17), /* EINT17 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D18 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD14 */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT0 */ + SUNXI_FUNCTION(0x5, "sim"), /* SCK */ + SUNXI_FUNCTION_IRQ(0x6, 18), /* EINT18 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D19 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAD15 */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT1 */ + SUNXI_FUNCTION(0x5, "sim"), /* SDA */ + SUNXI_FUNCTION_IRQ(0x6, 19), /* EINT19 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D20 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAOE */ + SUNXI_FUNCTION(0x4, "can"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 20), /* EINT20 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D21 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATADREQ */ + SUNXI_FUNCTION(0x4, "can"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 21), /* EINT21 */ + SUNXI_FUNCTION(0x7, "csi1")), /* D21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D22 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATADACK */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT2 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* CMD */ + SUNXI_FUNCTION(0x7, "csi1")), /* D22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* D23 */ + SUNXI_FUNCTION(0x3, "pata"), /* ATACS0 */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT3 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* CLK */ + SUNXI_FUNCTION(0x7, "csi1")), /* D23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* CLK */ + SUNXI_FUNCTION(0x3, "pata"), /* ATACS1 */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT4 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* D0 */ + SUNXI_FUNCTION(0x7, "csi1")), /* PCLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* DE */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAIORDY */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT5 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* D1 */ + SUNXI_FUNCTION(0x7, "csi1")), /* FIELD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAIOR */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT6 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* D2 */ + SUNXI_FUNCTION(0x7, "csi1")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd1"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "pata"), /* ATAIOW */ + SUNXI_FUNCTION(0x4, "keypad"), /* OUT7 */ + SUNXI_FUNCTION(0x5, "mmc1"), /* D3 */ + SUNXI_FUNCTION(0x7, "csi1")), /* VSYNC */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm")), /* PWM1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc3")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* CS0 */ + SUNXI_FUNCTION(0x3, "uart5"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart5"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart6"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart6"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* CS1 */ + SUNXI_FUNCTION(0x3, "ps2"), /* SCK1 */ + SUNXI_FUNCTION(0x4, "timer4"), /* TCLKIN0 */ + SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ + SUNXI_FUNCTION(0x3, "ps2"), /* SDA1 */ + SUNXI_FUNCTION(0x4, "timer5"), /* TCLKIN1 */ + SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x3, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart2"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 29)), /* EINT29 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 30)), /* EINT30 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 31)), /* EINT31 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ps2"), /* SCK0 */ + SUNXI_FUNCTION(0x3, "uart7"), /* TX */ + SUNXI_FUNCTION(0x4, "hdmi")), /* HSCL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ps2"), /* SDA0 */ + SUNXI_FUNCTION(0x3, "uart7"), /* RX */ + SUNXI_FUNCTION(0x4, "hdmi")), /* HSDA */ +}; + +static const struct sunxi_desc_pin sun5i_a10s_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */ + SUNXI_FUNCTION(0x3, "ts0"), /* CLK */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */ + SUNXI_FUNCTION(0x3, "ts0"), /* ERR */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */ + SUNXI_FUNCTION(0x3, "ts0"), /* SYNC */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */ + SUNXI_FUNCTION(0x3, "ts0"), /* DLVD */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D0 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D1 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D2 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */ + SUNXI_FUNCTION(0x3, "ts0"), /* D3 */ + SUNXI_FUNCTION(0x5, "keypad")), /* IN7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */ + SUNXI_FUNCTION(0x3, "ts0"), /* D4 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DTR */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */ + SUNXI_FUNCTION(0x3, "ts0"), /* D5 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DSR */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */ + SUNXI_FUNCTION(0x3, "ts0"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DCD */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDC */ + SUNXI_FUNCTION(0x3, "ts0"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RING */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */ + SUNXI_FUNCTION(0x3, "uart1"), /* TX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */ + SUNXI_FUNCTION(0x3, "uart1"), /* RX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */ + SUNXI_FUNCTION(0x3, "uart1"), /* CTS */ + SUNXI_FUNCTION(0x4, "uart3"), /* TX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECRS */ + SUNXI_FUNCTION(0x3, "uart1"), /* RTS */ + SUNXI_FUNCTION(0x4, "uart3"), /* RX */ + SUNXI_FUNCTION(0x5, "keypad")), /* OUT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ECOL */ + SUNXI_FUNCTION(0x3, "uart2")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */ + SUNXI_FUNCTION(0x3, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 31)), /* EINT31 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */ + SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */ + SUNXI_FUNCTION_IRQ(0x6, 19)), /* EINT19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */ + SUNXI_FUNCTION_IRQ(0x6, 20)), /* EINT20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */ + SUNXI_FUNCTION_IRQ(0x6, 21)), /* EINT21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DO */ + SUNXI_FUNCTION_IRQ(0x6, 22)), /* EINT22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s"), /* DI */ + SUNXI_FUNCTION_IRQ(0x6, 23)), /* EINT23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ + SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ + SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */ + SUNXI_FUNCTION_IRQ(0x6, 25)), /* EINT25 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ + SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */ + SUNXI_FUNCTION_IRQ(0x6, 26)), /* EINT26 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ + SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */ + SUNXI_FUNCTION_IRQ(0x6, 27)), /* EINT27 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ + SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */ + SUNXI_FUNCTION_IRQ(0x6, 28)), /* EINT28 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 29)), /* EINT29 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 30)), /* EINT30 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWP */ + SUNXI_FUNCTION(0x4, "uart3")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE2 */ + SUNXI_FUNCTION(0x4, "uart3")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE3 */ + SUNXI_FUNCTION(0x3, "uart2"), /* TX */ + SUNXI_FUNCTION(0x4, "uart3")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */ + SUNXI_FUNCTION(0x3, "uart2"), /* RX */ + SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "uart2")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "uart2")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "uart2")), /* CTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "uart2")), /* RTS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "emac")), /* ECRS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "emac")), /* ECOL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXD3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXERR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ + SUNXI_FUNCTION(0x3, "emac")), /* ERXDV */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXD3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXEN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ + SUNXI_FUNCTION(0x3, "emac")), /* ETXERR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "emac")), /* EMDC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "emac")), /* EMDIO */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ + SUNXI_FUNCTION(0x3, "csi0"), /* PCK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ + SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ + SUNXI_FUNCTION(0x3, "csi0"), /* CK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ + SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ + SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ + SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart1")), /* RX */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* SIGN */ + SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x2, "gps"), /* MAG */ + SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION(0x4, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* DO */ + SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 5)), /* EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ + SUNXI_FUNCTION(0x5, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 6)), /* EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION(0x5, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 7)), /* EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION(0x5, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ + SUNXI_FUNCTION(0x3, "uart3"), /* PWM1 */ + SUNXI_FUNCTION(0x5, "uart2"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 13)), /* EINT13 */ +}; + +static const struct sunxi_desc_pin sun5i_a13_pins[] = { + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm"), + SUNXI_FUNCTION_IRQ(0x6, 16)), /* EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 17)), /* EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "ir0"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 18)), /* EINT18 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS1 */ + SUNXI_FUNCTION_IRQ(0x6, 24)), /* EINT24 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */ + SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D7 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* DE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x3, "csi0"), /* PCLK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CS0 */ + SUNXI_FUNCTION_IRQ(0x6, 14)), /* EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x3, "csi0"), /* MCLK */ + SUNXI_FUNCTION(0x4, "spi2"), /* CLK */ + SUNXI_FUNCTION_IRQ(0x6, 15)), /* EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ + SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ + SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ + SUNXI_FUNCTION(0x4, "uart1")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ + SUNXI_FUNCTION(0x4, "uart1")), /* RX */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION_IRQ(0x6, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION_IRQ(0x6, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION_IRQ(0x6, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION(0x4, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 4)), /* EINT4 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ(0x6, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ(0x6, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ(0x6, 11)), /* EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ(0x6, 12)), /* EINT12 */ +}; + +static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = { + .pins = sun4i_a10_pins, + .npins = ARRAY_SIZE(sun4i_a10_pins), +}; + +static const struct sunxi_pinctrl_desc sun5i_a10s_pinctrl_data = { + .pins = sun5i_a10s_pins, + .npins = ARRAY_SIZE(sun5i_a10s_pins), +}; + +static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = { + .pins = sun5i_a13_pins, + .npins = ARRAY_SIZE(sun5i_a13_pins), +}; + +#endif /* __PINCTRL_SUNXI_PINS_H */ diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index b7d8c890514..c47fd1e5450 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c @@ -13,10 +13,12 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/gpio.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinctrl.h> @@ -27,1319 +29,7 @@ #include "core.h" #include "pinctrl-sunxi.h" - -static const struct sunxi_desc_pin sun4i_a10_pins[] = { - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */ - SUNXI_FUNCTION(0x3, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x4, "uart2")), /* RTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */ - SUNXI_FUNCTION(0x3, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart2")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */ - SUNXI_FUNCTION(0x3, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x4, "uart2")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */ - SUNXI_FUNCTION(0x3, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x4, "uart2")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */ - SUNXI_FUNCTION(0x3, "spi1")), /* CS1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */ - SUNXI_FUNCTION(0x3, "spi3")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */ - SUNXI_FUNCTION(0x3, "spi3")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */ - SUNXI_FUNCTION(0x3, "spi3")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */ - SUNXI_FUNCTION(0x3, "spi3")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */ - SUNXI_FUNCTION(0x3, "spi3")), /* CS1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* EMDC */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */ - SUNXI_FUNCTION(0x3, "uart6"), /* TX */ - SUNXI_FUNCTION(0x4, "uart1")), /* RTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */ - SUNXI_FUNCTION(0x3, "uart6"), /* RX */ - SUNXI_FUNCTION(0x4, "uart1")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */ - SUNXI_FUNCTION(0x3, "uart7"), /* TX */ - SUNXI_FUNCTION(0x4, "uart1")), /* DTR */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ECRS */ - SUNXI_FUNCTION(0x3, "uart7"), /* RX */ - SUNXI_FUNCTION(0x4, "uart1")), /* DSR */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ECOL */ - SUNXI_FUNCTION(0x3, "can"), /* TX */ - SUNXI_FUNCTION(0x4, "uart1")), /* DCD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */ - SUNXI_FUNCTION(0x3, "can"), /* RX */ - SUNXI_FUNCTION(0x4, "uart1")), /* RING */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm")), /* PWM0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */ - SUNXI_FUNCTION(0x3, "ac97")), /* MCLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */ - SUNXI_FUNCTION(0x3, "ac97")), /* BCLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */ - SUNXI_FUNCTION(0x3, "ac97")), /* SYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* DO0 */ - SUNXI_FUNCTION(0x3, "ac97")), /* DO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s")), /* DO1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s")), /* DO2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s")), /* DO3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2s"), /* DI */ - SUNXI_FUNCTION(0x3, "ac97")), /* DI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2")), /* CS1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ - SUNXI_FUNCTION(0x3, "jtag")), /* MS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ - SUNXI_FUNCTION(0x3, "jtag")), /* CK0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ - SUNXI_FUNCTION(0x3, "jtag")), /* DO0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ - SUNXI_FUNCTION(0x3, "jtag")), /* DI0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "uart0"), /* TX */ - SUNXI_FUNCTION(0x3, "ir1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "uart0"), /* RX */ - SUNXI_FUNCTION(0x3, "ir1")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ - SUNXI_FUNCTION(0x3, "spi0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NRE# */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NDQ4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NDQ5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NDQ6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NDQ7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NWP */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */ - SUNXI_FUNCTION(0x3, "spi2")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE5 */ - SUNXI_FUNCTION(0x3, "spi2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE6 */ - SUNXI_FUNCTION(0x3, "spi2")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE7 */ - SUNXI_FUNCTION(0x3, "spi2")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NDQS */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */ - SUNXI_FUNCTION(0x3, "lvds0")), /* VM3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VP0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VN0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VP1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VN1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VP2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VN2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VPC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VP3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ - SUNXI_FUNCTION(0x3, "lvds1")), /* VN3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ - SUNXI_FUNCTION(0x3, "csi1")), /* MCLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ - SUNXI_FUNCTION(0x3, "sim")), /* VPPEN */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ - SUNXI_FUNCTION(0x3, "sim")), /* VPPPP */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ - SUNXI_FUNCTION(0x3, "sim")), /* DET */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ - SUNXI_FUNCTION(0x3, "sim")), /* VCCEN */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ - SUNXI_FUNCTION(0x3, "sim")), /* RST */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ - SUNXI_FUNCTION(0x3, "sim")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ - SUNXI_FUNCTION(0x3, "sim")), /* SDA */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* CLK */ - SUNXI_FUNCTION(0x3, "csi0")), /* PCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* ERR */ - SUNXI_FUNCTION(0x3, "csi0")), /* CK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */ - SUNXI_FUNCTION(0x3, "csi0")), /* HSYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */ - SUNXI_FUNCTION(0x3, "csi0")), /* VSYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D0 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D1 */ - SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ - SUNXI_FUNCTION(0x4, "sim")), /* VPPEN */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D2 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D3 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D4 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D5 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D6 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts0"), /* D7 */ - SUNXI_FUNCTION(0x3, "csi0")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ - SUNXI_FUNCTION(0x4, "jtag")), /* MSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ - SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart0")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ - SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ - SUNXI_FUNCTION(0x4, "uart0")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ - SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* CLK */ - SUNXI_FUNCTION(0x3, "csi1"), /* PCK */ - SUNXI_FUNCTION(0x4, "mmc1")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* ERR */ - SUNXI_FUNCTION(0x3, "csi1"), /* CK */ - SUNXI_FUNCTION(0x4, "mmc1")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* SYNC */ - SUNXI_FUNCTION(0x3, "csi1"), /* HSYNC */ - SUNXI_FUNCTION(0x4, "mmc1")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* DVLD */ - SUNXI_FUNCTION(0x3, "csi1"), /* VSYNC */ - SUNXI_FUNCTION(0x4, "mmc1")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D0 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D0 */ - SUNXI_FUNCTION(0x4, "mmc1"), /* D2 */ - SUNXI_FUNCTION(0x5, "csi0")), /* D8 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D1 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D1 */ - SUNXI_FUNCTION(0x4, "mmc1"), /* D3 */ - SUNXI_FUNCTION(0x5, "csi0")), /* D9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D2 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D2 */ - SUNXI_FUNCTION(0x4, "uart3"), /* TX */ - SUNXI_FUNCTION(0x5, "csi0")), /* D10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D3 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D3 */ - SUNXI_FUNCTION(0x4, "uart3"), /* RX */ - SUNXI_FUNCTION(0x5, "csi0")), /* D11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D4 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D4 */ - SUNXI_FUNCTION(0x4, "uart3"), /* RTS */ - SUNXI_FUNCTION(0x5, "csi0")), /* D12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D5 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D5 */ - SUNXI_FUNCTION(0x4, "uart3"), /* CTS */ - SUNXI_FUNCTION(0x5, "csi0")), /* D13 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D6 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart4"), /* TX */ - SUNXI_FUNCTION(0x5, "csi0")), /* D14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ts1"), /* D7 */ - SUNXI_FUNCTION(0x3, "csi1"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart4"), /* RX */ - SUNXI_FUNCTION(0x5, "csi0")), /* D15 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D0 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAA0 */ - SUNXI_FUNCTION(0x4, "uart3"), /* TX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D1 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAA1 */ - SUNXI_FUNCTION(0x4, "uart3"), /* RX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D2 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAA2 */ - SUNXI_FUNCTION(0x4, "uart3"), /* RTS */ - SUNXI_FUNCTION(0x7, "csi1")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D3 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAIRQ */ - SUNXI_FUNCTION(0x4, "uart3"), /* CTS */ - SUNXI_FUNCTION(0x7, "csi1")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D4 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD0 */ - SUNXI_FUNCTION(0x4, "uart4"), /* TX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D5 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD1 */ - SUNXI_FUNCTION(0x4, "uart4"), /* RX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D6 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD2 */ - SUNXI_FUNCTION(0x4, "uart5"), /* TX */ - SUNXI_FUNCTION(0x5, "ms"), /* BS */ - SUNXI_FUNCTION(0x7, "csi1")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D7 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD3 */ - SUNXI_FUNCTION(0x4, "uart5"), /* RX */ - SUNXI_FUNCTION(0x5, "ms"), /* CLK */ - SUNXI_FUNCTION(0x7, "csi1")), /* D7 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D8 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD4 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN0 */ - SUNXI_FUNCTION(0x5, "ms"), /* D0 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D8 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D9 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD5 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN1 */ - SUNXI_FUNCTION(0x5, "ms"), /* D1 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D9 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D10 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD6 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN2 */ - SUNXI_FUNCTION(0x5, "ms"), /* D2 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D11 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD7 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN3 */ - SUNXI_FUNCTION(0x5, "ms"), /* D3 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D12 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD8 */ - SUNXI_FUNCTION(0x4, "ps2"), /* SCK1 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D13 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD9 */ - SUNXI_FUNCTION(0x4, "ps2"), /* SDA1 */ - SUNXI_FUNCTION(0x5, "sim"), /* RST */ - SUNXI_FUNCTION(0x7, "csi1")), /* D13 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D14 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD10 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN4 */ - SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */ - SUNXI_FUNCTION(0x7, "csi1")), /* D14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D15 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD11 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN5 */ - SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */ - SUNXI_FUNCTION(0x7, "csi1")), /* D15 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D16 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD12 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN6 */ - SUNXI_FUNCTION(0x7, "csi1")), /* D16 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D17 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD13 */ - SUNXI_FUNCTION(0x4, "keypad"), /* IN7 */ - SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */ - SUNXI_FUNCTION(0x7, "csi1")), /* D17 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D18 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD14 */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT0 */ - SUNXI_FUNCTION(0x5, "sim"), /* SCK */ - SUNXI_FUNCTION(0x7, "csi1")), /* D18 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D19 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAD15 */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT1 */ - SUNXI_FUNCTION(0x5, "sim"), /* SDA */ - SUNXI_FUNCTION(0x7, "csi1")), /* D19 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D20 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAOE */ - SUNXI_FUNCTION(0x4, "can"), /* TX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D20 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D21 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATADREQ */ - SUNXI_FUNCTION(0x4, "can"), /* RX */ - SUNXI_FUNCTION(0x7, "csi1")), /* D21 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D22 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATADACK */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT2 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* CMD */ - SUNXI_FUNCTION(0x7, "csi1")), /* D22 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* D23 */ - SUNXI_FUNCTION(0x3, "pata"), /* ATACS0 */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT3 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* CLK */ - SUNXI_FUNCTION(0x7, "csi1")), /* D23 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* CLK */ - SUNXI_FUNCTION(0x3, "pata"), /* ATACS1 */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT4 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* D0 */ - SUNXI_FUNCTION(0x7, "csi1")), /* PCLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* DE */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAIORDY */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT5 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* D1 */ - SUNXI_FUNCTION(0x7, "csi1")), /* FIELD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* HSYNC */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAIOR */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT6 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* D2 */ - SUNXI_FUNCTION(0x7, "csi1")), /* HSYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd1"), /* VSYNC */ - SUNXI_FUNCTION(0x3, "pata"), /* ATAIOW */ - SUNXI_FUNCTION(0x4, "keypad"), /* OUT7 */ - SUNXI_FUNCTION(0x5, "mmc1"), /* D3 */ - SUNXI_FUNCTION(0x7, "csi1")), /* VSYNC */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm")), /* PWM1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc3")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi0"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart5")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi0"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart5")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart6")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi0"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart6")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi0"), /* CS1 */ - SUNXI_FUNCTION(0x3, "ps2"), /* SCK1 */ - SUNXI_FUNCTION(0x4, "timer4")), /* TCLKIN0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ - SUNXI_FUNCTION(0x3, "ps2"), /* SDA1 */ - SUNXI_FUNCTION(0x4, "timer5")), /* TCLKIN1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart2")), /* RTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart2")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart2")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart2")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ps2"), /* SCK0 */ - SUNXI_FUNCTION(0x3, "uart7"), /* TX */ - SUNXI_FUNCTION(0x4, "hdmi")), /* HSCL */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ps2"), /* SDA0 */ - SUNXI_FUNCTION(0x3, "uart7"), /* RX */ - SUNXI_FUNCTION(0x4, "hdmi")), /* HSDA */ -}; - -static const struct sunxi_desc_pin sun5i_a13_pins[] = { - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "pwm")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "ir0")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi2")), /* CS1 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ - SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ - SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ - SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0")), /* NRE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ - SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */ - SUNXI_FUNCTION(0x4, "uart3")), /* RTS */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D4 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D5 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D6 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D7 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D10 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* DE */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* PCLK */ - SUNXI_FUNCTION(0x4, "spi2")), /* CS0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* MCLK */ - SUNXI_FUNCTION(0x4, "spi2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */ - SUNXI_FUNCTION(0x4, "spi2")), /* MISO */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D0 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D1 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D2 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D3 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D4 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D5 */ - SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D6 */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "csi0"), /* D7 */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */ - /* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out")), - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ - SUNXI_FUNCTION(0x4, "uart1")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ - SUNXI_FUNCTION(0x4, "uart1")), /* RX */ -/* Hole */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ - SUNXI_FUNCTION(0x3, "uart3")), /* TX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ - SUNXI_FUNCTION(0x3, "uart3")), /* RX */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ - SUNXI_FUNCTION(0x3, "uart3")), /* CTS */ - SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12, - SUNXI_FUNCTION(0x0, "gpio_in"), - SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ - SUNXI_FUNCTION(0x3, "uart3")), /* RTS */ -}; - -static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = { - .pins = sun4i_a10_pins, - .npins = ARRAY_SIZE(sun4i_a10_pins), -}; - -static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = { - .pins = sun5i_a13_pins, - .npins = ARRAY_SIZE(sun5i_a13_pins), -}; +#include "pinctrl-sunxi-pins.h" static struct sunxi_pinctrl_group * sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group) @@ -1399,6 +89,31 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, return NULL; } +static struct sunxi_desc_function * +sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl, + const u16 pin_num, + const char *func_name) +{ + int i; + + for (i = 0; i < pctl->desc->npins; i++) { + const struct sunxi_desc_pin *pin = pctl->desc->pins + i; + + if (pin->pin.number == pin_num) { + struct sunxi_desc_function *func = pin->functions; + + while (func->name) { + if (!strcmp(func->name, func_name)) + return func; + + func++; + } + } + } + + return NULL; +} + static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); @@ -1680,37 +395,20 @@ sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_desc_function *desc; - char pin_name[SUNXI_PIN_NAME_MAX_LEN]; const char *func; - u8 bank, pin; - int ret; - - bank = (offset) / PINS_PER_BANK; - pin = (offset) % PINS_PER_BANK; - - ret = sprintf(pin_name, "P%c%d", 'A' + bank, pin); - if (!ret) - goto error; if (input) func = "gpio_in"; else func = "gpio_out"; - desc = sunxi_pinctrl_desc_find_function_by_name(pctl, - pin_name, - func); - if (!desc) { - ret = -EINVAL; - goto error; - } + desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func); + if (!desc) + return -EINVAL; sunxi_pmx_set(pctldev, offset, desc->muxval); - ret = 0; - -error: - return ret; + return 0; } static const struct pinmux_ops sunxi_pmx_ops = { @@ -1788,6 +486,26 @@ static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, return pin; } +static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); + struct sunxi_desc_function *desc; + + if (offset > chip->ngpio) + return -ENXIO; + + desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq"); + if (!desc) + return -EINVAL; + + pctl->irq_array[desc->irqnum] = offset; + + dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", + chip->label, offset + chip->base, desc->irqnum); + + return irq_find_mapping(pctl->domain, desc->irqnum); +} + static struct gpio_chip sunxi_pinctrl_gpio_chip = { .owner = THIS_MODULE, .request = sunxi_pinctrl_gpio_request, @@ -1797,12 +515,121 @@ static struct gpio_chip sunxi_pinctrl_gpio_chip = { .get = sunxi_pinctrl_gpio_get, .set = sunxi_pinctrl_gpio_set, .of_xlate = sunxi_pinctrl_gpio_of_xlate, + .to_irq = sunxi_pinctrl_gpio_to_irq, .of_gpio_n_cells = 3, .can_sleep = 0, }; +static int sunxi_pinctrl_irq_set_type(struct irq_data *d, + unsigned int type) +{ + struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); + u32 reg = sunxi_irq_cfg_reg(d->hwirq); + u8 index = sunxi_irq_cfg_offset(d->hwirq); + u8 mode; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + mode = IRQ_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + mode = IRQ_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + mode = IRQ_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + mode = IRQ_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + mode = IRQ_LEVEL_LOW; + break; + default: + return -EINVAL; + } + + writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg); + + return 0; +} + +static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d) +{ + struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); + u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq); + u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq); + u32 status_reg = sunxi_irq_status_reg(d->hwirq); + u8 status_idx = sunxi_irq_status_offset(d->hwirq); + u32 val; + + /* Mask the IRQ */ + val = readl(pctl->membase + ctrl_reg); + writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg); + + /* Clear the IRQ */ + writel(1 << status_idx, pctl->membase + status_reg); +} + +static void sunxi_pinctrl_irq_mask(struct irq_data *d) +{ + struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); + u32 reg = sunxi_irq_ctrl_reg(d->hwirq); + u8 idx = sunxi_irq_ctrl_offset(d->hwirq); + u32 val; + + /* Mask the IRQ */ + val = readl(pctl->membase + reg); + writel(val & ~(1 << idx), pctl->membase + reg); +} + +static void sunxi_pinctrl_irq_unmask(struct irq_data *d) +{ + struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); + struct sunxi_desc_function *func; + u32 reg = sunxi_irq_ctrl_reg(d->hwirq); + u8 idx = sunxi_irq_ctrl_offset(d->hwirq); + u32 val; + + func = sunxi_pinctrl_desc_find_function_by_pin(pctl, + pctl->irq_array[d->hwirq], + "irq"); + + /* Change muxing to INT mode */ + sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); + + /* Unmask the IRQ */ + val = readl(pctl->membase + reg); + writel(val | (1 << idx), pctl->membase + reg); +} + +static struct irq_chip sunxi_pinctrl_irq_chip = { + .irq_mask = sunxi_pinctrl_irq_mask, + .irq_mask_ack = sunxi_pinctrl_irq_mask_ack, + .irq_unmask = sunxi_pinctrl_irq_unmask, + .irq_set_type = sunxi_pinctrl_irq_set_type, +}; + +static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); + const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG); + + /* Clear all interrupts */ + writel(reg, pctl->membase + IRQ_STATUS_REG); + + if (reg) { + int irqoffset; + + for_each_set_bit(irqoffset, ®, SUNXI_IRQ_NUMBER) { + int pin_irq = irq_find_mapping(pctl->domain, irqoffset); + generic_handle_irq(pin_irq); + } + } +} + static struct of_device_id sunxi_pinctrl_match[] = { { .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data }, + { .compatible = "allwinner,sun5i-a10s-pinctrl", .data = (void *)&sun5i_a10s_pinctrl_data }, { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data }, {} }; @@ -1997,6 +824,31 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) clk_prepare_enable(clk); + pctl->irq = irq_of_parse_and_map(node, 0); + if (!pctl->irq) { + ret = -EINVAL; + goto gpiochip_error; + } + + pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER, + &irq_domain_simple_ops, NULL); + if (!pctl->domain) { + dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); + ret = -ENOMEM; + goto gpiochip_error; + } + + for (i = 0; i < SUNXI_IRQ_NUMBER; i++) { + int irqno = irq_create_mapping(pctl->domain, i); + + irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip, + handle_simple_irq); + irq_set_chip_data(irqno, pctl); + }; + + irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler); + irq_set_handler_data(pctl->irq, pctl); + dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); return 0; diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h index e921621059c..d68047d8f69 100644 --- a/drivers/pinctrl/pinctrl-sunxi.h +++ b/drivers/pinctrl/pinctrl-sunxi.h @@ -344,9 +344,31 @@ #define PULL_PINS_BITS 2 #define PULL_PINS_MASK 0x03 +#define SUNXI_IRQ_NUMBER 32 + +#define IRQ_CFG_REG 0x200 +#define IRQ_CFG_IRQ_PER_REG 8 +#define IRQ_CFG_IRQ_BITS 4 +#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1) +#define IRQ_CTRL_REG 0x210 +#define IRQ_CTRL_IRQ_PER_REG 32 +#define IRQ_CTRL_IRQ_BITS 1 +#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1) +#define IRQ_STATUS_REG 0x214 +#define IRQ_STATUS_IRQ_PER_REG 32 +#define IRQ_STATUS_IRQ_BITS 1 +#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1) + +#define IRQ_EDGE_RISING 0x00 +#define IRQ_EDGE_FALLING 0x01 +#define IRQ_LEVEL_HIGH 0x02 +#define IRQ_LEVEL_LOW 0x03 +#define IRQ_EDGE_BOTH 0x04 + struct sunxi_desc_function { const char *name; u8 muxval; + u8 irqnum; }; struct sunxi_desc_pin { @@ -378,10 +400,13 @@ struct sunxi_pinctrl { struct gpio_chip *chip; struct sunxi_pinctrl_desc *desc; struct device *dev; + struct irq_domain *domain; struct sunxi_pinctrl_function *functions; unsigned nfunctions; struct sunxi_pinctrl_group *groups; unsigned ngroups; + int irq; + int irq_array[SUNXI_IRQ_NUMBER]; struct pinctrl_dev *pctl_dev; }; @@ -398,6 +423,13 @@ struct sunxi_pinctrl { .muxval = _val, \ } +#define SUNXI_FUNCTION_IRQ(_val, _irq) \ + { \ + .name = "irq", \ + .muxval = _val, \ + .irqnum = _irq, \ + } + /* * The sunXi PIO registers are organized as is: * 0x00 - 0x0c Muxing values. @@ -475,4 +507,40 @@ static inline u32 sunxi_pull_offset(u16 pin) return pin_num * PULL_PINS_BITS; } +static inline u32 sunxi_irq_cfg_reg(u16 irq) +{ + u8 reg = irq / IRQ_CFG_IRQ_PER_REG; + return reg + IRQ_CFG_REG; +} + +static inline u32 sunxi_irq_cfg_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG; + return irq_num * IRQ_CFG_IRQ_BITS; +} + +static inline u32 sunxi_irq_ctrl_reg(u16 irq) +{ + u8 reg = irq / IRQ_CTRL_IRQ_PER_REG; + return reg + IRQ_CTRL_REG; +} + +static inline u32 sunxi_irq_ctrl_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG; + return irq_num * IRQ_CTRL_IRQ_BITS; +} + +static inline u32 sunxi_irq_status_reg(u16 irq) +{ + u8 reg = irq / IRQ_STATUS_IRQ_PER_REG; + return reg + IRQ_STATUS_REG; +} + +static inline u32 sunxi_irq_status_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG; + return irq_num * IRQ_STATUS_IRQ_BITS; +} + #endif /* __PINCTRL_SUNXI_H */ diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c new file mode 100644 index 00000000000..d4f12cc556b --- /dev/null +++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c @@ -0,0 +1,1024 @@ +/* + * Pinctrl driver for the Toumaz Xenif TZ1090 PowerDown Controller pins + * + * Copyright (c) 2013, Imagination Technologies Ltd. + * + * Derived from Tegra code: + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * + * Derived from code: + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010 NVIDIA Corporation + * Copyright (C) 2009-2011 ST-Ericsson AB + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/slab.h> + +/* + * The registers may be shared with other threads/cores, so we need to use the + * metag global lock2 for atomicity. + */ +#include <asm/global_lock.h> + +#include "core.h" +#include "pinconf.h" + +/* Register offsets from bank base address */ +#define REG_GPIO_CONTROL0 0x00 +#define REG_GPIO_CONTROL2 0x08 + +/* Register field information */ +#define REG_GPIO_CONTROL2_PU_PD_S 16 +#define REG_GPIO_CONTROL2_PDC_POS_S 4 +#define REG_GPIO_CONTROL2_PDC_DR_S 2 +#define REG_GPIO_CONTROL2_PDC_SR_S 1 +#define REG_GPIO_CONTROL2_PDC_SCHMITT_S 0 + +/* PU_PD field values */ +#define REG_PU_PD_TRISTATE 0 +#define REG_PU_PD_UP 1 +#define REG_PU_PD_DOWN 2 +#define REG_PU_PD_REPEATER 3 + +/* DR field values */ +#define REG_DR_2mA 0 +#define REG_DR_4mA 1 +#define REG_DR_8mA 2 +#define REG_DR_12mA 3 + +/** + * struct tz1090_pdc_function - TZ1090 PDC pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct tz1090_pdc_function { + const char *name; + const char * const *groups; + unsigned int ngroups; +}; + +/** + * struct tz1090_pdc_pingroup - TZ1090 PDC pin group + * @name: Name of pin group. + * @pins: Array of pin numbers in this pin group. + * @npins: Number of pins in this pin group. + * @func: Function enabled by the mux. + * @reg: Mux register offset. + * @bit: Mux register bit. + * @drv: Drive control supported, otherwise it's a mux. + * This means Schmitt, Slew, and Drive strength. + * + * A representation of a group of pins (possibly just one pin) in the TZ1090 + * PDC pin controller. Each group allows some parameter or parameters to be + * configured. The most common is mux function selection. + */ +struct tz1090_pdc_pingroup { + const char *name; + const unsigned int *pins; + unsigned int npins; + int func; + u16 reg; + u8 bit; + bool drv; +}; + +/* + * All PDC pins can be GPIOs. Define these first to match how the GPIO driver + * names/numbers its pins. + */ + +enum tz1090_pdc_pin { + TZ1090_PDC_PIN_GPIO0, + TZ1090_PDC_PIN_GPIO1, + TZ1090_PDC_PIN_SYS_WAKE0, + TZ1090_PDC_PIN_SYS_WAKE1, + TZ1090_PDC_PIN_SYS_WAKE2, + TZ1090_PDC_PIN_IR_DATA, + TZ1090_PDC_PIN_EXT_POWER, +}; + +/* Pin names */ + +static const struct pinctrl_pin_desc tz1090_pdc_pins[] = { + /* PDC GPIOs */ + PINCTRL_PIN(TZ1090_PDC_PIN_GPIO0, "gpio0"), + PINCTRL_PIN(TZ1090_PDC_PIN_GPIO1, "gpio1"), + PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE0, "sys_wake0"), + PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE1, "sys_wake1"), + PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE2, "sys_wake2"), + PINCTRL_PIN(TZ1090_PDC_PIN_IR_DATA, "ir_data"), + PINCTRL_PIN(TZ1090_PDC_PIN_EXT_POWER, "ext_power"), +}; + +/* Pin group pins */ + +static const unsigned int gpio0_pins[] = { + TZ1090_PDC_PIN_GPIO0, +}; + +static const unsigned int gpio1_pins[] = { + TZ1090_PDC_PIN_GPIO1, +}; + +static const unsigned int pdc_pins[] = { + TZ1090_PDC_PIN_GPIO0, + TZ1090_PDC_PIN_GPIO1, + TZ1090_PDC_PIN_SYS_WAKE0, + TZ1090_PDC_PIN_SYS_WAKE1, + TZ1090_PDC_PIN_SYS_WAKE2, + TZ1090_PDC_PIN_IR_DATA, + TZ1090_PDC_PIN_EXT_POWER, +}; + +/* Mux functions */ + +enum tz1090_pdc_mux { + /* PDC_GPIO0 mux */ + TZ1090_PDC_MUX_IR_MOD_STABLE_OUT, + /* PDC_GPIO1 mux */ + TZ1090_PDC_MUX_IR_MOD_POWER_OUT, +}; + +/* Pin groups a function can be muxed to */ + +static const char * const gpio0_groups[] = { + "gpio0", +}; + +static const char * const gpio1_groups[] = { + "gpio1", +}; + +#define FUNCTION(mux, fname, group) \ + [(TZ1090_PDC_MUX_ ## mux)] = { \ + .name = #fname, \ + .groups = group##_groups, \ + .ngroups = ARRAY_SIZE(group##_groups), \ + } + +/* Must correlate with enum tz1090_pdc_mux */ +static const struct tz1090_pdc_function tz1090_pdc_functions[] = { + /* MUX fn pingroups */ + FUNCTION(IR_MOD_STABLE_OUT, ir_mod_stable_out, gpio0), + FUNCTION(IR_MOD_POWER_OUT, ir_mod_power_out, gpio1), +}; + +/** + * MUX_PG() - Initialise a pin group with mux control + * @pg_name: Pin group name (stringified, _pins appended to get pins array) + * @f0: Function 0 (TZ1090_PDC_MUX_ is prepended) + * @mux_r: Mux register (REG_PINCTRL_ is prepended) + * @mux_b: Bit number in register of mux field + */ +#define MUX_PG(pg_name, f0, mux_r, mux_b) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .func = TZ1090_PDC_MUX_ ## f0, \ + .reg = (REG_ ## mux_r), \ + .bit = (mux_b), \ + } + +/** + * DRV_PG() - Initialise a pin group with drive control + * @pg_name: Pin group name (stringified, _pins appended to get pins array) + */ +#define DRV_PG(pg_name) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .drv = true, \ + } + +static const struct tz1090_pdc_pingroup tz1090_pdc_groups[] = { + /* Muxing pin groups */ + /* pg_name, f0, mux register, mux bit */ + MUX_PG(gpio0, IR_MOD_STABLE_OUT, GPIO_CONTROL0, 7), + MUX_PG(gpio1, IR_MOD_POWER_OUT, GPIO_CONTROL0, 6), + + /* Drive pin groups */ + /* pg_name */ + DRV_PG(pdc), +}; + +/** + * struct tz1090_pdc_pmx - Private pinctrl data + * @dev: Platform device + * @pctl: Pin control device + * @regs: Register region + * @lock: Lock protecting coherency of mux_en and gpio_en + * @mux_en: Muxes that have been enabled + * @gpio_en: Muxable GPIOs that have been enabled + */ +struct tz1090_pdc_pmx { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *regs; + spinlock_t lock; + u32 mux_en; + u32 gpio_en; +}; + +static inline u32 pmx_read(struct tz1090_pdc_pmx *pmx, u32 reg) +{ + return ioread32(pmx->regs + reg); +} + +static inline void pmx_write(struct tz1090_pdc_pmx *pmx, u32 val, u32 reg) +{ + iowrite32(val, pmx->regs + reg); +} + +/* + * Pin control operations + */ + +static int tz1090_pdc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(tz1090_pdc_groups); +} + +static const char *tz1090_pdc_pinctrl_get_group_name(struct pinctrl_dev *pctl, + unsigned int group) +{ + return tz1090_pdc_groups[group].name; +} + +static int tz1090_pdc_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + *pins = tz1090_pdc_groups[group].pins; + *num_pins = tz1090_pdc_groups[group].npins; + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void tz1090_pdc_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, " %s", dev_name(pctldev->dev)); +} +#endif + +static int reserve_map(struct device *dev, struct pinctrl_map **map, + unsigned int *reserved_maps, unsigned int *num_maps, + unsigned int reserve) +{ + unsigned int old_num = *reserved_maps; + unsigned int new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) { + dev_err(dev, "krealloc(map) failed\n"); + return -ENOMEM; + } + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + + return 0; +} + +static int add_map_mux(struct pinctrl_map **map, unsigned int *reserved_maps, + unsigned int *num_maps, const char *group, + const char *function) +{ + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +/** + * get_group_selector() - returns the group selector for a group + * @pin_group: the pin group to look up + * + * This is the same as pinctrl_get_group_selector except it doesn't produce an + * error message if the group isn't found or debug messages. + */ +static int get_group_selector(const char *pin_group) +{ + unsigned int group; + + for (group = 0; group < ARRAY_SIZE(tz1090_pdc_groups); ++group) + if (!strcmp(tz1090_pdc_groups[group].name, pin_group)) + return group; + + return -EINVAL; +} + +static int add_map_configs(struct device *dev, + struct pinctrl_map **map, + unsigned int *reserved_maps, unsigned int *num_maps, + const char *group, unsigned long *configs, + unsigned int num_configs) +{ + unsigned long *dup_configs; + enum pinctrl_map_type type; + + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) { + dev_err(dev, "kmemdup(configs) failed\n"); + return -ENOMEM; + } + + /* + * We support both pins and pin groups, but we need to figure out which + * one we have. + */ + if (get_group_selector(group) >= 0) + type = PIN_MAP_TYPE_CONFIGS_GROUP; + else + type = PIN_MAP_TYPE_CONFIGS_PIN; + (*map)[*num_maps].type = type; + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static void tz1090_pdc_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned int num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + + kfree(map); +} + +static int tz1090_pdc_pinctrl_dt_subnode_to_map(struct device *dev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps) +{ + int ret; + const char *function; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + unsigned int reserve; + struct property *prop; + const char *group; + + ret = of_property_read_string(np, "tz1090,function", &function); + if (ret < 0) { + /* EINVAL=missing, which is fine since it's optional */ + if (ret != -EINVAL) + dev_err(dev, + "could not parse property function\n"); + function = NULL; + } + + ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + if (ret) + return ret; + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "tz1090,pins"); + if (ret < 0) { + dev_err(dev, "could not parse property pins\n"); + goto exit; + } + reserve *= ret; + + ret = reserve_map(dev, map, reserved_maps, num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "tz1090,pins", prop, group) { + if (function) { + ret = add_map_mux(map, reserved_maps, num_maps, + group, function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = add_map_configs(dev, map, reserved_maps, + num_maps, group, configs, + num_configs); + if (ret < 0) + goto exit; + } + } + + ret = 0; + +exit: + kfree(configs); + return ret; +} + +static int tz1090_pdc_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + unsigned int reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = tz1090_pdc_pinctrl_dt_subnode_to_map(pctldev->dev, np, + map, &reserved_maps, + num_maps); + if (ret < 0) { + tz1090_pdc_pinctrl_dt_free_map(pctldev, *map, + *num_maps); + return ret; + } + } + + return 0; +} + +static struct pinctrl_ops tz1090_pdc_pinctrl_ops = { + .get_groups_count = tz1090_pdc_pinctrl_get_groups_count, + .get_group_name = tz1090_pdc_pinctrl_get_group_name, + .get_group_pins = tz1090_pdc_pinctrl_get_group_pins, +#ifdef CONFIG_DEBUG_FS + .pin_dbg_show = tz1090_pdc_pinctrl_pin_dbg_show, +#endif + .dt_node_to_map = tz1090_pdc_pinctrl_dt_node_to_map, + .dt_free_map = tz1090_pdc_pinctrl_dt_free_map, +}; + +/* + * Pin mux operations + */ + +static int tz1090_pdc_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(tz1090_pdc_functions); +} + +static const char *tz1090_pdc_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + return tz1090_pdc_functions[function].name; +} + +static int tz1090_pdc_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = tz1090_pdc_functions[function].groups; + *num_groups = tz1090_pdc_functions[function].ngroups; + + return 0; +} + +/** + * tz1090_pdc_pinctrl_mux() - update mux bit + * @pmx: Pinmux data + * @grp: Pin mux group + */ +static void tz1090_pdc_pinctrl_mux(struct tz1090_pdc_pmx *pmx, + const struct tz1090_pdc_pingroup *grp) +{ + u32 reg, select; + unsigned int pin_shift = grp->pins[0]; + unsigned long flags; + + /* select = mux && !gpio */ + select = ((pmx->mux_en & ~pmx->gpio_en) >> pin_shift) & 1; + + /* set up the mux */ + __global_lock2(flags); + reg = pmx_read(pmx, grp->reg); + reg &= ~BIT(grp->bit); + reg |= select << grp->bit; + pmx_write(pmx, reg, grp->reg); + __global_unlock2(flags); +} + +static int tz1090_pdc_pinctrl_enable(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *grp = &tz1090_pdc_groups[group]; + + dev_dbg(pctldev->dev, "%s(func=%u (%s), group=%u (%s))\n", + __func__, + function, tz1090_pdc_functions[function].name, + group, tz1090_pdc_groups[group].name); + + /* is it even a mux? */ + if (grp->drv) + return -EINVAL; + + /* does this group even control the function? */ + if (function != grp->func) + return -EINVAL; + + /* record the pin being muxed and update mux bit */ + spin_lock(&pmx->lock); + pmx->mux_en |= BIT(grp->pins[0]); + tz1090_pdc_pinctrl_mux(pmx, grp); + spin_unlock(&pmx->lock); + return 0; +} + +static void tz1090_pdc_pinctrl_disable(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *grp = &tz1090_pdc_groups[group]; + + dev_dbg(pctldev->dev, "%s(func=%u (%s), group=%u (%s))\n", + __func__, + function, tz1090_pdc_functions[function].name, + group, tz1090_pdc_groups[group].name); + + /* is it even a mux? */ + if (grp->drv) + return; + + /* does this group even control the function? */ + if (function != grp->func) + return; + + /* record the pin being unmuxed and update mux bit */ + spin_lock(&pmx->lock); + pmx->mux_en &= ~BIT(grp->pins[0]); + tz1090_pdc_pinctrl_mux(pmx, grp); + spin_unlock(&pmx->lock); +} + +static const struct tz1090_pdc_pingroup *find_mux_group( + struct tz1090_pdc_pmx *pmx, + unsigned int pin) +{ + const struct tz1090_pdc_pingroup *grp; + unsigned int group; + + grp = tz1090_pdc_groups; + for (group = 0; group < ARRAY_SIZE(tz1090_pdc_groups); ++group, ++grp) { + /* only match muxes */ + if (grp->drv) + continue; + + /* with a matching pin */ + if (grp->pins[0] == pin) + return grp; + } + + return NULL; +} + +static int tz1090_pdc_pinctrl_gpio_request_enable( + struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *grp = find_mux_group(pmx, pin); + + if (grp) { + /* record the pin in GPIO use and update mux bit */ + spin_lock(&pmx->lock); + pmx->gpio_en |= BIT(pin); + tz1090_pdc_pinctrl_mux(pmx, grp); + spin_unlock(&pmx->lock); + } + return 0; +} + +static void tz1090_pdc_pinctrl_gpio_disable_free( + struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *grp = find_mux_group(pmx, pin); + + if (grp) { + /* record the pin not in GPIO use and update mux bit */ + spin_lock(&pmx->lock); + pmx->gpio_en &= ~BIT(pin); + tz1090_pdc_pinctrl_mux(pmx, grp); + spin_unlock(&pmx->lock); + } +} + +static struct pinmux_ops tz1090_pdc_pinmux_ops = { + .get_functions_count = tz1090_pdc_pinctrl_get_funcs_count, + .get_function_name = tz1090_pdc_pinctrl_get_func_name, + .get_function_groups = tz1090_pdc_pinctrl_get_func_groups, + .enable = tz1090_pdc_pinctrl_enable, + .disable = tz1090_pdc_pinctrl_disable, + .gpio_request_enable = tz1090_pdc_pinctrl_gpio_request_enable, + .gpio_disable_free = tz1090_pdc_pinctrl_gpio_disable_free, +}; + +/* + * Pin config operations + */ + +static int tz1090_pdc_pinconf_reg(struct pinctrl_dev *pctldev, + unsigned int pin, + enum pin_config_param param, + bool report_err, + u32 *reg, u32 *width, u32 *mask, u32 *shift, + u32 *val) +{ + /* Find information about parameter's register */ + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + *val = REG_PU_PD_TRISTATE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + *val = REG_PU_PD_UP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + *val = REG_PU_PD_DOWN; + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + *val = REG_PU_PD_REPEATER; + break; + default: + return -ENOTSUPP; + }; + + /* Only input bias parameters supported */ + *reg = REG_GPIO_CONTROL2; + *shift = REG_GPIO_CONTROL2_PU_PD_S + pin*2; + *width = 2; + + /* Calculate field information */ + *mask = (BIT(*width) - 1) << *shift; + + return 0; +} + +static int tz1090_pdc_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + int ret; + u32 reg, width, mask, shift, val, tmp, arg; + + /* Get register information */ + ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true, + ®, &width, &mask, &shift, &val); + if (ret < 0) + return ret; + + /* Extract field from register */ + tmp = pmx_read(pmx, reg); + arg = ((tmp & mask) >> shift) == val; + + /* Config not active */ + if (!arg) + return -EINVAL; + + /* And pack config */ + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int tz1090_pdc_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long config) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); + int ret; + u32 reg, width, mask, shift, val, tmp; + unsigned long flags; + + dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", + __func__, tz1090_pdc_pins[pin].name, config); + + /* Get register information */ + ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true, + ®, &width, &mask, &shift, &val); + if (ret < 0) + return ret; + + /* Unpack argument and range check it */ + if (arg > 1) { + dev_dbg(pctldev->dev, "%s: arg %u out of range\n", + __func__, arg); + return -EINVAL; + } + + /* Write register field */ + __global_lock2(flags); + tmp = pmx_read(pmx, reg); + tmp &= ~mask; + if (arg) + tmp |= val << shift; + pmx_write(pmx, tmp, reg); + __global_unlock2(flags); + + return 0; +} + +static const int tz1090_pdc_boolean_map[] = { + [0] = -EINVAL, + [1] = 1, +}; + +static const int tz1090_pdc_dr_map[] = { + [REG_DR_2mA] = 2, + [REG_DR_4mA] = 4, + [REG_DR_8mA] = 8, + [REG_DR_12mA] = 12, +}; + +static int tz1090_pdc_pinconf_group_reg(struct pinctrl_dev *pctldev, + const struct tz1090_pdc_pingroup *g, + enum pin_config_param param, + bool report_err, u32 *reg, u32 *width, + u32 *mask, u32 *shift, const int **map) +{ + /* Drive configuration applies in groups, but not to all groups. */ + if (!g->drv) { + if (report_err) + dev_dbg(pctldev->dev, + "%s: group %s has no drive control\n", + __func__, g->name); + return -ENOTSUPP; + } + + /* Find information about drive parameter's register */ + *reg = REG_GPIO_CONTROL2; + switch (param) { + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + *shift = REG_GPIO_CONTROL2_PDC_SCHMITT_S; + *width = 1; + *map = tz1090_pdc_boolean_map; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + *shift = REG_GPIO_CONTROL2_PDC_DR_S; + *width = 2; + *map = tz1090_pdc_dr_map; + break; + case PIN_CONFIG_LOW_POWER_MODE: + *shift = REG_GPIO_CONTROL2_PDC_POS_S; + *width = 1; + *map = tz1090_pdc_boolean_map; + break; + default: + return -ENOTSUPP; + }; + + /* Calculate field information */ + *mask = (BIT(*width) - 1) << *shift; + + return 0; +} + +static int tz1090_pdc_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *config) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group]; + enum pin_config_param param = pinconf_to_config_param(*config); + int ret, arg; + u32 reg, width, mask, shift, val; + const int *map; + + /* Get register information */ + ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true, + ®, &width, &mask, &shift, &map); + if (ret < 0) + return ret; + + /* Extract field from register */ + val = pmx_read(pmx, reg); + arg = map[(val & mask) >> shift]; + if (arg < 0) + return arg; + + /* And pack config */ + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int tz1090_pdc_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long config) +{ + struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group]; + enum pin_config_param param = pinconf_to_config_param(config); + const unsigned int *pit; + unsigned int i; + int ret, arg; + u32 reg, width, mask, shift, val; + unsigned long flags; + const int *map; + + dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", + __func__, g->name, config); + + /* Get register information */ + ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true, + ®, &width, &mask, &shift, &map); + if (ret < 0) { + /* + * Maybe we're trying to set a per-pin configuration of a group, + * so do the pins one by one. This is mainly as a convenience. + */ + for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) { + ret = tz1090_pdc_pinconf_set(pctldev, *pit, config); + if (ret) + return ret; + } + return 0; + } + + /* Unpack argument and map it to register value */ + arg = pinconf_to_config_argument(config); + for (i = 0; i < BIT(width); ++i) { + if (map[i] == arg || (map[i] == -EINVAL && !arg)) { + /* Write register field */ + __global_lock2(flags); + val = pmx_read(pmx, reg); + val &= ~mask; + val |= i << shift; + pmx_write(pmx, val, reg); + __global_unlock2(flags); + return 0; + } + } + + dev_dbg(pctldev->dev, "%s: arg %u not supported\n", + __func__, arg); + return 0; +} + +static struct pinconf_ops tz1090_pdc_pinconf_ops = { + .is_generic = true, + .pin_config_get = tz1090_pdc_pinconf_get, + .pin_config_set = tz1090_pdc_pinconf_set, + .pin_config_group_get = tz1090_pdc_pinconf_group_get, + .pin_config_group_set = tz1090_pdc_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +/* + * Pin control driver setup + */ + +static struct pinctrl_desc tz1090_pdc_pinctrl_desc = { + .pctlops = &tz1090_pdc_pinctrl_ops, + .pmxops = &tz1090_pdc_pinmux_ops, + .confops = &tz1090_pdc_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int tz1090_pdc_pinctrl_probe(struct platform_device *pdev) +{ + struct tz1090_pdc_pmx *pmx; + struct resource *res; + + pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); + if (!pmx) { + dev_err(&pdev->dev, "Can't alloc tz1090_pdc_pmx\n"); + return -ENOMEM; + } + pmx->dev = &pdev->dev; + spin_lock_init(&pmx->lock); + + tz1090_pdc_pinctrl_desc.name = dev_name(&pdev->dev); + tz1090_pdc_pinctrl_desc.pins = tz1090_pdc_pins; + tz1090_pdc_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pdc_pins); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing MEM resource\n"); + return -ENODEV; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, + "Couldn't request MEM resource\n"); + return -ENODEV; + } + + pmx->regs = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pmx->regs) { + dev_err(&pdev->dev, "Couldn't ioremap regs\n"); + return -ENODEV; + } + + pmx->pctl = pinctrl_register(&tz1090_pdc_pinctrl_desc, &pdev->dev, pmx); + if (!pmx->pctl) { + dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, pmx); + + dev_info(&pdev->dev, "TZ1090 PDC pinctrl driver initialised\n"); + + return 0; +} + +static int tz1090_pdc_pinctrl_remove(struct platform_device *pdev) +{ + struct tz1090_pdc_pmx *pmx = platform_get_drvdata(pdev); + + pinctrl_unregister(pmx->pctl); + + return 0; +} + +static struct of_device_id tz1090_pdc_pinctrl_of_match[] = { + { .compatible = "img,tz1090-pdc-pinctrl", }, + { }, +}; + +static struct platform_driver tz1090_pdc_pinctrl_driver = { + .driver = { + .name = "tz1090-pdc-pinctrl", + .owner = THIS_MODULE, + .of_match_table = tz1090_pdc_pinctrl_of_match, + }, + .probe = tz1090_pdc_pinctrl_probe, + .remove = tz1090_pdc_pinctrl_remove, +}; + +static int __init tz1090_pdc_pinctrl_init(void) +{ + return platform_driver_register(&tz1090_pdc_pinctrl_driver); +} +arch_initcall(tz1090_pdc_pinctrl_init); + +static void __exit tz1090_pdc_pinctrl_exit(void) +{ + platform_driver_unregister(&tz1090_pdc_pinctrl_driver); +} +module_exit(tz1090_pdc_pinctrl_exit); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION("Toumaz Xenif TZ1090 PDC pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, tz1090_pdc_pinctrl_of_match); diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c new file mode 100644 index 00000000000..4edae08a0a6 --- /dev/null +++ b/drivers/pinctrl/pinctrl-tz1090.c @@ -0,0 +1,2072 @@ +/* + * Pinctrl driver for the Toumaz Xenif TZ1090 SoC + * + * Copyright (c) 2013, Imagination Technologies Ltd. + * + * Derived from Tegra code: + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * + * Derived from code: + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010 NVIDIA Corporation + * Copyright (C) 2009-2011 ST-Ericsson AB + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +/* + * The registers may be shared with other threads/cores, so we need to use the + * metag global lock2 for atomicity. + */ +#include <asm/global_lock.h> + +#include "core.h" +#include "pinconf.h" + +/* Register offsets from bank base address */ +#define REG_PINCTRL_SELECT 0x10 +#define REG_PINCTRL_SCHMITT 0x90 +#define REG_PINCTRL_PU_PD 0xa0 +#define REG_PINCTRL_SR 0xc0 +#define REG_PINCTRL_DR 0xd0 +#define REG_PINCTRL_IF_CTL 0xe0 + +/* REG_PINCTRL_PU_PD field values */ +#define REG_PU_PD_TRISTATE 0 +#define REG_PU_PD_UP 1 +#define REG_PU_PD_DOWN 2 +#define REG_PU_PD_REPEATER 3 + +/* REG_PINCTRL_DR field values */ +#define REG_DR_2mA 0 +#define REG_DR_4mA 1 +#define REG_DR_8mA 2 +#define REG_DR_12mA 3 + +/** + * struct tz1090_function - TZ1090 pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct tz1090_function { + const char *name; + const char * const *groups; + unsigned int ngroups; +}; + +/** + * struct tz1090_muxdesc - TZ1090 individual mux description + * @funcs: Function for each mux value. + * @reg: Mux register offset. 0 if unsupported. + * @bit: Mux register bit. 0 if unsupported. + * @width: Mux field width. 0 if unsupported. + * + * A representation of a group of signals (possibly just one signal) in the + * TZ1090 which can be muxed to a set of functions or sub muxes. + */ +struct tz1090_muxdesc { + int funcs[5]; + u16 reg; + u8 bit; + u8 width; +}; + +/** + * struct tz1090_pingroup - TZ1090 pin group + * @name: Name of pin group. + * @pins: Array of pin numbers in this pin group. + * @npins: Number of pins in this pin group. + * @mux: Top level mux. + * @drv: Drive control supported, 0 if unsupported. + * This means Schmitt, Slew, and Drive strength. + * @slw_bit: Slew register bit. 0 if unsupported. + * The same bit is used for Schmitt, and Drive (*2). + * @func: Currently muxed function. + * @func_count: Number of pins using current mux function. + * + * A representation of a group of pins (possibly just one pin) in the TZ1090 + * pin controller. Each group allows some parameter or parameters to be + * configured. The most common is mux function selection. + */ +struct tz1090_pingroup { + const char *name; + const unsigned int *pins; + unsigned int npins; + struct tz1090_muxdesc mux; + + bool drv; + u8 slw_bit; + + int func; + unsigned int func_count; +}; + +/* + * Most pins affected by the pinmux can also be GPIOs. Define these first. + * These must match how the GPIO driver names/numbers its pins. + */ + +enum tz1090_pin { + /* GPIO pins */ + TZ1090_PIN_SDIO_CLK, + TZ1090_PIN_SDIO_CMD, + TZ1090_PIN_SDIO_D0, + TZ1090_PIN_SDIO_D1, + TZ1090_PIN_SDIO_D2, + TZ1090_PIN_SDIO_D3, + TZ1090_PIN_SDH_CD, + TZ1090_PIN_SDH_WP, + TZ1090_PIN_SPI0_MCLK, + TZ1090_PIN_SPI0_CS0, + TZ1090_PIN_SPI0_CS1, + TZ1090_PIN_SPI0_CS2, + TZ1090_PIN_SPI0_DOUT, + TZ1090_PIN_SPI0_DIN, + TZ1090_PIN_SPI1_MCLK, + TZ1090_PIN_SPI1_CS0, + TZ1090_PIN_SPI1_CS1, + TZ1090_PIN_SPI1_CS2, + TZ1090_PIN_SPI1_DOUT, + TZ1090_PIN_SPI1_DIN, + TZ1090_PIN_UART0_RXD, + TZ1090_PIN_UART0_TXD, + TZ1090_PIN_UART0_CTS, + TZ1090_PIN_UART0_RTS, + TZ1090_PIN_UART1_RXD, + TZ1090_PIN_UART1_TXD, + TZ1090_PIN_SCB0_SDAT, + TZ1090_PIN_SCB0_SCLK, + TZ1090_PIN_SCB1_SDAT, + TZ1090_PIN_SCB1_SCLK, + TZ1090_PIN_SCB2_SDAT, + TZ1090_PIN_SCB2_SCLK, + TZ1090_PIN_I2S_MCLK, + TZ1090_PIN_I2S_BCLK_OUT, + TZ1090_PIN_I2S_LRCLK_OUT, + TZ1090_PIN_I2S_DOUT0, + TZ1090_PIN_I2S_DOUT1, + TZ1090_PIN_I2S_DOUT2, + TZ1090_PIN_I2S_DIN, + TZ1090_PIN_PDM_A, + TZ1090_PIN_PDM_B, + TZ1090_PIN_PDM_C, + TZ1090_PIN_PDM_D, + TZ1090_PIN_TFT_RED0, + TZ1090_PIN_TFT_RED1, + TZ1090_PIN_TFT_RED2, + TZ1090_PIN_TFT_RED3, + TZ1090_PIN_TFT_RED4, + TZ1090_PIN_TFT_RED5, + TZ1090_PIN_TFT_RED6, + TZ1090_PIN_TFT_RED7, + TZ1090_PIN_TFT_GREEN0, + TZ1090_PIN_TFT_GREEN1, + TZ1090_PIN_TFT_GREEN2, + TZ1090_PIN_TFT_GREEN3, + TZ1090_PIN_TFT_GREEN4, + TZ1090_PIN_TFT_GREEN5, + TZ1090_PIN_TFT_GREEN6, + TZ1090_PIN_TFT_GREEN7, + TZ1090_PIN_TFT_BLUE0, + TZ1090_PIN_TFT_BLUE1, + TZ1090_PIN_TFT_BLUE2, + TZ1090_PIN_TFT_BLUE3, + TZ1090_PIN_TFT_BLUE4, + TZ1090_PIN_TFT_BLUE5, + TZ1090_PIN_TFT_BLUE6, + TZ1090_PIN_TFT_BLUE7, + TZ1090_PIN_TFT_VDDEN_GD, + TZ1090_PIN_TFT_PANELCLK, + TZ1090_PIN_TFT_BLANK_LS, + TZ1090_PIN_TFT_VSYNC_NS, + TZ1090_PIN_TFT_HSYNC_NR, + TZ1090_PIN_TFT_VD12ACB, + TZ1090_PIN_TFT_PWRSAVE, + TZ1090_PIN_TX_ON, + TZ1090_PIN_RX_ON, + TZ1090_PIN_PLL_ON, + TZ1090_PIN_PA_ON, + TZ1090_PIN_RX_HP, + TZ1090_PIN_GAIN0, + TZ1090_PIN_GAIN1, + TZ1090_PIN_GAIN2, + TZ1090_PIN_GAIN3, + TZ1090_PIN_GAIN4, + TZ1090_PIN_GAIN5, + TZ1090_PIN_GAIN6, + TZ1090_PIN_GAIN7, + TZ1090_PIN_ANT_SEL0, + TZ1090_PIN_ANT_SEL1, + TZ1090_PIN_SDH_CLK_IN, + + /* Non-GPIO pins */ + TZ1090_PIN_TCK, + TZ1090_PIN_TRST, + TZ1090_PIN_TDI, + TZ1090_PIN_TDO, + TZ1090_PIN_TMS, + TZ1090_PIN_CLK_OUT0, + TZ1090_PIN_CLK_OUT1, + + NUM_GPIOS = TZ1090_PIN_TCK, +}; + +/* Pin names */ + +static const struct pinctrl_pin_desc tz1090_pins[] = { + /* GPIO pins */ + PINCTRL_PIN(TZ1090_PIN_SDIO_CLK, "sdio_clk"), + PINCTRL_PIN(TZ1090_PIN_SDIO_CMD, "sdio_cmd"), + PINCTRL_PIN(TZ1090_PIN_SDIO_D0, "sdio_d0"), + PINCTRL_PIN(TZ1090_PIN_SDIO_D1, "sdio_d1"), + PINCTRL_PIN(TZ1090_PIN_SDIO_D2, "sdio_d2"), + PINCTRL_PIN(TZ1090_PIN_SDIO_D3, "sdio_d3"), + PINCTRL_PIN(TZ1090_PIN_SDH_CD, "sdh_cd"), + PINCTRL_PIN(TZ1090_PIN_SDH_WP, "sdh_wp"), + PINCTRL_PIN(TZ1090_PIN_SPI0_MCLK, "spi0_mclk"), + PINCTRL_PIN(TZ1090_PIN_SPI0_CS0, "spi0_cs0"), + PINCTRL_PIN(TZ1090_PIN_SPI0_CS1, "spi0_cs1"), + PINCTRL_PIN(TZ1090_PIN_SPI0_CS2, "spi0_cs2"), + PINCTRL_PIN(TZ1090_PIN_SPI0_DOUT, "spi0_dout"), + PINCTRL_PIN(TZ1090_PIN_SPI0_DIN, "spi0_din"), + PINCTRL_PIN(TZ1090_PIN_SPI1_MCLK, "spi1_mclk"), + PINCTRL_PIN(TZ1090_PIN_SPI1_CS0, "spi1_cs0"), + PINCTRL_PIN(TZ1090_PIN_SPI1_CS1, "spi1_cs1"), + PINCTRL_PIN(TZ1090_PIN_SPI1_CS2, "spi1_cs2"), + PINCTRL_PIN(TZ1090_PIN_SPI1_DOUT, "spi1_dout"), + PINCTRL_PIN(TZ1090_PIN_SPI1_DIN, "spi1_din"), + PINCTRL_PIN(TZ1090_PIN_UART0_RXD, "uart0_rxd"), + PINCTRL_PIN(TZ1090_PIN_UART0_TXD, "uart0_txd"), + PINCTRL_PIN(TZ1090_PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(TZ1090_PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(TZ1090_PIN_UART1_RXD, "uart1_rxd"), + PINCTRL_PIN(TZ1090_PIN_UART1_TXD, "uart1_txd"), + PINCTRL_PIN(TZ1090_PIN_SCB0_SDAT, "scb0_sdat"), + PINCTRL_PIN(TZ1090_PIN_SCB0_SCLK, "scb0_sclk"), + PINCTRL_PIN(TZ1090_PIN_SCB1_SDAT, "scb1_sdat"), + PINCTRL_PIN(TZ1090_PIN_SCB1_SCLK, "scb1_sclk"), + PINCTRL_PIN(TZ1090_PIN_SCB2_SDAT, "scb2_sdat"), + PINCTRL_PIN(TZ1090_PIN_SCB2_SCLK, "scb2_sclk"), + PINCTRL_PIN(TZ1090_PIN_I2S_MCLK, "i2s_mclk"), + PINCTRL_PIN(TZ1090_PIN_I2S_BCLK_OUT, "i2s_bclk_out"), + PINCTRL_PIN(TZ1090_PIN_I2S_LRCLK_OUT, "i2s_lrclk_out"), + PINCTRL_PIN(TZ1090_PIN_I2S_DOUT0, "i2s_dout0"), + PINCTRL_PIN(TZ1090_PIN_I2S_DOUT1, "i2s_dout1"), + PINCTRL_PIN(TZ1090_PIN_I2S_DOUT2, "i2s_dout2"), + PINCTRL_PIN(TZ1090_PIN_I2S_DIN, "i2s_din"), + PINCTRL_PIN(TZ1090_PIN_PDM_A, "pdm_a"), + PINCTRL_PIN(TZ1090_PIN_PDM_B, "pdm_b"), + PINCTRL_PIN(TZ1090_PIN_PDM_C, "pdm_c"), + PINCTRL_PIN(TZ1090_PIN_PDM_D, "pdm_d"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED0, "tft_red0"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED1, "tft_red1"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED2, "tft_red2"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED3, "tft_red3"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED4, "tft_red4"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED5, "tft_red5"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED6, "tft_red6"), + PINCTRL_PIN(TZ1090_PIN_TFT_RED7, "tft_red7"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN0, "tft_green0"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN1, "tft_green1"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN2, "tft_green2"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN3, "tft_green3"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN4, "tft_green4"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN5, "tft_green5"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN6, "tft_green6"), + PINCTRL_PIN(TZ1090_PIN_TFT_GREEN7, "tft_green7"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE0, "tft_blue0"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE1, "tft_blue1"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE2, "tft_blue2"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE3, "tft_blue3"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE4, "tft_blue4"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE5, "tft_blue5"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE6, "tft_blue6"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLUE7, "tft_blue7"), + PINCTRL_PIN(TZ1090_PIN_TFT_VDDEN_GD, "tft_vdden_gd"), + PINCTRL_PIN(TZ1090_PIN_TFT_PANELCLK, "tft_panelclk"), + PINCTRL_PIN(TZ1090_PIN_TFT_BLANK_LS, "tft_blank_ls"), + PINCTRL_PIN(TZ1090_PIN_TFT_VSYNC_NS, "tft_vsync_ns"), + PINCTRL_PIN(TZ1090_PIN_TFT_HSYNC_NR, "tft_hsync_nr"), + PINCTRL_PIN(TZ1090_PIN_TFT_VD12ACB, "tft_vd12acb"), + PINCTRL_PIN(TZ1090_PIN_TFT_PWRSAVE, "tft_pwrsave"), + PINCTRL_PIN(TZ1090_PIN_TX_ON, "tx_on"), + PINCTRL_PIN(TZ1090_PIN_RX_ON, "rx_on"), + PINCTRL_PIN(TZ1090_PIN_PLL_ON, "pll_on"), + PINCTRL_PIN(TZ1090_PIN_PA_ON, "pa_on"), + PINCTRL_PIN(TZ1090_PIN_RX_HP, "rx_hp"), + PINCTRL_PIN(TZ1090_PIN_GAIN0, "gain0"), + PINCTRL_PIN(TZ1090_PIN_GAIN1, "gain1"), + PINCTRL_PIN(TZ1090_PIN_GAIN2, "gain2"), + PINCTRL_PIN(TZ1090_PIN_GAIN3, "gain3"), + PINCTRL_PIN(TZ1090_PIN_GAIN4, "gain4"), + PINCTRL_PIN(TZ1090_PIN_GAIN5, "gain5"), + PINCTRL_PIN(TZ1090_PIN_GAIN6, "gain6"), + PINCTRL_PIN(TZ1090_PIN_GAIN7, "gain7"), + PINCTRL_PIN(TZ1090_PIN_ANT_SEL0, "ant_sel0"), + PINCTRL_PIN(TZ1090_PIN_ANT_SEL1, "ant_sel1"), + PINCTRL_PIN(TZ1090_PIN_SDH_CLK_IN, "sdh_clk_in"), + + /* Non-GPIO pins */ + PINCTRL_PIN(TZ1090_PIN_TCK, "tck"), + PINCTRL_PIN(TZ1090_PIN_TRST, "trst"), + PINCTRL_PIN(TZ1090_PIN_TDI, "tdi"), + PINCTRL_PIN(TZ1090_PIN_TDO, "tdo"), + PINCTRL_PIN(TZ1090_PIN_TMS, "tms"), + PINCTRL_PIN(TZ1090_PIN_CLK_OUT0, "clk_out0"), + PINCTRL_PIN(TZ1090_PIN_CLK_OUT1, "clk_out1"), +}; + +/* Pins in each pin group */ + +static const unsigned int spi1_cs2_pins[] = { + TZ1090_PIN_SPI1_CS2, +}; + +static const unsigned int pdm_d_pins[] = { + TZ1090_PIN_PDM_D, +}; + +static const unsigned int tft_pins[] = { + TZ1090_PIN_TFT_RED0, + TZ1090_PIN_TFT_RED1, + TZ1090_PIN_TFT_RED2, + TZ1090_PIN_TFT_RED3, + TZ1090_PIN_TFT_RED4, + TZ1090_PIN_TFT_RED5, + TZ1090_PIN_TFT_RED6, + TZ1090_PIN_TFT_RED7, + TZ1090_PIN_TFT_GREEN0, + TZ1090_PIN_TFT_GREEN1, + TZ1090_PIN_TFT_GREEN2, + TZ1090_PIN_TFT_GREEN3, + TZ1090_PIN_TFT_GREEN4, + TZ1090_PIN_TFT_GREEN5, + TZ1090_PIN_TFT_GREEN6, + TZ1090_PIN_TFT_GREEN7, + TZ1090_PIN_TFT_BLUE0, + TZ1090_PIN_TFT_BLUE1, + TZ1090_PIN_TFT_BLUE2, + TZ1090_PIN_TFT_BLUE3, + TZ1090_PIN_TFT_BLUE4, + TZ1090_PIN_TFT_BLUE5, + TZ1090_PIN_TFT_BLUE6, + TZ1090_PIN_TFT_BLUE7, + TZ1090_PIN_TFT_VDDEN_GD, + TZ1090_PIN_TFT_PANELCLK, + TZ1090_PIN_TFT_BLANK_LS, + TZ1090_PIN_TFT_VSYNC_NS, + TZ1090_PIN_TFT_HSYNC_NR, + TZ1090_PIN_TFT_VD12ACB, + TZ1090_PIN_TFT_PWRSAVE, +}; + +static const unsigned int afe_pins[] = { + TZ1090_PIN_TX_ON, + TZ1090_PIN_RX_ON, + TZ1090_PIN_PLL_ON, + TZ1090_PIN_PA_ON, + TZ1090_PIN_RX_HP, + TZ1090_PIN_ANT_SEL0, + TZ1090_PIN_ANT_SEL1, + TZ1090_PIN_GAIN0, + TZ1090_PIN_GAIN1, + TZ1090_PIN_GAIN2, + TZ1090_PIN_GAIN3, + TZ1090_PIN_GAIN4, + TZ1090_PIN_GAIN5, + TZ1090_PIN_GAIN6, + TZ1090_PIN_GAIN7, +}; + +static const unsigned int sdio_pins[] = { + TZ1090_PIN_SDIO_CLK, + TZ1090_PIN_SDIO_CMD, + TZ1090_PIN_SDIO_D0, + TZ1090_PIN_SDIO_D1, + TZ1090_PIN_SDIO_D2, + TZ1090_PIN_SDIO_D3, +}; + +static const unsigned int sdh_pins[] = { + TZ1090_PIN_SDH_CD, + TZ1090_PIN_SDH_WP, + TZ1090_PIN_SDH_CLK_IN, +}; + +static const unsigned int spi0_pins[] = { + TZ1090_PIN_SPI0_MCLK, + TZ1090_PIN_SPI0_CS0, + TZ1090_PIN_SPI0_CS1, + TZ1090_PIN_SPI0_CS2, + TZ1090_PIN_SPI0_DOUT, + TZ1090_PIN_SPI0_DIN, +}; + +static const unsigned int spi1_pins[] = { + TZ1090_PIN_SPI1_MCLK, + TZ1090_PIN_SPI1_CS0, + TZ1090_PIN_SPI1_CS1, + TZ1090_PIN_SPI1_CS2, + TZ1090_PIN_SPI1_DOUT, + TZ1090_PIN_SPI1_DIN, +}; + +static const unsigned int uart0_pins[] = { + TZ1090_PIN_UART0_RTS, + TZ1090_PIN_UART0_CTS, + TZ1090_PIN_UART0_TXD, + TZ1090_PIN_UART0_RXD, +}; + +static const unsigned int uart1_pins[] = { + TZ1090_PIN_UART1_TXD, + TZ1090_PIN_UART1_RXD, +}; + +static const unsigned int uart_pins[] = { + TZ1090_PIN_UART1_TXD, + TZ1090_PIN_UART1_RXD, + TZ1090_PIN_UART0_RTS, + TZ1090_PIN_UART0_CTS, + TZ1090_PIN_UART0_TXD, + TZ1090_PIN_UART0_RXD, +}; + +static const unsigned int scb0_pins[] = { + TZ1090_PIN_SCB0_SDAT, + TZ1090_PIN_SCB0_SCLK, +}; + +static const unsigned int scb1_pins[] = { + TZ1090_PIN_SCB1_SDAT, + TZ1090_PIN_SCB1_SCLK, +}; + +static const unsigned int scb2_pins[] = { + TZ1090_PIN_SCB2_SDAT, + TZ1090_PIN_SCB2_SCLK, +}; + +static const unsigned int i2s_pins[] = { + TZ1090_PIN_I2S_MCLK, + TZ1090_PIN_I2S_BCLK_OUT, + TZ1090_PIN_I2S_LRCLK_OUT, + TZ1090_PIN_I2S_DOUT0, + TZ1090_PIN_I2S_DOUT1, + TZ1090_PIN_I2S_DOUT2, + TZ1090_PIN_I2S_DIN, +}; + +static const unsigned int jtag_pins[] = { + TZ1090_PIN_TCK, + TZ1090_PIN_TRST, + TZ1090_PIN_TDI, + TZ1090_PIN_TDO, + TZ1090_PIN_TMS, +}; + +/* Pins in each drive pin group */ + +static const unsigned int drive_sdio_pins[] = { + TZ1090_PIN_SDIO_CLK, + TZ1090_PIN_SDIO_CMD, + TZ1090_PIN_SDIO_D0, + TZ1090_PIN_SDIO_D1, + TZ1090_PIN_SDIO_D2, + TZ1090_PIN_SDIO_D3, + TZ1090_PIN_SDH_WP, + TZ1090_PIN_SDH_CD, + TZ1090_PIN_SDH_CLK_IN, +}; + +static const unsigned int drive_i2s_pins[] = { + TZ1090_PIN_CLK_OUT1, + TZ1090_PIN_I2S_DIN, + TZ1090_PIN_I2S_DOUT0, + TZ1090_PIN_I2S_DOUT1, + TZ1090_PIN_I2S_DOUT2, + TZ1090_PIN_I2S_LRCLK_OUT, + TZ1090_PIN_I2S_BCLK_OUT, + TZ1090_PIN_I2S_MCLK, +}; + +static const unsigned int drive_scb0_pins[] = { + TZ1090_PIN_SCB0_SCLK, + TZ1090_PIN_SCB0_SDAT, + TZ1090_PIN_PDM_D, + TZ1090_PIN_PDM_C, +}; + +static const unsigned int drive_pdm_pins[] = { + TZ1090_PIN_CLK_OUT0, + TZ1090_PIN_PDM_B, + TZ1090_PIN_PDM_A, +}; + +/* Pin groups each function can be muxed to */ + +/* + * The magic "perip" function allows otherwise non-muxing pins to be enabled in + * peripheral mode. + */ +static const char * const perip_groups[] = { + /* non-muxing convenient gpio pingroups */ + "uart", + "uart0", + "uart1", + "spi0", + "spi1", + "scb0", + "scb1", + "scb2", + "i2s", + /* individual pins not part of a pin mux group */ + "spi0_mclk", + "spi0_cs0", + "spi0_cs1", + "spi0_cs2", + "spi0_dout", + "spi0_din", + "spi1_mclk", + "spi1_cs0", + "spi1_cs1", + "spi1_dout", + "spi1_din", + "uart0_rxd", + "uart0_txd", + "uart0_cts", + "uart0_rts", + "uart1_rxd", + "uart1_txd", + "scb0_sdat", + "scb0_sclk", + "scb1_sdat", + "scb1_sclk", + "scb2_sdat", + "scb2_sclk", + "i2s_mclk", + "i2s_bclk_out", + "i2s_lrclk_out", + "i2s_dout0", + "i2s_dout1", + "i2s_dout2", + "i2s_din", + "pdm_a", + "pdm_b", + "pdm_c", +}; + +static const char * const sdh_sdio_groups[] = { + "sdh", + "sdio", + /* sdh pins */ + "sdh_cd", + "sdh_wp", + "sdh_clk_in", + /* sdio pins */ + "sdio_clk", + "sdio_cmd", + "sdio_d0", + "sdio_d1", + "sdio_d2", + "sdio_d3", +}; + +static const char * const spi1_cs2_groups[] = { + "spi1_cs2", +}; + +static const char * const pdm_dac_groups[] = { + "pdm_d", +}; + +static const char * const usb_vbus_groups[] = { + "spi1_cs2", + "pdm_d", +}; + +static const char * const afe_groups[] = { + "afe", + /* afe pins */ + "tx_on", + "rx_on", + "pll_on", + "pa_on", + "rx_hp", + "ant_sel0", + "ant_sel1", + "gain0", + "gain1", + "gain2", + "gain3", + "gain4", + "gain5", + "gain6", + "gain7", +}; + +static const char * const tft_groups[] = { + "tft", + /* tft pins */ + "tft_red0", + "tft_red1", + "tft_red2", + "tft_red3", + "tft_red4", + "tft_red5", + "tft_red6", + "tft_red7", + "tft_green0", + "tft_green1", + "tft_green2", + "tft_green3", + "tft_green4", + "tft_green5", + "tft_green6", + "tft_green7", + "tft_blue0", + "tft_blue1", + "tft_blue2", + "tft_blue3", + "tft_blue4", + "tft_blue5", + "tft_blue6", + "tft_blue7", + "tft_vdden_gd", + "tft_panelclk", + "tft_blank_ls", + "tft_vsync_ns", + "tft_hsync_nr", + "tft_vd12acb", + "tft_pwrsave", +}; + +/* Mux functions that can be used by a mux */ + +enum tz1090_mux { + /* internal placeholder */ + TZ1090_MUX_NA = -1, + /* magic per-non-muxing-GPIO-pin peripheral mode mux */ + TZ1090_MUX_PERIP, + /* SDH/SDIO mux */ + TZ1090_MUX_SDH, + TZ1090_MUX_SDIO, + /* USB_VBUS muxes */ + TZ1090_MUX_SPI1_CS2, + TZ1090_MUX_PDM_DAC, + TZ1090_MUX_USB_VBUS, + /* AFE mux */ + TZ1090_MUX_AFE, + TZ1090_MUX_TS_OUT_0, + /* EXT_DAC mux */ + TZ1090_MUX_DAC, + TZ1090_MUX_NOT_IQADC_STB, + TZ1090_MUX_IQDAC_STB, + /* TFT mux */ + TZ1090_MUX_TFT, + TZ1090_MUX_EXT_DAC, + TZ1090_MUX_TS_OUT_1, + TZ1090_MUX_LCD_TRACE, + TZ1090_MUX_PHY_RINGOSC, +}; + +#define FUNCTION(mux, fname, group) \ + [(TZ1090_MUX_ ## mux)] = { \ + .name = #fname, \ + .groups = group##_groups, \ + .ngroups = ARRAY_SIZE(group##_groups), \ + } +/* For intermediate functions with submuxes */ +#define NULL_FUNCTION(mux, fname) \ + [(TZ1090_MUX_ ## mux)] = { \ + .name = #fname, \ + } + +/* Must correlate with enum tz1090_mux */ +static const struct tz1090_function tz1090_functions[] = { + /* FUNCTION function name pingroups */ + FUNCTION(PERIP, perip, perip), + FUNCTION(SDH, sdh, sdh_sdio), + FUNCTION(SDIO, sdio, sdh_sdio), + FUNCTION(SPI1_CS2, spi1_cs2, spi1_cs2), + FUNCTION(PDM_DAC, pdm_dac, pdm_dac), + FUNCTION(USB_VBUS, usb_vbus, usb_vbus), + FUNCTION(AFE, afe, afe), + FUNCTION(TS_OUT_0, ts_out_0, afe), + FUNCTION(DAC, ext_dac, tft), + FUNCTION(NOT_IQADC_STB, not_iqadc_stb, tft), + FUNCTION(IQDAC_STB, iqdac_stb, tft), + FUNCTION(TFT, tft, tft), + NULL_FUNCTION(EXT_DAC, _ext_dac), + FUNCTION(TS_OUT_1, ts_out_1, tft), + FUNCTION(LCD_TRACE, lcd_trace, tft), + FUNCTION(PHY_RINGOSC, phy_ringosc, tft), +}; + +/* Sub muxes */ + +/** + * MUX() - Initialise a mux description. + * @f0: Function 0 (TZ1090_MUX_ is prepended, NA for none) + * @f1: Function 1 (TZ1090_MUX_ is prepended, NA for none) + * @f2: Function 2 (TZ1090_MUX_ is prepended, NA for none) + * @f3: Function 3 (TZ1090_MUX_ is prepended, NA for none) + * @f4: Function 4 (TZ1090_MUX_ is prepended, NA for none) + * @mux_r: Mux register (REG_PINCTRL_ is prepended) + * @mux_b: Bit number in register that the mux field begins + * @mux_w: Width of mux field in register + */ +#define MUX(f0, f1, f2, f3, f4, mux_r, mux_b, mux_w) \ + { \ + .funcs = { \ + TZ1090_MUX_ ## f0, \ + TZ1090_MUX_ ## f1, \ + TZ1090_MUX_ ## f2, \ + TZ1090_MUX_ ## f3, \ + TZ1090_MUX_ ## f4, \ + }, \ + .reg = (REG_PINCTRL_ ## mux_r), \ + .bit = (mux_b), \ + .width = (mux_w), \ + } + +/** + * DEFINE_SUBMUX() - Defines a submux description separate from a pin group. + * @mux: Mux name (_submux is appended) + * @f0: Function 0 (TZ1090_MUX_ is prepended, NA for none) + * @f1: Function 1 (TZ1090_MUX_ is prepended, NA for none) + * @f2: Function 2 (TZ1090_MUX_ is prepended, NA for none) + * @f3: Function 3 (TZ1090_MUX_ is prepended, NA for none) + * @f4: Function 4 (TZ1090_MUX_ is prepended, NA for none) + * @mux_r: Mux register (REG_PINCTRL_ is prepended) + * @mux_b: Bit number in register that the mux field begins + * @mux_w: Width of mux field in register + * + * A sub mux is a nested mux that can be bound to a magic function number used + * by another mux description. For example value 4 of the top level mux might + * correspond to a function which has a submux pointed to in tz1090_submux[]. + * The outer mux can then take on any function in the top level mux or the + * submux, and if a submux function is chosen both muxes are updated to route + * the signal from the submux. + * + * The submux can be defined with DEFINE_SUBMUX and pointed to from + * tz1090_submux[] using SUBMUX. + */ +#define DEFINE_SUBMUX(mux, f0, f1, f2, f3, f4, mux_r, mux_b, mux_w) \ + static struct tz1090_muxdesc mux ## _submux = \ + MUX(f0, f1, f2, f3, f4, mux_r, mux_b, mux_w) + +/** + * SUBMUX() - Link a submux to a function number. + * @f: Function name (TZ1090_MUX_ is prepended) + * @submux: Submux name (_submux is appended) + * + * For use in tz1090_submux[] initialisation to link an intermediate function + * number to a particular submux description. It indicates that when the + * function is chosen the signal is connected to the submux. + */ +#define SUBMUX(f, submux) [(TZ1090_MUX_ ## f)] = &(submux ## _submux) + +/** + * MUX_PG() - Initialise a pin group with mux control + * @pg_name: Pin group name (stringified, _pins appended to get pins array) + * @f0: Function 0 (TZ1090_MUX_ is prepended, NA for none) + * @f1: Function 1 (TZ1090_MUX_ is prepended, NA for none) + * @f2: Function 2 (TZ1090_MUX_ is prepended, NA for none) + * @f3: Function 3 (TZ1090_MUX_ is prepended, NA for none) + * @f4: Function 4 (TZ1090_MUX_ is prepended, NA for none) + * @mux_r: Mux register (REG_PINCTRL_ is prepended) + * @mux_b: Bit number in register that the mux field begins + * @mux_w: Width of mux field in register + */ +#define MUX_PG(pg_name, f0, f1, f2, f3, f4, \ + mux_r, mux_b, mux_w) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .mux = MUX(f0, f1, f2, f3, f4, \ + mux_r, mux_b, mux_w), \ + } + +/** + * SIMPLE_PG() - Initialise a simple convenience pin group + * @pg_name: Pin group name (stringified, _pins appended to get pins array) + * + * A simple pin group is simply used for binding pins together so they can be + * referred to by a single name instead of having to list every pin + * individually. + */ +#define SIMPLE_PG(pg_name) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + } + +/** + * DRV_PG() - Initialise a pin group with drive control + * @pg_name: Pin group name (stringified, _pins appended to get pins array) + * @slw_b: Slew register bit. + * The same bit is used for Schmitt, and Drive (*2). + */ +#define DRV_PG(pg_name, slw_b) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .drv = true, \ + .slw_bit = (slw_b), \ + } + +/* + * Define main muxing pin groups + */ + +/* submuxes */ + +/* name f0, f1, f2, f3, f4, mux r/b/w */ +DEFINE_SUBMUX(ext_dac, DAC, NOT_IQADC_STB, IQDAC_STB, NA, NA, IF_CTL, 6, 2); + +/* bind submuxes to internal functions */ +static struct tz1090_muxdesc *tz1090_submux[] = { + SUBMUX(EXT_DAC, ext_dac), +}; + +/* + * These are the pin mux groups. Pin muxing can be enabled and disabled for each + * pin individually so these groups are internal. The mapping of pins to pin mux + * group is below (tz1090_mux_pins). + */ +static struct tz1090_pingroup tz1090_mux_groups[] = { + /* Muxing pin groups */ + /* pg_name, f0, f1, f2, f3, f4, mux r/b/w */ + MUX_PG(sdh, SDH, SDIO, NA, NA, NA, IF_CTL, 20, 2), + MUX_PG(sdio, SDIO, SDH, NA, NA, NA, IF_CTL, 16, 2), + MUX_PG(spi1_cs2, SPI1_CS2, USB_VBUS, NA, NA, NA, IF_CTL, 10, 2), + MUX_PG(pdm_d, PDM_DAC, USB_VBUS, NA, NA, NA, IF_CTL, 8, 2), + MUX_PG(afe, AFE, TS_OUT_0, NA, NA, NA, IF_CTL, 4, 2), + MUX_PG(tft, TFT, EXT_DAC, TS_OUT_1, LCD_TRACE, PHY_RINGOSC, IF_CTL, 0, 3), +}; + +/* + * This is the mapping from GPIO pins to pin mux groups in tz1090_mux_groups[]. + * Pins which aren't muxable to multiple peripherals are set to + * TZ1090_MUX_GROUP_MAX to enable the "perip" function to enable/disable + * peripheral control of the pin. + * + * This array is initialised in tz1090_init_mux_pins(). + */ +static u8 tz1090_mux_pins[NUM_GPIOS]; + +/* TZ1090_MUX_GROUP_MAX is used in tz1090_mux_pins[] for non-muxing pins */ +#define TZ1090_MUX_GROUP_MAX ARRAY_SIZE(tz1090_mux_groups) + +/** + * tz1090_init_mux_pins() - Initialise GPIO pin to mux group mapping. + * + * Initialises the tz1090_mux_pins[] array to be the inverse of the pin lists in + * each pin mux group in tz1090_mux_groups[]. + * + * It is assumed that no pin mux groups overlap (share pins). + */ +static void __init tz1090_init_mux_pins(void) +{ + unsigned int g, p; + const struct tz1090_pingroup *grp; + const unsigned int *pin; + + for (p = 0; p < NUM_GPIOS; ++p) + tz1090_mux_pins[p] = TZ1090_MUX_GROUP_MAX; + + grp = tz1090_mux_groups; + for (g = 0, grp = tz1090_mux_groups; + g < ARRAY_SIZE(tz1090_mux_groups); ++g, ++grp) + for (pin = grp->pins, p = 0; p < grp->npins; ++p, ++pin) + tz1090_mux_pins[*pin] = g; +} + +/* + * These are the externally visible pin groups. Some of them allow group control + * of drive configuration. Some are just simple convenience pingroups. All the + * internal pin mux groups in tz1090_mux_groups[] are mirrored here with the + * same pins. + * Pseudo pin groups follow in the group numbers after this array for each GPIO + * pin. Any group used for muxing must have all pins belonging to the same pin + * mux group. + */ +static struct tz1090_pingroup tz1090_groups[] = { + /* Pin groups with drive control (with no out of place pins) */ + /* pg_name, slw/schmitt/drv b */ + DRV_PG(jtag, 11 /* 11, 22 */), + DRV_PG(tft, 10 /* 10, 20 */), + DRV_PG(scb2, 9 /* 9, 18 */), + DRV_PG(spi0, 7 /* 7, 14 */), + DRV_PG(uart, 5 /* 5, 10 */), + DRV_PG(scb1, 4 /* 4, 8 */), + DRV_PG(spi1, 3 /* 3, 6 */), + DRV_PG(afe, 0 /* 0, 0 */), + + /* + * Drive specific pin groups (with odd combinations of pins which makes + * the pin group naming somewhat arbitrary) + */ + /* pg_name, slw/schmitt/drv b */ + DRV_PG(drive_sdio, 8 /* 8, 16 */), /* sdio_* + sdh_* */ + DRV_PG(drive_i2s, 6 /* 6, 12 */), /* i2s_* + clk_out1 */ + DRV_PG(drive_scb0, 2 /* 2, 4 */), /* scb0_* + pdm_{c,d} */ + DRV_PG(drive_pdm, 1 /* 1, 2 */), /* pdm_{a,b} + clk_out0 */ + + /* Convenience pin groups */ + /* pg_name */ + SIMPLE_PG(uart0), + SIMPLE_PG(uart1), + SIMPLE_PG(scb0), + SIMPLE_PG(i2s), + SIMPLE_PG(sdh), + SIMPLE_PG(sdio), + + /* pseudo-pingroups for each GPIO pin follow */ +}; + +/** + * struct tz1090_pmx - Private pinctrl data + * @dev: Platform device + * @pctl: Pin control device + * @regs: Register region + * @lock: Lock protecting coherency of pin_en, gpio_en, and SELECT regs + * @pin_en: Pins that have been enabled (32 pins packed into each element) + * @gpio_en: GPIOs that have been enabled (32 pins packed into each element) + */ +struct tz1090_pmx { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *regs; + spinlock_t lock; + u32 pin_en[3]; + u32 gpio_en[3]; +}; + +static inline u32 pmx_read(struct tz1090_pmx *pmx, u32 reg) +{ + return ioread32(pmx->regs + reg); +} + +static inline void pmx_write(struct tz1090_pmx *pmx, u32 val, u32 reg) +{ + iowrite32(val, pmx->regs + reg); +} + +/* + * Pin control operations + */ + +/* each GPIO pin has it's own pseudo pingroup containing only itself */ + +static int tz1090_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(tz1090_groups) + NUM_GPIOS; +} + +static const char *tz1090_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + if (group < ARRAY_SIZE(tz1090_groups)) { + /* normal pingroup */ + return tz1090_groups[group].name; + } else { + /* individual gpio pin pseudo-pingroup */ + unsigned int pin = group - ARRAY_SIZE(tz1090_groups); + return tz1090_pins[pin].name; + } +} + +static int tz1090_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + if (group < ARRAY_SIZE(tz1090_groups)) { + /* normal pingroup */ + *pins = tz1090_groups[group].pins; + *num_pins = tz1090_groups[group].npins; + } else { + /* individual gpio pin pseudo-pingroup */ + unsigned int pin = group - ARRAY_SIZE(tz1090_groups); + *pins = &tz1090_pins[pin].number; + *num_pins = 1; + } + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void tz1090_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, " %s", dev_name(pctldev->dev)); +} +#endif + +static int reserve_map(struct device *dev, struct pinctrl_map **map, + unsigned int *reserved_maps, unsigned int *num_maps, + unsigned int reserve) +{ + unsigned int old_num = *reserved_maps; + unsigned int new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) { + dev_err(dev, "krealloc(map) failed\n"); + return -ENOMEM; + } + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + + return 0; +} + +static int add_map_mux(struct pinctrl_map **map, unsigned int *reserved_maps, + unsigned int *num_maps, const char *group, + const char *function) +{ + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int add_map_configs(struct device *dev, + struct pinctrl_map **map, + unsigned int *reserved_maps, unsigned int *num_maps, + const char *group, unsigned long *configs, + unsigned int num_configs) +{ + unsigned long *dup_configs; + + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) { + dev_err(dev, "kmemdup(configs) failed\n"); + return -ENOMEM; + } + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static void tz1090_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned int num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + + kfree(map); +} + +static int tz1090_pinctrl_dt_subnode_to_map(struct device *dev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps) +{ + int ret; + const char *function; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + unsigned int reserve; + struct property *prop; + const char *group; + + ret = of_property_read_string(np, "tz1090,function", &function); + if (ret < 0) { + /* EINVAL=missing, which is fine since it's optional */ + if (ret != -EINVAL) + dev_err(dev, "could not parse property function\n"); + function = NULL; + } + + ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + if (ret) + return ret; + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "tz1090,pins"); + if (ret < 0) { + dev_err(dev, "could not parse property pins\n"); + goto exit; + } + reserve *= ret; + + ret = reserve_map(dev, map, reserved_maps, num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "tz1090,pins", prop, group) { + if (function) { + ret = add_map_mux(map, reserved_maps, num_maps, + group, function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = add_map_configs(dev, map, reserved_maps, + num_maps, group, configs, + num_configs); + if (ret < 0) + goto exit; + } + } + + ret = 0; + +exit: + kfree(configs); + return ret; +} + +static int tz1090_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + unsigned int reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = tz1090_pinctrl_dt_subnode_to_map(pctldev->dev, np, map, + &reserved_maps, + num_maps); + if (ret < 0) { + tz1090_pinctrl_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + +static struct pinctrl_ops tz1090_pinctrl_ops = { + .get_groups_count = tz1090_pinctrl_get_groups_count, + .get_group_name = tz1090_pinctrl_get_group_name, + .get_group_pins = tz1090_pinctrl_get_group_pins, +#ifdef CONFIG_DEBUG_FS + .pin_dbg_show = tz1090_pinctrl_pin_dbg_show, +#endif + .dt_node_to_map = tz1090_pinctrl_dt_node_to_map, + .dt_free_map = tz1090_pinctrl_dt_free_map, +}; + +/* + * Pin mux operations + */ + +static int tz1090_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(tz1090_functions); +} + +static const char *tz1090_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + return tz1090_functions[function].name; +} + +static int tz1090_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const num_groups) +{ + /* pingroup functions */ + *groups = tz1090_functions[function].groups; + *num_groups = tz1090_functions[function].ngroups; + return 0; +} + +/** + * tz1090_pinctrl_select() - update bit in SELECT register + * @pmx: Pinmux data + * @pin: Pin number (must be within GPIO range) + */ +static void tz1090_pinctrl_select(struct tz1090_pmx *pmx, + unsigned int pin) +{ + u32 reg, reg_shift, select, val; + unsigned int pmx_index, pmx_shift; + unsigned long flags; + + /* uses base 32 instead of base 30 */ + pmx_index = pin >> 5; + pmx_shift = pin & 0x1f; + + /* select = !perip || gpio */ + select = ((~pmx->pin_en[pmx_index] | + pmx->gpio_en[pmx_index]) >> pmx_shift) & 1; + + /* find register and bit offset (base 30) */ + reg = REG_PINCTRL_SELECT + 4*(pin / 30); + reg_shift = pin % 30; + + /* modify gpio select bit */ + __global_lock2(flags); + val = pmx_read(pmx, reg); + val &= ~BIT(reg_shift); + val |= select << reg_shift; + pmx_write(pmx, val, reg); + __global_unlock2(flags); +} + +/** + * tz1090_pinctrl_gpio_select() - enable/disable GPIO usage for a pin + * @pmx: Pinmux data + * @pin: Pin number + * @gpio_select: true to enable pin as GPIO, + * false to leave control to whatever function is enabled + * + * Records that GPIO usage is enabled/disabled so that enabling a function + * doesn't override the SELECT register bit. + */ +static void tz1090_pinctrl_gpio_select(struct tz1090_pmx *pmx, + unsigned int pin, + bool gpio_select) +{ + unsigned int index, shift; + u32 gpio_en; + + if (pin >= NUM_GPIOS) + return; + + /* uses base 32 instead of base 30 */ + index = pin >> 5; + shift = pin & 0x1f; + + spin_lock(&pmx->lock); + + /* keep a record whether gpio is selected */ + gpio_en = pmx->gpio_en[index]; + gpio_en &= ~BIT(shift); + if (gpio_select) + gpio_en |= BIT(shift); + pmx->gpio_en[index] = gpio_en; + + /* update the select bit */ + tz1090_pinctrl_select(pmx, pin); + + spin_unlock(&pmx->lock); +} + +/** + * tz1090_pinctrl_perip_select() - enable/disable peripheral interface for a pin + * @pmx: Pinmux data + * @pin: Pin number + * @perip_select: true to enable peripheral interface when not GPIO, + * false to leave pin in GPIO mode + * + * Records that peripheral usage is enabled/disabled so that SELECT register can + * be set appropriately when GPIO is disabled. + */ +static void tz1090_pinctrl_perip_select(struct tz1090_pmx *pmx, + unsigned int pin, + bool perip_select) +{ + unsigned int index, shift; + u32 pin_en; + + if (pin >= NUM_GPIOS) + return; + + /* uses base 32 instead of base 30 */ + index = pin >> 5; + shift = pin & 0x1f; + + spin_lock(&pmx->lock); + + /* keep a record whether peripheral is selected */ + pin_en = pmx->pin_en[index]; + pin_en &= ~BIT(shift); + if (perip_select) + pin_en |= BIT(shift); + pmx->pin_en[index] = pin_en; + + /* update the select bit */ + tz1090_pinctrl_select(pmx, pin); + + spin_unlock(&pmx->lock); +} + +/** + * tz1090_pinctrl_enable_mux() - Switch a pin mux group to a function. + * @pmx: Pinmux data + * @desc: Pinmux description + * @function: Function to switch to + * + * Enable a particular function on a pin mux group. Since pin mux descriptions + * are nested this function is recursive. + */ +static int tz1090_pinctrl_enable_mux(struct tz1090_pmx *pmx, + const struct tz1090_muxdesc *desc, + unsigned int function) +{ + const int *fit; + unsigned long flags; + int mux; + unsigned int func, ret; + u32 reg, mask; + + /* find the mux value for this function, searching recursively */ + for (mux = 0, fit = desc->funcs; + mux < ARRAY_SIZE(desc->funcs); ++mux, ++fit) { + func = *fit; + if (func == function) + goto found_mux; + + /* maybe it's a sub-mux */ + if (func < ARRAY_SIZE(tz1090_submux) && tz1090_submux[func]) { + ret = tz1090_pinctrl_enable_mux(pmx, + tz1090_submux[func], + function); + if (!ret) + goto found_mux; + } + } + + return -EINVAL; +found_mux: + + /* Set up the mux */ + if (desc->width) { + mask = (BIT(desc->width) - 1) << desc->bit; + __global_lock2(flags); + reg = pmx_read(pmx, desc->reg); + reg &= ~mask; + reg |= (mux << desc->bit) & mask; + pmx_write(pmx, reg, desc->reg); + __global_unlock2(flags); + } + + return 0; +} + +/** + * tz1090_pinctrl_enable() - Enable a function on a pin group. + * @pctldev: Pin control data + * @function: Function index to enable + * @group: Group index to enable + * + * Enable a particular function on a group of pins. The per GPIO pin pseudo pin + * groups can be used (in which case the pin will be enabled in peripheral mode + * and if it belongs to a pin mux group the mux will be switched if it isn't + * already in use. Some convenience pin groups can also be used in which case + * the effect is the same as enabling the function on each individual pin in the + * group. + */ +static int tz1090_pinctrl_enable(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct tz1090_pingroup *grp; + int ret; + unsigned int pin_num, mux_group, i, npins; + const unsigned int *pins; + + /* group of pins? */ + if (group < ARRAY_SIZE(tz1090_groups)) { + grp = &tz1090_groups[group]; + npins = grp->npins; + pins = grp->pins; + /* + * All pins in the group must belong to the same mux group, + * which allows us to just use the mux group of the first pin. + * By explicitly listing permitted pingroups for each function + * the pinmux core should ensure this is always the case. + */ + } else { + pin_num = group - ARRAY_SIZE(tz1090_groups); + npins = 1; + pins = &pin_num; + } + mux_group = tz1090_mux_pins[*pins]; + + /* no mux group, but can still be individually muxed to peripheral */ + if (mux_group >= TZ1090_MUX_GROUP_MAX) { + if (function == TZ1090_MUX_PERIP) + goto mux_pins; + return -EINVAL; + } + + /* mux group already set to a different function? */ + grp = &tz1090_mux_groups[mux_group]; + if (grp->func_count && grp->func != function) { + dev_err(pctldev->dev, + "%s: can't mux pin(s) to '%s', group already muxed to '%s'\n", + __func__, tz1090_functions[function].name, + tz1090_functions[grp->func].name); + return -EBUSY; + } + + dev_dbg(pctldev->dev, "%s: muxing %u pin(s) in '%s' to '%s'\n", + __func__, npins, grp->name, tz1090_functions[function].name); + + /* if first pin in mux group to be enabled, enable the group mux */ + if (!grp->func_count) { + grp->func = function; + ret = tz1090_pinctrl_enable_mux(pmx, &grp->mux, function); + if (ret) + return ret; + } + /* add pins to ref count and mux individually to peripheral */ + grp->func_count += npins; +mux_pins: + for (i = 0; i < npins; ++i) + tz1090_pinctrl_perip_select(pmx, pins[i], true); + + return 0; +} + +/** + * tz1090_pinctrl_disable() - Disable a function on a pin group. + * @pctldev: Pin control data + * @function: Function index to disable + * @group: Group index to disable + * + * Disable a particular function on a group of pins. The per GPIO pin pseudo pin + * groups can be used (in which case the pin will be taken out of peripheral + * mode. Some convenience pin groups can also be used in which case the effect + * is the same as enabling the function on each individual pin in the group. + */ +static void tz1090_pinctrl_disable(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct tz1090_pingroup *grp; + unsigned int pin_num, mux_group, i, npins; + const unsigned int *pins; + + /* group of pins? */ + if (group < ARRAY_SIZE(tz1090_groups)) { + grp = &tz1090_groups[group]; + npins = grp->npins; + pins = grp->pins; + /* + * All pins in the group must belong to the same mux group, + * which allows us to just use the mux group of the first pin. + * By explicitly listing permitted pingroups for each function + * the pinmux core should ensure this is always the case. + */ + } else { + pin_num = group - ARRAY_SIZE(tz1090_groups); + npins = 1; + pins = &pin_num; + } + mux_group = tz1090_mux_pins[*pins]; + + /* no mux group, but can still be individually muxed to peripheral */ + if (mux_group >= TZ1090_MUX_GROUP_MAX) { + if (function == TZ1090_MUX_PERIP) + goto unmux_pins; + return; + } + + /* mux group already set to a different function? */ + grp = &tz1090_mux_groups[mux_group]; + dev_dbg(pctldev->dev, "%s: unmuxing %u pin(s) in '%s' from '%s'\n", + __func__, npins, grp->name, tz1090_functions[function].name); + + /* subtract pins from ref count and unmux individually */ + WARN_ON(grp->func_count < npins); + grp->func_count -= npins; +unmux_pins: + for (i = 0; i < npins; ++i) + tz1090_pinctrl_perip_select(pmx, pins[i], false); +} + +/** + * tz1090_pinctrl_gpio_request_enable() - Put pin in GPIO mode. + * @pctldev: Pin control data + * @range: GPIO range + * @pin: Pin number + * + * Puts a particular pin into GPIO mode, disabling peripheral control until it's + * disabled again. + */ +static int tz1090_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + tz1090_pinctrl_gpio_select(pmx, pin, true); + return 0; +} + +/** + * tz1090_pinctrl_gpio_disable_free() - Take pin out of GPIO mode. + * @pctldev: Pin control data + * @range: GPIO range + * @pin: Pin number + * + * Take a particular pin out of GPIO mode. If the pin is enabled for a + * peripheral it will return to peripheral mode. + */ +static void tz1090_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + tz1090_pinctrl_gpio_select(pmx, pin, false); +} + +static struct pinmux_ops tz1090_pinmux_ops = { + .get_functions_count = tz1090_pinctrl_get_funcs_count, + .get_function_name = tz1090_pinctrl_get_func_name, + .get_function_groups = tz1090_pinctrl_get_func_groups, + .enable = tz1090_pinctrl_enable, + .disable = tz1090_pinctrl_disable, + .gpio_request_enable = tz1090_pinctrl_gpio_request_enable, + .gpio_disable_free = tz1090_pinctrl_gpio_disable_free, +}; + +/* + * Pin config operations + */ + +struct tz1090_pinconf_pullup { + unsigned char index; + unsigned char shift; +}; + +/* The mapping of pin to pull up/down register index and shift */ +static struct tz1090_pinconf_pullup tz1090_pinconf_pullup[] = { + {5, 22}, /* 0 - TZ1090_PIN_SDIO_CLK */ + {0, 14}, /* 1 - TZ1090_PIN_SDIO_CMD */ + {0, 6}, /* 2 - TZ1090_PIN_SDIO_D0 */ + {0, 8}, /* 3 - TZ1090_PIN_SDIO_D1 */ + {0, 10}, /* 4 - TZ1090_PIN_SDIO_D2 */ + {0, 12}, /* 5 - TZ1090_PIN_SDIO_D3 */ + {0, 2}, /* 6 - TZ1090_PIN_SDH_CD */ + {0, 4}, /* 7 - TZ1090_PIN_SDH_WP */ + {0, 16}, /* 8 - TZ1090_PIN_SPI0_MCLK */ + {0, 18}, /* 9 - TZ1090_PIN_SPI0_CS0 */ + {0, 20}, /* 10 - TZ1090_PIN_SPI0_CS1 */ + {0, 22}, /* 11 - TZ1090_PIN_SPI0_CS2 */ + {0, 24}, /* 12 - TZ1090_PIN_SPI0_DOUT */ + {0, 26}, /* 13 - TZ1090_PIN_SPI0_DIN */ + {0, 28}, /* 14 - TZ1090_PIN_SPI1_MCLK */ + {0, 30}, /* 15 - TZ1090_PIN_SPI1_CS0 */ + {1, 0}, /* 16 - TZ1090_PIN_SPI1_CS1 */ + {1, 2}, /* 17 - TZ1090_PIN_SPI1_CS2 */ + {1, 4}, /* 18 - TZ1090_PIN_SPI1_DOUT */ + {1, 6}, /* 19 - TZ1090_PIN_SPI1_DIN */ + {1, 8}, /* 20 - TZ1090_PIN_UART0_RXD */ + {1, 10}, /* 21 - TZ1090_PIN_UART0_TXD */ + {1, 12}, /* 22 - TZ1090_PIN_UART0_CTS */ + {1, 14}, /* 23 - TZ1090_PIN_UART0_RTS */ + {1, 16}, /* 24 - TZ1090_PIN_UART1_RXD */ + {1, 18}, /* 25 - TZ1090_PIN_UART1_TXD */ + {1, 20}, /* 26 - TZ1090_PIN_SCB0_SDAT */ + {1, 22}, /* 27 - TZ1090_PIN_SCB0_SCLK */ + {1, 24}, /* 28 - TZ1090_PIN_SCB1_SDAT */ + {1, 26}, /* 29 - TZ1090_PIN_SCB1_SCLK */ + + {1, 28}, /* 30 - TZ1090_PIN_SCB2_SDAT */ + {1, 30}, /* 31 - TZ1090_PIN_SCB2_SCLK */ + {2, 0}, /* 32 - TZ1090_PIN_I2S_MCLK */ + {2, 2}, /* 33 - TZ1090_PIN_I2S_BCLK_OUT */ + {2, 4}, /* 34 - TZ1090_PIN_I2S_LRCLK_OUT */ + {2, 6}, /* 35 - TZ1090_PIN_I2S_DOUT0 */ + {2, 8}, /* 36 - TZ1090_PIN_I2S_DOUT1 */ + {2, 10}, /* 37 - TZ1090_PIN_I2S_DOUT2 */ + {2, 12}, /* 38 - TZ1090_PIN_I2S_DIN */ + {4, 12}, /* 39 - TZ1090_PIN_PDM_A */ + {4, 14}, /* 40 - TZ1090_PIN_PDM_B */ + {4, 18}, /* 41 - TZ1090_PIN_PDM_C */ + {4, 20}, /* 42 - TZ1090_PIN_PDM_D */ + {2, 14}, /* 43 - TZ1090_PIN_TFT_RED0 */ + {2, 16}, /* 44 - TZ1090_PIN_TFT_RED1 */ + {2, 18}, /* 45 - TZ1090_PIN_TFT_RED2 */ + {2, 20}, /* 46 - TZ1090_PIN_TFT_RED3 */ + {2, 22}, /* 47 - TZ1090_PIN_TFT_RED4 */ + {2, 24}, /* 48 - TZ1090_PIN_TFT_RED5 */ + {2, 26}, /* 49 - TZ1090_PIN_TFT_RED6 */ + {2, 28}, /* 50 - TZ1090_PIN_TFT_RED7 */ + {2, 30}, /* 51 - TZ1090_PIN_TFT_GREEN0 */ + {3, 0}, /* 52 - TZ1090_PIN_TFT_GREEN1 */ + {3, 2}, /* 53 - TZ1090_PIN_TFT_GREEN2 */ + {3, 4}, /* 54 - TZ1090_PIN_TFT_GREEN3 */ + {3, 6}, /* 55 - TZ1090_PIN_TFT_GREEN4 */ + {3, 8}, /* 56 - TZ1090_PIN_TFT_GREEN5 */ + {3, 10}, /* 57 - TZ1090_PIN_TFT_GREEN6 */ + {3, 12}, /* 58 - TZ1090_PIN_TFT_GREEN7 */ + {3, 14}, /* 59 - TZ1090_PIN_TFT_BLUE0 */ + + {3, 16}, /* 60 - TZ1090_PIN_TFT_BLUE1 */ + {3, 18}, /* 61 - TZ1090_PIN_TFT_BLUE2 */ + {3, 20}, /* 62 - TZ1090_PIN_TFT_BLUE3 */ + {3, 22}, /* 63 - TZ1090_PIN_TFT_BLUE4 */ + {3, 24}, /* 64 - TZ1090_PIN_TFT_BLUE5 */ + {3, 26}, /* 65 - TZ1090_PIN_TFT_BLUE6 */ + {3, 28}, /* 66 - TZ1090_PIN_TFT_BLUE7 */ + {3, 30}, /* 67 - TZ1090_PIN_TFT_VDDEN_GD */ + {4, 0}, /* 68 - TZ1090_PIN_TFT_PANELCLK */ + {4, 2}, /* 69 - TZ1090_PIN_TFT_BLANK_LS */ + {4, 4}, /* 70 - TZ1090_PIN_TFT_VSYNC_NS */ + {4, 6}, /* 71 - TZ1090_PIN_TFT_HSYNC_NR */ + {4, 8}, /* 72 - TZ1090_PIN_TFT_VD12ACB */ + {4, 10}, /* 73 - TZ1090_PIN_TFT_PWRSAVE */ + {4, 24}, /* 74 - TZ1090_PIN_TX_ON */ + {4, 26}, /* 75 - TZ1090_PIN_RX_ON */ + {4, 28}, /* 76 - TZ1090_PIN_PLL_ON */ + {4, 30}, /* 77 - TZ1090_PIN_PA_ON */ + {5, 0}, /* 78 - TZ1090_PIN_RX_HP */ + {5, 6}, /* 79 - TZ1090_PIN_GAIN0 */ + {5, 8}, /* 80 - TZ1090_PIN_GAIN1 */ + {5, 10}, /* 81 - TZ1090_PIN_GAIN2 */ + {5, 12}, /* 82 - TZ1090_PIN_GAIN3 */ + {5, 14}, /* 83 - TZ1090_PIN_GAIN4 */ + {5, 16}, /* 84 - TZ1090_PIN_GAIN5 */ + {5, 18}, /* 85 - TZ1090_PIN_GAIN6 */ + {5, 20}, /* 86 - TZ1090_PIN_GAIN7 */ + {5, 2}, /* 87 - TZ1090_PIN_ANT_SEL0 */ + {5, 4}, /* 88 - TZ1090_PIN_ANT_SEL1 */ + {0, 0}, /* 89 - TZ1090_PIN_SDH_CLK_IN */ + + {5, 24}, /* 90 - TZ1090_PIN_TCK */ + {5, 26}, /* 91 - TZ1090_PIN_TRST */ + {5, 28}, /* 92 - TZ1090_PIN_TDI */ + {5, 30}, /* 93 - TZ1090_PIN_TDO */ + {6, 0}, /* 94 - TZ1090_PIN_TMS */ + {4, 16}, /* 95 - TZ1090_PIN_CLK_OUT0 */ + {4, 22}, /* 96 - TZ1090_PIN_CLK_OUT1 */ +}; + +static int tz1090_pinconf_reg(struct pinctrl_dev *pctldev, + unsigned int pin, + enum pin_config_param param, + bool report_err, + u32 *reg, u32 *width, u32 *mask, u32 *shift, + u32 *val) +{ + struct tz1090_pinconf_pullup *pu; + + /* All supported pins have controllable input bias */ + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + *val = REG_PU_PD_TRISTATE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + *val = REG_PU_PD_UP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + *val = REG_PU_PD_DOWN; + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + *val = REG_PU_PD_REPEATER; + break; + default: + return -ENOTSUPP; + }; + + /* Only input bias parameters supported */ + pu = &tz1090_pinconf_pullup[pin]; + *reg = REG_PINCTRL_PU_PD + 4*pu->index; + *shift = pu->shift; + *width = 2; + + /* Calculate field information */ + *mask = (BIT(*width) - 1) << *shift; + + return 0; +} + +static int tz1090_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + int ret; + u32 reg, width, mask, shift, val, tmp, arg; + + /* Get register information */ + ret = tz1090_pinconf_reg(pctldev, pin, param, true, + ®, &width, &mask, &shift, &val); + if (ret < 0) + return ret; + + /* Extract field from register */ + tmp = pmx_read(pmx, reg); + arg = ((tmp & mask) >> shift) == val; + + /* Config not active */ + if (!arg) + return -EINVAL; + + /* And pack config */ + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int tz1090_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long config) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); + int ret; + u32 reg, width, mask, shift, val, tmp; + unsigned long flags; + + dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", + __func__, tz1090_pins[pin].name, config); + + /* Get register information */ + ret = tz1090_pinconf_reg(pctldev, pin, param, true, + ®, &width, &mask, &shift, &val); + if (ret < 0) + return ret; + + /* Unpack argument and range check it */ + if (arg > 1) { + dev_dbg(pctldev->dev, "%s: arg %u out of range\n", + __func__, arg); + return -EINVAL; + } + + /* Write register field */ + __global_lock2(flags); + tmp = pmx_read(pmx, reg); + tmp &= ~mask; + if (arg) + tmp |= val << shift; + pmx_write(pmx, tmp, reg); + __global_unlock2(flags); + + return 0; +} + +static const int tz1090_boolean_map[] = { + [0] = -EINVAL, + [1] = 1, +}; + +static const int tz1090_dr_map[] = { + [REG_DR_2mA] = 2, + [REG_DR_4mA] = 4, + [REG_DR_8mA] = 8, + [REG_DR_12mA] = 12, +}; + +static int tz1090_pinconf_group_reg(struct pinctrl_dev *pctldev, + const struct tz1090_pingroup *g, + enum pin_config_param param, + bool report_err, + u32 *reg, u32 *width, u32 *mask, u32 *shift, + const int **map) +{ + /* Drive configuration applies in groups, but not to all groups. */ + if (!g->drv) { + if (report_err) + dev_dbg(pctldev->dev, + "%s: group %s has no drive control\n", + __func__, g->name); + return -ENOTSUPP; + } + + /* Find information about drive parameter's register */ + switch (param) { + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + *reg = REG_PINCTRL_SCHMITT; + *width = 1; + *map = tz1090_boolean_map; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + *reg = REG_PINCTRL_DR; + *width = 2; + *map = tz1090_dr_map; + break; + default: + return -ENOTSUPP; + }; + + /* Calculate field information */ + *shift = g->slw_bit * *width; + *mask = (BIT(*width) - 1) << *shift; + + return 0; +} + +static int tz1090_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *config) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pingroup *g; + enum pin_config_param param = pinconf_to_config_param(*config); + int ret, arg; + unsigned int pin; + u32 reg, width, mask, shift, val; + const int *map; + + if (group >= ARRAY_SIZE(tz1090_groups)) { + pin = group - ARRAY_SIZE(tz1090_groups); + return tz1090_pinconf_get(pctldev, pin, config); + } + + g = &tz1090_groups[group]; + if (g->npins == 1) { + pin = g->pins[0]; + ret = tz1090_pinconf_get(pctldev, pin, config); + if (ret != -ENOTSUPP) + return ret; + } + + /* Get register information */ + ret = tz1090_pinconf_group_reg(pctldev, g, param, true, + ®, &width, &mask, &shift, &map); + if (ret < 0) + return ret; + + /* Extract field from register */ + val = pmx_read(pmx, reg); + arg = map[(val & mask) >> shift]; + if (arg < 0) + return arg; + + /* And pack config */ + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long config) +{ + struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tz1090_pingroup *g; + enum pin_config_param param = pinconf_to_config_param(config); + unsigned int arg, pin, i; + const unsigned int *pit; + int ret; + u32 reg, width, mask, shift, val; + unsigned long flags; + const int *map; + + if (group >= ARRAY_SIZE(tz1090_groups)) { + pin = group - ARRAY_SIZE(tz1090_groups); + return tz1090_pinconf_set(pctldev, pin, config); + } + + g = &tz1090_groups[group]; + if (g->npins == 1) { + pin = g->pins[0]; + ret = tz1090_pinconf_set(pctldev, pin, config); + if (ret != -ENOTSUPP) + return ret; + } + + dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", + __func__, g->name, config); + + /* Get register information */ + ret = tz1090_pinconf_group_reg(pctldev, g, param, true, + ®, &width, &mask, &shift, &map); + if (ret < 0) { + /* + * Maybe we're trying to set a per-pin configuration of a group, + * so do the pins one by one. This is mainly as a convenience. + */ + for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) { + ret = tz1090_pinconf_set(pctldev, *pit, config); + if (ret) + return ret; + } + return 0; + } + + /* Unpack argument and map it to register value */ + arg = pinconf_to_config_argument(config); + for (i = 0; i < BIT(width); ++i) { + if (map[i] == arg || (map[i] == -EINVAL && !arg)) { + /* Write register field */ + __global_lock2(flags); + val = pmx_read(pmx, reg); + val &= ~mask; + val |= i << shift; + pmx_write(pmx, val, reg); + __global_unlock2(flags); + return 0; + } + } + + dev_dbg(pctldev->dev, "%s: arg %u not supported\n", + __func__, arg); + return -EINVAL; +} + +static struct pinconf_ops tz1090_pinconf_ops = { + .is_generic = true, + .pin_config_get = tz1090_pinconf_get, + .pin_config_set = tz1090_pinconf_set, + .pin_config_group_get = tz1090_pinconf_group_get, + .pin_config_group_set = tz1090_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +/* + * Pin control driver setup + */ + +static struct pinctrl_desc tz1090_pinctrl_desc = { + .pctlops = &tz1090_pinctrl_ops, + .pmxops = &tz1090_pinmux_ops, + .confops = &tz1090_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int tz1090_pinctrl_probe(struct platform_device *pdev) +{ + struct tz1090_pmx *pmx; + struct resource *res; + + pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); + if (!pmx) { + dev_err(&pdev->dev, "Can't alloc tz1090_pmx\n"); + return -ENOMEM; + } + pmx->dev = &pdev->dev; + spin_lock_init(&pmx->lock); + + tz1090_pinctrl_desc.name = dev_name(&pdev->dev); + tz1090_pinctrl_desc.pins = tz1090_pins; + tz1090_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pins); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing MEM resource\n"); + return -ENODEV; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, + "Couldn't request MEM resource\n"); + return -ENODEV; + } + + pmx->regs = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pmx->regs) { + dev_err(&pdev->dev, "Couldn't ioremap regs\n"); + return -ENODEV; + } + + pmx->pctl = pinctrl_register(&tz1090_pinctrl_desc, &pdev->dev, pmx); + if (!pmx->pctl) { + dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, pmx); + + dev_info(&pdev->dev, "TZ1090 pinctrl driver initialised\n"); + + return 0; +} + +static int tz1090_pinctrl_remove(struct platform_device *pdev) +{ + struct tz1090_pmx *pmx = platform_get_drvdata(pdev); + + pinctrl_unregister(pmx->pctl); + + return 0; +} + +static struct of_device_id tz1090_pinctrl_of_match[] = { + { .compatible = "img,tz1090-pinctrl", }, + { }, +}; + +static struct platform_driver tz1090_pinctrl_driver = { + .driver = { + .name = "tz1090-pinctrl", + .owner = THIS_MODULE, + .of_match_table = tz1090_pinctrl_of_match, + }, + .probe = tz1090_pinctrl_probe, + .remove = tz1090_pinctrl_remove, +}; + +static int __init tz1090_pinctrl_init(void) +{ + tz1090_init_mux_pins(); + return platform_driver_register(&tz1090_pinctrl_driver); +} +arch_initcall(tz1090_pinctrl_init); + +static void __exit tz1090_pinctrl_exit(void) +{ + platform_driver_unregister(&tz1090_pinctrl_driver); +} +module_exit(tz1090_pinctrl_exit); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION("Toumaz Xenif TZ1090 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, tz1090_pinctrl_of_match); diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 06bfa09bb15..46a152d1735 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -1100,7 +1100,6 @@ static int u300_pmx_remove(struct platform_device *pdev) struct u300_pmx *upmx = platform_get_drvdata(pdev); pinctrl_unregister(upmx->pctl); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/pinctrl/pinctrl-vf610.c b/drivers/pinctrl/pinctrl-vf610.c new file mode 100644 index 00000000000..68a970b1dbc --- /dev/null +++ b/drivers/pinctrl/pinctrl-vf610.c @@ -0,0 +1,338 @@ +/* + * VF610 pinctrl driver based on imx pinmux and pinconf core + * + * Copyright 2013 Freescale Semiconductor, Inc. + * + * 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/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-imx.h" + +enum vf610_pads { + VF610_PAD_PTA6 = 0, + VF610_PAD_PTA8 = 1, + VF610_PAD_PTA9 = 2, + VF610_PAD_PTA10 = 3, + VF610_PAD_PTA11 = 4, + VF610_PAD_PTA12 = 5, + VF610_PAD_PTA16 = 6, + VF610_PAD_PTA17 = 7, + VF610_PAD_PTA18 = 8, + VF610_PAD_PTA19 = 9, + VF610_PAD_PTA20 = 10, + VF610_PAD_PTA21 = 11, + VF610_PAD_PTA22 = 12, + VF610_PAD_PTA23 = 13, + VF610_PAD_PTA24 = 14, + VF610_PAD_PTA25 = 15, + VF610_PAD_PTA26 = 16, + VF610_PAD_PTA27 = 17, + VF610_PAD_PTA28 = 18, + VF610_PAD_PTA29 = 19, + VF610_PAD_PTA30 = 20, + VF610_PAD_PTA31 = 21, + VF610_PAD_PTB0 = 22, + VF610_PAD_PTB1 = 23, + VF610_PAD_PTB2 = 24, + VF610_PAD_PTB3 = 25, + VF610_PAD_PTB4 = 26, + VF610_PAD_PTB5 = 27, + VF610_PAD_PTB6 = 28, + VF610_PAD_PTB7 = 29, + VF610_PAD_PTB8 = 30, + VF610_PAD_PTB9 = 31, + VF610_PAD_PTB10 = 32, + VF610_PAD_PTB11 = 33, + VF610_PAD_PTB12 = 34, + VF610_PAD_PTB13 = 35, + VF610_PAD_PTB14 = 36, + VF610_PAD_PTB15 = 37, + VF610_PAD_PTB16 = 38, + VF610_PAD_PTB17 = 39, + VF610_PAD_PTB18 = 40, + VF610_PAD_PTB19 = 41, + VF610_PAD_PTB20 = 42, + VF610_PAD_PTB21 = 43, + VF610_PAD_PTB22 = 44, + VF610_PAD_PTC0 = 45, + VF610_PAD_PTC1 = 46, + VF610_PAD_PTC2 = 47, + VF610_PAD_PTC3 = 48, + VF610_PAD_PTC4 = 49, + VF610_PAD_PTC5 = 50, + VF610_PAD_PTC6 = 51, + VF610_PAD_PTC7 = 52, + VF610_PAD_PTC8 = 53, + VF610_PAD_PTC9 = 54, + VF610_PAD_PTC10 = 55, + VF610_PAD_PTC11 = 56, + VF610_PAD_PTC12 = 57, + VF610_PAD_PTC13 = 58, + VF610_PAD_PTC14 = 59, + VF610_PAD_PTC15 = 60, + VF610_PAD_PTC16 = 61, + VF610_PAD_PTC17 = 62, + VF610_PAD_PTD31 = 63, + VF610_PAD_PTD30 = 64, + VF610_PAD_PTD29 = 65, + VF610_PAD_PTD28 = 66, + VF610_PAD_PTD27 = 67, + VF610_PAD_PTD26 = 68, + VF610_PAD_PTD25 = 69, + VF610_PAD_PTD24 = 70, + VF610_PAD_PTD23 = 71, + VF610_PAD_PTD22 = 72, + VF610_PAD_PTD21 = 73, + VF610_PAD_PTD20 = 74, + VF610_PAD_PTD19 = 75, + VF610_PAD_PTD18 = 76, + VF610_PAD_PTD17 = 77, + VF610_PAD_PTD16 = 78, + VF610_PAD_PTD0 = 79, + VF610_PAD_PTD1 = 80, + VF610_PAD_PTD2 = 81, + VF610_PAD_PTD3 = 82, + VF610_PAD_PTD4 = 83, + VF610_PAD_PTD5 = 84, + VF610_PAD_PTD6 = 85, + VF610_PAD_PTD7 = 86, + VF610_PAD_PTD8 = 87, + VF610_PAD_PTD9 = 88, + VF610_PAD_PTD10 = 89, + VF610_PAD_PTD11 = 90, + VF610_PAD_PTD12 = 91, + VF610_PAD_PTD13 = 92, + VF610_PAD_PTB23 = 93, + VF610_PAD_PTB24 = 94, + VF610_PAD_PTB25 = 95, + VF610_PAD_PTB26 = 96, + VF610_PAD_PTB27 = 97, + VF610_PAD_PTB28 = 98, + VF610_PAD_PTC26 = 99, + VF610_PAD_PTC27 = 100, + VF610_PAD_PTC28 = 101, + VF610_PAD_PTC29 = 102, + VF610_PAD_PTC30 = 103, + VF610_PAD_PTC31 = 104, + VF610_PAD_PTE0 = 105, + VF610_PAD_PTE1 = 106, + VF610_PAD_PTE2 = 107, + VF610_PAD_PTE3 = 108, + VF610_PAD_PTE4 = 109, + VF610_PAD_PTE5 = 110, + VF610_PAD_PTE6 = 111, + VF610_PAD_PTE7 = 112, + VF610_PAD_PTE8 = 113, + VF610_PAD_PTE9 = 114, + VF610_PAD_PTE10 = 115, + VF610_PAD_PTE11 = 116, + VF610_PAD_PTE12 = 117, + VF610_PAD_PTE13 = 118, + VF610_PAD_PTE14 = 119, + VF610_PAD_PTE15 = 120, + VF610_PAD_PTE16 = 121, + VF610_PAD_PTE17 = 122, + VF610_PAD_PTE18 = 123, + VF610_PAD_PTE19 = 124, + VF610_PAD_PTE20 = 125, + VF610_PAD_PTE21 = 126, + VF610_PAD_PTE22 = 127, + VF610_PAD_PTE23 = 128, + VF610_PAD_PTE24 = 129, + VF610_PAD_PTE25 = 130, + VF610_PAD_PTE26 = 131, + VF610_PAD_PTE27 = 132, + VF610_PAD_PTE28 = 133, + VF610_PAD_PTA7 = 134, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = { + IMX_PINCTRL_PIN(VF610_PAD_PTA6), + IMX_PINCTRL_PIN(VF610_PAD_PTA8), + IMX_PINCTRL_PIN(VF610_PAD_PTA9), + IMX_PINCTRL_PIN(VF610_PAD_PTA10), + IMX_PINCTRL_PIN(VF610_PAD_PTA11), + IMX_PINCTRL_PIN(VF610_PAD_PTA12), + IMX_PINCTRL_PIN(VF610_PAD_PTA16), + IMX_PINCTRL_PIN(VF610_PAD_PTA17), + IMX_PINCTRL_PIN(VF610_PAD_PTA18), + IMX_PINCTRL_PIN(VF610_PAD_PTA19), + IMX_PINCTRL_PIN(VF610_PAD_PTA20), + IMX_PINCTRL_PIN(VF610_PAD_PTA21), + IMX_PINCTRL_PIN(VF610_PAD_PTA22), + IMX_PINCTRL_PIN(VF610_PAD_PTA23), + IMX_PINCTRL_PIN(VF610_PAD_PTA24), + IMX_PINCTRL_PIN(VF610_PAD_PTA25), + IMX_PINCTRL_PIN(VF610_PAD_PTA26), + IMX_PINCTRL_PIN(VF610_PAD_PTA27), + IMX_PINCTRL_PIN(VF610_PAD_PTA28), + IMX_PINCTRL_PIN(VF610_PAD_PTA29), + IMX_PINCTRL_PIN(VF610_PAD_PTA30), + IMX_PINCTRL_PIN(VF610_PAD_PTA31), + IMX_PINCTRL_PIN(VF610_PAD_PTB0), + IMX_PINCTRL_PIN(VF610_PAD_PTB1), + IMX_PINCTRL_PIN(VF610_PAD_PTB2), + IMX_PINCTRL_PIN(VF610_PAD_PTB3), + IMX_PINCTRL_PIN(VF610_PAD_PTB4), + IMX_PINCTRL_PIN(VF610_PAD_PTB5), + IMX_PINCTRL_PIN(VF610_PAD_PTB6), + IMX_PINCTRL_PIN(VF610_PAD_PTB7), + IMX_PINCTRL_PIN(VF610_PAD_PTB8), + IMX_PINCTRL_PIN(VF610_PAD_PTB9), + IMX_PINCTRL_PIN(VF610_PAD_PTB10), + IMX_PINCTRL_PIN(VF610_PAD_PTB11), + IMX_PINCTRL_PIN(VF610_PAD_PTB12), + IMX_PINCTRL_PIN(VF610_PAD_PTB13), + IMX_PINCTRL_PIN(VF610_PAD_PTB14), + IMX_PINCTRL_PIN(VF610_PAD_PTB15), + IMX_PINCTRL_PIN(VF610_PAD_PTB16), + IMX_PINCTRL_PIN(VF610_PAD_PTB17), + IMX_PINCTRL_PIN(VF610_PAD_PTB18), + IMX_PINCTRL_PIN(VF610_PAD_PTB19), + IMX_PINCTRL_PIN(VF610_PAD_PTB20), + IMX_PINCTRL_PIN(VF610_PAD_PTB21), + IMX_PINCTRL_PIN(VF610_PAD_PTB22), + IMX_PINCTRL_PIN(VF610_PAD_PTC0), + IMX_PINCTRL_PIN(VF610_PAD_PTC1), + IMX_PINCTRL_PIN(VF610_PAD_PTC2), + IMX_PINCTRL_PIN(VF610_PAD_PTC3), + IMX_PINCTRL_PIN(VF610_PAD_PTC4), + IMX_PINCTRL_PIN(VF610_PAD_PTC5), + IMX_PINCTRL_PIN(VF610_PAD_PTC6), + IMX_PINCTRL_PIN(VF610_PAD_PTC7), + IMX_PINCTRL_PIN(VF610_PAD_PTC8), + IMX_PINCTRL_PIN(VF610_PAD_PTC9), + IMX_PINCTRL_PIN(VF610_PAD_PTC10), + IMX_PINCTRL_PIN(VF610_PAD_PTC11), + IMX_PINCTRL_PIN(VF610_PAD_PTC12), + IMX_PINCTRL_PIN(VF610_PAD_PTC13), + IMX_PINCTRL_PIN(VF610_PAD_PTC14), + IMX_PINCTRL_PIN(VF610_PAD_PTC15), + IMX_PINCTRL_PIN(VF610_PAD_PTC16), + IMX_PINCTRL_PIN(VF610_PAD_PTC17), + IMX_PINCTRL_PIN(VF610_PAD_PTD31), + IMX_PINCTRL_PIN(VF610_PAD_PTD30), + IMX_PINCTRL_PIN(VF610_PAD_PTD29), + IMX_PINCTRL_PIN(VF610_PAD_PTD28), + IMX_PINCTRL_PIN(VF610_PAD_PTD27), + IMX_PINCTRL_PIN(VF610_PAD_PTD26), + IMX_PINCTRL_PIN(VF610_PAD_PTD25), + IMX_PINCTRL_PIN(VF610_PAD_PTD24), + IMX_PINCTRL_PIN(VF610_PAD_PTD23), + IMX_PINCTRL_PIN(VF610_PAD_PTD22), + IMX_PINCTRL_PIN(VF610_PAD_PTD21), + IMX_PINCTRL_PIN(VF610_PAD_PTD20), + IMX_PINCTRL_PIN(VF610_PAD_PTD19), + IMX_PINCTRL_PIN(VF610_PAD_PTD18), + IMX_PINCTRL_PIN(VF610_PAD_PTD17), + IMX_PINCTRL_PIN(VF610_PAD_PTD16), + IMX_PINCTRL_PIN(VF610_PAD_PTD0), + IMX_PINCTRL_PIN(VF610_PAD_PTD1), + IMX_PINCTRL_PIN(VF610_PAD_PTD2), + IMX_PINCTRL_PIN(VF610_PAD_PTD3), + IMX_PINCTRL_PIN(VF610_PAD_PTD4), + IMX_PINCTRL_PIN(VF610_PAD_PTD5), + IMX_PINCTRL_PIN(VF610_PAD_PTD6), + IMX_PINCTRL_PIN(VF610_PAD_PTD7), + IMX_PINCTRL_PIN(VF610_PAD_PTD8), + IMX_PINCTRL_PIN(VF610_PAD_PTD9), + IMX_PINCTRL_PIN(VF610_PAD_PTD10), + IMX_PINCTRL_PIN(VF610_PAD_PTD11), + IMX_PINCTRL_PIN(VF610_PAD_PTD12), + IMX_PINCTRL_PIN(VF610_PAD_PTD13), + IMX_PINCTRL_PIN(VF610_PAD_PTB23), + IMX_PINCTRL_PIN(VF610_PAD_PTB24), + IMX_PINCTRL_PIN(VF610_PAD_PTB25), + IMX_PINCTRL_PIN(VF610_PAD_PTB26), + IMX_PINCTRL_PIN(VF610_PAD_PTB27), + IMX_PINCTRL_PIN(VF610_PAD_PTB28), + IMX_PINCTRL_PIN(VF610_PAD_PTC26), + IMX_PINCTRL_PIN(VF610_PAD_PTC27), + IMX_PINCTRL_PIN(VF610_PAD_PTC28), + IMX_PINCTRL_PIN(VF610_PAD_PTC29), + IMX_PINCTRL_PIN(VF610_PAD_PTC30), + IMX_PINCTRL_PIN(VF610_PAD_PTC31), + IMX_PINCTRL_PIN(VF610_PAD_PTE0), + IMX_PINCTRL_PIN(VF610_PAD_PTE1), + IMX_PINCTRL_PIN(VF610_PAD_PTE2), + IMX_PINCTRL_PIN(VF610_PAD_PTE3), + IMX_PINCTRL_PIN(VF610_PAD_PTE4), + IMX_PINCTRL_PIN(VF610_PAD_PTE5), + IMX_PINCTRL_PIN(VF610_PAD_PTE6), + IMX_PINCTRL_PIN(VF610_PAD_PTE7), + IMX_PINCTRL_PIN(VF610_PAD_PTE8), + IMX_PINCTRL_PIN(VF610_PAD_PTE9), + IMX_PINCTRL_PIN(VF610_PAD_PTE10), + IMX_PINCTRL_PIN(VF610_PAD_PTE11), + IMX_PINCTRL_PIN(VF610_PAD_PTE12), + IMX_PINCTRL_PIN(VF610_PAD_PTE13), + IMX_PINCTRL_PIN(VF610_PAD_PTE14), + IMX_PINCTRL_PIN(VF610_PAD_PTE15), + IMX_PINCTRL_PIN(VF610_PAD_PTE16), + IMX_PINCTRL_PIN(VF610_PAD_PTE17), + IMX_PINCTRL_PIN(VF610_PAD_PTE18), + IMX_PINCTRL_PIN(VF610_PAD_PTE19), + IMX_PINCTRL_PIN(VF610_PAD_PTE20), + IMX_PINCTRL_PIN(VF610_PAD_PTE21), + IMX_PINCTRL_PIN(VF610_PAD_PTE22), + IMX_PINCTRL_PIN(VF610_PAD_PTE23), + IMX_PINCTRL_PIN(VF610_PAD_PTE24), + IMX_PINCTRL_PIN(VF610_PAD_PTE25), + IMX_PINCTRL_PIN(VF610_PAD_PTE26), + IMX_PINCTRL_PIN(VF610_PAD_PTE27), + IMX_PINCTRL_PIN(VF610_PAD_PTE28), + IMX_PINCTRL_PIN(VF610_PAD_PTA7), +}; + +static struct imx_pinctrl_soc_info vf610_pinctrl_info = { + .pins = vf610_pinctrl_pads, + .npins = ARRAY_SIZE(vf610_pinctrl_pads), + .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG, +}; + +static struct of_device_id vf610_pinctrl_of_match[] = { + { .compatible = "fsl,vf610-iomuxc", }, + { /* sentinel */ } +}; + +static int vf610_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &vf610_pinctrl_info); +} + +static struct platform_driver vf610_pinctrl_driver = { + .driver = { + .name = "vf610-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(vf610_pinctrl_of_match), + }, + .probe = vf610_pinctrl_probe, + .remove = imx_pinctrl_remove, +}; + +static int __init vf610_pinctrl_init(void) +{ + return platform_driver_register(&vf610_pinctrl_driver); +} +arch_initcall(vf610_pinctrl_init); + +static void __exit vf610_pinctrl_exit(void) +{ + platform_driver_unregister(&vf610_pinctrl_driver); +} +module_exit(vf610_pinctrl_exit); + +MODULE_DESCRIPTION("Freescale VF610 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 3b2fd43ff29..f3fc66b2437 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -18,6 +18,8 @@ #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/pinctrl/machine.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -348,14 +350,72 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id sh_pfc_of_table[] = { +#ifdef CONFIG_PINCTRL_PFC_R8A73A4 + { + .compatible = "renesas,pfc-r8a73a4", + .data = &r8a73a4_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_R8A7740 + { + .compatible = "renesas,pfc-r8a7740", + .data = &r8a7740_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_R8A7778 + { + .compatible = "renesas,pfc-r8a7778", + .data = &r8a7778_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_R8A7779 + { + .compatible = "renesas,pfc-r8a7779", + .data = &r8a7779_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_R8A7790 + { + .compatible = "renesas,pfc-r8a7790", + .data = &r8a7790_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_SH7372 + { + .compatible = "renesas,pfc-sh7372", + .data = &sh7372_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_SH73A0 + { + .compatible = "renesas,pfc-sh73a0", + .data = &sh73a0_pinmux_info, + }, +#endif + { }, +}; +MODULE_DEVICE_TABLE(of, sh_pfc_of_table); +#endif + static int sh_pfc_probe(struct platform_device *pdev) { + const struct platform_device_id *platid = platform_get_device_id(pdev); +#ifdef CONFIG_OF + struct device_node *np = pdev->dev.of_node; +#endif const struct sh_pfc_soc_info *info; struct sh_pfc *pfc; int ret; - info = pdev->id_entry->driver_data - ? (void *)pdev->id_entry->driver_data : pdev->dev.platform_data; +#ifdef CONFIG_OF + if (np) + info = of_match_device(sh_pfc_of_table, &pdev->dev)->data; + else +#endif + info = platid ? (const void *)platid->driver_data : NULL; + if (info == NULL) return -ENODEV; @@ -501,6 +561,7 @@ static struct platform_driver sh_pfc_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sh_pfc_of_table), }, }; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 3492ec9a33b..bc8b028bb5d 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -14,7 +14,9 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinctrl.h> @@ -72,11 +74,214 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, seq_printf(s, "%s", DRV_NAME); } +#ifdef CONFIG_OF +static int sh_pfc_map_add_config(struct pinctrl_map *map, + const char *group_or_pin, + enum pinctrl_map_type type, + unsigned long *configs, + unsigned int num_configs) +{ + unsigned long *cfgs; + + cfgs = kmemdup(configs, num_configs * sizeof(*cfgs), + GFP_KERNEL); + if (cfgs == NULL) + return -ENOMEM; + + map->type = type; + map->data.configs.group_or_pin = group_or_pin; + map->data.configs.configs = cfgs; + map->data.configs.num_configs = num_configs; + + return 0; +} + +static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps, unsigned int *index) +{ + struct pinctrl_map *maps = *map; + unsigned int nmaps = *num_maps; + unsigned int idx = *index; + unsigned int num_configs; + const char *function = NULL; + unsigned long *configs; + struct property *prop; + unsigned int num_groups; + unsigned int num_pins; + const char *group; + const char *pin; + int ret; + + /* Parse the function and configuration properties. At least a function + * or one configuration must be specified. + */ + ret = of_property_read_string(np, "renesas,function", &function); + if (ret < 0 && ret != -EINVAL) { + dev_err(dev, "Invalid function in DT\n"); + return ret; + } + + ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + if (ret < 0) + return ret; + + if (!function && num_configs == 0) { + dev_err(dev, + "DT node must contain at least a function or config\n"); + goto done; + } + + /* Count the number of pins and groups and reallocate mappings. */ + ret = of_property_count_strings(np, "renesas,pins"); + if (ret == -EINVAL) { + num_pins = 0; + } else if (ret < 0) { + dev_err(dev, "Invalid pins list in DT\n"); + goto done; + } else { + num_pins = ret; + } + + ret = of_property_count_strings(np, "renesas,groups"); + if (ret == -EINVAL) { + num_groups = 0; + } else if (ret < 0) { + dev_err(dev, "Invalid pin groups list in DT\n"); + goto done; + } else { + num_groups = ret; + } + + if (!num_pins && !num_groups) { + dev_err(dev, "No pin or group provided in DT node\n"); + ret = -ENODEV; + goto done; + } + + if (function) + nmaps += num_groups; + if (configs) + nmaps += num_pins + num_groups; + + maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL); + if (maps == NULL) { + ret = -ENOMEM; + goto done; + } + + *map = maps; + *num_maps = nmaps; + + /* Iterate over pins and groups and create the mappings. */ + of_property_for_each_string(np, "renesas,groups", prop, group) { + if (function) { + maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; + maps[idx].data.mux.group = group; + maps[idx].data.mux.function = function; + idx++; + } + + if (configs) { + ret = sh_pfc_map_add_config(&maps[idx], group, + PIN_MAP_TYPE_CONFIGS_GROUP, + configs, num_configs); + if (ret < 0) + goto done; + + idx++; + } + } + + if (!configs) { + ret = 0; + goto done; + } + + of_property_for_each_string(np, "renesas,pins", prop, pin) { + ret = sh_pfc_map_add_config(&maps[idx], pin, + PIN_MAP_TYPE_CONFIGS_PIN, + configs, num_configs); + if (ret < 0) + goto done; + + idx++; + } + +done: + *index = idx; + kfree(configs); + return ret; +} + +static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + unsigned int i; + + if (map == NULL) + return; + + for (i = 0; i < num_maps; ++i) { + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP || + map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) + kfree(map[i].data.configs.configs); + } + + kfree(map); +} + +static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pmx->pfc->dev; + struct device_node *child; + unsigned int index; + int ret; + + *map = NULL; + *num_maps = 0; + index = 0; + + for_each_child_of_node(np, child) { + ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps, + &index); + if (ret < 0) + goto done; + } + + /* If no mapping has been found in child nodes try the config node. */ + if (*num_maps == 0) { + ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index); + if (ret < 0) + goto done; + } + + if (*num_maps) + return 0; + + dev_err(dev, "no mapping found in node %s\n", np->full_name); + ret = -EINVAL; + +done: + if (ret < 0) + sh_pfc_dt_free_map(pctldev, *map, *num_maps); + + return ret; +} +#endif /* CONFIG_OF */ + static const struct pinctrl_ops sh_pfc_pinctrl_ops = { .get_groups_count = sh_pfc_get_groups_count, .get_group_name = sh_pfc_get_group_name, .get_group_pins = sh_pfc_get_group_pins, .pin_dbg_show = sh_pfc_pin_dbg_show, +#ifdef CONFIG_OF + .dt_node_to_map = sh_pfc_dt_node_to_map, + .dt_free_map = sh_pfc_dt_free_map, +#endif }; static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) diff --git a/drivers/pinctrl/sirf/Makefile b/drivers/pinctrl/sirf/Makefile new file mode 100644 index 00000000000..3ffc475ce40 --- /dev/null +++ b/drivers/pinctrl/sirf/Makefile @@ -0,0 +1,5 @@ +# CSR SiRFsoc pinmux support + +obj-y += pinctrl-sirf.o +obj-y += pinctrl-prima2.o +obj-y += pinctrl-atlas6.o diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c new file mode 100644 index 00000000000..1fa39a44417 --- /dev/null +++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c @@ -0,0 +1,947 @@ +/* + * pinctrl pads, groups, functions for CSR SiRFatlasVI + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/pinctrl/pinctrl.h> +#include <linux/bitops.h> + +#include "pinctrl-sirf.h" + +/* + * pad list for the pinmux subsystem + * refer to atlasVI_io_table_v0.93.xls + */ +static const struct pinctrl_pin_desc sirfsoc_pads[] = { + PINCTRL_PIN(0, "gpio0-0"), + PINCTRL_PIN(1, "gpio0-1"), + PINCTRL_PIN(2, "gpio0-2"), + PINCTRL_PIN(3, "gpio0-3"), + PINCTRL_PIN(4, "pwm0"), + PINCTRL_PIN(5, "pwm1"), + PINCTRL_PIN(6, "pwm2"), + PINCTRL_PIN(7, "pwm3"), + PINCTRL_PIN(8, "warm_rst_b"), + PINCTRL_PIN(9, "odo_0"), + PINCTRL_PIN(10, "odo_1"), + PINCTRL_PIN(11, "dr_dir"), + PINCTRL_PIN(12, "rts_0"), + PINCTRL_PIN(13, "scl_1"), + PINCTRL_PIN(14, "ntrst"), + PINCTRL_PIN(15, "sda_1"), + PINCTRL_PIN(16, "x_ldd[16]"), + PINCTRL_PIN(17, "x_ldd[17]"), + PINCTRL_PIN(18, "x_ldd[18]"), + PINCTRL_PIN(19, "x_ldd[19]"), + PINCTRL_PIN(20, "x_ldd[20]"), + PINCTRL_PIN(21, "x_ldd[21]"), + PINCTRL_PIN(22, "x_ldd[22]"), + PINCTRL_PIN(23, "x_ldd[23]"), + PINCTRL_PIN(24, "gps_sgn"), + PINCTRL_PIN(25, "gps_mag"), + PINCTRL_PIN(26, "gps_clk"), + PINCTRL_PIN(27, "sd_cd_b_2"), + PINCTRL_PIN(28, "sd_vcc_on_2"), + PINCTRL_PIN(29, "sd_wp_b_2"), + PINCTRL_PIN(30, "sd_clk_3"), + PINCTRL_PIN(31, "sd_cmd_3"), + + PINCTRL_PIN(32, "x_sd_dat_3[0]"), + PINCTRL_PIN(33, "x_sd_dat_3[1]"), + PINCTRL_PIN(34, "x_sd_dat_3[2]"), + PINCTRL_PIN(35, "x_sd_dat_3[3]"), + PINCTRL_PIN(36, "usb_clk"), + PINCTRL_PIN(37, "usb_dir"), + PINCTRL_PIN(38, "usb_nxt"), + PINCTRL_PIN(39, "usb_stp"), + PINCTRL_PIN(40, "usb_dat[7]"), + PINCTRL_PIN(41, "usb_dat[6]"), + PINCTRL_PIN(42, "x_cko_1"), + PINCTRL_PIN(43, "spi_clk_1"), + PINCTRL_PIN(44, "spi_dout_1"), + PINCTRL_PIN(45, "spi_din_1"), + PINCTRL_PIN(46, "spi_en_1"), + PINCTRL_PIN(47, "x_txd_1"), + PINCTRL_PIN(48, "x_txd_2"), + PINCTRL_PIN(49, "x_rxd_1"), + PINCTRL_PIN(50, "x_rxd_2"), + PINCTRL_PIN(51, "x_usclk_0"), + PINCTRL_PIN(52, "x_utxd_0"), + PINCTRL_PIN(53, "x_urxd_0"), + PINCTRL_PIN(54, "x_utfs_0"), + PINCTRL_PIN(55, "x_urfs_0"), + PINCTRL_PIN(56, "usb_dat5"), + PINCTRL_PIN(57, "usb_dat4"), + PINCTRL_PIN(58, "usb_dat3"), + PINCTRL_PIN(59, "usb_dat2"), + PINCTRL_PIN(60, "usb_dat1"), + PINCTRL_PIN(61, "usb_dat0"), + PINCTRL_PIN(62, "x_ldd[14]"), + PINCTRL_PIN(63, "x_ldd[15]"), + + PINCTRL_PIN(64, "x_gps_gpio"), + PINCTRL_PIN(65, "x_ldd[13]"), + PINCTRL_PIN(66, "x_df_we_b"), + PINCTRL_PIN(67, "x_df_re_b"), + PINCTRL_PIN(68, "x_txd_0"), + PINCTRL_PIN(69, "x_rxd_0"), + PINCTRL_PIN(70, "x_l_lck"), + PINCTRL_PIN(71, "x_l_fck"), + PINCTRL_PIN(72, "x_l_de"), + PINCTRL_PIN(73, "x_ldd[0]"), + PINCTRL_PIN(74, "x_ldd[1]"), + PINCTRL_PIN(75, "x_ldd[2]"), + PINCTRL_PIN(76, "x_ldd[3]"), + PINCTRL_PIN(77, "x_ldd[4]"), + PINCTRL_PIN(78, "x_cko_0"), + PINCTRL_PIN(79, "x_ldd[5]"), + PINCTRL_PIN(80, "x_ldd[6]"), + PINCTRL_PIN(81, "x_ldd[7]"), + PINCTRL_PIN(82, "x_ldd[8]"), + PINCTRL_PIN(83, "x_ldd[9]"), + PINCTRL_PIN(84, "x_ldd[10]"), + PINCTRL_PIN(85, "x_ldd[11]"), + PINCTRL_PIN(86, "x_ldd[12]"), + PINCTRL_PIN(87, "x_vip_vsync"), + PINCTRL_PIN(88, "x_vip_hsync"), + PINCTRL_PIN(89, "x_vip_pxclk"), + PINCTRL_PIN(90, "x_sda_0"), + PINCTRL_PIN(91, "x_scl_0"), + PINCTRL_PIN(92, "x_df_ry_by"), + PINCTRL_PIN(93, "x_df_cs_b[1]"), + PINCTRL_PIN(94, "x_df_cs_b[0]"), + PINCTRL_PIN(95, "x_l_pclk"), + + PINCTRL_PIN(96, "x_df_dqs"), + PINCTRL_PIN(97, "x_df_wp_b"), + PINCTRL_PIN(98, "ac97_sync"), + PINCTRL_PIN(99, "ac97_bit_clk "), + PINCTRL_PIN(100, "ac97_dout"), + PINCTRL_PIN(101, "ac97_din"), + PINCTRL_PIN(102, "x_rtc_io"), +}; + +static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { + { + .group = 1, + .mask = BIT(30) | BIT(31), + }, { + .group = 2, + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + BIT(20) | BIT(21) | BIT(22) | BIT(31), + }, +}; + +static const struct sirfsoc_padmux lcd_16bits_padmux = { + .muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask), + .muxmask = lcd_16bits_sirfsoc_muxmask, + .funcmask = BIT(4), + .funcval = 0, +}; + +static const unsigned lcd_16bits_pins[] = { 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, + 84, 85, 86, 95 }; + +static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = { + { + .group = 2, + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + BIT(20) | BIT(21) | BIT(22) | BIT(31), + }, { + .group = 1, + .mask = BIT(30) | BIT(31), + }, { + .group = 0, + .mask = BIT(16) | BIT(17), + }, +}; + +static const struct sirfsoc_padmux lcd_18bits_padmux = { + .muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask), + .muxmask = lcd_18bits_muxmask, + .funcmask = BIT(4) | BIT(15), + .funcval = 0, +}; + +static const unsigned lcd_18bits_pins[] = { 16, 17, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, + 84, 85, 86, 95 }; + +static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = { + { + .group = 2, + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + BIT(20) | BIT(21) | BIT(22) | BIT(31), + }, { + .group = 1, + .mask = BIT(30) | BIT(31), + }, { + .group = 0, + .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23), + }, +}; + +static const struct sirfsoc_padmux lcd_24bits_padmux = { + .muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask), + .muxmask = lcd_24bits_muxmask, + .funcmask = BIT(4) | BIT(15), + .funcval = 0, +}; + +static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, + 80, 81, 82, 83, 84, 85, 86, 95}; + +static const struct sirfsoc_muxmask lcdrom_muxmask[] = { + { + .group = 2, + .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | + BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | + BIT(20) | BIT(21) | BIT(22) | BIT(31), + }, { + .group = 1, + .mask = BIT(30) | BIT(31), + }, { + .group = 0, + .mask = BIT(8), + }, +}; + +static const struct sirfsoc_padmux lcdrom_padmux = { + .muxmask_counts = ARRAY_SIZE(lcdrom_muxmask), + .muxmask = lcdrom_muxmask, + .funcmask = BIT(4), + .funcval = BIT(4), +}; + +static const unsigned lcdrom_pins[] = { 8, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, + 84, 85, 86, 95}; + +static const struct sirfsoc_muxmask uart0_muxmask[] = { + { + .group = 0, + .mask = BIT(12), + }, { + .group = 1, + .mask = BIT(23), + }, { + .group = 2, + .mask = BIT(4) | BIT(5), + }, +}; + +static const struct sirfsoc_padmux uart0_padmux = { + .muxmask_counts = ARRAY_SIZE(uart0_muxmask), + .muxmask = uart0_muxmask, + .funcmask = BIT(9), + .funcval = BIT(9), +}; + +static const unsigned uart0_pins[] = { 12, 55, 68, 69 }; + +static const struct sirfsoc_muxmask uart0_nostreamctrl_muxmask[] = { + { + .group = 2, + .mask = BIT(4) | BIT(5), + }, +}; + +static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = { + .muxmask_counts = ARRAY_SIZE(uart0_nostreamctrl_muxmask), + .muxmask = uart0_nostreamctrl_muxmask, +}; + +static const unsigned uart0_nostreamctrl_pins[] = { 68, 69 }; + +static const struct sirfsoc_muxmask uart1_muxmask[] = { + { + .group = 1, + .mask = BIT(15) | BIT(17), + }, +}; + +static const struct sirfsoc_padmux uart1_padmux = { + .muxmask_counts = ARRAY_SIZE(uart1_muxmask), + .muxmask = uart1_muxmask, +}; + +static const unsigned uart1_pins[] = { 47, 49 }; + +static const struct sirfsoc_muxmask uart2_muxmask[] = { + { + .group = 0, + .mask = BIT(10) | BIT(14), + }, { + .group = 1, + .mask = BIT(16) | BIT(18), + }, +}; + +static const struct sirfsoc_padmux uart2_padmux = { + .muxmask_counts = ARRAY_SIZE(uart2_muxmask), + .muxmask = uart2_muxmask, + .funcmask = BIT(10), + .funcval = BIT(10), +}; + +static const unsigned uart2_pins[] = { 10, 14, 48, 50 }; + +static const struct sirfsoc_muxmask uart2_nostreamctrl_muxmask[] = { + { + .group = 1, + .mask = BIT(16) | BIT(18), + }, +}; + +static const struct sirfsoc_padmux uart2_nostreamctrl_padmux = { + .muxmask_counts = ARRAY_SIZE(uart2_nostreamctrl_muxmask), + .muxmask = uart2_nostreamctrl_muxmask, +}; + +static const unsigned uart2_nostreamctrl_pins[] = { 48, 50 }; + +static const struct sirfsoc_muxmask sdmmc3_muxmask[] = { + { + .group = 0, + .mask = BIT(30) | BIT(31), + }, { + .group = 1, + .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), + }, +}; + +static const struct sirfsoc_padmux sdmmc3_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask), + .muxmask = sdmmc3_muxmask, + .funcmask = BIT(7), + .funcval = 0, +}; + +static const unsigned sdmmc3_pins[] = { 30, 31, 32, 33, 34, 35 }; + +static const struct sirfsoc_muxmask spi0_muxmask[] = { + { + .group = 0, + .mask = BIT(30), + }, { + .group = 1, + .mask = BIT(0) | BIT(2) | BIT(3), + }, +}; + +static const struct sirfsoc_padmux spi0_padmux = { + .muxmask_counts = ARRAY_SIZE(spi0_muxmask), + .muxmask = spi0_muxmask, + .funcmask = BIT(7), + .funcval = BIT(7), +}; + +static const unsigned spi0_pins[] = { 30, 32, 34, 35 }; + +static const struct sirfsoc_muxmask cko1_muxmask[] = { + { + .group = 1, + .mask = BIT(10), + }, +}; + +static const struct sirfsoc_padmux cko1_padmux = { + .muxmask_counts = ARRAY_SIZE(cko1_muxmask), + .muxmask = cko1_muxmask, + .funcmask = BIT(3), + .funcval = 0, +}; + +static const unsigned cko1_pins[] = { 42 }; + +static const struct sirfsoc_muxmask i2s_muxmask[] = { + { + .group = 1, + .mask = BIT(10), + }, { + .group = 3, + .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5), + }, +}; + +static const struct sirfsoc_padmux i2s_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_muxmask), + .muxmask = i2s_muxmask, + .funcmask = BIT(3), + .funcval = BIT(3), +}; + +static const unsigned i2s_pins[] = { 42, 98, 99, 100, 101 }; + +static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = { + { + .group = 1, + .mask = BIT(10), + }, { + .group = 3, + .mask = BIT(2) | BIT(3) | BIT(4), + }, +}; + +static const struct sirfsoc_padmux i2s_no_din_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask), + .muxmask = i2s_no_din_muxmask, + .funcmask = BIT(3), + .funcval = BIT(3), +}; + +static const unsigned i2s_no_din_pins[] = { 42, 98, 99, 100 }; + +static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = { + { + .group = 1, + .mask = BIT(10) | BIT(20) | BIT(23), + }, { + .group = 3, + .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5), + }, +}; + +static const struct sirfsoc_padmux i2s_6chn_padmux = { + .muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask), + .muxmask = i2s_6chn_muxmask, + .funcmask = BIT(1) | BIT(3) | BIT(9), + .funcval = BIT(1) | BIT(3) | BIT(9), +}; + +static const unsigned i2s_6chn_pins[] = { 42, 52, 55, 98, 99, 100, 101 }; + +static const struct sirfsoc_muxmask ac97_muxmask[] = { + { + .group = 3, + .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5), + }, +}; + +static const struct sirfsoc_padmux ac97_padmux = { + .muxmask_counts = ARRAY_SIZE(ac97_muxmask), + .muxmask = ac97_muxmask, +}; + +static const unsigned ac97_pins[] = { 98, 99, 100, 101 }; + +static const struct sirfsoc_muxmask spi1_muxmask[] = { + { + .group = 1, + .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14), + }, +}; + +static const struct sirfsoc_padmux spi1_padmux = { + .muxmask_counts = ARRAY_SIZE(spi1_muxmask), + .muxmask = spi1_muxmask, + .funcmask = BIT(16), + .funcval = 0, +}; + +static const unsigned spi1_pins[] = { 43, 44, 45, 46 }; + +static const struct sirfsoc_muxmask sdmmc1_muxmask[] = { + { + .group = 2, + .mask = BIT(2) | BIT(3), + }, +}; + +static const struct sirfsoc_padmux sdmmc1_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc1_muxmask), + .muxmask = sdmmc1_muxmask, + .funcmask = BIT(5), + .funcval = BIT(5), +}; + +static const unsigned sdmmc1_pins[] = { 66, 67 }; + +static const struct sirfsoc_muxmask gps_muxmask[] = { + { + .group = 0, + .mask = BIT(24) | BIT(25) | BIT(26), + }, +}; + +static const struct sirfsoc_padmux gps_padmux = { + .muxmask_counts = ARRAY_SIZE(gps_muxmask), + .muxmask = gps_muxmask, + .funcmask = BIT(13), + .funcval = 0, +}; + +static const unsigned gps_pins[] = { 24, 25, 26 }; + +static const struct sirfsoc_muxmask sdmmc5_muxmask[] = { + { + .group = 0, + .mask = BIT(24) | BIT(25) | BIT(26), + }, +}; + +static const struct sirfsoc_padmux sdmmc5_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask), + .muxmask = sdmmc5_muxmask, + .funcmask = BIT(13), + .funcval = BIT(13), +}; + +static const unsigned sdmmc5_pins[] = { 24, 25, 26 }; + +static const struct sirfsoc_muxmask usp0_muxmask[] = { + { + .group = 1, + .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22), + }, +}; + +static const struct sirfsoc_padmux usp0_padmux = { + .muxmask_counts = ARRAY_SIZE(usp0_muxmask), + .muxmask = usp0_muxmask, + .funcmask = BIT(1) | BIT(2) | BIT(9), + .funcval = 0, +}; + +static const unsigned usp0_pins[] = { 51, 52, 53, 54 }; + +static const struct sirfsoc_muxmask usp1_muxmask[] = { + { + .group = 0, + .mask = BIT(15), + }, { + .group = 1, + .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14), + }, +}; + +static const struct sirfsoc_padmux usp1_padmux = { + .muxmask_counts = ARRAY_SIZE(usp1_muxmask), + .muxmask = usp1_muxmask, + .funcmask = BIT(16), + .funcval = BIT(16), +}; + +static const unsigned usp1_pins[] = { 15, 43, 44, 45, 46 }; + +static const struct sirfsoc_muxmask nand_muxmask[] = { + { + .group = 2, + .mask = BIT(2) | BIT(3) | BIT(28) | BIT(29) | BIT(30), + }, { + .group = 3, + .mask = BIT(0) | BIT(1), + }, +}; + +static const struct sirfsoc_padmux nand_padmux = { + .muxmask_counts = ARRAY_SIZE(nand_muxmask), + .muxmask = nand_muxmask, + .funcmask = BIT(5) | BIT(19), + .funcval = 0, +}; + +static const unsigned nand_pins[] = { 66, 67, 92, 93, 94, 96, 97 }; + +static const struct sirfsoc_muxmask sdmmc0_muxmask[] = { + { + .group = 3, + .mask = BIT(1), + }, +}; + +static const struct sirfsoc_padmux sdmmc0_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc0_muxmask), + .muxmask = sdmmc0_muxmask, + .funcmask = BIT(5) | BIT(19), + .funcval = BIT(19), +}; + +static const unsigned sdmmc0_pins[] = { 97 }; + +static const struct sirfsoc_muxmask sdmmc2_muxmask[] = { + { + .group = 0, + .mask = BIT(27) | BIT(28) | BIT(29), + }, +}; + +static const struct sirfsoc_padmux sdmmc2_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask), + .muxmask = sdmmc2_muxmask, + .funcmask = BIT(11), + .funcval = 0, +}; + +static const unsigned sdmmc2_pins[] = { 27, 28, 29 }; + +static const struct sirfsoc_muxmask sdmmc2_nowp_muxmask[] = { + { + .group = 0, + .mask = BIT(27) | BIT(28), + }, +}; + +static const struct sirfsoc_padmux sdmmc2_nowp_padmux = { + .muxmask_counts = ARRAY_SIZE(sdmmc2_nowp_muxmask), + .muxmask = sdmmc2_nowp_muxmask, + .funcmask = BIT(11), + .funcval = 0, +}; + +static const unsigned sdmmc2_nowp_pins[] = { 27, 28 }; + +static const struct sirfsoc_muxmask cko0_muxmask[] = { + { + .group = 2, + .mask = BIT(14), + }, +}; + +static const struct sirfsoc_padmux cko0_padmux = { + .muxmask_counts = ARRAY_SIZE(cko0_muxmask), + .muxmask = cko0_muxmask, +}; + +static const unsigned cko0_pins[] = { 78 }; + +static const struct sirfsoc_muxmask vip_muxmask[] = { + { + .group = 1, + .mask = BIT(4) | BIT(5) | BIT(6) | BIT(8) | BIT(9) + | BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28) | + BIT(29), + }, +}; + +static const struct sirfsoc_padmux vip_padmux = { + .muxmask_counts = ARRAY_SIZE(vip_muxmask), + .muxmask = vip_muxmask, + .funcmask = BIT(18), + .funcval = BIT(18), +}; + +static const unsigned vip_pins[] = { 36, 37, 38, 40, 41, 56, 57, 58, 59, 60, 61 }; + +static const struct sirfsoc_muxmask vip_noupli_muxmask[] = { + { + .group = 0, + .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) + | BIT(21) | BIT(22) | BIT(23), + }, { + .group = 2, + .mask = BIT(23) | BIT(24) | BIT(25), + }, +}; + +static const struct sirfsoc_padmux vip_noupli_padmux = { + .muxmask_counts = ARRAY_SIZE(vip_noupli_muxmask), + .muxmask = vip_noupli_muxmask, + .funcmask = BIT(15), + .funcval = BIT(15), +}; + +static const unsigned vip_noupli_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 87, 88, 89 }; + +static const struct sirfsoc_muxmask i2c0_muxmask[] = { + { + .group = 2, + .mask = BIT(26) | BIT(27), + }, +}; + +static const struct sirfsoc_padmux i2c0_padmux = { + .muxmask_counts = ARRAY_SIZE(i2c0_muxmask), + .muxmask = i2c0_muxmask, +}; + +static const unsigned i2c0_pins[] = { 90, 91 }; + +static const struct sirfsoc_muxmask i2c1_muxmask[] = { + { + .group = 0, + .mask = BIT(13) | BIT(15), + }, +}; + +static const struct sirfsoc_padmux i2c1_padmux = { + .muxmask_counts = ARRAY_SIZE(i2c1_muxmask), + .muxmask = i2c1_muxmask, + .funcmask = BIT(16), + .funcval = 0, +}; + +static const unsigned i2c1_pins[] = { 13, 15 }; + +static const struct sirfsoc_muxmask pwm0_muxmask[] = { + { + .group = 0, + .mask = BIT(4), + }, +}; + +static const struct sirfsoc_padmux pwm0_padmux = { + .muxmask_counts = ARRAY_SIZE(pwm0_muxmask), + .muxmask = pwm0_muxmask, + .funcmask = BIT(12), + .funcval = 0, +}; + +static const unsigned pwm0_pins[] = { 4 }; + +static const struct sirfsoc_muxmask pwm1_muxmask[] = { + { + .group = 0, + .mask = BIT(5), + }, +}; + +static const struct sirfsoc_padmux pwm1_padmux = { + .muxmask_counts = ARRAY_SIZE(pwm1_muxmask), + .muxmask = pwm1_muxmask, +}; + +static const unsigned pwm1_pins[] = { 5 }; + +static const struct sirfsoc_muxmask pwm2_muxmask[] = { + { + .group = 0, + .mask = BIT(6), + }, +}; + +static const struct sirfsoc_padmux pwm2_padmux = { + .muxmask_counts = ARRAY_SIZE(pwm2_muxmask), + .muxmask = pwm2_muxmask, +}; + +static const unsigned pwm2_pins[] = { 6 }; + +static const struct sirfsoc_muxmask pwm3_muxmask[] = { + { + .group = 0, + .mask = BIT(7), + }, +}; + +static const struct sirfsoc_padmux pwm3_padmux = { + .muxmask_counts = ARRAY_SIZE(pwm3_muxmask), + .muxmask = pwm3_muxmask, +}; + +static const unsigned pwm3_pins[] = { 7 }; + +static const struct sirfsoc_muxmask pwm4_muxmask[] = { + { + .group = 2, + .mask = BIT(14), + }, +}; + +static const struct sirfsoc_padmux pwm4_padmux = { + .muxmask_counts = ARRAY_SIZE(pwm4_muxmask), + .muxmask = pwm4_muxmask, +}; + +static const unsigned pwm4_pins[] = { 78 }; + +static const struct sirfsoc_muxmask warm_rst_muxmask[] = { + { + .group = 0, + .mask = BIT(8), + }, +}; + +static const struct sirfsoc_padmux warm_rst_padmux = { + .muxmask_counts = ARRAY_SIZE(warm_rst_muxmask), + .muxmask = warm_rst_muxmask, + .funcmask = BIT(4), + .funcval = 0, +}; + +static const unsigned warm_rst_pins[] = { 8 }; + +static const struct sirfsoc_muxmask usb0_upli_drvbus_muxmask[] = { + { + .group = 1, + .mask = BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) + | BIT(9) | BIT(24) | BIT(25) | BIT(26) | + BIT(27) | BIT(28) | BIT(29), + }, +}; +static const struct sirfsoc_padmux usb0_upli_drvbus_padmux = { + .muxmask_counts = ARRAY_SIZE(usb0_upli_drvbus_muxmask), + .muxmask = usb0_upli_drvbus_muxmask, + .funcmask = BIT(18), + .funcval = 0, +}; + +static const unsigned usb0_upli_drvbus_pins[] = { 36, 37, 38, 39, 40, 41, 56, 57, 58, 59, 60, 61 }; + +static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = { + { + .group = 0, + .mask = BIT(28), + }, +}; + +static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = { + .muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask), + .muxmask = usb1_utmi_drvbus_muxmask, + .funcmask = BIT(11), + .funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */ +}; + +static const unsigned usb1_utmi_drvbus_pins[] = { 28 }; + +static const struct sirfsoc_muxmask pulse_count_muxmask[] = { + { + .group = 0, + .mask = BIT(9) | BIT(10) | BIT(11), + }, +}; + +static const struct sirfsoc_padmux pulse_count_padmux = { + .muxmask_counts = ARRAY_SIZE(pulse_count_muxmask), + .muxmask = pulse_count_muxmask, +}; + +static const unsigned pulse_count_pins[] = { 9, 10, 11 }; + +static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { + SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins), + SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins), + SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins), + SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins), + SIRFSOC_PIN_GROUP("uart0grp", uart0_pins), + SIRFSOC_PIN_GROUP("uart1grp", uart1_pins), + SIRFSOC_PIN_GROUP("uart2grp", uart2_pins), + SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins), + SIRFSOC_PIN_GROUP("usp0grp", usp0_pins), + SIRFSOC_PIN_GROUP("usp1grp", usp1_pins), + SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins), + SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins), + SIRFSOC_PIN_GROUP("pwm0grp", pwm0_pins), + SIRFSOC_PIN_GROUP("pwm1grp", pwm1_pins), + SIRFSOC_PIN_GROUP("pwm2grp", pwm2_pins), + SIRFSOC_PIN_GROUP("pwm3grp", pwm3_pins), + SIRFSOC_PIN_GROUP("pwm4grp", pwm4_pins), + SIRFSOC_PIN_GROUP("vipgrp", vip_pins), + SIRFSOC_PIN_GROUP("vip_noupligrp", vip_noupli_pins), + SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins), + SIRFSOC_PIN_GROUP("cko0grp", cko0_pins), + SIRFSOC_PIN_GROUP("cko1grp", cko1_pins), + SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins), + SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins), + SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins), + SIRFSOC_PIN_GROUP("sdmmc2_nowpgrp", sdmmc2_nowp_pins), + SIRFSOC_PIN_GROUP("sdmmc3grp", sdmmc3_pins), + SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins), + SIRFSOC_PIN_GROUP("usb0_upli_drvbusgrp", usb0_upli_drvbus_pins), + SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins), + SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins), + SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins), + SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins), + SIRFSOC_PIN_GROUP("i2s_6chngrp", i2s_6chn_pins), + SIRFSOC_PIN_GROUP("ac97grp", ac97_pins), + SIRFSOC_PIN_GROUP("nandgrp", nand_pins), + SIRFSOC_PIN_GROUP("spi0grp", spi0_pins), + SIRFSOC_PIN_GROUP("spi1grp", spi1_pins), + SIRFSOC_PIN_GROUP("gpsgrp", gps_pins), +}; + +static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" }; +static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" }; +static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" }; +static const char * const lcdromgrp[] = { "lcdromgrp" }; +static const char * const uart0grp[] = { "uart0grp" }; +static const char * const uart1grp[] = { "uart1grp" }; +static const char * const uart2grp[] = { "uart2grp" }; +static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" }; +static const char * const usp0grp[] = { "usp0grp" }; +static const char * const usp1grp[] = { "usp1grp" }; +static const char * const i2c0grp[] = { "i2c0grp" }; +static const char * const i2c1grp[] = { "i2c1grp" }; +static const char * const pwm0grp[] = { "pwm0grp" }; +static const char * const pwm1grp[] = { "pwm1grp" }; +static const char * const pwm2grp[] = { "pwm2grp" }; +static const char * const pwm3grp[] = { "pwm3grp" }; +static const char * const pwm4grp[] = { "pwm4grp" }; +static const char * const vipgrp[] = { "vipgrp" }; +static const char * const vip_noupligrp[] = { "vip_noupligrp" }; +static const char * const warm_rstgrp[] = { "warm_rstgrp" }; +static const char * const cko0grp[] = { "cko0grp" }; +static const char * const cko1grp[] = { "cko1grp" }; +static const char * const sdmmc0grp[] = { "sdmmc0grp" }; +static const char * const sdmmc1grp[] = { "sdmmc1grp" }; +static const char * const sdmmc2grp[] = { "sdmmc2grp" }; +static const char * const sdmmc3grp[] = { "sdmmc3grp" }; +static const char * const sdmmc5grp[] = { "sdmmc5grp" }; +static const char * const sdmmc2_nowpgrp[] = { "sdmmc2_nowpgrp" }; +static const char * const usb0_upli_drvbusgrp[] = { "usb0_upli_drvbusgrp" }; +static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" }; +static const char * const pulse_countgrp[] = { "pulse_countgrp" }; +static const char * const i2sgrp[] = { "i2sgrp" }; +static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" }; +static const char * const i2s_6chngrp[] = { "i2s_6chngrp" }; +static const char * const ac97grp[] = { "ac97grp" }; +static const char * const nandgrp[] = { "nandgrp" }; +static const char * const spi0grp[] = { "spi0grp" }; +static const char * const spi1grp[] = { "spi1grp" }; +static const char * const gpsgrp[] = { "gpsgrp" }; + +static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { + SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux), + SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux), + SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux), + SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux), + SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux), + SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux), + SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux), + SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), + SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux), + SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux), + SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux), + SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux), + SIRFSOC_PMX_FUNCTION("pwm0", pwm0grp, pwm0_padmux), + SIRFSOC_PMX_FUNCTION("pwm1", pwm1grp, pwm1_padmux), + SIRFSOC_PMX_FUNCTION("pwm2", pwm2grp, pwm2_padmux), + SIRFSOC_PMX_FUNCTION("pwm3", pwm3grp, pwm3_padmux), + SIRFSOC_PMX_FUNCTION("pwm4", pwm4grp, pwm4_padmux), + SIRFSOC_PMX_FUNCTION("vip", vipgrp, vip_padmux), + SIRFSOC_PMX_FUNCTION("vip_noupli", vip_noupligrp, vip_noupli_padmux), + SIRFSOC_PMX_FUNCTION("warm_rst", warm_rstgrp, warm_rst_padmux), + SIRFSOC_PMX_FUNCTION("cko0", cko0grp, cko0_padmux), + SIRFSOC_PMX_FUNCTION("cko1", cko1grp, cko1_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc0", sdmmc0grp, sdmmc0_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc1", sdmmc1grp, sdmmc1_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc2", sdmmc2grp, sdmmc2_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux), + SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", sdmmc2_nowpgrp, sdmmc2_nowp_padmux), + SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux), + SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux), + SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux), + SIRFSOC_PMX_FUNCTION("i2s_6chn", i2s_6chngrp, i2s_6chn_padmux), + SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux), + SIRFSOC_PMX_FUNCTION("nand", nandgrp, nand_padmux), + SIRFSOC_PMX_FUNCTION("spi0", spi0grp, spi0_padmux), + SIRFSOC_PMX_FUNCTION("spi1", spi1grp, spi1_padmux), + SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux), +}; + +struct sirfsoc_pinctrl_data atlas6_pinctrl_data = { + (struct pinctrl_pin_desc *)sirfsoc_pads, + ARRAY_SIZE(sirfsoc_pads), + (struct sirfsoc_pin_group *)sirfsoc_pin_groups, + ARRAY_SIZE(sirfsoc_pin_groups), + (struct sirfsoc_pmx_func *)sirfsoc_pmx_functions, + ARRAY_SIZE(sirfsoc_pmx_functions), +}; + diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-prima2.c index bc9d1be27fb..1f0ad1ef5a3 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-prima2.c @@ -1,70 +1,15 @@ /* - * pinmux driver for CSR SiRFprimaII + * pinctrl pads, groups, functions for CSR SiRFprimaII * * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. * * Licensed under GPLv2 or later. */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/irqdomain.h> -#include <linux/irqchip/chained_irq.h> #include <linux/pinctrl/pinctrl.h> -#include <linux/pinctrl/pinmux.h> -#include <linux/pinctrl/consumer.h> -#include <linux/pinctrl/machine.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> #include <linux/bitops.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#define DRIVER_NAME "pinmux-sirf" - -#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_CLR(g) ((g)*0x100 + 0x90) -#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) -#define SIRFSOC_GPIO_DSP_EN0 (0x80) -#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) - -#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 -#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK 0x2 -#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK 0x4 -#define SIRFSOC_GPIO_CTL_INTR_EN_MASK 0x8 -#define SIRFSOC_GPIO_CTL_INTR_STS_MASK 0x10 -#define SIRFSOC_GPIO_CTL_OUT_EN_MASK 0x20 -#define SIRFSOC_GPIO_CTL_DATAOUT_MASK 0x40 -#define SIRFSOC_GPIO_CTL_DATAIN_MASK 0x80 -#define SIRFSOC_GPIO_CTL_PULL_MASK 0x100 -#define SIRFSOC_GPIO_CTL_PULL_HIGH 0x200 -#define SIRFSOC_GPIO_CTL_DSP_INT 0x400 - -#define SIRFSOC_GPIO_NO_OF_BANKS 5 -#define SIRFSOC_GPIO_BANK_SIZE 32 -#define SIRFSOC_GPIO_NUM(bank, index) (((bank)*(32)) + (index)) - -struct sirfsoc_gpio_bank { - struct of_mm_gpio_chip chip; - struct irq_domain *domain; - 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]; -static DEFINE_SPINLOCK(sgpio_lock); + +#include "pinctrl-sirf.h" /* * pad list for the pinmux subsystem @@ -183,46 +128,6 @@ static const struct pinctrl_pin_desc sirfsoc_pads[] = { PINCTRL_PIN(114, "x_ldd[15]"), }; -/** - * @dev: a pointer back to containing device - * @virtbase: the offset to the controller in virtual memory - */ -struct sirfsoc_pmx { - struct device *dev; - struct pinctrl_dev *pmx; - void __iomem *gpio_virtbase; - void __iomem *rsc_virtbase; - bool is_marco; -}; - -/* SIRFSOC_GPIO_PAD_EN set */ -struct sirfsoc_muxmask { - unsigned long group; - unsigned long mask; -}; - -struct sirfsoc_padmux { - unsigned long muxmask_counts; - const struct sirfsoc_muxmask *muxmask; - /* RSC_PIN_MUX set */ - unsigned long funcmask; - unsigned long funcval; -}; - - /** - * struct sirfsoc_pin_group - describes a SiRFprimaII pin group - * @name: the name of this specific pin group - * @pins: an array of discrete physical pins used in this group, taken - * from the driver-local pin enumeration space - * @num_pins: the number of pins in this group array, i.e. the number of - * elements in .pins so we can iterate over that array - */ -struct sirfsoc_pin_group { - const char *name; - const unsigned int *pins; - const unsigned num_pins; -}; - static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { { .group = 3, @@ -351,7 +256,7 @@ static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = { .muxmask = uart0_nostreamctrl_muxmask, }; -static const unsigned uart0_nostreamctrl_pins[] = { 68, 39 }; +static const unsigned uart0_nostreamctrl_pins[] = { 68, 69 }; static const struct sirfsoc_muxmask uart1_muxmask[] = { { @@ -853,13 +758,6 @@ static const struct sirfsoc_padmux pulse_count_padmux = { static const unsigned pulse_count_pins[] = { 9, 10, 11 }; -#define SIRFSOC_PIN_GROUP(n, p) \ - { \ - .name = n, \ - .pins = p, \ - .num_pins = ARRAY_SIZE(p), \ - } - static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins), SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins), @@ -881,8 +779,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("vipgrp", vip_pins), SIRFSOC_PIN_GROUP("vipromgrp", viprom_pins), SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins), - SIRFSOC_PIN_GROUP("cko0_rstgrp", cko0_pins), - SIRFSOC_PIN_GROUP("cko1_rstgrp", cko1_pins), + SIRFSOC_PIN_GROUP("cko0grp", cko0_pins), + SIRFSOC_PIN_GROUP("cko1grp", cko1_pins), SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins), SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins), SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins), @@ -900,101 +798,6 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("gpsgrp", gps_pins), }; -static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev) -{ - return ARRAY_SIZE(sirfsoc_pin_groups); -} - -static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - return sirfsoc_pin_groups[selector].name; -} - -static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, - const unsigned **pins, - unsigned *num_pins) -{ - *pins = sirfsoc_pin_groups[selector].pins; - *num_pins = sirfsoc_pin_groups[selector].num_pins; - return 0; -} - -static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) -{ - seq_printf(s, " " DRIVER_NAME); -} - -static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *num_maps) -{ - struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev); - struct device_node *np; - struct property *prop; - const char *function, *group; - int ret, index = 0, count = 0; - - /* calculate number of maps required */ - for_each_child_of_node(np_config, np) { - ret = of_property_read_string(np, "sirf,function", &function); - if (ret < 0) - return ret; - - ret = of_property_count_strings(np, "sirf,pins"); - if (ret < 0) - return ret; - - count += ret; - } - - if (!count) { - dev_err(spmx->dev, "No child nodes passed via DT\n"); - return -ENODEV; - } - - *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); - if (!*map) - return -ENOMEM; - - for_each_child_of_node(np_config, np) { - of_property_read_string(np, "sirf,function", &function); - of_property_for_each_string(np, "sirf,pins", prop, group) { - (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; - (*map)[index].data.mux.group = group; - (*map)[index].data.mux.function = function; - index++; - } - } - - *num_maps = count; - - return 0; -} - -static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) -{ - kfree(map); -} - -static const struct pinctrl_ops sirfsoc_pctrl_ops = { - .get_groups_count = sirfsoc_get_groups_count, - .get_group_name = sirfsoc_get_group_name, - .get_group_pins = sirfsoc_get_group_pins, - .pin_dbg_show = sirfsoc_pin_dbg_show, - .dt_node_to_map = sirfsoc_dt_node_to_map, - .dt_free_map = sirfsoc_dt_free_map, -}; - -struct sirfsoc_pmx_func { - const char *name; - const char * const *groups; - const unsigned num_groups; - const struct sirfsoc_padmux *padmux; -}; - static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" }; static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" }; static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" }; @@ -1033,14 +836,6 @@ static const char * const spi0grp[] = { "spi0grp" }; static const char * const spi1grp[] = { "spi1grp" }; static const char * const gpsgrp[] = { "gpsgrp" }; -#define SIRFSOC_PMX_FUNCTION(n, g, m) \ - { \ - .name = n, \ - .groups = g, \ - .num_groups = ARRAY_SIZE(g), \ - .padmux = &m, \ - } - static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux), SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux), @@ -1081,730 +876,12 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux), }; -static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector, - bool enable) -{ - int i; - const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux; - const struct sirfsoc_muxmask *mask = mux->muxmask; - - for (i = 0; i < mux->muxmask_counts; i++) { - u32 muxval; - 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) { - u32 func_en_val; - func_en_val = - readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); - func_en_val = - (func_en_val & ~mux->funcmask) | (mux-> - funcval); - writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); - } -} - -static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector, - unsigned group) -{ - struct sirfsoc_pmx *spmx; - - spmx = pinctrl_dev_get_drvdata(pmxdev); - sirfsoc_pinmux_endisable(spmx, selector, true); - - return 0; -} - -static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector, - unsigned group) -{ - struct sirfsoc_pmx *spmx; - - spmx = pinctrl_dev_get_drvdata(pmxdev); - sirfsoc_pinmux_endisable(spmx, selector, false); -} - -static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev) -{ - return ARRAY_SIZE(sirfsoc_pmx_functions); -} - -static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - return sirfsoc_pmx_functions[selector].name; -} - -static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector, - const char * const **groups, - unsigned * const num_groups) -{ - *groups = sirfsoc_pmx_functions[selector].groups; - *num_groups = sirfsoc_pmx_functions[selector].num_groups; - return 0; -} - -static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, - struct pinctrl_gpio_range *range, unsigned offset) -{ - struct sirfsoc_pmx *spmx; - - int group = range->id; - - u32 muxval; - - spmx = pinctrl_dev_get_drvdata(pmxdev); - - 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; -} - -static const struct pinmux_ops sirfsoc_pinmux_ops = { - .enable = sirfsoc_pinmux_enable, - .disable = sirfsoc_pinmux_disable, - .get_functions_count = sirfsoc_pinmux_get_funcs_count, - .get_function_name = sirfsoc_pinmux_get_func_name, - .get_function_groups = sirfsoc_pinmux_get_groups, - .gpio_request_enable = sirfsoc_pinmux_request_gpio, -}; - -static struct pinctrl_desc sirfsoc_pinmux_desc = { - .name = DRIVER_NAME, - .pins = sirfsoc_pads, - .npins = ARRAY_SIZE(sirfsoc_pads), - .pctlops = &sirfsoc_pctrl_ops, - .pmxops = &sirfsoc_pinmux_ops, - .owner = THIS_MODULE, -}; - -/* - * Todo: bind irq_chip to every pinctrl_gpio_range - */ -static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = { - { - .name = "sirfsoc-gpio*", - .id = 0, - .base = 0, - .pin_base = 0, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 1, - .base = 32, - .pin_base = 32, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 2, - .base = 64, - .pin_base = 64, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 3, - .base = 96, - .pin_base = 96, - .npins = 19, - }, -}; - -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; - - np = of_find_matching_node(NULL, rsc_ids); - if (!np) - panic("unable to find compatible rsc node in dtb\n"); - - return of_iomap(np, 0); -} - -static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) -{ - if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE) - return -EINVAL; - - if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc) - return -EINVAL; - - if (flags) - *flags = gpiospec->args[1]; - - return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE; -} - -static int sirfsoc_pinmux_probe(struct platform_device *pdev) -{ - int ret; - struct sirfsoc_pmx *spmx; - struct device_node *np = pdev->dev.of_node; - int i; - - /* Create state holders etc for this driver */ - spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL); - if (!spmx) - return -ENOMEM; - - spmx->dev = &pdev->dev; - - platform_set_drvdata(pdev, spmx); - - spmx->gpio_virtbase = of_iomap(np, 0); - if (!spmx->gpio_virtbase) { - ret = -ENOMEM; - dev_err(&pdev->dev, "can't map gpio registers\n"); - goto out_no_gpio_remap; - } - - spmx->rsc_virtbase = sirfsoc_rsc_of_iomap(); - if (!spmx->rsc_virtbase) { - ret = -ENOMEM; - dev_err(&pdev->dev, "can't map rsc registers\n"); - 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) { - dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n"); - ret = -EINVAL; - goto out_no_pmx; - } - - for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) { - sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc; - pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]); - } - - dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n"); - - return 0; - -out_no_pmx: - iounmap(spmx->rsc_virtbase); -out_no_rsc_remap: - iounmap(spmx->gpio_virtbase); -out_no_gpio_remap: - platform_set_drvdata(pdev, NULL); - return ret; -} - -static const struct of_device_id pinmux_ids[] = { - { .compatible = "sirf,prima2-pinctrl" }, - { .compatible = "sirf,marco-pinctrl" }, - {} -}; - -static struct platform_driver sirfsoc_pinmux_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = pinmux_ids, - }, - .probe = sirfsoc_pinmux_probe, +struct sirfsoc_pinctrl_data prima2_pinctrl_data = { + (struct pinctrl_pin_desc *)sirfsoc_pads, + ARRAY_SIZE(sirfsoc_pads), + (struct sirfsoc_pin_group *)sirfsoc_pin_groups, + ARRAY_SIZE(sirfsoc_pin_groups), + (struct sirfsoc_pmx_func *)sirfsoc_pmx_functions, + ARRAY_SIZE(sirfsoc_pmx_functions), }; -static int __init sirfsoc_pinmux_init(void) -{ - return platform_driver_register(&sirfsoc_pinmux_driver); -} -arch_initcall(sirfsoc_pinmux_init); - -static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip), - struct sirfsoc_gpio_bank, chip); - - return irq_create_mapping(bank->domain, offset); -} - -static inline int sirfsoc_gpio_to_offset(unsigned int gpio) -{ - return gpio % SIRFSOC_GPIO_BANK_SIZE; -} - -static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio) -{ - return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE]; -} - -static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip) -{ - return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip); -} - -static void sirfsoc_gpio_irq_ack(struct irq_data *d) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; - u32 val, offset; - unsigned long flags; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&sgpio_lock, flags); - - val = readl(bank->chip.regs + offset); - - writel(val, bank->chip.regs + offset); - - spin_unlock_irqrestore(&sgpio_lock, flags); -} - -static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx) -{ - u32 val, offset; - unsigned long flags; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&sgpio_lock, flags); - - val = readl(bank->chip.regs + offset); - val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; - val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; - writel(val, bank->chip.regs + offset); - - spin_unlock_irqrestore(&sgpio_lock, flags); -} - -static void sirfsoc_gpio_irq_mask(struct irq_data *d) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - - __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); -} - -static void sirfsoc_gpio_irq_unmask(struct irq_data *d) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; - u32 val, offset; - unsigned long flags; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&sgpio_lock, flags); - - val = readl(bank->chip.regs + offset); - val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; - val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK; - writel(val, bank->chip.regs + offset); - - spin_unlock_irqrestore(&sgpio_lock, flags); -} - -static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; - u32 val, offset; - unsigned long flags; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&sgpio_lock, flags); - - val = readl(bank->chip.regs + offset); - val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; - - switch (type) { - case IRQ_TYPE_NONE: - break; - case IRQ_TYPE_EDGE_RISING: - val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; - val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK; - break; - case IRQ_TYPE_EDGE_FALLING: - val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; - val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; - break; - case IRQ_TYPE_EDGE_BOTH: - val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK | - SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; - break; - case IRQ_TYPE_LEVEL_LOW: - val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); - val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK; - break; - case IRQ_TYPE_LEVEL_HIGH: - val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; - val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); - break; - } - - writel(val, bank->chip.regs + offset); - - spin_unlock_irqrestore(&sgpio_lock, flags); - - return 0; -} - -static struct irq_chip sirfsoc_irq_chip = { - .name = "sirf-gpio-irq", - .irq_ack = sirfsoc_gpio_irq_ack, - .irq_mask = sirfsoc_gpio_irq_mask, - .irq_unmask = sirfsoc_gpio_irq_unmask, - .irq_set_type = sirfsoc_gpio_irq_type, -}; - -static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) -{ - struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq); - u32 status, ctrl; - int idx = 0; - struct irq_chip *chip = irq_get_chip(irq); - - chained_irq_enter(chip, desc); - - status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id)); - if (!status) { - printk(KERN_WARNING - "%s: gpio id %d status %#x no interrupt is flaged\n", - __func__, bank->id, status); - handle_bad_irq(irq, desc); - return; - } - - while (status) { - ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx)); - - /* - * Here we must check whether the corresponding GPIO's interrupt - * has been enabled, otherwise just skip it - */ - if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) { - pr_debug("%s: gpio id %d idx %d happens\n", - __func__, bank->id, idx); - generic_handle_irq(irq_find_mapping(bank->domain, idx)); - } - - idx++; - status = status >> 1; - } - - chained_irq_exit(chip, desc); -} - -static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset) -{ - u32 val; - - val = readl(bank->chip.regs + ctrl_offset); - val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK; - writel(val, bank->chip.regs + ctrl_offset); -} - -static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - unsigned long flags; - - if (pinctrl_request_gpio(chip->base + offset)) - return -ENODEV; - - spin_lock_irqsave(&bank->lock, flags); - - /* - * default status: - * set direction as input and mask irq - */ - sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); - __sirfsoc_gpio_irq_mask(bank, offset); - - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - - __sirfsoc_gpio_irq_mask(bank, offset); - sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); - - spin_unlock_irqrestore(&bank->lock, flags); - - pinctrl_free_gpio(chip->base + offset); -} - -static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - int idx = sirfsoc_gpio_to_offset(gpio); - unsigned long flags; - unsigned offset; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&bank->lock, flags); - - sirfsoc_gpio_set_input(bank, offset); - - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset, - int value) -{ - u32 out_ctrl; - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - - out_ctrl = readl(bank->chip.regs + offset); - if (value) - out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; - else - out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; - - out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; - out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK; - writel(out_ctrl, bank->chip.regs + offset); - - spin_unlock_irqrestore(&bank->lock, flags); -} - -static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - int idx = sirfsoc_gpio_to_offset(gpio); - u32 offset; - unsigned long flags; - - offset = SIRFSOC_GPIO_CTRL(bank->id, idx); - - spin_lock_irqsave(&sgpio_lock, flags); - - sirfsoc_gpio_set_output(bank, offset, value); - - spin_unlock_irqrestore(&sgpio_lock, flags); - - return 0; -} - -static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - - val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); - - spin_unlock_irqrestore(&bank->lock, flags); - - return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK); -} - -static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - u32 ctrl; - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - - ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); - if (value) - ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; - else - ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; - writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); - - spin_unlock_irqrestore(&bank->lock, flags); -} - -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; - - if (!bank) - return -EINVAL; - - irq_set_chip(irq, &sirfsoc_irq_chip); - irq_set_handler(irq, handle_level_irq); - irq_set_chip_data(irq, bank); - set_irq_flags(irq, IRQF_VALID); - - return 0; -} - -const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = { - .map = sirfsoc_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void sirfsoc_gpio_set_pullup(const u32 *pullups) -{ - int i, n; - const unsigned long *p = (const unsigned long *)pullups; - - for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { - for_each_set_bit(n, p + i, BITS_PER_LONG) { - u32 offset = SIRFSOC_GPIO_CTRL(i, n); - u32 val = readl(sgpio_bank[i].chip.regs + offset); - val |= SIRFSOC_GPIO_CTL_PULL_MASK; - val |= SIRFSOC_GPIO_CTL_PULL_HIGH; - writel(val, sgpio_bank[i].chip.regs + offset); - } - } -} - -static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns) -{ - int i, n; - const unsigned long *p = (const unsigned long *)pulldowns; - - for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { - for_each_set_bit(n, p + i, BITS_PER_LONG) { - u32 offset = SIRFSOC_GPIO_CTRL(i, n); - u32 val = readl(sgpio_bank[i].chip.regs + offset); - val |= SIRFSOC_GPIO_CTL_PULL_MASK; - val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH; - writel(val, sgpio_bank[i].chip.regs + offset); - } - } -} - -static int sirfsoc_gpio_probe(struct device_node *np) -{ - int i, err = 0; - struct sirfsoc_gpio_bank *bank; - void *regs; - struct platform_device *pdev; - bool is_marco = false; - - u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS]; - - pdev = of_find_device_by_node(np); - if (!pdev) - return -ENODEV; - - regs = of_iomap(np, 0); - 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); - bank->chip.gc.request = sirfsoc_gpio_request; - bank->chip.gc.free = sirfsoc_gpio_free; - bank->chip.gc.direction_input = sirfsoc_gpio_direction_input; - bank->chip.gc.get = sirfsoc_gpio_get_value; - bank->chip.gc.direction_output = sirfsoc_gpio_direction_output; - bank->chip.gc.set = sirfsoc_gpio_set_value; - bank->chip.gc.to_irq = sirfsoc_gpio_to_irq; - bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE; - bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE; - bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); - bank->chip.gc.of_node = np; - bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate; - bank->chip.gc.of_gpio_n_cells = 2; - 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; - goto out; - } - - err = gpiochip_add(&bank->chip.gc); - if (err) { - pr_err("%s: error in probe function with status %d\n", - np->full_name, err); - goto out; - } - - bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE, - &sirfsoc_gpio_irq_simple_ops, bank); - - if (!bank->domain) { - pr_err("%s: Failed to create irqdomain\n", np->full_name); - err = -ENOSYS; - goto out; - } - - irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq); - irq_set_handler_data(bank->parent_irq, bank); - } - - if (!of_property_read_u32_array(np, "sirf,pullups", pullups, - SIRFSOC_GPIO_NO_OF_BANKS)) - sirfsoc_gpio_set_pullup(pullups); - - if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns, - SIRFSOC_GPIO_NO_OF_BANKS)) - sirfsoc_gpio_set_pulldown(pulldowns); - - return 0; - -out: - iounmap(regs); - return err; -} - -static int __init sirfsoc_gpio_init(void) -{ - - struct device_node *np; - - np = of_find_matching_node(NULL, pinmux_ids); - - if (!np) - return -ENODEV; - - return sirfsoc_gpio_probe(np); -} -subsys_initcall(sirfsoc_gpio_init); - -MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " - "Yuping Luo <yuping.luo@csr.com>, " - "Barry Song <baohua.song@csr.com>"); -MODULE_DESCRIPTION("SIRFSOC pin control driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c new file mode 100644 index 00000000000..0677e198db6 --- /dev/null +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -0,0 +1,929 @@ +/* + * pinmux driver for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <asm/mach/irq.h> + +#include "pinctrl-sirf.h" + +#define DRIVER_NAME "pinmux-sirf" + +struct sirfsoc_gpio_bank { + struct of_mm_gpio_chip chip; + struct irq_domain *domain; + 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]; +static DEFINE_SPINLOCK(sgpio_lock); + +static struct sirfsoc_pin_group *sirfsoc_pin_groups; +static int sirfsoc_pingrp_cnt; + +static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev) +{ + return sirfsoc_pingrp_cnt; +} + +static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return sirfsoc_pin_groups[selector].name; +} + +static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + *pins = sirfsoc_pin_groups[selector].pins; + *num_pins = sirfsoc_pin_groups[selector].num_pins; + return 0; +} + +static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, " " DRIVER_NAME); +} + +static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev); + struct device_node *np; + struct property *prop; + const char *function, *group; + int ret, index = 0, count = 0; + + /* calculate number of maps required */ + for_each_child_of_node(np_config, np) { + ret = of_property_read_string(np, "sirf,function", &function); + if (ret < 0) + return ret; + + ret = of_property_count_strings(np, "sirf,pins"); + if (ret < 0) + return ret; + + count += ret; + } + + if (!count) { + dev_err(spmx->dev, "No child nodes passed via DT\n"); + return -ENODEV; + } + + *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); + if (!*map) + return -ENOMEM; + + for_each_child_of_node(np_config, np) { + of_property_read_string(np, "sirf,function", &function); + of_property_for_each_string(np, "sirf,pins", prop, group) { + (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[index].data.mux.group = group; + (*map)[index].data.mux.function = function; + index++; + } + } + + *num_maps = count; + + return 0; +} + +static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + kfree(map); +} + +static struct pinctrl_ops sirfsoc_pctrl_ops = { + .get_groups_count = sirfsoc_get_groups_count, + .get_group_name = sirfsoc_get_group_name, + .get_group_pins = sirfsoc_get_group_pins, + .pin_dbg_show = sirfsoc_pin_dbg_show, + .dt_node_to_map = sirfsoc_dt_node_to_map, + .dt_free_map = sirfsoc_dt_free_map, +}; + +static struct sirfsoc_pmx_func *sirfsoc_pmx_functions; +static int sirfsoc_pmxfunc_cnt; + +static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector, + bool enable) +{ + int i; + const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux; + const struct sirfsoc_muxmask *mask = mux->muxmask; + + for (i = 0; i < mux->muxmask_counts; i++) { + u32 muxval; + 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) { + u32 func_en_val; + func_en_val = + readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); + func_en_val = + (func_en_val & ~mux->funcmask) | (mux-> + funcval); + writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); + } +} + +static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector, + unsigned group) +{ + struct sirfsoc_pmx *spmx; + + spmx = pinctrl_dev_get_drvdata(pmxdev); + sirfsoc_pinmux_endisable(spmx, selector, true); + + return 0; +} + +static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector, + unsigned group) +{ + struct sirfsoc_pmx *spmx; + + spmx = pinctrl_dev_get_drvdata(pmxdev); + sirfsoc_pinmux_endisable(spmx, selector, false); +} + +static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev) +{ + return sirfsoc_pmxfunc_cnt; +} + +static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return sirfsoc_pmx_functions[selector].name; +} + +static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = sirfsoc_pmx_functions[selector].groups; + *num_groups = sirfsoc_pmx_functions[selector].num_groups; + return 0; +} + +static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + struct sirfsoc_pmx *spmx; + + int group = range->id; + + u32 muxval; + + spmx = pinctrl_dev_get_drvdata(pmxdev); + + 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; +} + +static struct pinmux_ops sirfsoc_pinmux_ops = { + .enable = sirfsoc_pinmux_enable, + .disable = sirfsoc_pinmux_disable, + .get_functions_count = sirfsoc_pinmux_get_funcs_count, + .get_function_name = sirfsoc_pinmux_get_func_name, + .get_function_groups = sirfsoc_pinmux_get_groups, + .gpio_request_enable = sirfsoc_pinmux_request_gpio, +}; + +static struct pinctrl_desc sirfsoc_pinmux_desc = { + .name = DRIVER_NAME, + .pctlops = &sirfsoc_pctrl_ops, + .pmxops = &sirfsoc_pinmux_ops, + .owner = THIS_MODULE, +}; + +/* + * Todo: bind irq_chip to every pinctrl_gpio_range + */ +static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = { + { + .name = "sirfsoc-gpio*", + .id = 0, + .base = 0, + .pin_base = 0, + .npins = 32, + }, { + .name = "sirfsoc-gpio*", + .id = 1, + .base = 32, + .pin_base = 32, + .npins = 32, + }, { + .name = "sirfsoc-gpio*", + .id = 2, + .base = 64, + .pin_base = 64, + .npins = 32, + }, { + .name = "sirfsoc-gpio*", + .id = 3, + .base = 96, + .pin_base = 96, + .npins = 19, + }, +}; + +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; + + np = of_find_matching_node(NULL, rsc_ids); + if (!np) + panic("unable to find compatible rsc node in dtb\n"); + + return of_iomap(np, 0); +} + +static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE) + return -EINVAL; + + if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE; +} + +static const struct of_device_id pinmux_ids[] = { + { .compatible = "sirf,prima2-pinctrl", .data = &prima2_pinctrl_data, }, + { .compatible = "sirf,atlas6-pinctrl", .data = &atlas6_pinctrl_data, }, + { .compatible = "sirf,marco-pinctrl", .data = &prima2_pinctrl_data, }, + {} +}; + +static int sirfsoc_pinmux_probe(struct platform_device *pdev) +{ + int ret; + struct sirfsoc_pmx *spmx; + struct device_node *np = pdev->dev.of_node; + const struct sirfsoc_pinctrl_data *pdata; + int i; + + /* Create state holders etc for this driver */ + spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL); + if (!spmx) + return -ENOMEM; + + spmx->dev = &pdev->dev; + + platform_set_drvdata(pdev, spmx); + + spmx->gpio_virtbase = of_iomap(np, 0); + if (!spmx->gpio_virtbase) { + dev_err(&pdev->dev, "can't map gpio registers\n"); + return -ENOMEM; + } + + spmx->rsc_virtbase = sirfsoc_rsc_of_iomap(); + if (!spmx->rsc_virtbase) { + ret = -ENOMEM; + dev_err(&pdev->dev, "can't map rsc registers\n"); + goto out_no_rsc_remap; + } + + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + spmx->is_marco = 1; + + pdata = of_match_node(pinmux_ids, np)->data; + sirfsoc_pin_groups = pdata->grps; + sirfsoc_pingrp_cnt = pdata->grps_cnt; + sirfsoc_pmx_functions = pdata->funcs; + sirfsoc_pmxfunc_cnt = pdata->funcs_cnt; + sirfsoc_pinmux_desc.pins = pdata->pads; + sirfsoc_pinmux_desc.npins = pdata->pads_cnt; + + + /* Now register the pin controller and all pins it handles */ + spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx); + if (!spmx->pmx) { + dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n"); + ret = -EINVAL; + goto out_no_pmx; + } + + for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) { + sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc; + pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]); + } + + dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n"); + + return 0; + +out_no_pmx: + iounmap(spmx->rsc_virtbase); +out_no_rsc_remap: + iounmap(spmx->gpio_virtbase); + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int sirfsoc_pinmux_suspend_noirq(struct device *dev) +{ + int i, j; + struct sirfsoc_pmx *spmx = dev_get_drvdata(dev); + + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { + for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) { + spmx->gpio_regs[i][j] = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_CTRL(i, j)); + } + spmx->ints_regs[i] = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_INT_STATUS(i)); + spmx->paden_regs[i] = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(i)); + } + spmx->dspen_regs = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0); + + for (i = 0; i < 3; i++) + spmx->rsc_regs[i] = readl(spmx->rsc_virtbase + 4 * i); + + return 0; +} + +static int sirfsoc_pinmux_resume_noirq(struct device *dev) +{ + int i, j; + struct sirfsoc_pmx *spmx = dev_get_drvdata(dev); + + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { + for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) { + writel(spmx->gpio_regs[i][j], spmx->gpio_virtbase + + SIRFSOC_GPIO_CTRL(i, j)); + } + writel(spmx->ints_regs[i], spmx->gpio_virtbase + + SIRFSOC_GPIO_INT_STATUS(i)); + writel(spmx->paden_regs[i], spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(i)); + } + writel(spmx->dspen_regs, spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0); + + for (i = 0; i < 3; i++) + writel(spmx->rsc_regs[i], spmx->rsc_virtbase + 4 * i); + + return 0; +} + +static const struct dev_pm_ops sirfsoc_pinmux_pm_ops = { + .suspend_noirq = sirfsoc_pinmux_suspend_noirq, + .resume_noirq = sirfsoc_pinmux_resume_noirq, +}; +#endif + +static struct platform_driver sirfsoc_pinmux_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = pinmux_ids, +#ifdef CONFIG_PM_SLEEP + .pm = &sirfsoc_pinmux_pm_ops, +#endif + }, + .probe = sirfsoc_pinmux_probe, +}; + +static int __init sirfsoc_pinmux_init(void) +{ + return platform_driver_register(&sirfsoc_pinmux_driver); +} +arch_initcall(sirfsoc_pinmux_init); + +static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip), + struct sirfsoc_gpio_bank, chip); + + return irq_create_mapping(bank->domain, offset); +} + +static inline int sirfsoc_gpio_to_offset(unsigned int gpio) +{ + return gpio % SIRFSOC_GPIO_BANK_SIZE; +} + +static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio) +{ + return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE]; +} + +static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip) +{ + return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip); +} + +static void sirfsoc_gpio_irq_ack(struct irq_data *d) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; + u32 val, offset; + unsigned long flags; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&sgpio_lock, flags); + + val = readl(bank->chip.regs + offset); + + writel(val, bank->chip.regs + offset); + + spin_unlock_irqrestore(&sgpio_lock, flags); +} + +static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx) +{ + u32 val, offset; + unsigned long flags; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&sgpio_lock, flags); + + val = readl(bank->chip.regs + offset); + val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; + val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; + writel(val, bank->chip.regs + offset); + + spin_unlock_irqrestore(&sgpio_lock, flags); +} + +static void sirfsoc_gpio_irq_mask(struct irq_data *d) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + + __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); +} + +static void sirfsoc_gpio_irq_unmask(struct irq_data *d) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; + u32 val, offset; + unsigned long flags; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&sgpio_lock, flags); + + val = readl(bank->chip.regs + offset); + val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; + val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK; + writel(val, bank->chip.regs + offset); + + spin_unlock_irqrestore(&sgpio_lock, flags); +} + +static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; + u32 val, offset; + unsigned long flags; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&sgpio_lock, flags); + + val = readl(bank->chip.regs + offset); + val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; + + switch (type) { + case IRQ_TYPE_NONE: + break; + case IRQ_TYPE_EDGE_RISING: + val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK; + break; + case IRQ_TYPE_EDGE_FALLING: + val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; + val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + break; + case IRQ_TYPE_EDGE_BOTH: + val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK | + SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; + break; + case IRQ_TYPE_LEVEL_LOW: + val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); + val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK; + break; + case IRQ_TYPE_LEVEL_HIGH: + val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; + val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); + break; + } + + writel(val, bank->chip.regs + offset); + + spin_unlock_irqrestore(&sgpio_lock, flags); + + return 0; +} + +static struct irq_chip sirfsoc_irq_chip = { + .name = "sirf-gpio-irq", + .irq_ack = sirfsoc_gpio_irq_ack, + .irq_mask = sirfsoc_gpio_irq_mask, + .irq_unmask = sirfsoc_gpio_irq_unmask, + .irq_set_type = sirfsoc_gpio_irq_type, +}; + +static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) +{ + struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq); + u32 status, ctrl; + int idx = 0; + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); + + status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id)); + if (!status) { + printk(KERN_WARNING + "%s: gpio id %d status %#x no interrupt is flaged\n", + __func__, bank->id, status); + handle_bad_irq(irq, desc); + return; + } + + while (status) { + ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx)); + + /* + * Here we must check whether the corresponding GPIO's interrupt + * has been enabled, otherwise just skip it + */ + if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) { + pr_debug("%s: gpio id %d idx %d happens\n", + __func__, bank->id, idx); + generic_handle_irq(irq_find_mapping(bank->domain, idx)); + } + + idx++; + status = status >> 1; + } + + chained_irq_exit(chip, desc); +} + +static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset) +{ + u32 val; + + val = readl(bank->chip.regs + ctrl_offset); + val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK; + writel(val, bank->chip.regs + ctrl_offset); +} + +static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + unsigned long flags; + + if (pinctrl_request_gpio(chip->base + offset)) + return -ENODEV; + + spin_lock_irqsave(&bank->lock, flags); + + /* + * default status: + * set direction as input and mask irq + */ + sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); + __sirfsoc_gpio_irq_mask(bank, offset); + + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + + __sirfsoc_gpio_irq_mask(bank, offset); + sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); + + spin_unlock_irqrestore(&bank->lock, flags); + + pinctrl_free_gpio(chip->base + offset); +} + +static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + int idx = sirfsoc_gpio_to_offset(gpio); + unsigned long flags; + unsigned offset; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&bank->lock, flags); + + sirfsoc_gpio_set_input(bank, offset); + + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset, + int value) +{ + u32 out_ctrl; + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + + out_ctrl = readl(bank->chip.regs + offset); + if (value) + out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; + else + out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; + + out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; + out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK; + writel(out_ctrl, bank->chip.regs + offset); + + spin_unlock_irqrestore(&bank->lock, flags); +} + +static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + int idx = sirfsoc_gpio_to_offset(gpio); + u32 offset; + unsigned long flags; + + offset = SIRFSOC_GPIO_CTRL(bank->id, idx); + + spin_lock_irqsave(&sgpio_lock, flags); + + sirfsoc_gpio_set_output(bank, offset, value); + + spin_unlock_irqrestore(&sgpio_lock, flags); + + return 0; +} + +static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + u32 val; + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + + val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + + spin_unlock_irqrestore(&bank->lock, flags); + + return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK); +} + +static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + u32 ctrl; + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + + ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + if (value) + ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; + else + ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; + writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + + spin_unlock_irqrestore(&bank->lock, flags); +} + +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; + + if (!bank) + return -EINVAL; + + irq_set_chip(irq, &sirfsoc_irq_chip); + irq_set_handler(irq, handle_level_irq); + irq_set_chip_data(irq, bank); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = { + .map = sirfsoc_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void sirfsoc_gpio_set_pullup(const u32 *pullups) +{ + int i, n; + const unsigned long *p = (const unsigned long *)pullups; + + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { + for_each_set_bit(n, p + i, BITS_PER_LONG) { + u32 offset = SIRFSOC_GPIO_CTRL(i, n); + u32 val = readl(sgpio_bank[i].chip.regs + offset); + val |= SIRFSOC_GPIO_CTL_PULL_MASK; + val |= SIRFSOC_GPIO_CTL_PULL_HIGH; + writel(val, sgpio_bank[i].chip.regs + offset); + } + } +} + +static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns) +{ + int i, n; + const unsigned long *p = (const unsigned long *)pulldowns; + + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { + for_each_set_bit(n, p + i, BITS_PER_LONG) { + u32 offset = SIRFSOC_GPIO_CTRL(i, n); + u32 val = readl(sgpio_bank[i].chip.regs + offset); + val |= SIRFSOC_GPIO_CTL_PULL_MASK; + val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH; + writel(val, sgpio_bank[i].chip.regs + offset); + } + } +} + +static int sirfsoc_gpio_probe(struct device_node *np) +{ + int i, err = 0; + struct sirfsoc_gpio_bank *bank; + void *regs; + struct platform_device *pdev; + bool is_marco = false; + + u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS]; + + pdev = of_find_device_by_node(np); + if (!pdev) + return -ENODEV; + + regs = of_iomap(np, 0); + 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); + bank->chip.gc.request = sirfsoc_gpio_request; + bank->chip.gc.free = sirfsoc_gpio_free; + bank->chip.gc.direction_input = sirfsoc_gpio_direction_input; + bank->chip.gc.get = sirfsoc_gpio_get_value; + bank->chip.gc.direction_output = sirfsoc_gpio_direction_output; + bank->chip.gc.set = sirfsoc_gpio_set_value; + bank->chip.gc.to_irq = sirfsoc_gpio_to_irq; + bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE; + bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE; + bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); + bank->chip.gc.of_node = np; + bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate; + bank->chip.gc.of_gpio_n_cells = 2; + 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; + goto out; + } + + err = gpiochip_add(&bank->chip.gc); + if (err) { + pr_err("%s: error in probe function with status %d\n", + np->full_name, err); + goto out; + } + + bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE, + &sirfsoc_gpio_irq_simple_ops, bank); + + if (!bank->domain) { + pr_err("%s: Failed to create irqdomain\n", np->full_name); + err = -ENOSYS; + goto out; + } + + irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq); + irq_set_handler_data(bank->parent_irq, bank); + } + + if (!of_property_read_u32_array(np, "sirf,pullups", pullups, + SIRFSOC_GPIO_NO_OF_BANKS)) + sirfsoc_gpio_set_pullup(pullups); + + if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns, + SIRFSOC_GPIO_NO_OF_BANKS)) + sirfsoc_gpio_set_pulldown(pulldowns); + + return 0; + +out: + iounmap(regs); + return err; +} + +static int __init sirfsoc_gpio_init(void) +{ + + struct device_node *np; + + np = of_find_matching_node(NULL, pinmux_ids); + + if (!np) + return -ENODEV; + + return sirfsoc_gpio_probe(np); +} +subsys_initcall(sirfsoc_gpio_init); + +MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " + "Yuping Luo <yuping.luo@csr.com>, " + "Barry Song <baohua.song@csr.com>"); +MODULE_DESCRIPTION("SIRFSOC pin control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.h b/drivers/pinctrl/sirf/pinctrl-sirf.h new file mode 100644 index 00000000000..17cc108510b --- /dev/null +++ b/drivers/pinctrl/sirf/pinctrl-sirf.h @@ -0,0 +1,116 @@ +/* + * pinmux driver shared headfile for CSR SiRFsoc + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __PINMUX_SIRF_H__ +#define __PINMUX_SIRF_H__ + +#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_CLR(g) ((g)*0x100 + 0x90) +#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) +#define SIRFSOC_GPIO_DSP_EN0 (0x80) +#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) + +#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 +#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK 0x2 +#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK 0x4 +#define SIRFSOC_GPIO_CTL_INTR_EN_MASK 0x8 +#define SIRFSOC_GPIO_CTL_INTR_STS_MASK 0x10 +#define SIRFSOC_GPIO_CTL_OUT_EN_MASK 0x20 +#define SIRFSOC_GPIO_CTL_DATAOUT_MASK 0x40 +#define SIRFSOC_GPIO_CTL_DATAIN_MASK 0x80 +#define SIRFSOC_GPIO_CTL_PULL_MASK 0x100 +#define SIRFSOC_GPIO_CTL_PULL_HIGH 0x200 +#define SIRFSOC_GPIO_CTL_DSP_INT 0x400 + +#define SIRFSOC_GPIO_NO_OF_BANKS 5 +#define SIRFSOC_GPIO_BANK_SIZE 32 +#define SIRFSOC_GPIO_NUM(bank, index) (((bank)*(32)) + (index)) + +/** + * @dev: a pointer back to containing device + * @virtbase: the offset to the controller in virtual memory + */ +struct sirfsoc_pmx { + struct device *dev; + struct pinctrl_dev *pmx; + void __iomem *gpio_virtbase; + void __iomem *rsc_virtbase; + u32 gpio_regs[SIRFSOC_GPIO_NO_OF_BANKS][SIRFSOC_GPIO_BANK_SIZE]; + u32 ints_regs[SIRFSOC_GPIO_NO_OF_BANKS]; + u32 paden_regs[SIRFSOC_GPIO_NO_OF_BANKS]; + u32 dspen_regs; + u32 rsc_regs[3]; + bool is_marco; +}; + +/* SIRFSOC_GPIO_PAD_EN set */ +struct sirfsoc_muxmask { + unsigned long group; + unsigned long mask; +}; + +struct sirfsoc_padmux { + unsigned long muxmask_counts; + const struct sirfsoc_muxmask *muxmask; + /* RSC_PIN_MUX set */ + unsigned long funcmask; + unsigned long funcval; +}; + + /** + * struct sirfsoc_pin_group - describes a SiRFprimaII pin group + * @name: the name of this specific pin group + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @num_pins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + */ +struct sirfsoc_pin_group { + const char *name; + const unsigned int *pins; + const unsigned num_pins; +}; + +#define SIRFSOC_PIN_GROUP(n, p) \ + { \ + .name = n, \ + .pins = p, \ + .num_pins = ARRAY_SIZE(p), \ + } + +struct sirfsoc_pmx_func { + const char *name; + const char * const *groups; + const unsigned num_groups; + const struct sirfsoc_padmux *padmux; +}; + +#define SIRFSOC_PMX_FUNCTION(n, g, m) \ + { \ + .name = n, \ + .groups = g, \ + .num_groups = ARRAY_SIZE(g), \ + .padmux = &m, \ + } + +struct sirfsoc_pinctrl_data { + struct pinctrl_pin_desc *pads; + int pads_cnt; + struct sirfsoc_pin_group *grps; + int grps_cnt; + struct sirfsoc_pmx_func *funcs; + int funcs_cnt; +}; + +extern struct sirfsoc_pinctrl_data prima2_pinctrl_data; +extern struct sirfsoc_pinctrl_data atlas6_pinctrl_data; + +#endif diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index 3e5a887216b..0a7f0bdbaa7 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -441,7 +441,7 @@ static int spear310_p2o(int pin) return offset; } -int spear310_o2p(int offset) +static int spear310_o2p(int offset) { if (offset <= 3) return 101 - offset; @@ -528,18 +528,13 @@ static int plgpio_probe(struct platform_device *pdev) 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; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); plgpio->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(plgpio->base)) return PTR_ERR(plgpio->base); diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index 70d986e04af..0cc4335bc0f 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -569,11 +569,9 @@ int wmt_pinctrl_probe(struct platform_device *pdev, struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->base = devm_request_and_ioremap(&pdev->dev, res); - if (!data->base) { - dev_err(&pdev->dev, "failed to map memory resource\n"); - return -EBUSY; - } + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); wmt_desc.pins = data->pins; wmt_desc.npins = data->npins; |