diff options
author | David Daney <david.daney@cavium.com> | 2013-07-29 17:29:10 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-08-26 09:33:40 -0400 |
commit | aca58a662067606e6020e1d42ced1b88cab65ca1 (patch) | |
tree | 30f129adbb1f18d1f995162303d0890863ca1fd0 /drivers/gpio | |
parent | 99cab4bb4fdf6c2cb26324bd8537fdc35ff92021 (diff) |
gpio MIPS/OCTEON: Add a driver for OCTEON's on-chip GPIO pins.
The SOCs in the OCTEON family have 16 (or in some cases 20) on-chip
GPIO pins, this driver handles them all. Configuring the pins as
interrupt sources is handled elsewhere (OCTEON's irq handling code).
Signed-off-by: David Daney <david.daney@cavium.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Cc: linux-gpio@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/5633/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-octeon.c | 157 |
3 files changed, 166 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b2450ba14138..b21b7a2d1c3d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -193,6 +193,14 @@ config GPIO_MXS | |||
193 | select GPIO_GENERIC | 193 | select GPIO_GENERIC |
194 | select GENERIC_IRQ_CHIP | 194 | select GENERIC_IRQ_CHIP |
195 | 195 | ||
196 | config GPIO_OCTEON | ||
197 | tristate "Cavium OCTEON GPIO" | ||
198 | depends on GPIOLIB && CAVIUM_OCTEON_SOC | ||
199 | default y | ||
200 | help | ||
201 | Say yes here to support the on-chip GPIO lines on the OCTEON | ||
202 | family of SOCs. | ||
203 | |||
196 | config GPIO_PL061 | 204 | config GPIO_PL061 |
197 | bool "PrimeCell PL061 GPIO support" | 205 | bool "PrimeCell PL061 GPIO support" |
198 | depends on ARM && ARM_AMBA | 206 | depends on ARM && ARM_AMBA |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ef3e983a2f1e..e7fd9800dad4 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -50,6 +50,7 @@ obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o | |||
50 | obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o | 50 | obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o |
51 | obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o | 51 | obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o |
52 | obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o | 52 | obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o |
53 | obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o | ||
53 | obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o | 54 | obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o |
54 | obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o | 55 | obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o |
55 | obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o | 56 | obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o |
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c new file mode 100644 index 000000000000..71a4a318315d --- /dev/null +++ b/drivers/gpio/gpio-octeon.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2011, 2012 Cavium Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/gpio.h> | ||
13 | #include <linux/io.h> | ||
14 | |||
15 | #include <asm/octeon/octeon.h> | ||
16 | #include <asm/octeon/cvmx-gpio-defs.h> | ||
17 | |||
18 | #define RX_DAT 0x80 | ||
19 | #define TX_SET 0x88 | ||
20 | #define TX_CLEAR 0x90 | ||
21 | /* | ||
22 | * The address offset of the GPIO configuration register for a given | ||
23 | * line. | ||
24 | */ | ||
25 | static unsigned int bit_cfg_reg(unsigned int offset) | ||
26 | { | ||
27 | /* | ||
28 | * The register stride is 8, with a discontinuity after the | ||
29 | * first 16. | ||
30 | */ | ||
31 | if (offset < 16) | ||
32 | return 8 * offset; | ||
33 | else | ||
34 | return 8 * (offset - 16) + 0x100; | ||
35 | } | ||
36 | |||
37 | struct octeon_gpio { | ||
38 | struct gpio_chip chip; | ||
39 | u64 register_base; | ||
40 | }; | ||
41 | |||
42 | static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) | ||
43 | { | ||
44 | struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip); | ||
45 | |||
46 | cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
51 | { | ||
52 | struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip); | ||
53 | u64 mask = 1ull << offset; | ||
54 | u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR); | ||
55 | cvmx_write_csr(reg, mask); | ||
56 | } | ||
57 | |||
58 | static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, | ||
59 | int value) | ||
60 | { | ||
61 | struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip); | ||
62 | union cvmx_gpio_bit_cfgx cfgx; | ||
63 | |||
64 | octeon_gpio_set(chip, offset, value); | ||
65 | |||
66 | cfgx.u64 = 0; | ||
67 | cfgx.s.tx_oe = 1; | ||
68 | |||
69 | cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), cfgx.u64); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
74 | { | ||
75 | struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip); | ||
76 | u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT); | ||
77 | |||
78 | return ((1ull << offset) & read_bits) != 0; | ||
79 | } | ||
80 | |||
81 | static int octeon_gpio_probe(struct platform_device *pdev) | ||
82 | { | ||
83 | struct octeon_gpio *gpio; | ||
84 | struct gpio_chip *chip; | ||
85 | struct resource *res_mem; | ||
86 | int err = 0; | ||
87 | |||
88 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); | ||
89 | if (!gpio) | ||
90 | return -ENOMEM; | ||
91 | chip = &gpio->chip; | ||
92 | |||
93 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
94 | if (res_mem == NULL) { | ||
95 | dev_err(&pdev->dev, "found no memory resource\n"); | ||
96 | err = -ENXIO; | ||
97 | goto out; | ||
98 | } | ||
99 | if (!devm_request_mem_region(&pdev->dev, res_mem->start, | ||
100 | resource_size(res_mem), | ||
101 | res_mem->name)) { | ||
102 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
103 | err = -ENXIO; | ||
104 | goto out; | ||
105 | } | ||
106 | gpio->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, | ||
107 | resource_size(res_mem)); | ||
108 | |||
109 | pdev->dev.platform_data = chip; | ||
110 | chip->label = "octeon-gpio"; | ||
111 | chip->dev = &pdev->dev; | ||
112 | chip->owner = THIS_MODULE; | ||
113 | chip->base = 0; | ||
114 | chip->can_sleep = 0; | ||
115 | chip->ngpio = 20; | ||
116 | chip->direction_input = octeon_gpio_dir_in; | ||
117 | chip->get = octeon_gpio_get; | ||
118 | chip->direction_output = octeon_gpio_dir_out; | ||
119 | chip->set = octeon_gpio_set; | ||
120 | err = gpiochip_add(chip); | ||
121 | if (err) | ||
122 | goto out; | ||
123 | |||
124 | dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n"); | ||
125 | out: | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | static int octeon_gpio_remove(struct platform_device *pdev) | ||
130 | { | ||
131 | struct gpio_chip *chip = pdev->dev.platform_data; | ||
132 | return gpiochip_remove(chip); | ||
133 | } | ||
134 | |||
135 | static struct of_device_id octeon_gpio_match[] = { | ||
136 | { | ||
137 | .compatible = "cavium,octeon-3860-gpio", | ||
138 | }, | ||
139 | {}, | ||
140 | }; | ||
141 | MODULE_DEVICE_TABLE(of, octeon_gpio_match); | ||
142 | |||
143 | static struct platform_driver octeon_gpio_driver = { | ||
144 | .driver = { | ||
145 | .name = "octeon_gpio", | ||
146 | .owner = THIS_MODULE, | ||
147 | .of_match_table = octeon_gpio_match, | ||
148 | }, | ||
149 | .probe = octeon_gpio_probe, | ||
150 | .remove = octeon_gpio_remove, | ||
151 | }; | ||
152 | |||
153 | module_platform_driver(octeon_gpio_driver); | ||
154 | |||
155 | MODULE_DESCRIPTION("Cavium Inc. OCTEON GPIO Driver"); | ||
156 | MODULE_AUTHOR("David Daney"); | ||
157 | MODULE_LICENSE("GPL"); | ||