• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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