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 struct clk *clk; 40 41 bool clk_enabled; 42 }; 43 44 static int rfkill_gpio_set_power(void *data, bool blocked) 45 { 46 struct rfkill_gpio_data *rfkill = data; 47 48 if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled) 49 clk_enable(rfkill->clk); 50 51 gpiod_set_value_cansleep(rfkill->shutdown_gpio, !blocked); 52 gpiod_set_value_cansleep(rfkill->reset_gpio, !blocked); 53 54 if (blocked && !IS_ERR(rfkill->clk) && rfkill->clk_enabled) 55 clk_disable(rfkill->clk); 56 57 rfkill->clk_enabled = blocked; 58 59 return 0; 60 } 61 62 static const struct rfkill_ops rfkill_gpio_ops = { 63 .set_block = rfkill_gpio_set_power, 64 }; 65 66 static int rfkill_gpio_acpi_probe(struct device *dev, 67 struct rfkill_gpio_data *rfkill) 68 { 69 const struct acpi_device_id *id; 70 71 id = acpi_match_device(dev->driver->acpi_match_table, dev); 72 if (!id) 73 return -ENODEV; 74 75 rfkill->name = dev_name(dev); 76 rfkill->type = (unsigned)id->driver_data; 77 78 return 0; 79 } 80 81 static int rfkill_gpio_probe(struct platform_device *pdev) 82 { 83 struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; 84 struct rfkill_gpio_data *rfkill; 85 struct gpio_desc *gpio; 86 int ret; 87 88 rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); 89 if (!rfkill) 90 return -ENOMEM; 91 92 if (ACPI_HANDLE(&pdev->dev)) { 93 ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); 94 if (ret) 95 return ret; 96 } else if (pdata) { 97 rfkill->name = pdata->name; 98 rfkill->type = pdata->type; 99 } else { 100 return -ENODEV; 101 } 102 103 rfkill->clk = devm_clk_get(&pdev->dev, NULL); 104 105 gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0); 106 if (!IS_ERR(gpio)) { 107 ret = gpiod_direction_output(gpio, 0); 108 if (ret) 109 return ret; 110 rfkill->reset_gpio = gpio; 111 } 112 113 gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1); 114 if (!IS_ERR(gpio)) { 115 ret = gpiod_direction_output(gpio, 0); 116 if (ret) 117 return ret; 118 rfkill->shutdown_gpio = gpio; 119 } 120 121 /* Make sure at-least one of the GPIO is defined and that 122 * a name is specified for this instance 123 */ 124 if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) { 125 dev_err(&pdev->dev, "invalid platform data\n"); 126 return -EINVAL; 127 } 128 129 rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev, 130 rfkill->type, &rfkill_gpio_ops, 131 rfkill); 132 if (!rfkill->rfkill_dev) 133 return -ENOMEM; 134 135 ret = rfkill_register(rfkill->rfkill_dev); 136 if (ret < 0) 137 return ret; 138 139 platform_set_drvdata(pdev, rfkill); 140 141 dev_info(&pdev->dev, "%s device registered.\n", rfkill->name); 142 143 return 0; 144 } 145 146 static int rfkill_gpio_remove(struct platform_device *pdev) 147 { 148 struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); 149 150 rfkill_unregister(rfkill->rfkill_dev); 151 rfkill_destroy(rfkill->rfkill_dev); 152 153 return 0; 154 } 155 156 #ifdef CONFIG_ACPI 157 static const struct acpi_device_id rfkill_acpi_match[] = { 158 { "BCM2E1A", RFKILL_TYPE_BLUETOOTH }, 159 { "BCM2E39", RFKILL_TYPE_BLUETOOTH }, 160 { "BCM2E3D", RFKILL_TYPE_BLUETOOTH }, 161 { "BCM4752", RFKILL_TYPE_GPS }, 162 { "LNV4752", RFKILL_TYPE_GPS }, 163 { }, 164 }; 165 #endif 166 167 static struct platform_driver rfkill_gpio_driver = { 168 .probe = rfkill_gpio_probe, 169 .remove = rfkill_gpio_remove, 170 .driver = { 171 .name = "rfkill_gpio", 172 .owner = THIS_MODULE, 173 .acpi_match_table = ACPI_PTR(rfkill_acpi_match), 174 }, 175 }; 176 177 module_platform_driver(rfkill_gpio_driver); 178 179 MODULE_DESCRIPTION("gpio rfkill"); 180 MODULE_AUTHOR("NVIDIA"); 181 MODULE_LICENSE("GPL"); 182