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 #include <linux/acpi.h> 28 #include <linux/gpio/consumer.h> 29 30 #include <linux/rfkill-gpio.h> 31 32 struct rfkill_gpio_data { 33 const char *name; 34 enum rfkill_type type; 35 struct gpio_desc *reset_gpio; 36 struct gpio_desc *shutdown_gpio; 37 38 struct rfkill *rfkill_dev; 39 char *reset_name; 40 char *shutdown_name; 41 struct clk *clk; 42 43 bool clk_enabled; 44 }; 45 46 static int rfkill_gpio_set_power(void *data, bool blocked) 47 { 48 struct rfkill_gpio_data *rfkill = data; 49 50 if (blocked) { 51 gpiod_set_value(rfkill->shutdown_gpio, 0); 52 gpiod_set_value(rfkill->reset_gpio, 0); 53 if (!IS_ERR(rfkill->clk) && rfkill->clk_enabled) 54 clk_disable(rfkill->clk); 55 } else { 56 if (!IS_ERR(rfkill->clk) && !rfkill->clk_enabled) 57 clk_enable(rfkill->clk); 58 gpiod_set_value(rfkill->reset_gpio, 1); 59 gpiod_set_value(rfkill->shutdown_gpio, 1); 60 } 61 62 rfkill->clk_enabled = blocked; 63 64 return 0; 65 } 66 67 static const struct rfkill_ops rfkill_gpio_ops = { 68 .set_block = rfkill_gpio_set_power, 69 }; 70 71 static int rfkill_gpio_acpi_probe(struct device *dev, 72 struct rfkill_gpio_data *rfkill) 73 { 74 const struct acpi_device_id *id; 75 76 id = acpi_match_device(dev->driver->acpi_match_table, dev); 77 if (!id) 78 return -ENODEV; 79 80 rfkill->name = dev_name(dev); 81 rfkill->type = (unsigned)id->driver_data; 82 83 return 0; 84 } 85 86 static int rfkill_gpio_probe(struct platform_device *pdev) 87 { 88 struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; 89 struct rfkill_gpio_data *rfkill; 90 const char *clk_name = NULL; 91 struct gpio_desc *gpio; 92 int ret; 93 int len; 94 95 rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); 96 if (!rfkill) 97 return -ENOMEM; 98 99 if (ACPI_HANDLE(&pdev->dev)) { 100 ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); 101 if (ret) 102 return ret; 103 } else if (pdata) { 104 clk_name = pdata->power_clk_name; 105 rfkill->name = pdata->name; 106 rfkill->type = pdata->type; 107 } else { 108 return -ENODEV; 109 } 110 111 len = strlen(rfkill->name); 112 rfkill->reset_name = devm_kzalloc(&pdev->dev, len + 7, GFP_KERNEL); 113 if (!rfkill->reset_name) 114 return -ENOMEM; 115 116 rfkill->shutdown_name = devm_kzalloc(&pdev->dev, len + 10, GFP_KERNEL); 117 if (!rfkill->shutdown_name) 118 return -ENOMEM; 119 120 snprintf(rfkill->reset_name, len + 6 , "%s_reset", rfkill->name); 121 snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", rfkill->name); 122 123 rfkill->clk = devm_clk_get(&pdev->dev, clk_name); 124 125 gpio = devm_gpiod_get_index(&pdev->dev, rfkill->reset_name, 0); 126 if (!IS_ERR(gpio)) { 127 ret = gpiod_direction_output(gpio, 0); 128 if (ret) 129 return ret; 130 rfkill->reset_gpio = gpio; 131 } 132 133 gpio = devm_gpiod_get_index(&pdev->dev, rfkill->shutdown_name, 1); 134 if (!IS_ERR(gpio)) { 135 ret = gpiod_direction_output(gpio, 0); 136 if (ret) 137 return ret; 138 rfkill->shutdown_gpio = gpio; 139 } 140 141 /* Make sure at-least one of the GPIO is defined and that 142 * a name is specified for this instance 143 */ 144 if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) { 145 dev_err(&pdev->dev, "invalid platform data\n"); 146 return -EINVAL; 147 } 148 149 if (pdata && pdata->gpio_runtime_setup) { 150 ret = pdata->gpio_runtime_setup(pdev); 151 if (ret) { 152 dev_err(&pdev->dev, "can't set up gpio\n"); 153 return ret; 154 } 155 } 156 157 rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev, 158 rfkill->type, &rfkill_gpio_ops, 159 rfkill); 160 if (!rfkill->rfkill_dev) 161 return -ENOMEM; 162 163 ret = rfkill_register(rfkill->rfkill_dev); 164 if (ret < 0) 165 return ret; 166 167 platform_set_drvdata(pdev, rfkill); 168 169 dev_info(&pdev->dev, "%s device registered.\n", rfkill->name); 170 171 return 0; 172 } 173 174 static int rfkill_gpio_remove(struct platform_device *pdev) 175 { 176 struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); 177 struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; 178 179 if (pdata && pdata->gpio_runtime_close) 180 pdata->gpio_runtime_close(pdev); 181 rfkill_unregister(rfkill->rfkill_dev); 182 rfkill_destroy(rfkill->rfkill_dev); 183 184 return 0; 185 } 186 187 static const struct acpi_device_id rfkill_acpi_match[] = { 188 { "BCM4752", RFKILL_TYPE_GPS }, 189 { }, 190 }; 191 192 static struct platform_driver rfkill_gpio_driver = { 193 .probe = rfkill_gpio_probe, 194 .remove = rfkill_gpio_remove, 195 .driver = { 196 .name = "rfkill_gpio", 197 .owner = THIS_MODULE, 198 .acpi_match_table = ACPI_PTR(rfkill_acpi_match), 199 }, 200 }; 201 202 module_platform_driver(rfkill_gpio_driver); 203 204 MODULE_DESCRIPTION("gpio rfkill"); 205 MODULE_AUTHOR("NVIDIA"); 206 MODULE_LICENSE("GPL"); 207