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/of_gpio.h>
9 #include <linux/platform_device.h>
10 #include <linux/capability.h>
11 #include "internal.h"
12 #include "sunxi-rfkill.h"
13
14 #define MODULE_CUR_VERSION "v1.1.0"
15
16 static struct sunxi_rfkill_platdata *rfkill_data;
17
rfkill_chipen_set(int dev,int on_off)18 void rfkill_chipen_set(int dev, int on_off)
19 {
20 /* Only wifi and bt both close, chip_en goes down,
21 * otherwise, set chip_en up to keep module work.
22 * dev : device to set power status. 0: wifi, 1: bt
23 * on_off: power status to set. 0: off, 1: on
24 */
25 static int power_state;
26 bool set_val;
27
28 if (!rfkill_data)
29 return;
30
31 if (dev == WL_DEV_WIFI || dev == WL_DEV_BLUETOOTH) {
32 power_state &= ~(1 << dev);
33 power_state |= ((on_off > 0) << dev);
34 }
35
36 if (gpio_is_valid(rfkill_data->gpio_chip_en)) {
37 set_val = (power_state != 0) ?
38 rfkill_data->gpio_chip_en_assert :
39 !rfkill_data->gpio_chip_en_assert;
40 gpio_set_value(rfkill_data->gpio_chip_en, set_val);
41 }
42 }
43
rfkill_poweren_set(int dev,int on_off)44 void rfkill_poweren_set(int dev, int on_off)
45 {
46 /* Only wifi and bt both close, power_en goes down,
47 * otherwise, set power_en up to keep module work.
48 * dev : device to set power status. 0: wifi, 1: bt
49 * on_off: power status to set. 0: off, 1: on
50 */
51 static int power_state;
52 bool set_val;
53
54 if (!rfkill_data)
55 return;
56
57 if (dev == WL_DEV_WIFI || dev == WL_DEV_BLUETOOTH) {
58 power_state &= ~(1 << dev);
59 power_state |= ((on_off > 0) << dev);
60 }
61
62 if (gpio_is_valid(rfkill_data->gpio_power_en)) {
63 set_val = (power_state != 0) ?
64 rfkill_data->gpio_power_en_assert :
65 !rfkill_data->gpio_power_en_assert;
66 gpio_set_value(rfkill_data->gpio_power_en, set_val);
67 }
68 }
69
rfkill_probe(struct platform_device * pdev)70 static int rfkill_probe(struct platform_device *pdev)
71 {
72 struct device_node *np = pdev->dev.of_node;
73 struct device *dev = &pdev->dev;
74 struct sunxi_rfkill_platdata *data;
75 enum of_gpio_flags config;
76 char *pctrl_name = PINCTRL_STATE_DEFAULT;
77 struct pinctrl_state *pctrl_state = NULL;
78 int ret = 0;
79
80 if (!dev)
81 return -ENOMEM;
82
83 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
84
85 dev_info(dev, "module version: %s\n", MODULE_CUR_VERSION);
86 data->pctrl = devm_pinctrl_get(dev);
87 if (IS_ERR(data->pctrl)) {
88 dev_warn(dev, "devm_pinctrl_get() failed!\n");
89 } else {
90 pctrl_state = pinctrl_lookup_state(data->pctrl, pctrl_name);
91 if (IS_ERR(pctrl_state)) {
92 dev_warn(dev, "pinctrl_lookup_state(%s) failed! return %p \n",
93 pctrl_name, pctrl_state);
94 } else {
95 ret = pinctrl_select_state(data->pctrl, pctrl_state);
96 if (ret < 0) {
97 dev_warn(dev, "pinctrl_select_state(%s) failed! return %d \n",
98 pctrl_name, ret);
99 }
100 }
101 }
102
103 data->gpio_chip_en = of_get_named_gpio_flags(np, "chip_en", 0, &config);
104 if (!gpio_is_valid(data->gpio_chip_en)) {
105 dev_err(dev, "get gpio chip_en failed\n");
106 } else {
107 data->gpio_chip_en_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
108 dev_info(dev, "chip_en gpio=%d assert=%d\n", data->gpio_chip_en, data->gpio_chip_en_assert);
109
110 ret = devm_gpio_request(dev, data->gpio_chip_en, "chip_en");
111 if (ret < 0) {
112 dev_err(dev, "can't request chip_en gpio %d\n",
113 data->gpio_chip_en);
114 return ret;
115 }
116
117 ret = gpio_direction_output(data->gpio_chip_en, !data->gpio_chip_en_assert);
118 if (ret < 0) {
119 dev_err(dev, "can't request output direction chip_en gpio %d\n",
120 data->gpio_chip_en);
121 return ret;
122 }
123 }
124
125 data->gpio_power_en = of_get_named_gpio_flags(np, "power_en", 0, &config);
126 if (!gpio_is_valid(data->gpio_power_en)) {
127 dev_err(dev, "get gpio power_en failed\n");
128 } else {
129 data->gpio_power_en_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
130 dev_info(dev, "power_en gpio=%d assert=%d\n", data->gpio_power_en, data->gpio_power_en_assert);
131
132 ret = devm_gpio_request(dev, data->gpio_power_en, "power_en");
133 if (ret < 0) {
134 dev_err(dev, "can't request power_en gpio %d\n",
135 data->gpio_power_en);
136 return ret;
137 }
138
139 ret = gpio_direction_output(data->gpio_power_en, !data->gpio_power_en);
140 if (ret < 0) {
141 dev_err(dev, "can't request output direction power_en gpio %d\n",
142 data->gpio_power_en);
143 return ret;
144 }
145 }
146
147 ret = sunxi_wlan_init(pdev);
148 if (ret)
149 goto err_wlan;
150
151 ret = sunxi_bt_init(pdev);
152 if (ret)
153 goto err_bt;
154
155 ret = sunxi_modem_init(pdev);
156 if (ret)
157 goto err_modem;
158
159 rfkill_data = data;
160 return 0;
161
162 err_modem:
163 sunxi_bt_deinit(pdev);
164 err_bt:
165 sunxi_wlan_deinit(pdev);
166 err_wlan:
167 return ret;
168 }
169
rfkill_remove(struct platform_device * pdev)170 static int rfkill_remove(struct platform_device *pdev)
171 {
172 sunxi_modem_deinit(pdev);
173 sunxi_bt_deinit(pdev);
174 sunxi_wlan_deinit(pdev);
175 rfkill_data = NULL;
176 return 0;
177 }
178
179 static const struct of_device_id rfkill_ids[] = {
180 { .compatible = "allwinner,sunxi-rfkill" },
181 { /* Sentinel */ }
182 };
183
184 static struct platform_driver rfkill_driver = {
185 .probe = rfkill_probe,
186 .remove = rfkill_remove,
187 .driver = {
188 .owner = THIS_MODULE,
189 .name = "sunxi-rfkill",
190 .of_match_table = rfkill_ids,
191 },
192 };
193
194 module_platform_driver_probe(rfkill_driver, rfkill_probe);
195
196 MODULE_DESCRIPTION("sunxi rfkill driver");
197 MODULE_LICENSE("GPL");
198