diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2016-08-31 03:49:47 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2018-03-24 10:16:08 -0400 |
commit | 7be893aa2d6a11d3ff16fe5f614cb94d1cfc9149 (patch) | |
tree | 9ce29352fbb4b2e0cdb92668f89c86b0aad8a23d /drivers | |
parent | 7928b2cbe55b2a410a0f5c1f154610059c57b1b2 (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.c | 103 |
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 | ||
46 | static 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 | |||
53 | static 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 | |||
85 | static 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 | |||
91 | static 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 | |||
44 | int __init pcmcia_collie_init(struct device *dev); | 98 | int __init pcmcia_collie_init(struct device *dev); |
45 | 99 | ||
46 | static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { | 100 | static 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 | ||
70 | static int sa11x0_drv_pcmcia_probe(struct platform_device *dev) | 124 | static 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 | ||
86 | static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) | 140 | static 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 | ||
153 | static 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 | |||
178 | static 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 | |||
99 | static struct platform_driver sa11x0_pcmcia_driver = { | 192 | static struct platform_driver sa11x0_pcmcia_driver = { |
100 | .driver = { | 193 | .driver = { |
101 | .name = "sa11x0-pcmcia", | 194 | .name = "sa11x0-pcmcia", |