diff options
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-clps711x/include/mach/gpio.h | 13 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 4 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-clps711x.c | 163 |
5 files changed, 182 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 73067efd4845..f456cf4ae3ca 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -364,6 +364,7 @@ config ARCH_CNS3XXX | |||
364 | 364 | ||
365 | config ARCH_CLPS711X | 365 | config ARCH_CLPS711X |
366 | bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" | 366 | bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" |
367 | select ARCH_REQUIRE_GPIOLIB | ||
367 | select ARCH_USES_GETTIMEOFFSET | 368 | select ARCH_USES_GETTIMEOFFSET |
368 | select CLKDEV_LOOKUP | 369 | select CLKDEV_LOOKUP |
369 | select COMMON_CLK | 370 | select COMMON_CLK |
diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h new file mode 100644 index 000000000000..8ac6889fabcd --- /dev/null +++ b/arch/arm/mach-clps711x/include/mach/gpio.h | |||
@@ -0,0 +1,13 @@ | |||
1 | /* | ||
2 | * This file contains the CLPS711X GPIO definitions. | ||
3 | * | ||
4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | /* Simple helper for convert port & pin to GPIO number */ | ||
13 | #define CLPS711X_GPIO(port, bit) ((port) * 8 + (bit)) | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 150eeb705fbc..9e3fb3438718 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -102,6 +102,10 @@ config GPIO_MAX730X | |||
102 | 102 | ||
103 | comment "Memory mapped GPIO drivers:" | 103 | comment "Memory mapped GPIO drivers:" |
104 | 104 | ||
105 | config GPIO_CLPS711X | ||
106 | def_bool y | ||
107 | depends on ARCH_CLPS711X | ||
108 | |||
105 | config GPIO_GENERIC_PLATFORM | 109 | config GPIO_GENERIC_PLATFORM |
106 | tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" | 110 | tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" |
107 | select GPIO_GENERIC | 111 | select GPIO_GENERIC |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e6f8e379a2ec..1c1b63fcaeb3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o | |||
16 | obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o | 16 | obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o |
17 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o | 17 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o |
18 | obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o | 18 | obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o |
19 | obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o | ||
19 | obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o | 20 | obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o |
20 | obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o | 21 | obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o |
21 | obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o | 22 | obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o |
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c new file mode 100644 index 000000000000..ea21822b3de9 --- /dev/null +++ b/drivers/gpio/gpio-clps711x.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * CLPS711X GPIO driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/io.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/gpio.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | |||
19 | #include <mach/hardware.h> | ||
20 | |||
21 | #define CLPS711X_GPIO_PORTS 5 | ||
22 | #define CLPS711X_GPIO_NAME "gpio-clps711x" | ||
23 | |||
24 | struct clps711x_gpio { | ||
25 | struct gpio_chip chip[CLPS711X_GPIO_PORTS]; | ||
26 | spinlock_t lock; | ||
27 | }; | ||
28 | |||
29 | static void __iomem *clps711x_ports[] = { | ||
30 | CLPS711X_VIRT_BASE + PADR, | ||
31 | CLPS711X_VIRT_BASE + PBDR, | ||
32 | CLPS711X_VIRT_BASE + PCDR, | ||
33 | CLPS711X_VIRT_BASE + PDDR, | ||
34 | CLPS711X_VIRT_BASE + PEDR, | ||
35 | }; | ||
36 | |||
37 | static void __iomem *clps711x_pdirs[] = { | ||
38 | CLPS711X_VIRT_BASE + PADDR, | ||
39 | CLPS711X_VIRT_BASE + PBDDR, | ||
40 | CLPS711X_VIRT_BASE + PCDDR, | ||
41 | CLPS711X_VIRT_BASE + PDDDR, | ||
42 | CLPS711X_VIRT_BASE + PEDDR, | ||
43 | }; | ||
44 | |||
45 | #define clps711x_port(x) clps711x_ports[x->base / 8] | ||
46 | #define clps711x_pdir(x) clps711x_pdirs[x->base / 8] | ||
47 | |||
48 | static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) | ||
49 | { | ||
50 | return !!readb(clps711x_port(chip)) & (1 << offset); | ||
51 | } | ||
52 | |||
53 | static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, | ||
54 | int value) | ||
55 | { | ||
56 | int tmp; | ||
57 | unsigned long flags; | ||
58 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
59 | |||
60 | spin_lock_irqsave(&gpio->lock, flags); | ||
61 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | ||
62 | if (value) | ||
63 | tmp |= 1 << offset; | ||
64 | writeb(tmp, clps711x_port(chip)); | ||
65 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
66 | } | ||
67 | |||
68 | static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) | ||
69 | { | ||
70 | int tmp; | ||
71 | unsigned long flags; | ||
72 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
73 | |||
74 | spin_lock_irqsave(&gpio->lock, flags); | ||
75 | tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); | ||
76 | writeb(tmp, clps711x_pdir(chip)); | ||
77 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, | ||
83 | int value) | ||
84 | { | ||
85 | int tmp; | ||
86 | unsigned long flags; | ||
87 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
88 | |||
89 | spin_lock_irqsave(&gpio->lock, flags); | ||
90 | tmp = readb(clps711x_pdir(chip)) | (1 << offset); | ||
91 | writeb(tmp, clps711x_pdir(chip)); | ||
92 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | ||
93 | if (value) | ||
94 | tmp |= 1 << offset; | ||
95 | writeb(tmp, clps711x_port(chip)); | ||
96 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct clps711x_gpio_port { | ||
102 | char *name; | ||
103 | int nr; | ||
104 | }; | ||
105 | |||
106 | static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { | ||
107 | { "PORTA", 8, }, | ||
108 | { "PORTB", 8, }, | ||
109 | { "PORTC", 8, }, | ||
110 | { "PORTD", 8, }, | ||
111 | { "PORTE", 3, }, | ||
112 | }; | ||
113 | |||
114 | static int __init gpio_clps711x_init(void) | ||
115 | { | ||
116 | int i; | ||
117 | struct platform_device *pdev; | ||
118 | struct clps711x_gpio *gpio; | ||
119 | |||
120 | pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); | ||
121 | if (!pdev) { | ||
122 | pr_err("Cannot create platform device: %s\n", | ||
123 | CLPS711X_GPIO_NAME); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | platform_device_add(pdev); | ||
128 | |||
129 | gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), | ||
130 | GFP_KERNEL); | ||
131 | if (!gpio) { | ||
132 | dev_err(&pdev->dev, "GPIO allocating memory error\n"); | ||
133 | platform_device_del(pdev); | ||
134 | platform_device_put(pdev); | ||
135 | return -ENOMEM; | ||
136 | } | ||
137 | |||
138 | platform_set_drvdata(pdev, gpio); | ||
139 | |||
140 | spin_lock_init(&gpio->lock); | ||
141 | |||
142 | for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { | ||
143 | gpio->chip[i].owner = THIS_MODULE; | ||
144 | gpio->chip[i].dev = &pdev->dev; | ||
145 | gpio->chip[i].label = clps711x_gpio_ports[i].name; | ||
146 | gpio->chip[i].base = i * 8; | ||
147 | gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; | ||
148 | gpio->chip[i].direction_input = gpio_clps711x_direction_in; | ||
149 | gpio->chip[i].get = gpio_clps711x_get; | ||
150 | gpio->chip[i].direction_output = gpio_clps711x_direction_out; | ||
151 | gpio->chip[i].set = gpio_clps711x_set; | ||
152 | WARN_ON(gpiochip_add(&gpio->chip[i])); | ||
153 | } | ||
154 | |||
155 | dev_info(&pdev->dev, "GPIO driver initialized\n"); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | arch_initcall(gpio_clps711x_init); | ||
160 | |||
161 | MODULE_LICENSE("GPL v2"); | ||
162 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); | ||
163 | MODULE_DESCRIPTION("CLPS711X GPIO driver"); | ||