Blame view
net/rfkill/rfkill-gpio.c
4.63 KB
7176ba23f net: rfkill: add ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* * Copyright (c) 2011, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/gpio.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/rfkill.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/slab.h> |
ef91ffaa0 net: rfkill: gpio... |
27 |
#include <linux/acpi.h> |
2111cad65 net: rfkill: gpio... |
28 |
#include <linux/gpio/consumer.h> |
7176ba23f net: rfkill: add ... |
29 |
|
7176ba23f net: rfkill: add ... |
30 |
struct rfkill_gpio_data { |
262c91ee5 net: rfkill: gpio... |
31 32 |
const char *name; enum rfkill_type type; |
2111cad65 net: rfkill: gpio... |
33 34 |
struct gpio_desc *reset_gpio; struct gpio_desc *shutdown_gpio; |
262c91ee5 net: rfkill: gpio... |
35 36 |
struct rfkill *rfkill_dev; |
262c91ee5 net: rfkill: gpio... |
37 38 39 |
struct clk *clk; bool clk_enabled; |
7176ba23f net: rfkill: add ... |
40 41 42 43 44 |
}; static int rfkill_gpio_set_power(void *data, bool blocked) { struct rfkill_gpio_data *rfkill = data; |
771bb3ddc rfkill-gpio: Use ... |
45 46 47 48 49 50 51 52 |
if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled) clk_enable(rfkill->clk); gpiod_set_value_cansleep(rfkill->shutdown_gpio, !blocked); gpiod_set_value_cansleep(rfkill->reset_gpio, !blocked); if (blocked && !IS_ERR(rfkill->clk) && rfkill->clk_enabled) clk_disable(rfkill->clk); |
7176ba23f net: rfkill: add ... |
53 |
|
fa5c107cc net: rfkill: gpio... |
54 |
rfkill->clk_enabled = !blocked; |
7176ba23f net: rfkill: add ... |
55 56 57 58 59 60 61 |
return 0; } static const struct rfkill_ops rfkill_gpio_ops = { .set_block = rfkill_gpio_set_power, }; |
72daceb9a net: rfkill: gpio... |
62 63 64 65 66 67 68 69 |
static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false }; static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = { { "reset-gpios", &reset_gpios, 1 }, { "shutdown-gpios", &shutdown_gpios, 1 }, { }, }; |
ef91ffaa0 net: rfkill: gpio... |
70 71 72 73 74 75 76 77 |
static int rfkill_gpio_acpi_probe(struct device *dev, struct rfkill_gpio_data *rfkill) { const struct acpi_device_id *id; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) return -ENODEV; |
ef91ffaa0 net: rfkill: gpio... |
78 |
rfkill->type = (unsigned)id->driver_data; |
ef91ffaa0 net: rfkill: gpio... |
79 |
|
4524667b1 net: rfkill: gpio... |
80 |
return devm_acpi_dev_add_driver_gpios(dev, acpi_rfkill_default_gpios); |
ef91ffaa0 net: rfkill: gpio... |
81 |
} |
7176ba23f net: rfkill: add ... |
82 83 |
static int rfkill_gpio_probe(struct platform_device *pdev) { |
262c91ee5 net: rfkill: gpio... |
84 |
struct rfkill_gpio_data *rfkill; |
2111cad65 net: rfkill: gpio... |
85 |
struct gpio_desc *gpio; |
7d5e9737e net: rfkill: gpio... |
86 |
const char *type_name; |
2111cad65 net: rfkill: gpio... |
87 |
int ret; |
7176ba23f net: rfkill: add ... |
88 |
|
262c91ee5 net: rfkill: gpio... |
89 90 91 |
rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); if (!rfkill) return -ENOMEM; |
7d5e9737e net: rfkill: gpio... |
92 93 94 95 96 97 98 |
device_property_read_string(&pdev->dev, "name", &rfkill->name); device_property_read_string(&pdev->dev, "type", &type_name); if (!rfkill->name) rfkill->name = dev_name(&pdev->dev); rfkill->type = rfkill_find_type(type_name); |
ef91ffaa0 net: rfkill: gpio... |
99 100 101 102 |
if (ACPI_HANDLE(&pdev->dev)) { ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); if (ret) return ret; |
7176ba23f net: rfkill: add ... |
103 |
} |
848ef5869 net: rfkill: gpio... |
104 |
rfkill->clk = devm_clk_get(&pdev->dev, NULL); |
7176ba23f net: rfkill: add ... |
105 |
|
f7959e9c7 net: rfkill: gpio... |
106 107 108 |
gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpio)) return PTR_ERR(gpio); |
2111cad65 net: rfkill: gpio... |
109 |
|
f7959e9c7 net: rfkill: gpio... |
110 111 112 113 114 115 116 |
rfkill->reset_gpio = gpio; gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_OUT_LOW); if (IS_ERR(gpio)) return PTR_ERR(gpio); rfkill->shutdown_gpio = gpio; |
7176ba23f net: rfkill: add ... |
117 |
|
7d5e9737e net: rfkill: gpio... |
118 119 |
/* Make sure at-least one GPIO is defined for this instance */ if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) { |
2111cad65 net: rfkill: gpio... |
120 121 122 123 |
dev_err(&pdev->dev, "invalid platform data "); return -EINVAL; } |
262c91ee5 net: rfkill: gpio... |
124 125 126 |
rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev, rfkill->type, &rfkill_gpio_ops, rfkill); |
5e7ca3937 net: rfkill: gpio... |
127 128 |
if (!rfkill->rfkill_dev) return -ENOMEM; |
7176ba23f net: rfkill: add ... |
129 130 131 |
ret = rfkill_register(rfkill->rfkill_dev); if (ret < 0) |
d1d5c31fc rfkill: gpio: fix... |
132 |
goto err_destroy; |
7176ba23f net: rfkill: add ... |
133 134 |
platform_set_drvdata(pdev, rfkill); |
262c91ee5 net: rfkill: gpio... |
135 136 |
dev_info(&pdev->dev, "%s device registered. ", rfkill->name); |
7176ba23f net: rfkill: add ... |
137 138 |
return 0; |
d1d5c31fc rfkill: gpio: fix... |
139 140 141 142 143 |
err_destroy: rfkill_destroy(rfkill->rfkill_dev); return ret; |
7176ba23f net: rfkill: add ... |
144 145 146 147 148 149 150 151 |
} static int rfkill_gpio_remove(struct platform_device *pdev) { struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); rfkill_unregister(rfkill->rfkill_dev); rfkill_destroy(rfkill->rfkill_dev); |
7176ba23f net: rfkill: add ... |
152 153 154 |
return 0; } |
41d09df1e net: rfkill: gpio... |
155 |
#ifdef CONFIG_ACPI |
ef91ffaa0 net: rfkill: gpio... |
156 157 |
static const struct acpi_device_id rfkill_acpi_match[] = { { "BCM4752", RFKILL_TYPE_GPS }, |
04f1b47cd net: rfkill: gpio... |
158 |
{ "LNV4752", RFKILL_TYPE_GPS }, |
ef91ffaa0 net: rfkill: gpio... |
159 160 |
{ }, }; |
dda3b191e net: rfkill: gpio... |
161 |
MODULE_DEVICE_TABLE(acpi, rfkill_acpi_match); |
41d09df1e net: rfkill: gpio... |
162 |
#endif |
ef91ffaa0 net: rfkill: gpio... |
163 |
|
7176ba23f net: rfkill: add ... |
164 165 |
static struct platform_driver rfkill_gpio_driver = { .probe = rfkill_gpio_probe, |
9e2b29d0d rfkill: remove __... |
166 |
.remove = rfkill_gpio_remove, |
7176ba23f net: rfkill: add ... |
167 |
.driver = { |
262c91ee5 net: rfkill: gpio... |
168 |
.name = "rfkill_gpio", |
ef91ffaa0 net: rfkill: gpio... |
169 |
.acpi_match_table = ACPI_PTR(rfkill_acpi_match), |
7176ba23f net: rfkill: add ... |
170 171 |
}, }; |
98ef55f66 net: rfkill: conv... |
172 |
module_platform_driver(rfkill_gpio_driver); |
7176ba23f net: rfkill: add ... |
173 174 175 176 |
MODULE_DESCRIPTION("gpio rfkill"); MODULE_AUTHOR("NVIDIA"); MODULE_LICENSE("GPL"); |