[PATCH v3 1/2] pinctrl: Add driver for Alphascale asm9260 pinctrl

From: Oleksij Rempel
Date: Sun Apr 05 2015 - 02:27:07 EST


This patch adds driver for Alphascale asm9260 pinctrl support.
Alphascale asm9260t is SoC based on ARM926EJ (240MHz) in LQFP176 package.
On silicon are:
- 32MB SDRAM
- USB2.0 HS/OTG
- 2x CAN
- SD/MMC
- 5x Times/PWM
- 10x USART
- 24-channel DMA
- 2x i2c
- 2x SPI
- Quad SPI
- 10/100 Ethernet MAC
- Camera IF
- WD
- RTC
- i2s
- GPIO
- 12-bit A/D
- LCD IF
- 8-channel 12-bit ADC
- NAND

Signed-off-by: Oleksij Rempel <linux@xxxxxxxxxxxxxxxx>
---
drivers/pinctrl/Kconfig | 8 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-asm9260.c | 733 ++++++++++++++++++++++++++++++++++++++
3 files changed, 742 insertions(+)
create mode 100644 drivers/pinctrl/pinctrl-asm9260.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d014f22..054ecbc 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -47,6 +47,14 @@ config PINCTRL_AS3722
open drain configuration for the GPIO pins of AS3722 devices. It also
supports the GPIO functionality through gpiolib.

