Chromium Code Reviews| 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 |