aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-08-31 03:49:47 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2018-03-24 10:16:08 -0400
commit7be893aa2d6a11d3ff16fe5f614cb94d1cfc9149 (patch)
tree9ce29352fbb4b2e0cdb92668f89c86b0aad8a23d /drivers
parent7928b2cbe55b2a410a0f5c1f154610059c57b1b2 (diff)
pcmcia: sa1100: provide generic CF support
Provide generic non-voltage sensing socket support for StrongARM platforms using the gpiolib and regulator subsystems to obtain the resources to control the socket. Acked-by: Dominik Brodowski <linux@dominikbrodowski.net> (for drivers/pcmcia) Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pcmcia/sa1100_generic.c103
1 files changed, 98 insertions, 5 deletions
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index 66acdc85727c..324e3e631353 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -31,7 +31,9 @@
31======================================================================*/ 31======================================================================*/
32 32
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/gpio/consumer.h>
34#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/regulator/consumer.h>
35#include <linux/slab.h> 37#include <linux/slab.h>
36#include <linux/platform_device.h> 38#include <linux/platform_device.h>
37 39
@@ -41,9 +43,61 @@
41 43
42#include "sa1100_generic.h" 44#include "sa1100_generic.h"
43 45
46static const char *sa11x0_cf_gpio_names[] = {
47 [SOC_STAT_CD] = "detect",
48 [SOC_STAT_BVD1] = "bvd1",
49 [SOC_STAT_BVD2] = "bvd2",
50 [SOC_STAT_RDY] = "ready",
51};
52
53static int sa11x0_cf_hw_init(struct soc_pcmcia_socket *skt)
54{
55 struct device *dev = skt->socket.dev.parent;
56 int i;
57
58 skt->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
59 if (IS_ERR(skt->gpio_reset))
60 return PTR_ERR(skt->gpio_reset);
61
62 skt->gpio_bus_enable = devm_gpiod_get_optional(dev, "bus-enable",
63 GPIOD_OUT_HIGH);
64 if (IS_ERR(skt->gpio_bus_enable))
65 return PTR_ERR(skt->gpio_bus_enable);
66
67 skt->vcc.reg = devm_regulator_get_optional(dev, "vcc");
68 if (IS_ERR(skt->vcc.reg))
69 return PTR_ERR(skt->vcc.reg);
70
71 if (!skt->vcc.reg)
72 dev_warn(dev,
73 "no Vcc regulator provided, ignoring Vcc controls\n");
74
75 for (i = 0; i < ARRAY_SIZE(sa11x0_cf_gpio_names); i++) {
76 skt->stat[i].name = sa11x0_cf_gpio_names[i];
77 skt->stat[i].desc = devm_gpiod_get_optional(dev,
78 sa11x0_cf_gpio_names[i], GPIOD_IN);
79 if (IS_ERR(skt->stat[i].desc))
80 return PTR_ERR(skt->stat[i].desc);
81 }
82 return 0;
83}
84
85static int sa11x0_cf_configure_socket(struct soc_pcmcia_socket *skt,
86 const socket_state_t *state)
87{
88 return soc_pcmcia_regulator_set(skt, &skt->vcc, state->Vcc);
89}
90
91static struct pcmcia_low_level sa11x0_cf_ops = {
92 .owner = THIS_MODULE,
93 .hw_init = sa11x0_cf_hw_init,
94 .socket_state = soc_common_cf_socket_state,
95 .configure_socket = sa11x0_cf_configure_socket,
96};
97
44int __init pcmcia_collie_init(struct device *dev); 98int __init pcmcia_collie_init(struct device *dev);
45 99
46static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { 100static int (*sa11x0_pcmcia_legacy_hw_init[])(struct device *dev) = {
47#ifdef CONFIG_SA1100_ASSABET 101#ifdef CONFIG_SA1100_ASSABET
48 pcmcia_assabet_init, 102 pcmcia_assabet_init,
49#endif 103#endif
@@ -67,15 +121,15 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
67#endif 121#endif
68}; 122};
69 123
70static int sa11x0_drv_pcmcia_probe(struct platform_device *dev) 124static int sa11x0_drv_pcmcia_legacy_probe(struct platform_device *dev)
71{ 125{
72 int i, ret = -ENODEV; 126 int i, ret = -ENODEV;
73 127
74 /* 128 /*
75 * Initialise any "on-board" PCMCIA sockets. 129 * Initialise any "on-board" PCMCIA sockets.
76 */ 130 */
77 for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { 131 for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_legacy_hw_init); i++) {
78 ret = sa11x0_pcmcia_hw_init[i](&dev->dev); 132 ret = sa11x0_pcmcia_legacy_hw_init[i](&dev->dev);
79 if (ret == 0) 133 if (ret == 0)
80 break; 134 break;
81 } 135 }
@@ -83,7 +137,7 @@ static int sa11x0_drv_pcmcia_probe(struct platform_device *dev)
83 return ret; 137 return ret;
84} 138}
85 139
86static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) 140static int sa11x0_drv_pcmcia_legacy_remove(struct platform_device *dev)
87{ 141{
88 struct skt_dev_info *sinfo = platform_get_drvdata(dev); 142 struct skt_dev_info *sinfo = platform_get_drvdata(dev);
89 int i; 143 int i;
@@ -96,6 +150,45 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
96 return 0; 150 return 0;
97} 151}
98 152
153static int sa11x0_drv_pcmcia_probe(struct platform_device *pdev)
154{
155 struct soc_pcmcia_socket *skt;
156 struct device *dev = &pdev->dev;
157
158 if (pdev->id == -1)
159 return sa11x0_drv_pcmcia_legacy_probe(pdev);
160
161 skt = devm_kzalloc(dev, sizeof(*skt), GFP_KERNEL);
162 if (!skt)
163 return -ENOMEM;
164
165 platform_set_drvdata(pdev, skt);
166
167 skt->nr = pdev->id;
168 skt->clk = devm_clk_get(dev, NULL);
169 if (IS_ERR(skt->clk))
170 return PTR_ERR(skt->clk);
171
172 sa11xx_drv_pcmcia_ops(&sa11x0_cf_ops);
173 soc_pcmcia_init_one(skt, &sa11x0_cf_ops, dev);
174
175 return sa11xx_drv_pcmcia_add_one(skt);
176}
177
178static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
179{
180 struct soc_pcmcia_socket *skt;
181
182 if (dev->id == -1)
183 return sa11x0_drv_pcmcia_legacy_remove(dev);
184
185 skt = platform_get_drvdata(dev);
186
187 soc_pcmcia_remove_one(skt);
188
189 return 0;
190}
191
99static struct platform_driver sa11x0_pcmcia_driver = { 192static struct platform_driver sa11x0_pcmcia_driver = {
100 .driver = { 193 .driver = {
101 .name = "sa11x0-pcmcia", 194 .name = "sa11x0-pcmcia",