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 int ret = 0; 34 35 pr_debug("%s: blocked: %d\n", __func__, blocked); 36 37 if (blocked) { 38 if (rfkill_data->reg_enabled) { 39 regulator_disable(rfkill_data->vcc); 40 rfkill_data->reg_enabled = false; 41 } 42 } else { 43 if (!rfkill_data->reg_enabled) { 44 ret = regulator_enable(rfkill_data->vcc); 45 if (!ret) 46 rfkill_data->reg_enabled = true; 47 } 48 } 49 50 pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__, 51 regulator_is_enabled(rfkill_data->vcc)); 52 53 return ret; 54} 55 56static struct rfkill_ops rfkill_regulator_ops = { 57 .set_block = rfkill_regulator_set_block, 58}; 59 60static int rfkill_regulator_probe(struct platform_device *pdev) 61{ 62 struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data; 63 struct rfkill_regulator_data *rfkill_data; 64 struct regulator *vcc; 65 struct rfkill *rf_kill; 66 int ret = 0; 67 68 if (pdata == NULL) { 69 dev_err(&pdev->dev, "no platform data\n"); 70 return -ENODEV; 71 } 72 73 if (pdata->name == NULL || pdata->type == 0) { 74 dev_err(&pdev->dev, "invalid name or type in platform data\n"); 75 return -EINVAL; 76 } 77 78 vcc = regulator_get_exclusive(&pdev->dev, "vrfkill"); 79 if (IS_ERR(vcc)) { 80 dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name); 81 ret = PTR_ERR(vcc); 82 goto out; 83 } 84 85 rfkill_data = kzalloc(sizeof(*rfkill_data), GFP_KERNEL); 86 if (rfkill_data == NULL) { 87 ret = -ENOMEM; 88 goto err_data_alloc; 89 } 90 91 rf_kill = rfkill_alloc(pdata->name, &pdev->dev, 92 pdata->type, 93 &rfkill_regulator_ops, rfkill_data); 94 if (rf_kill == NULL) { 95 ret = -ENOMEM; 96 goto err_rfkill_alloc; 97 } 98 99 if (regulator_is_enabled(vcc)) { 100 dev_dbg(&pdev->dev, "Regulator already enabled\n"); 101 rfkill_data->reg_enabled = true; 102 } 103 rfkill_data->vcc = vcc; 104 rfkill_data->rf_kill = rf_kill; 105 106 ret = rfkill_register(rf_kill); 107 if (ret) { 108 dev_err(&pdev->dev, "Cannot register rfkill device\n"); 109 goto err_rfkill_register; 110 } 111 112 platform_set_drvdata(pdev, rfkill_data); 113 dev_info(&pdev->dev, "%s initialized\n", pdata->name); 114 115 return 0; 116 117err_rfkill_register: 118 rfkill_destroy(rf_kill); 119err_rfkill_alloc: 120 kfree(rfkill_data); 121err_data_alloc: 122 regulator_put(vcc); 123out: 124 return ret; 125} 126 127static int rfkill_regulator_remove(struct platform_device *pdev) 128{ 129 struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); 130 struct rfkill *rf_kill = rfkill_data->rf_kill; 131 132 rfkill_unregister(rf_kill); 133 rfkill_destroy(rf_kill); 134 regulator_put(rfkill_data->vcc); 135 kfree(rfkill_data); 136 137 return 0; 138} 139 140static struct platform_driver rfkill_regulator_driver = { 141 .probe = rfkill_regulator_probe, 142 .remove = rfkill_regulator_remove, 143 .driver = { 144 .name = "rfkill-regulator", 145 }, 146}; 147 148module_platform_driver(rfkill_regulator_driver); 149 150MODULE_AUTHOR("Guiming Zhuo <gmzhuo@gmail.com>"); 151MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 152MODULE_DESCRIPTION("Regulator consumer driver for rfkill"); 153MODULE_LICENSE("GPL"); 154MODULE_ALIAS("platform:rfkill-regulator"); 155