Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rfkill: Regulator consumer driver for rfkill

Add a regulator consumer driver for rfkill to enable controlling radio
transmitters connected to voltage regulators using the regulator
framework.

A new "vrfkill" virtual supply is provided to use in platform code.

Signed-off-by: Guiming Zhuo <gmzhuo@gmail.com>
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Antonio Ospite and committed by
John W. Linville
cbc6a6ed bb411b4d

+224
+48
include/linux/rfkill-regulator.h
··· 1 + /* 2 + * rfkill-regulator.c - Regulator consumer driver for rfkill 3 + * 4 + * Copyright (C) 2009 Guiming Zhuo <gmzhuo@gmail.com> 5 + * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + */ 12 + 13 + #ifndef __LINUX_RFKILL_REGULATOR_H 14 + #define __LINUX_RFKILL_REGULATOR_H 15 + 16 + /* 17 + * Use "vrfkill" as supply id when declaring the regulator consumer: 18 + * 19 + * static struct regulator_consumer_supply pcap_regulator_V6_consumers [] = { 20 + * { .dev_name = "rfkill-regulator.0", .supply = "vrfkill" }, 21 + * }; 22 + * 23 + * If you have several regulator driven rfkill, you can append a numerical id to 24 + * .dev_name as done above, and use the same id when declaring the platform 25 + * device: 26 + * 27 + * static struct rfkill_regulator_platform_data ezx_rfkill_bt_data = { 28 + * .name = "ezx-bluetooth", 29 + * .type = RFKILL_TYPE_BLUETOOTH, 30 + * }; 31 + * 32 + * static struct platform_device a910_rfkill = { 33 + * .name = "rfkill-regulator", 34 + * .id = 0, 35 + * .dev = { 36 + * .platform_data = &ezx_rfkill_bt_data, 37 + * }, 38 + * }; 39 + */ 40 + 41 + #include <linux/rfkill.h> 42 + 43 + struct rfkill_regulator_platform_data { 44 + char *name; /* the name for the rfkill switch */ 45 + enum rfkill_type type; /* the type as specified in rfkill.h */ 46 + }; 47 + 48 + #endif /* __LINUX_RFKILL_REGULATOR_H */
+11
net/rfkill/Kconfig
··· 22 22 depends on RFKILL 23 23 depends on INPUT = y || RFKILL = INPUT 24 24 default y if !EXPERT 25 + 26 + config RFKILL_REGULATOR 27 + tristate "Generic rfkill regulator driver" 28 + depends on RFKILL || !RFKILL 29 + depends on REGULATOR 30 + help 31 + This options enable controlling radio transmitters connected to 32 + voltage regulator using the regulator framework. 33 + 34 + To compile this driver as a module, choose M here: the module will 35 + be called rfkill-regulator.
+1
net/rfkill/Makefile
··· 5 5 rfkill-y += core.o 6 6 rfkill-$(CONFIG_RFKILL_INPUT) += input.o 7 7 obj-$(CONFIG_RFKILL) += rfkill.o 8 + obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o
+164
net/rfkill/rfkill-regulator.c
··· 1 + /* 2 + * rfkill-regulator.c - Regulator consumer driver for rfkill 3 + * 4 + * Copyright (C) 2009 Guiming Zhuo <gmzhuo@gmail.com> 5 + * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> 6 + * 7 + * Implementation inspired by leds-regulator driver. 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + * 13 + */ 14 + 15 + #include <linux/module.h> 16 + #include <linux/err.h> 17 + #include <linux/slab.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/regulator/consumer.h> 20 + #include <linux/rfkill.h> 21 + #include <linux/rfkill-regulator.h> 22 + 23 + struct rfkill_regulator_data { 24 + struct rfkill *rf_kill; 25 + bool reg_enabled; 26 + 27 + struct regulator *vcc; 28 + }; 29 + 30 + static int rfkill_regulator_set_block(void *data, bool blocked) 31 + { 32 + struct rfkill_regulator_data *rfkill_data = data; 33 + 34 + pr_debug("%s: blocked: %d\n", __func__, blocked); 35 + 36 + if (blocked) { 37 + if (rfkill_data->reg_enabled) { 38 + regulator_disable(rfkill_data->vcc); 39 + rfkill_data->reg_enabled = 0; 40 + } 41 + } else { 42 + if (!rfkill_data->reg_enabled) { 43 + regulator_enable(rfkill_data->vcc); 44 + rfkill_data->reg_enabled = 1; 45 + } 46 + } 47 + 48 + pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__, 49 + regulator_is_enabled(rfkill_data->vcc)); 50 + 51 + return 0; 52 + } 53 + 54 + struct rfkill_ops rfkill_regulator_ops = { 55 + .set_block = rfkill_regulator_set_block, 56 + }; 57 + 58 + static int __devinit rfkill_regulator_probe(struct platform_device *pdev) 59 + { 60 + struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data; 61 + struct rfkill_regulator_data *rfkill_data; 62 + struct regulator *vcc; 63 + struct rfkill *rf_kill; 64 + int ret = 0; 65 + 66 + if (pdata == NULL) { 67 + dev_err(&pdev->dev, "no platform data\n"); 68 + return -ENODEV; 69 + } 70 + 71 + if (pdata->name == NULL || pdata->type == 0) { 72 + dev_err(&pdev->dev, "invalid name or type in platform data\n"); 73 + return -EINVAL; 74 + } 75 + 76 + vcc = regulator_get_exclusive(&pdev->dev, "vrfkill"); 77 + if (IS_ERR(vcc)) { 78 + dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name); 79 + ret = PTR_ERR(vcc); 80 + goto out; 81 + } 82 + 83 + rfkill_data = kzalloc(sizeof(*rfkill_data), GFP_KERNEL); 84 + if (rfkill_data == NULL) { 85 + ret = -ENOMEM; 86 + goto err_data_alloc; 87 + } 88 + 89 + rf_kill = rfkill_alloc(pdata->name, &pdev->dev, 90 + pdata->type, 91 + &rfkill_regulator_ops, rfkill_data); 92 + if (rf_kill == NULL) { 93 + dev_err(&pdev->dev, "Cannot alloc rfkill device\n"); 94 + ret = -ENOMEM; 95 + goto err_rfkill_alloc; 96 + } 97 + 98 + if (regulator_is_enabled(vcc)) { 99 + dev_dbg(&pdev->dev, "Regulator already enabled\n"); 100 + rfkill_data->reg_enabled = 1; 101 + } 102 + rfkill_data->vcc = vcc; 103 + rfkill_data->rf_kill = rf_kill; 104 + 105 + ret = rfkill_register(rf_kill); 106 + if (ret) { 107 + dev_err(&pdev->dev, "Cannot register rfkill device\n"); 108 + goto err_rfkill_register; 109 + } 110 + 111 + platform_set_drvdata(pdev, rfkill_data); 112 + dev_info(&pdev->dev, "%s initialized\n", pdata->name); 113 + 114 + return 0; 115 + 116 + err_rfkill_register: 117 + rfkill_destroy(rf_kill); 118 + err_rfkill_alloc: 119 + kfree(rfkill_data); 120 + err_data_alloc: 121 + regulator_put(vcc); 122 + out: 123 + return ret; 124 + } 125 + 126 + static int __devexit rfkill_regulator_remove(struct platform_device *pdev) 127 + { 128 + struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); 129 + struct rfkill *rf_kill = rfkill_data->rf_kill; 130 + 131 + rfkill_unregister(rf_kill); 132 + rfkill_destroy(rf_kill); 133 + regulator_put(rfkill_data->vcc); 134 + kfree(rfkill_data); 135 + 136 + return 0; 137 + } 138 + 139 + static struct platform_driver rfkill_regulator_driver = { 140 + .probe = rfkill_regulator_probe, 141 + .remove = __devexit_p(rfkill_regulator_remove), 142 + .driver = { 143 + .name = "rfkill-regulator", 144 + .owner = THIS_MODULE, 145 + }, 146 + }; 147 + 148 + static int __init rfkill_regulator_init(void) 149 + { 150 + return platform_driver_register(&rfkill_regulator_driver); 151 + } 152 + module_init(rfkill_regulator_init); 153 + 154 + static void __exit rfkill_regulator_exit(void) 155 + { 156 + platform_driver_unregister(&rfkill_regulator_driver); 157 + } 158 + module_exit(rfkill_regulator_exit); 159 + 160 + MODULE_AUTHOR("Guiming Zhuo <gmzhuo@gmail.com>"); 161 + MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 162 + MODULE_DESCRIPTION("Regulator consumer driver for rfkill"); 163 + MODULE_LICENSE("GPL"); 164 + MODULE_ALIAS("platform:rfkill-regulator");