+config PINCTRL_ASM9260
+ tristate "Pinctrl driver for Alphascale asm9260"
+ depends on MACH_ASM9260
+ select PINMUX
+ select GENERIC_PINCONF
+ help
+ Say Y here to enable the Alphascale asm9260 pinctrl driver
+
config PINCTRL_BF54x
def_bool y if BF54x
select PINCTRL_ADI2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c030b3d..46ba7d1c 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -11,6 +11,7 @@ endif
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o
obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o
+obj-$(CONFIG_PINCTRL_ASM9260) += pinctrl-asm9260.o
obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o
obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
diff --git a/drivers/pinctrl/pinctrl-asm9260.c b/drivers/pinctrl/pinctrl-asm9260.c
new file mode 100644
index 0000000..d31d907
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-asm9260.c
@@ -0,0 +1,733 @@
+/*
+ * Pinctrl driver for the Alphascale ASM9260 SoC
+ *
+ * Copyright (c) 2014, Oleksij Rempel <linux@xxxxxxxxxxxxxxxx>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/* pinctrl register */
+#define IOCON_PIO0_0 0x0000
+/* only two modes are supported NONE and PULL UP */
+#define IOCON_MODE_SHIFT 3
+#define IOCON_MODE_MASK (0x3 << IOCON_MODE_SHIFT)
+/* Only GPIO0_* pins support pull up. */
+#define IOCON_MODE_PULL_UP (0x2 << IOCON_MODE_SHIFT)
+/* Only GPIO0_* pins don't support pull down. */
+#define IOCON_MODE_PULL_DOWN (0x1 << IOCON_MODE_SHIFT)
+#define IOCON_MODE_NONE (0x0 << IOCON_MODE_SHIFT)
+/* up to 8 functions per pin */
+#define IOCON_PINMUX_MASK (0x7 << 0)
+
+#define MUX_OFFSET(bank, pin) ((bank) * 32 + (pin) * 4)
+
+enum asm9260_mux {
+ ASM9260_MUX_na = -1,
+
+ ASM9260_MUX_gpio0,
+ ASM9260_MUX_cam0,
+ ASM9260_MUX_can0,
+ ASM9260_MUX_can1,
+ ASM9260_MUX_ct0,
+ ASM9260_MUX_ct1,
+ ASM9260_MUX_ct2,
+ ASM9260_MUX_ct3,
+ ASM9260_MUX_i2c0,
+ ASM9260_MUX_i2c1,
+ ASM9260_MUX_i2s0,
+ ASM9260_MUX_i2s1,
+ ASM9260_MUX_jtag,
+ ASM9260_MUX_lcd0,
+ ASM9260_MUX_lcd_if0,
+ ASM9260_MUX_mc,
+ ASM9260_MUX_mc0,
+ ASM9260_MUX_mii0,
+ ASM9260_MUX_nand0,
+ ASM9260_MUX_outclk,
+ ASM9260_MUX_qei0,
+ ASM9260_MUX_qspi0,
+ ASM9260_MUX_rmii0,
+ ASM9260_MUX_sd0,
+ ASM9260_MUX_spi0,
+ ASM9260_MUX_spi1,
+ ASM9260_MUX_uart0,
+ ASM9260_MUX_uart1,
+ ASM9260_MUX_uart2,
+ ASM9260_MUX_uart3,
+ ASM9260_MUX_uart4,
+ ASM9260_MUX_uart5,
+ ASM9260_MUX_uart6,
+ ASM9260_MUX_uart7,
+ ASM9260_MUX_uart8,
+ ASM9260_MUX_uart9,
+};
+
+struct asm9260_function {
+ const char *name;
+ const char **groups;
+ unsigned int ngroups;
+};
+
+#define FUNCTION(mux) \
+ [(ASM9260_MUX_ ## mux)] = { \
+ .name = #mux, \
+ .groups = NULL, \
+ .ngroups = 0, \
+ }
+
+static struct asm9260_function asm9260_functions[] = {
+ FUNCTION(gpio0),
+ FUNCTION(cam0),
+ FUNCTION(can0),
+ FUNCTION(can1),
+ FUNCTION(ct0),
+ FUNCTION(ct1),
+ FUNCTION(ct2),
+ FUNCTION(ct3),
+ FUNCTION(i2c0),
+ FUNCTION(i2c1),
+ FUNCTION(i2s0),
+ FUNCTION(i2s1),
+ FUNCTION(jtag),
+ FUNCTION(lcd0),
+ FUNCTION(lcd_if0),
+ FUNCTION(mc),
+ FUNCTION(mc0),
+ FUNCTION(mii0),
+ FUNCTION(nand0),
+ FUNCTION(outclk),
+ FUNCTION(qei0),
+ FUNCTION(qspi0),
+ FUNCTION(rmii0),
+ FUNCTION(sd0),
+ FUNCTION(spi0),
+ FUNCTION(spi1),
+ FUNCTION(uart0),
+ FUNCTION(uart1),
+ FUNCTION(uart2),
+ FUNCTION(uart3),
+ FUNCTION(uart4),
+ FUNCTION(uart5),
+ FUNCTION(uart6),
+ FUNCTION(uart7),
+ FUNCTION(uart8),
+ FUNCTION(uart9),
+};
+
+struct asm9260_pingroup {
+ const char *name;
+ const unsigned int number;
+ const unsigned int bank;
+ const unsigned int pin;
+
+#define MAX_FUNCS_PER_PIN 8
+ const int funcs[MAX_FUNCS_PER_PIN];
+};
+
+#define PMUX(p_number, p_bank, p_pin, p_name, f1, f2, f3, f4, f5, f6, f7) \
+ { \
+ .number = p_number, \
+ .bank = p_bank, \
+ .pin = p_pin, \
+ .name = #p_name, \
+ .funcs = { \
+ ASM9260_MUX_gpio0, \
+ ASM9260_MUX_ ## f1, \
+ ASM9260_MUX_ ## f2, \
+ ASM9260_MUX_ ## f3, \
+ ASM9260_MUX_ ## f4, \
+ ASM9260_MUX_ ## f5, \
+ ASM9260_MUX_ ## f6, \
+ ASM9260_MUX_ ## f7, \
+ }, \
+ }
+
+static struct asm9260_pingroup asm9260_mux_table[] = {
+ PMUX(120, 0, 0, GPIO0_0,
+ na, uart1, i2s0, spi1, na, jtag, na),
+ PMUX(121, 0, 1, GPIO0_1,
+ na, uart1, i2s0, spi1, na, jtag, na),
+ PMUX(122, 0, 2, GPIO0_2,
+ na, uart1, i2s0, spi1, na, jtag, na),
+ PMUX(123, 0, 3, GPIO0_3,
+ na, uart1, i2s0, spi1, na, jtag, na),
+ PMUX(124, 0, 4, GPIO0_4,
+ na, uart1, i2s0, spi0, na, jtag, i2c0),
+ PMUX(128, 1, 4, GPIO1_4,
+ ct0, uart0, lcd_if0, spi0, mii0, lcd0, na),
+ PMUX(129, 1, 5, GPIO1_5,
+ na, uart0, lcd_if0, spi0, rmii0, lcd0, na),
+ PMUX(130, 1, 6, GPIO1_6,
+ na, uart0, lcd_if0, spi0, rmii0, lcd0, i2c1),
+ PMUX(131, 1, 7, GPIO1_7,
+ na, uart0, lcd_if0, spi0, rmii0, lcd0, i2c1),
+ PMUX(132, 2, 0, GPIO2_0,
+ ct1, uart2, lcd_if0, spi1, mii0, lcd0, can0),
+ PMUX(133, 2, 1, GPIO2_1,
+ ct1, uart2, lcd_if0, spi1, mii0, lcd0, can0),
+ PMUX(134, 2, 2, GPIO2_2,
+ ct1, uart3, lcd_if0, spi1, mii0, lcd0, na),
+ PMUX(135, 2, 3, GPIO2_3,
+ ct1, uart3, lcd_if0, spi1, mii0, lcd0, na),
+ PMUX(136, 2, 4, GPIO2_4,
+ ct1, uart3, lcd_if0, na, mii0, lcd0, na),
+ PMUX(137, 2, 5, GPIO2_5,
+ na, uart3, lcd_if0, na, mii0, lcd0, outclk),
+ PMUX(138, 2, 6, GPIO2_6,
+ na, uart3, lcd_if0, na, mii0, lcd0, can1),
+ PMUX(139, 2, 7, GPIO2_7,
+ na, uart4, lcd_if0, na, mii0, lcd0, can1),
+ PMUX(140, 3, 0, GPIO3_0,
+ ct2, uart4, lcd_if0, sd0, rmii0, lcd0, na),
+ PMUX(141, 3, 1, GPIO3_1,
+ ct2, uart4, lcd_if0, sd0, rmii0, lcd0, na),
+ PMUX(142, 3, 2, GPIO3_2,
+ ct2, uart4, lcd_if0, sd0, rmii0, lcd0, can1),
+ PMUX(143, 3, 3, GPIO3_3,
+ ct2, uart4, lcd_if0, sd0, rmii0, lcd0, can1),
+ PMUX(144, 3, 4, GPIO3_4,
+ ct2, uart5, lcd_if0, sd0, rmii0, lcd0, outclk),
+ PMUX(145, 3, 5, GPIO3_5,
+ na, uart5, lcd_if0, sd0, rmii0, lcd0, i2c0),
+ PMUX(146, 3, 6, GPIO3_6,
+ na, uart5, lcd_if0, na, rmii0, lcd0, i2c0),
+ PMUX(147, 3, 7, GPIO3_7,
+ na, uart5, lcd_if0, na, rmii0, lcd0, na),
+ PMUX(151, 4, 0, GPIO4_0,
+ ct3, uart5, na, qspi0, mii0, lcd0, na),
+ PMUX(152, 4, 1, GPIO4_1,
+ ct3, uart6, na, qspi0, mii0, lcd0, na),
+ PMUX(153, 4, 2, GPIO4_2,
+ ct3, uart6, na, qspi0, mii0, lcd0, na),
+ PMUX(154, 4, 3, GPIO4_3,
+ ct3, uart6, na, qspi0, mii0, lcd0, na),
+ PMUX(155, 4, 4, GPIO4_4,
+ ct3, uart6, na, qspi0, mii0, lcd0, na),
+ PMUX(156, 4, 5, GPIO4_5,
+ na, uart6, na, qspi0, mii0, lcd0, na),
+ PMUX(157, 4, 6, GPIO4_6,
+ na, na, na, na, mii0, lcd0, i2c1),
+ PMUX(158, 4, 7, GPIO4_7,
+ na, na, na, na, mii0, lcd0, i2c1),
+ PMUX(169, 5, 0, GPIO5_0,
+ mc0, uart7, i2s1, sd0, rmii0, na, na),
+ PMUX(170, 5, 1, GPIO5_1,
+ mc0, uart7, i2s1, sd0, rmii0, na, na),
+ PMUX(171, 5, 2, GPIO5_2,
+ mc0, uart7, i2s1, sd0, rmii0, na, can0),
+ PMUX(172, 5, 3, GPIO5_3,
+ mc0, uart7, i2s1, sd0, rmii0, na, can0),
+ PMUX(173, 5, 4, GPIO5_4,
+ mc0, uart8, i2s1, sd0, rmii0, na, na),
+ PMUX(51, 8, 1, GPIO8_1,
+ na, uart2, cam0, na, mii0, na, na),
+ PMUX(52, 8, 2, GPIO8_2,
+ na, uart2, cam0, na, mii0, na, na),
+ PMUX(53, 8, 3, GPIO8_3,
+ na, uart2, cam0, na, mii0, na, na),
+ PMUX(54, 8, 4, GPIO8_4,
+ na, uart2, cam0, na, mii0, na, na),
+ PMUX(55, 8, 5, GPIO8_5,
+ na, uart3, cam0, na, mii0, na, na),
+ PMUX(56, 8, 6, GPIO8_6,
+ na, uart3, cam0, na, mii0, na, na),
+ PMUX(57, 8, 7, GPIO8_7,
+ na, uart3, cam0, na, mii0, na, na),
+ PMUX(45, 9, 0, GPIO9_0,
+ ct0, uart3, cam0, na, rmii0, na, i2c0),
+ PMUX(46, 9, 1, GPIO9_1,
+ ct0, uart3, cam0, na, rmii0, na, i2c0),
+ PMUX(47, 9, 2, GPIO9_2,
+ ct0, uart4, cam0, na, rmii0, na, na),
+ PMUX(48, 9, 3, GPIO9_3,
+ ct0, uart4, cam0, na, rmii0, na, na),
+ PMUX(49, 9, 4, GPIO9_4,
+ ct0, uart4, cam0, na, rmii0, na, na),
+ PMUX(50, 9, 5, GPIO9_5,
+ na, uart4, cam0, na, rmii0, na, i2c1),
+ PMUX(4, 10, 0, GPIO10_0,
+ ct1, uart5, i2s0, spi0, na, na, na),
+ PMUX(5, 10, 1, GPIO10_1,
+ ct1, uart5, i2s0, spi0, rmii0, na, na),
+ PMUX(6, 10, 2, GPIO10_2,
+ ct1, uart5, i2s0, spi0, rmii0, na, na),
+ PMUX(7, 10, 3, GPIO10_3,
+ ct1, uart5, i2s0, spi0, na, na, can0),
+ PMUX(8, 10, 4, GPIO10_4,
+ ct1, uart6, i2s0, spi1, rmii0, na, na),
+ PMUX(9, 10, 5, GPIO10_5,
+ na, uart6, i2s0, spi1, rmii0, na, can1),
+ PMUX(10, 10, 6, GPIO10_6,
+ na, uart6, i2s0, spi1, rmii0, na, can1),
+ PMUX(11, 10, 7, GPIO10_7,
+ na, uart6, cam0, spi1, rmii0, na, na),
+ PMUX(12, 11, 0, GPIO11_0,
+ ct2, uart7, i2s1, qspi0, nand0, na, na),
+ PMUX(13, 11, 1, GPIO11_1,
+ ct2, uart7, i2s1, qspi0, nand0, na, na),
+ PMUX(14, 11, 2, GPIO11_2,
+ ct2, uart7, i2s1, qspi0, nand0, na, na),
+ PMUX(15, 11, 3, GPIO11_3,
+ ct2, uart7, i2s1, qspi0, nand0, na, na),
+ PMUX(16, 11, 4, GPIO11_4,
+ ct2, uart8, i2s1, qspi0, nand0, na, na),
+ PMUX(17, 11, 5, GPIO11_5,
+ na, uart8, i2s1, qspi0, nand0, na, na),
+ PMUX(18, 11, 6, GPIO11_6,
+ na, uart9, i2s1, na, nand0, na, i2c0),
+ PMUX(19, 11, 7, GPIO11_7,
+ na, uart9, cam0, na, nand0, na, i2c0),
+ PMUX(23, 12, 0, GPIO12_0,
+ ct3, uart1, na, sd0, nand0, na, na),
+ PMUX(24, 12, 1, GPIO12_1,
+ ct3, uart1, na, sd0, nand0, na, na),
+ PMUX(25, 12, 2, GPIO12_2,
+ ct3, uart1, na, sd0, nand0, na, na),
+ PMUX(26, 12, 3, GPIO12_3,
+ ct3, uart1, na, sd0, nand0, na, na),
+ PMUX(27, 12, 4, GPIO12_4,
+ ct3, uart1, na, sd0, nand0, na, na),
+ PMUX(28, 12, 5, GPIO12_5,
+ na, uart8, na, sd0, nand0, na, na),
+ PMUX(29, 12, 6, GPIO12_6,
+ na, uart8, cam0, na, nand0, na, i2c1),
+ PMUX(30, 12, 7, GPIO12_7,
+ na, na, cam0, na, nand0, na, i2c1),
+ PMUX(31, 13, 4, GPIO13_4,
+ mc, uart2, na, spi1, nand0, na, na),
+ PMUX(32, 13, 5, GPIO13_5,
+ mc0, uart9, na, spi1, nand0, na, na),
+ PMUX(33, 13, 6, GPIO13_6,
+ mc0, uart9, na, spi1, nand0, na, na),
+ PMUX(34, 13, 7, GPIO13_7,
+ mc0, na, na, spi1, nand0, na, na),
+ PMUX(38, 14, 0, GPIO14_0,
+ mc0, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(39, 14, 1, GPIO14_1,
+ mc0, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(40, 14, 2, GPIO14_2,
+ na, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(41, 14, 3, GPIO14_3,
+ na, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(42, 14, 4, GPIO14_4,
+ na, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(43, 14, 5, GPIO14_5,
+ na, uart0, i2s0, sd0, nand0, na, na),
+ PMUX(44, 15, 0, GPIO15_0,
+ na, uart4, i2s0, sd0, rmii0, na, na),
+ PMUX(61, 15, 1, GPIO15_1,
+ na, uart4, i2s0, sd0, rmii0, na, na),
+ PMUX(62, 15, 2, GPIO15_2,
+ na, uart5, i2s0, sd0, rmii0, na, na),
+ PMUX(63, 15, 3, GPIO15_3,
+ na, uart5, i2s0, sd0, rmii0, na, na),
+ PMUX(64, 15, 4, GPIO15_4,
+ na, uart6, i2s0, sd0, rmii0, na, na),
+ PMUX(65, 15, 5, GPIO15_5,
+ na, uart6, i2s0, sd0, rmii0, na, na),
+ PMUX(66, 15, 6, GPIO15_6,
+ na, uart7, i2s0, na, rmii0, na, na),
+ PMUX(67, 15, 7, GPIO15_7,
+ na, uart7, na, na, rmii0, na, na),
+ PMUX(73, 16, 0, GPIO16_0,
+ ct2, uart4, na, na, mii0, na, na),
+ PMUX(74, 16, 1, GPIO16_1,
+ ct2, uart4, na, na, mii0, na, na),
+ PMUX(75, 16, 2, GPIO16_2,
+ ct2, uart5, na, na, mii0, na, na),
+ PMUX(76, 16, 3, GPIO16_3,
+ ct2, uart5, na, na, mii0, na, na),
+ PMUX(77, 16, 4, GPIO16_4,
+ ct2, uart6, na, na, mii0, na, na),
+ PMUX(78, 16, 5, GPIO16_5,
+ qei0, uart6, na, na, mii0, na, na),
+ PMUX(79, 16, 6, GPIO16_6,
+ qei0, uart6, na, na, mii0, na, can1),
+ PMUX(80, 16, 7, GPIO16_7,
+ qei0, uart6, na, na, mii0, na, can1),
+ PMUX(81, 17, 0, GPIO17_0,
+ ct3, uart7, i2s1, na, rmii0, na, na),
+ PMUX(82, 17, 1, GPIO17_1,
+ ct3, uart7, i2s1, na, na, na, na),
+ PMUX(83, 17, 2, GPIO17_2,
+ ct3, uart7, i2s1, na, na, na, i2c1),
+ PMUX(84, 17, 3, GPIO17_3,
+ ct3, uart7, i2s1, na, na, na, i2c1),
+ PMUX(85, 17, 4, GPIO17_4,
+ ct3, uart8, i2s1, na, na, na, na),
+ PMUX(86, 17, 5, GPIO17_5,
+ qei0, uart8, i2s1, na, rmii0, na, na),
+ PMUX(87, 17, 6, GPIO17_6,
+ qei0, uart9, i2s1, na, mii0, na, na),
+ PMUX(88, 17, 7, GPIO17_7,
+ qei0, uart9, na, na, mii0, na, na),
+};
+
+#define MUX_TABLE_SIZE ARRAY_SIZE(asm9260_mux_table)
+struct asm9260_pmx_priv {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *iobase;
+
+ struct clk *clk;
+ spinlock_t lock;
+
+ struct pinctrl_pin_desc pin_desc[MUX_TABLE_SIZE];
+};
+
+static void __init asm9260_init_mux_pins(struct asm9260_pmx_priv *priv)
+{
+ unsigned int i;
+
+ for (i = 0; i < MUX_TABLE_SIZE; i++) {
+ priv->pin_desc[i].name = asm9260_mux_table[i].name;
+ priv->pin_desc[i].number = asm9260_mux_table[i].number;
+ }
+}
+
+/*
+ * Pin control operations
+ */
+
+/* each GPIO pin has it's own pseudo pingroup containing only itself */
+static int asm9260_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return MUX_TABLE_SIZE;
+}
+
+static const char *asm9260_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int group)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+ return priv->pin_desc[group].name;
+}
+
+static int asm9260_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int group,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &priv->pin_desc[group].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static struct pinctrl_ops asm9260_pinctrl_ops = {
+ .get_groups_count = asm9260_pinctrl_get_groups_count,
+ .get_group_name = asm9260_pinctrl_get_group_name,
+ .get_group_pins = asm9260_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+/*
+ * Pin mux operations
+ */
+static int asm9260_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(asm9260_functions);
+}
+
+static const char *asm9260_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned int function)
+{
+ return asm9260_functions[function].name;
+}
+
+static int asm9260_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned int function,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+ struct asm9260_pingroup *table;
+ int a, b, count = 0, *tmp;
+ const char **gr;
+
+ if (asm9260_functions[function].groups != NULL)
+ goto done;
+
+ tmp = devm_kmalloc(priv->dev, sizeof(tmp) * MUX_TABLE_SIZE, GFP_KERNEL);
+ if (!tmp) {
+ dev_err(priv->dev, "Can't allocate func/pin array\n");
+ return PTR_ERR(tmp);
+ }
+
+ for (a = 0; a < MUX_TABLE_SIZE; a++) {
+ table = &asm9260_mux_table[a];
+
+ for (b = 0; b < MAX_FUNCS_PER_PIN; b++) {
+ if (table->funcs[b] == function) {
+ tmp[count] = a;
+ count++;
+ }
+
+ }
+
+ }
+
+ gr = devm_kmalloc(priv->dev,
+ sizeof(gr) * count, GFP_KERNEL);
+ if (!gr) {
+ dev_err(priv->dev, "Can't allocate func group\n");
+ devm_kfree(priv->dev, tmp);
+ return PTR_ERR(gr);
+ }
+
+ for (a = 0; a < count; a++)
+ gr[a] = asm9260_mux_table[tmp[a]].name;
+
+ asm9260_functions[function].groups = gr;
+ asm9260_functions[function].ngroups = count;
+done:
+ *groups = asm9260_functions[function].groups;
+ *num_groups = asm9260_functions[function].ngroups;
+ return 0;
+}
+
+static int asm9260_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int pin)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+ struct asm9260_pingroup *table;
+ void __iomem *offset;
+ int mux;
+ u32 val;
+
+ table = &asm9260_mux_table[pin];
+ for (mux = 0; mux < MAX_FUNCS_PER_PIN; ++mux) {
+ if (table->funcs[mux] == function)
+ goto found_mux;
+ }
+
+ return -EINVAL;
+
+found_mux:
+ offset = priv->iobase + MUX_OFFSET(table->bank, table->pin);
+ spin_lock(&priv->lock);
+ val = ioread32(offset);
+ val &= ~IOCON_PINMUX_MASK;
+ val |= mux;
+ iowrite32(val, offset);
+ spin_unlock(&priv->lock);
+
+ return 0;
+}
+
+static struct pinmux_ops asm9260_pinmux_ops = {
+ .get_functions_count = asm9260_pinctrl_get_funcs_count,
+ .get_function_name = asm9260_pinctrl_get_func_name,
+ .get_function_groups = asm9260_pinctrl_get_func_groups,
+ .set_mux = asm9260_pinctrl_set_mux,
+ /* TODO: should we care about gpios here? gpio_request_enable? */
+};
+
+static int asm9260_pinconf_reg(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ enum pin_config_param param,
+ void __iomem **reg, u32 *val)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+ struct asm9260_pingroup *table;
+ int a;
+
+ for (a = 0; a < MUX_TABLE_SIZE; a++) {
+ table = &asm9260_mux_table[a];
+ if (table->number == pin)
+ break;
+ }
+
+ *reg = priv->iobase + MUX_OFFSET(table->bank, table->pin);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ *val = IOCON_MODE_NONE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (table->bank != 0)
+ return -ENOTSUPP;
+ *val = IOCON_MODE_PULL_UP;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (table->bank == 0)
+ return -ENOTSUPP;
+ *val = IOCON_MODE_PULL_DOWN;
+ break;
+ default:
+ return -ENOTSUPP;
+ };
+
+ return 0;
+}
+
+static int asm9260_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ void __iomem *reg;
+ u32 val, tmp, arg;
+ int ret;
+
+ /* Get register information */
+ ret = asm9260_pinconf_reg(pctldev, pin, param,
+ &reg, &val);
+ if (ret < 0)
+ return ret;
+
+ /* Extract field from register */
+ tmp = ioread32(reg);
+ arg = (tmp & IOCON_MODE_MASK) == val;
+ if (!arg)
+ return -EINVAL;
+
+ /* And pack config */
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int asm9260_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *configs,
+ unsigned num_configs)
+{
+ struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param;
+ unsigned int arg;
+ int ret;
+ u32 val, tmp;
+ void __iomem *reg;
+ int i;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ /* Get register information */
+ ret = asm9260_pinconf_reg(pctldev, pin, param,
+ &reg, &val);
+ if (ret < 0)
+ return ret;
+
+ spin_lock(&priv->lock);
+ tmp = ioread32(reg);
+ tmp &= ~IOCON_MODE_MASK;
+ if (arg)
+ tmp |= val;
+ iowrite32(tmp, reg);
+ spin_unlock(&priv->lock);
+ }
+
+ return 0;
+}
+
+static struct pinconf_ops asm9260_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = asm9260_pinconf_get,
+ .pin_config_set = asm9260_pinconf_set,
+};
+
+/*
+ * Pin control driver setup
+ */
+static struct pinctrl_desc asm9260_pinctrl_desc = {
+ .pctlops = &asm9260_pinctrl_ops,
+ .pmxops = &asm9260_pinmux_ops,
+ .confops = &asm9260_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int asm9260_pinctrl_probe(struct platform_device *pdev)
+{
+ struct asm9260_pmx_priv *priv;
+ struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "Can't alloc asm9260_priv\n");
+ return -ENOMEM;
+ }
+ priv->dev = &pdev->dev;
+ spin_lock_init(&priv->lock);
+
+ asm9260_init_mux_pins(priv);
+
+ asm9260_pinctrl_desc.name = dev_name(&pdev->dev);
+ asm9260_pinctrl_desc.pins = priv->pin_desc;
+ asm9260_pinctrl_desc.npins = MUX_TABLE_SIZE;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ priv->clk = devm_clk_get(&pdev->dev, "ahb");
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable clk!\n");
+ return ret;
+ }
+
+ priv->pctl = pinctrl_register(&asm9260_pinctrl_desc, &pdev->dev, priv);
+ if (!priv->pctl) {
+ dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+ ret = -ENODEV;
+ goto err_return;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ dev_info(&pdev->dev, "ASM9260 pinctrl driver initialised\n");
+
+ return 0;
+err_return:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int asm9260_pinctrl_remove(struct platform_device *pdev)
+{
+ struct asm9260_pmx_priv *priv = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(priv->clk);
+ pinctrl_unregister(priv->pctl);
+
+ return 0;
+}
+
+static struct of_device_id asm9260_pinctrl_of_match[] = {
+ { .compatible = "alphascale,asm9260-pinctrl", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, asm9260_pinctrl_of_match);
+
+static struct platform_driver asm9260_pinctrl_driver = {
+ .driver = {
+ .name = "asm9260-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = asm9260_pinctrl_of_match,
+ },
+ .probe = asm9260_pinctrl_probe,
+ .remove = asm9260_pinctrl_remove,
+};
+module_platform_driver(asm9260_pinctrl_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <linux@xxxxxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("Alphascale ASM9260 pinctrl driver");
+MODULE_LICENSE("GPL");
--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/