at v3.2 163 lines 4.0 kB view raw
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 23struct rfkill_regulator_data { 24 struct rfkill *rf_kill; 25 bool reg_enabled; 26 27 struct regulator *vcc; 28}; 29 30static 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 54struct rfkill_ops rfkill_regulator_ops = { 55 .set_block = rfkill_regulator_set_block, 56}; 57 58static 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 ret = -ENOMEM; 94 goto err_rfkill_alloc; 95 } 96 97 if (regulator_is_enabled(vcc)) { 98 dev_dbg(&pdev->dev, "Regulator already enabled\n"); 99 rfkill_data->reg_enabled = 1; 100 } 101 rfkill_data->vcc = vcc; 102 rfkill_data->rf_kill = rf_kill; 103 104 ret = rfkill_register(rf_kill); 105 if (ret) { 106 dev_err(&pdev->dev, "Cannot register rfkill device\n"); 107 goto err_rfkill_register; 108 } 109 110 platform_set_drvdata(pdev, rfkill_data); 111 dev_info(&pdev->dev, "%s initialized\n", pdata->name); 112 113 return 0; 114 115err_rfkill_register: 116 rfkill_destroy(rf_kill); 117err_rfkill_alloc: 118 kfree(rfkill_data); 119err_data_alloc: 120 regulator_put(vcc); 121out: 122 return ret; 123} 124 125static int __devexit rfkill_regulator_remove(struct platform_device *pdev) 126{ 127 struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); 128 struct rfkill *rf_kill = rfkill_data->rf_kill; 129 130 rfkill_unregister(rf_kill); 131 rfkill_destroy(rf_kill); 132 regulator_put(rfkill_data->vcc); 133 kfree(rfkill_data); 134 135 return 0; 136} 137 138static struct platform_driver rfkill_regulator_driver = { 139 .probe = rfkill_regulator_probe, 140 .remove = __devexit_p(rfkill_regulator_remove), 141 .driver = { 142 .name = "rfkill-regulator", 143 .owner = THIS_MODULE, 144 }, 145}; 146 147static int __init rfkill_regulator_init(void) 148{ 149 return platform_driver_register(&rfkill_regulator_driver); 150} 151module_init(rfkill_regulator_init); 152 153static void __exit rfkill_regulator_exit(void) 154{ 155 platform_driver_unregister(&rfkill_regulator_driver); 156} 157module_exit(rfkill_regulator_exit); 158 159MODULE_AUTHOR("Guiming Zhuo <gmzhuo@gmail.com>"); 160MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 161MODULE_DESCRIPTION("Regulator consumer driver for rfkill"); 162MODULE_LICENSE("GPL"); 163MODULE_ALIAS("platform:rfkill-regulator");