1 /* 2 * Copyright (c) 2011, NVIDIA Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19 #include <linux/gpio.h> 20 #include <linux/init.h> 21 #include <linux/kernel.h> 22 #include <linux/module.h> 23 #include <linux/rfkill.h> 24 #include <linux/platform_device.h> 25 #include <linux/clk.h> 26 #include <linux/slab.h> 27 28 #include <linux/rfkill-gpio.h> 29 30 enum rfkill_gpio_clk_state { 31 UNSPECIFIED = 0, 32 PWR_ENABLED, 33 PWR_DISABLED 34 }; 35 36 #define PWR_CLK_SET(_RF, _EN) \ 37 ((_RF)->pwr_clk_enabled = (!(_EN) ? PWR_ENABLED : PWR_DISABLED)) 38 #define PWR_CLK_ENABLED(_RF) ((_RF)->pwr_clk_enabled == PWR_ENABLED) 39 #define PWR_CLK_DISABLED(_RF) ((_RF)->pwr_clk_enabled != PWR_ENABLED) 40 41 struct rfkill_gpio_data { 42 struct rfkill_gpio_platform_data *pdata; 43 struct rfkill *rfkill_dev; 44 char *reset_name; 45 char *shutdown_name; 46 enum rfkill_gpio_clk_state pwr_clk_enabled; 47 struct clk *pwr_clk; 48 }; 49 50 static int rfkill_gpio_set_power(void *data, bool blocked) 51 { 52 struct rfkill_gpio_data *rfkill = data; 53 54 if (blocked) { 55 if (gpio_is_valid(rfkill->pdata->shutdown_gpio)) 56 gpio_direction_output(rfkill->pdata->shutdown_gpio, 0); 57 if (gpio_is_valid(rfkill->pdata->reset_gpio)) 58 gpio_direction_output(rfkill->pdata->reset_gpio, 0); 59 if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill)) 60 clk_disable(rfkill->pwr_clk); 61 } else { 62 if (rfkill->pwr_clk && PWR_CLK_DISABLED(rfkill)) 63 clk_enable(rfkill->pwr_clk); 64 if (gpio_is_valid(rfkill->pdata->reset_gpio)) 65 gpio_direction_output(rfkill->pdata->reset_gpio, 1); 66 if (gpio_is_valid(rfkill->pdata->shutdown_gpio)) 67 gpio_direction_output(rfkill->pdata->shutdown_gpio, 1); 68 } 69 70 if (rfkill->pwr_clk) 71 PWR_CLK_SET(rfkill, blocked); 72 73 return 0; 74 } 75 76 static const struct rfkill_ops rfkill_gpio_ops = { 77 .set_block = rfkill_gpio_set_power, 78 }; 79 80 static int rfkill_gpio_probe(struct platform_device *pdev) 81 { 82 struct rfkill_gpio_data *rfkill; 83 struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; 84 int ret = 0; 85 int len = 0; 86 87 if (!pdata) { 88 pr_warn("%s: No platform data specified\n", __func__); 89 return -EINVAL; 90 } 91 92 /* make sure at-least one of the GPIO is defined and that 93 * a name is specified for this instance */ 94 if (!pdata->name || (!gpio_is_valid(pdata->reset_gpio) && 95 !gpio_is_valid(pdata->shutdown_gpio))) { 96 pr_warn("%s: invalid platform data\n", __func__); 97 return -EINVAL; 98 } 99 100 rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); 101 if (!rfkill) 102 return -ENOMEM; 103 104 rfkill->pdata = pdata; 105 106 len = strlen(pdata->name); 107 rfkill->reset_name = kzalloc(len + 7, GFP_KERNEL); 108 if (!rfkill->reset_name) { 109 ret = -ENOMEM; 110 goto fail_alloc; 111 } 112 113 rfkill->shutdown_name = kzalloc(len + 10, GFP_KERNEL); 114 if (!rfkill->shutdown_name) { 115 ret = -ENOMEM; 116 goto fail_reset_name; 117 } 118 119 snprintf(rfkill->reset_name, len + 6 , "%s_reset", pdata->name); 120 snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", pdata->name); 121 122 if (pdata->power_clk_name) { 123 rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name); 124 if (IS_ERR(rfkill->pwr_clk)) { 125 pr_warn("%s: can't find pwr_clk.\n", __func__); 126 goto fail_shutdown_name; 127 } 128 } 129 130 if (gpio_is_valid(pdata->reset_gpio)) { 131 ret = gpio_request(pdata->reset_gpio, rfkill->reset_name); 132 if (ret) { 133 pr_warn("%s: failed to get reset gpio.\n", __func__); 134 goto fail_clock; 135 } 136 } 137 138 if (gpio_is_valid(pdata->shutdown_gpio)) { 139 ret = gpio_request(pdata->shutdown_gpio, rfkill->shutdown_name); 140 if (ret) { 141 pr_warn("%s: failed to get shutdown gpio.\n", __func__); 142 goto fail_reset; 143 } 144 } 145 146 rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type, 147 &rfkill_gpio_ops, rfkill); 148 if (!rfkill->rfkill_dev) 149 goto fail_shutdown; 150 151 ret = rfkill_register(rfkill->rfkill_dev); 152 if (ret < 0) 153 goto fail_rfkill; 154 155 platform_set_drvdata(pdev, rfkill); 156 157 dev_info(&pdev->dev, "%s device registered.\n", pdata->name); 158 159 return 0; 160 161 fail_rfkill: 162 rfkill_destroy(rfkill->rfkill_dev); 163 fail_shutdown: 164 if (gpio_is_valid(pdata->shutdown_gpio)) 165 gpio_free(pdata->shutdown_gpio); 166 fail_reset: 167 if (gpio_is_valid(pdata->reset_gpio)) 168 gpio_free(pdata->reset_gpio); 169 fail_clock: 170 if (rfkill->pwr_clk) 171 clk_put(rfkill->pwr_clk); 172 fail_shutdown_name: 173 kfree(rfkill->shutdown_name); 174 fail_reset_name: 175 kfree(rfkill->reset_name); 176 fail_alloc: 177 kfree(rfkill); 178 179 return ret; 180 } 181 182 static int rfkill_gpio_remove(struct platform_device *pdev) 183 { 184 struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); 185 186 rfkill_unregister(rfkill->rfkill_dev); 187 rfkill_destroy(rfkill->rfkill_dev); 188 if (gpio_is_valid(rfkill->pdata->shutdown_gpio)) 189 gpio_free(rfkill->pdata->shutdown_gpio); 190 if (gpio_is_valid(rfkill->pdata->reset_gpio)) 191 gpio_free(rfkill->pdata->reset_gpio); 192 if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill)) 193 clk_disable(rfkill->pwr_clk); 194 if (rfkill->pwr_clk) 195 clk_put(rfkill->pwr_clk); 196 kfree(rfkill->shutdown_name); 197 kfree(rfkill->reset_name); 198 kfree(rfkill); 199 200 return 0; 201 } 202 203 static struct platform_driver rfkill_gpio_driver = { 204 .probe = rfkill_gpio_probe, 205 .remove = __devexit_p(rfkill_gpio_remove), 206 .driver = { 207 .name = "rfkill_gpio", 208 .owner = THIS_MODULE, 209 }, 210 }; 211 212 static int __init rfkill_gpio_init(void) 213 { 214 return platform_driver_register(&rfkill_gpio_driver); 215 } 216 217 static void __exit rfkill_gpio_exit(void) 218 { 219 platform_driver_unregister(&rfkill_gpio_driver); 220 } 221 222 module_init(rfkill_gpio_init); 223 module_exit(rfkill_gpio_exit); 224 225 MODULE_DESCRIPTION("gpio rfkill"); 226 MODULE_AUTHOR("NVIDIA"); 227 MODULE_LICENSE("GPL"); 228