OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * drivers/misc/bcm4329_rfkill.c | |
Olof Johansson
2011/01/18 19:26:11
See now why having filenames in the files themselv
| |
3 * | |
4 * Copyright (c) 2010, NVIDIA Corporation. | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 * more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License along | |
17 * with this program; if not, write to the Free Software Foundation, Inc., | |
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 */ | |
20 | |
21 #include <linux/err.h> | |
22 #include <linux/types.h> | |
23 #include <linux/uaccess.h> | |
24 #include <linux/fs.h> | |
25 #include <linux/gpio.h> | |
26 #include <linux/init.h> | |
27 #include <linux/kernel.h> | |
28 #include <linux/miscdevice.h> | |
29 #include <linux/module.h> | |
30 #include <linux/rfkill.h> | |
31 #include <linux/platform_device.h> | |
32 #include <linux/clk.h> | |
33 #include <linux/slab.h> | |
34 | |
35 struct bcm4329_rfkill_data { | |
Olof Johansson
2011/01/18 19:26:11
No need to call this bcm4329 either, etc.
| |
36 int gpio_reset; | |
37 int gpio_shutdown; | |
38 int delay; | |
39 struct clk *bt_32k_clk; | |
40 }; | |
41 | |
42 static struct bcm4329_rfkill_data *bcm4329_rfkill; | |
43 | |
44 static int bcm4329_bt_rfkill_set_power(void *data, bool blocked) | |
45 { | |
46 if (blocked) { | |
47 if (bcm4329_rfkill->gpio_shutdown) | |
48 gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 0); | |
49 if (bcm4329_rfkill->gpio_reset) | |
50 gpio_direction_output(bcm4329_rfkill->gpio_reset, 0); | |
51 if (bcm4329_rfkill->bt_32k_clk) | |
52 clk_disable(bcm4329_rfkill->bt_32k_clk); | |
53 } else { | |
54 if (bcm4329_rfkill->bt_32k_clk) | |
55 clk_enable(bcm4329_rfkill->bt_32k_clk); | |
56 if (bcm4329_rfkill->gpio_shutdown) | |
57 gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 1); | |
58 if (bcm4329_rfkill->gpio_reset) | |
59 gpio_direction_output(bcm4329_rfkill->gpio_reset, 1); | |
60 } | |
61 | |
62 return 0; | |
63 } | |
64 | |
65 static const struct rfkill_ops bcm4329_bt_rfkill_ops = { | |
66 .set_block = bcm4329_bt_rfkill_set_power, | |
67 }; | |
68 | |
69 static int bcm4329_rfkill_probe(struct platform_device *pdev) | |
70 { | |
71 struct rfkill *bt_rfkill; | |
72 struct resource *res; | |
73 int ret; | |
74 bool enable = false; /* off */ | |
75 bool default_sw_block_state; | |
76 | |
77 bcm4329_rfkill = kzalloc(sizeof(*bcm4329_rfkill), GFP_KERNEL); | |
78 if (!bcm4329_rfkill) | |
79 return -ENOMEM; | |
80 | |
81 bcm4329_rfkill->bt_32k_clk = clk_get(&pdev->dev, "bcm4329_32k_clk"); | |
82 if (IS_ERR(bcm4329_rfkill->bt_32k_clk)) { | |
83 pr_warn("%s: can't find bcm4329_32k_clk.\ | |
84 assuming 32k clock to chip\n", __func__); | |
85 bcm4329_rfkill->bt_32k_clk = NULL; | |
86 } | |
87 | |
88 res = platform_get_resource_byname(pdev, IORESOURCE_IO, | |
89 "bcm4329_nreset_gpio"); | |
90 if (res) { | |
91 bcm4329_rfkill->gpio_reset = res->start; | |
92 tegra_gpio_enable(bcm4329_rfkill->gpio_reset); | |
93 ret = gpio_request(bcm4329_rfkill->gpio_reset, | |
94 "bcm4329_nreset_gpio"); | |
95 } else { | |
96 pr_warn("%s : can't find reset gpio.\n", __func__); | |
97 bcm4329_rfkill->gpio_reset = 0; | |
98 } | |
99 | |
100 res = platform_get_resource_byname(pdev, IORESOURCE_IO, | |
101 "bcm4329_nshutdown_gpio"); | |
102 if (res) { | |
103 bcm4329_rfkill->gpio_shutdown = res->start; | |
104 tegra_gpio_enable(bcm4329_rfkill->gpio_shutdown); | |
105 ret = gpio_request(bcm4329_rfkill->gpio_shutdown, | |
106 "bcm4329_nshutdown_gpio"); | |
107 } else { | |
108 pr_warn("%s : can't find shutdown gpio.\n", __func__); | |
109 bcm4329_rfkill->gpio_shutdown = 0; | |
110 } | |
111 | |
112 /* make sure at-least one of the GPIO is defined */ | |
113 if (!bcm4329_rfkill->gpio_reset && !bcm4329_rfkill->gpio_shutdown) | |
114 goto free_bcm_res; | |
115 | |
116 if (bcm4329_rfkill->bt_32k_clk && enable) | |
117 clk_enable(bcm4329_rfkill->bt_32k_clk); | |
118 if (bcm4329_rfkill->gpio_shutdown) | |
119 gpio_direction_output(bcm4329_rfkill->gpio_shutdown, enable); | |
120 if (bcm4329_rfkill->gpio_reset) | |
121 gpio_direction_output(bcm4329_rfkill->gpio_reset, enable); | |
122 | |
123 bt_rfkill = rfkill_alloc("bcm4329 Bluetooth", &pdev->dev, | |
124 RFKILL_TYPE_BLUETOOTH, &bcm4329_bt_rfkill_ops, | |
125 NULL); | |
126 | |
127 if (unlikely(!bt_rfkill)) | |
128 goto free_bcm_res; | |
129 | |
130 default_sw_block_state = !enable; | |
131 rfkill_set_states(bt_rfkill, default_sw_block_state, false); | |
132 | |
133 ret = rfkill_register(bt_rfkill); | |
134 | |
135 if (unlikely(ret)) { | |
136 rfkill_destroy(bt_rfkill); | |
137 goto free_bcm_res; | |
138 } | |
139 | |
140 return 0; | |
141 | |
142 free_bcm_res: | |
143 if (bcm4329_rfkill->gpio_shutdown) | |
144 gpio_free(bcm4329_rfkill->gpio_shutdown); | |
145 if (bcm4329_rfkill->gpio_reset) | |
146 gpio_free(bcm4329_rfkill->gpio_reset); | |
147 if (bcm4329_rfkill->bt_32k_clk && enable) | |
148 clk_disable(bcm4329_rfkill->bt_32k_clk); | |
149 if (bcm4329_rfkill->bt_32k_clk) | |
150 clk_put(bcm4329_rfkill->bt_32k_clk); | |
151 kfree(bcm4329_rfkill); | |
152 return -ENODEV; | |
153 } | |
154 | |
155 static int bcm4329_rfkill_remove(struct platform_device *pdev) | |
156 { | |
157 struct rfkill *bt_rfkill = platform_get_drvdata(pdev); | |
158 | |
159 if (bcm4329_rfkill->bt_32k_clk) | |
160 clk_put(bcm4329_rfkill->bt_32k_clk); | |
161 rfkill_unregister(bt_rfkill); | |
162 rfkill_destroy(bt_rfkill); | |
163 if (bcm4329_rfkill->gpio_shutdown) | |
164 gpio_free(bcm4329_rfkill->gpio_shutdown); | |
165 if (bcm4329_rfkill->gpio_reset) | |
166 gpio_free(bcm4329_rfkill->gpio_reset); | |
167 kfree(bcm4329_rfkill); | |
168 | |
169 return 0; | |
170 } | |
171 | |
172 static struct platform_driver bcm4329_rfkill_driver = { | |
173 .probe = bcm4329_rfkill_probe, | |
174 .remove = bcm4329_rfkill_remove, | |
175 .driver = { | |
176 .name = "bcm4329_rfkill", | |
177 .owner = THIS_MODULE, | |
178 }, | |
179 }; | |
180 | |
181 static int __init bcm4329_rfkill_init(void) | |
182 { | |
183 return platform_driver_register(&bcm4329_rfkill_driver); | |
184 } | |
185 | |
186 static void __exit bcm4329_rfkill_exit(void) | |
187 { | |
188 platform_driver_unregister(&bcm4329_rfkill_driver); | |
189 } | |
190 | |
191 module_init(bcm4329_rfkill_init); | |
192 module_exit(bcm4329_rfkill_exit); | |
193 | |
194 MODULE_DESCRIPTION("BCM4329 rfkill"); | |
195 MODULE_AUTHOR("NVIDIA"); | |
196 MODULE_LICENSE("GPL"); | |
OLD | NEW |