1 #include <linux/kernel.h>
2 #include <linux/types.h>
3 #include <linux/module.h>
4 #include <linux/init.h>
5 #include <linux/gpio.h>
6 #include <linux/err.h>
7 #include <linux/device.h>
8 #include <linux/delay.h>
9 #include <linux/of_gpio.h>
10 #include <linux/clk.h>
11 #include <linux/interrupt.h>
12 #include <linux/rfkill.h>
13 #include <linux/regulator/consumer.h>
14 #include <linux/platform_device.h>
15 #include <linux/miscdevice.h>
16 #include <linux/capability.h>
17 #include <linux/pm_wakeirq.h>
18 #include "internal.h"
19 #include "sunxi-rfkill.h"
20
21 static struct sunxi_wlan_platdata *wlan_data;
22 static const struct of_device_id sunxi_wlan_ids[];
23
24 static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off);
25 static DEFINE_MUTEX(sunxi_wlan_mutex);
26
27 #if IS_ENABLED(CONFIG_MMC_SUNXI) || IS_ENABLED(CONFIG_AW_MMC)
28 extern void sunxi_mmc_rescan_card(unsigned ids);
29 #else
sunxi_mmc_rescan_card(unsigned ids)30 static void sunxi_mmc_rescan_card(unsigned ids)
31 {
32 (void)ids;
33 pr_err("sunxi-wlan: %s not support", __func__);
34 }
35 #endif
36
sunxi_wlan_set_power(bool on_off)37 void sunxi_wlan_set_power(bool on_off)
38 {
39 struct platform_device *pdev;
40 int ret = 0;
41
42 if (!wlan_data)
43 return;
44
45 pdev = wlan_data->pdev;
46 mutex_lock(&sunxi_wlan_mutex);
47 rfkill_poweren_set(WL_DEV_WIFI, on_off);
48 if (on_off != wlan_data->power_state) {
49 ret = sunxi_wlan_on(wlan_data, on_off);
50 if (ret)
51 dev_err(&pdev->dev, "set power failed\n");
52 }
53
54 rfkill_chipen_set(WL_DEV_WIFI, on_off);
55
56 mutex_unlock(&sunxi_wlan_mutex);
57 }
58 EXPORT_SYMBOL_GPL(sunxi_wlan_set_power);
59
sunxi_wlan_get_bus_index(void)60 int sunxi_wlan_get_bus_index(void)
61 {
62 struct platform_device *pdev;
63
64 if (!wlan_data)
65 return -EINVAL;
66
67 pdev = wlan_data->pdev;
68 dev_info(&pdev->dev, "bus_index: %d\n", wlan_data->bus_index);
69 return wlan_data->bus_index;
70 }
71 EXPORT_SYMBOL_GPL(sunxi_wlan_get_bus_index);
72
sunxi_wlan_get_oob_irq(int * irq_flags,int * wakup_enable)73 int sunxi_wlan_get_oob_irq(int *irq_flags, int *wakup_enable)
74 {
75 struct platform_device *pdev;
76 int host_oob_irq = 0;
77 int oob_irq_flags = 0;
78
79 if (!wlan_data || !gpio_is_valid(wlan_data->gpio_wlan_hostwake))
80 return 0;
81
82 pdev = wlan_data->pdev;
83
84 host_oob_irq = gpio_to_irq(wlan_data->gpio_wlan_hostwake);
85 if (host_oob_irq < 0)
86 dev_err(&pdev->dev, "map gpio [%d] to virq failed, errno = %d\n",
87 wlan_data->gpio_wlan_hostwake, host_oob_irq);
88
89 oob_irq_flags = IRQF_SHARED;
90 if (wlan_data->gpio_wlan_hostwake_assert)
91 oob_irq_flags |= IRQF_TRIGGER_HIGH;
92 else
93 oob_irq_flags |= IRQF_TRIGGER_LOW;
94
95 *irq_flags = oob_irq_flags;
96 *wakup_enable = wlan_data->wakeup_enable;
97
98 return host_oob_irq;
99 }
100 EXPORT_SYMBOL_GPL(sunxi_wlan_get_oob_irq);
101
sunxi_wlan_on(struct sunxi_wlan_platdata * data,bool on_off)102 static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off)
103 {
104 struct platform_device *pdev = data->pdev;
105 struct device *dev = &pdev->dev;
106 int ret = 0, i;
107
108 if (on_off) {
109 for (i = 0; i < CLK_MAX; i++) {
110 if (!IS_ERR_OR_NULL(data->clk[i]))
111 clk_prepare_enable(data->clk[i]);
112 }
113
114 for (i = 0; i < PWR_MAX; i++) {
115 if (!IS_ERR_OR_NULL(data->power[i])) {
116 if (data->power_vol[i]) {
117 ret = regulator_set_voltage(data->power[i],
118 data->power_vol[i], data->power_vol[i]);
119 if (ret < 0) {
120 dev_err(dev, "wlan power[%d] (%s) set voltage failed\n",
121 i, data->power_name[i]);
122 return ret;
123 }
124
125 ret = regulator_get_voltage(data->power[i]);
126 if (ret != data->power_vol[i]) {
127 dev_err(dev, "wlan power[%d] (%s) get voltage failed\n",
128 i, data->power_name[i]);
129 return ret;
130 }
131 }
132
133 ret = regulator_enable(data->power[i]);
134 if (ret < 0) {
135 dev_err(dev, "wlan power[%d] (%s) enable failed\n",
136 i, data->power_name[i]);
137 return ret;
138 }
139 }
140 }
141
142 if (gpio_is_valid(data->gpio_wlan_regon)) {
143 mdelay(10);
144 gpio_set_value(data->gpio_wlan_regon, data->gpio_wlan_regon_assert);
145 }
146 } else {
147 if (gpio_is_valid(data->gpio_wlan_regon))
148 gpio_set_value(data->gpio_wlan_regon, !data->gpio_wlan_regon_assert);
149
150 for (i = 0; i < PWR_MAX; i++) {
151 if (!IS_ERR_OR_NULL(data->power[i])) {
152 ret = regulator_disable(data->power[i]);
153 if (ret < 0) {
154 dev_err(dev, "wlan power[%d] (%s) disable failed\n",
155 i, data->power_name[i]);
156 return ret;
157 }
158 }
159 }
160
161 for (i = 0; i < CLK_MAX; i++) {
162 if (!IS_ERR_OR_NULL(data->clk[i]))
163 clk_disable_unprepare(data->clk[i]);
164 }
165 }
166
167 wlan_data->power_state = on_off;
168 dev_info(dev, "wlan power %s success\n", on_off ? "on" : "off");
169
170 return 0;
171 }
172
power_state_show(struct device * dev,struct device_attribute * attr,char * buf)173 static ssize_t power_state_show(struct device *dev,
174 struct device_attribute *attr, char *buf)
175 {
176 if (!wlan_data)
177 return 0;
178 return sprintf(buf, "%d\n", wlan_data->power_state);
179 }
180
power_state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)181 static ssize_t power_state_store(struct device *dev,
182 struct device_attribute *attr, const char *buf, size_t count)
183 {
184 unsigned long state;
185 int err;
186
187 if (!wlan_data)
188 return 0;
189
190 if (!capable(CAP_NET_ADMIN))
191 return -EPERM;
192
193 err = kstrtoul(buf, 0, &state);
194 if (err)
195 return err;
196
197 if (state > 1)
198 return -EINVAL;
199
200 if (state != wlan_data->power_state) {
201 sunxi_wlan_set_power(state);
202 }
203
204 return count;
205 }
206
207 static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
208 power_state_show, power_state_store);
209
scan_device_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)210 static ssize_t scan_device_store(struct device *dev,
211 struct device_attribute *attr, const char *buf, size_t count)
212 {
213 unsigned long state;
214 int err;
215 int bus = wlan_data->bus_index;
216
217 if (!wlan_data)
218 return 0;
219
220 err = kstrtoul(buf, 0, &state);
221 if (err)
222 return err;
223
224 dev_info(dev, "start scan device on bus_index: %d\n",
225 wlan_data->bus_index);
226 if (bus < 0) {
227 dev_err(dev, "scan device fail!\n");
228 return -1;
229 }
230 sunxi_mmc_rescan_card(bus);
231
232 return count;
233 }
234
235 static DEVICE_ATTR(scan_device, S_IRUGO | S_IWUSR,
236 NULL, scan_device_store);
237
238 static struct attribute *misc_attributes[] = {
239 &dev_attr_power_state.attr,
240 &dev_attr_scan_device.attr,
241 NULL,
242 };
243
244 static struct attribute_group misc_attribute_group = {
245 .name = "rf-ctrl",
246 .attrs = misc_attributes,
247 };
248
249 static struct miscdevice sunxi_wlan_dev = {
250 .minor = MISC_DYNAMIC_MINOR,
251 .name = "sunxi-wlan",
252 };
253
sunxi_wlan_init(struct platform_device * pdev)254 int sunxi_wlan_init(struct platform_device *pdev)
255 {
256 struct device_node *np = of_find_matching_node(pdev->dev.of_node, sunxi_wlan_ids);
257 struct device *dev = &pdev->dev;
258 struct sunxi_wlan_platdata *data;
259 enum of_gpio_flags config;
260 u32 val;
261 int ret = 0;
262 int count, i;
263
264 if (!dev)
265 return -ENOMEM;
266
267 if (!np)
268 return 0;
269
270 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
271
272 data->pdev = pdev;
273
274 data->bus_index = -1;
275 if (!of_property_read_u32(np, "wlan_busnum", &val)) {
276 switch (val) {
277 case 0:
278 case 1:
279 case 2:
280 case 3:
281 data->bus_index = val;
282 break;
283 default:
284 dev_err(dev, "unsupported wlan_busnum (%u)\n", val);
285 return -EINVAL;
286 }
287 }
288 dev_info(dev, "wlan_busnum (%u)\n", val);
289
290 count = of_property_count_strings(np, "wlan_power");
291 if (count <= 0) {
292 dev_warn(dev, "Missing wlan_power.\n");
293 } else {
294 if (count > PWR_MAX) {
295 dev_warn(dev, "wlan power count large than max(%d > %d).\n",
296 count, PWR_MAX);
297 count = PWR_MAX;
298 }
299 ret = of_property_read_string_array(np, "wlan_power",
300 (const char **)data->power_name, count);
301 if (ret < 0)
302 return -ENOMEM;
303
304 ret = of_property_read_u32_array(np, "wlan_power_vol",
305 (u32 *)data->power_vol, count);
306 if (ret < 0)
307 dev_warn(dev, "Missing wlan_power_vol config.\n");
308
309 for (i = 0; i < count; i++) {
310 data->power[i] = regulator_get(dev, data->power_name[i]);
311
312 if (IS_ERR_OR_NULL(data->power[i]))
313 return -ENOMEM;
314
315 dev_info(dev, "wlan power[%d] (%s) voltage: %dmV\n",
316 i, data->power_name[i], data->power_vol[i] / 1000);
317 }
318 }
319
320 count = of_property_count_strings(np, "clock-names");
321 if (count <= 0) {
322 count = CLK_MAX;
323 for (i = 0; i < count; i++) {
324 data->clk[i] = of_clk_get(np, i);
325 if (IS_ERR_OR_NULL(data->clk[i]))
326 break;
327 data->clk_name[i] = devm_kzalloc(dev, 16, GFP_KERNEL);
328 sprintf(data->clk_name[i], "clk%d", i);
329 dev_info(dev, "wlan clock[%d] (%s)\n", i, data->clk_name[i]);
330 }
331 } else {
332 if (count > CLK_MAX) {
333 dev_warn(dev, "wlan clocks count large than max(%d).\n", CLK_MAX);
334 count = CLK_MAX;
335 }
336 ret = of_property_read_string_array(np, "clock-names",
337 (const char **)data->clk_name, count);
338 if (ret < 0)
339 return -ENOMEM;
340
341 for (i = 0; i < count; i++) {
342 data->clk[i] = of_clk_get(np, i);
343 if (IS_ERR_OR_NULL(data->clk[i]))
344 return -ENOMEM;
345 dev_info(dev, "wlan clock[%d] (%s)\n", i, data->clk_name[i]);
346 }
347 }
348
349 data->gpio_wlan_regon = of_get_named_gpio_flags(np, "wlan_regon", 0, &config);
350 if (!gpio_is_valid(data->gpio_wlan_regon)) {
351 dev_err(dev, "get gpio wlan_regon failed\n");
352 } else {
353 data->gpio_wlan_regon_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
354 dev_info(dev, "wlan_regon gpio=%d assert=%d\n", data->gpio_wlan_regon, data->gpio_wlan_regon_assert);
355
356 ret = devm_gpio_request(dev, data->gpio_wlan_regon,
357 "wlan_regon");
358 if (ret < 0) {
359 dev_err(dev, "can't request wlan_regon gpio %d\n",
360 data->gpio_wlan_regon);
361 return ret;
362 }
363
364 ret = gpio_direction_output(data->gpio_wlan_regon, !data->gpio_wlan_regon_assert);
365 if (ret < 0) {
366 dev_err(dev, "can't request output direction wlan_regon gpio %d\n",
367 data->gpio_wlan_regon);
368 return ret;
369 }
370 }
371
372 data->gpio_wlan_hostwake = of_get_named_gpio_flags(np, "wlan_hostwake", 0, &config);
373 if (!gpio_is_valid(data->gpio_wlan_hostwake)) {
374 dev_err(dev, "get gpio wlan_hostwake failed\n");
375 } else {
376 data->gpio_wlan_hostwake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
377 dev_info(dev, "wlan_hostwake gpio=%d assert=%d\n", data->gpio_wlan_hostwake, data->gpio_wlan_hostwake_assert);
378
379 ret = devm_gpio_request(dev, data->gpio_wlan_hostwake,
380 "wlan_hostwake");
381 if (ret < 0) {
382 dev_err(dev, "can't request wlan_hostwake gpio %d\n",
383 data->gpio_wlan_hostwake);
384 return ret;
385 }
386
387 ret = gpio_direction_input(data->gpio_wlan_hostwake);
388 if (ret < 0) {
389 dev_err(dev,
390 "can't request input direction wlan_hostwake gpio %d\n",
391 data->gpio_wlan_hostwake);
392 return ret;
393 }
394
395 /*
396 * wakeup_source relys on wlan_hostwake, if wlan_hostwake gpio
397 * isn't configured, then whether wakeup_source is configured
398 * or not is unmeaningful.
399 */
400 if (!of_property_read_bool(np, "wakeup-source")) {
401 dev_info(dev, "wakeup source is disbled!\n");
402 } else {
403 dev_info(dev, "wakeup source is enabled\n");
404 data->wakeup_enable = 1;
405 }
406 }
407
408 ret = misc_register(&sunxi_wlan_dev);
409 if (ret) {
410 dev_err(dev, "sunxi-wlan register driver as misc device error!\n");
411 return ret;
412 }
413 ret = sysfs_create_group(&sunxi_wlan_dev.this_device->kobj,
414 &misc_attribute_group);
415 if (ret) {
416 dev_err(dev, "sunxi-wlan register sysfs create group failed!\n");
417 return ret;
418 }
419
420 data->power_state = 0;
421 wlan_data = data;
422 return 0;
423 }
424
sunxi_wlan_deinit(struct platform_device * pdev)425 int sunxi_wlan_deinit(struct platform_device *pdev)
426 {
427 struct sunxi_wlan_platdata *data = wlan_data;
428 int i;
429
430 if (!data)
431 return 0;
432
433 sysfs_remove_group(&(sunxi_wlan_dev.this_device->kobj),
434 &misc_attribute_group);
435 misc_deregister(&sunxi_wlan_dev);
436
437 if (data->power_state)
438 sunxi_wlan_set_power(0);
439
440 for (i = 0; i < PWR_MAX; i++) {
441 if (!IS_ERR_OR_NULL(data->power[i]))
442 regulator_put(data->power[i]);
443 }
444
445 wlan_data = NULL;
446
447 return 0;
448 }
449
450 static const struct of_device_id sunxi_wlan_ids[] = {
451 { .compatible = "allwinner,sunxi-wlan" },
452 { /* Sentinel */ }
453 };
454
455 MODULE_DESCRIPTION("sunxi wlan driver");
456 MODULE_LICENSE("GPL");
457