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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.6-rc2 279 lines 8.2 kB view raw
1/* 2 * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs. 3 * 4 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. 5 * Copyright (C) 2009 Sascha Hauer, Pengutronix 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program; if not, write to the Free Software Foundation, Inc., 51 18 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include <linux/mfd/mc13xxx.h> 22#include <linux/platform_device.h> 23#include <linux/hwmon-sysfs.h> 24#include <linux/kernel.h> 25#include <linux/module.h> 26#include <linux/hwmon.h> 27#include <linux/slab.h> 28#include <linux/init.h> 29#include <linux/err.h> 30 31#define DRIVER_NAME "mc13783-adc" 32 33/* platform device id driver data */ 34#define MC13783_ADC_16CHANS 1 35#define MC13783_ADC_BPDIV2 2 36 37struct mc13783_adc_priv { 38 struct mc13xxx *mc13xxx; 39 struct device *hwmon_dev; 40 char name[PLATFORM_NAME_SIZE]; 41}; 42 43static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute 44 *devattr, char *buf) 45{ 46 struct mc13783_adc_priv *priv = dev_get_drvdata(dev); 47 48 return sprintf(buf, "%s\n", priv->name); 49} 50 51static int mc13783_adc_read(struct device *dev, 52 struct device_attribute *devattr, unsigned int *val) 53{ 54 struct mc13783_adc_priv *priv = dev_get_drvdata(dev); 55 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 56 unsigned int channel = attr->index; 57 unsigned int sample[4]; 58 int ret; 59 60 ret = mc13xxx_adc_do_conversion(priv->mc13xxx, 61 MC13XXX_ADC_MODE_MULT_CHAN, 62 channel, 0, 0, sample); 63 if (ret) 64 return ret; 65 66 channel &= 0x7; 67 68 *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff; 69 70 return 0; 71} 72 73static ssize_t mc13783_adc_read_bp(struct device *dev, 74 struct device_attribute *devattr, char *buf) 75{ 76 unsigned val; 77 struct platform_device *pdev = to_platform_device(dev); 78 kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; 79 int ret = mc13783_adc_read(dev, devattr, &val); 80 81 if (ret) 82 return ret; 83 84 if (driver_data & MC13783_ADC_BPDIV2) 85 val = DIV_ROUND_CLOSEST(val * 9, 2); 86 else 87 /* 88 * BP (channel 2) reports with offset 2.4V to the actual value 89 * to fit the input range of the ADC. unit = 2.25mV = 9/4 mV. 90 */ 91 val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400; 92 93 return sprintf(buf, "%u\n", val); 94} 95 96static ssize_t mc13783_adc_read_gp(struct device *dev, 97 struct device_attribute *devattr, char *buf) 98{ 99 unsigned val; 100 int ret = mc13783_adc_read(dev, devattr, &val); 101 102 if (ret) 103 return ret; 104 105 /* 106 * input range is [0, 2.3V], val has 10 bits, so each bit 107 * is worth 9/4 mV. 108 */ 109 val = DIV_ROUND_CLOSEST(val * 9, 4); 110 111 return sprintf(buf, "%u\n", val); 112} 113 114static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL); 115static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2); 116static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5); 117static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6); 118static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7); 119static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8); 120static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9); 121static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10); 122static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11); 123static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12); 124static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13); 125static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); 126static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); 127 128static struct attribute *mc13783_attr_base[] = { 129 &dev_attr_name.attr, 130 &sensor_dev_attr_in2_input.dev_attr.attr, 131 &sensor_dev_attr_in5_input.dev_attr.attr, 132 &sensor_dev_attr_in6_input.dev_attr.attr, 133 &sensor_dev_attr_in7_input.dev_attr.attr, 134 NULL 135}; 136 137static const struct attribute_group mc13783_group_base = { 138 .attrs = mc13783_attr_base, 139}; 140 141/* these are only used if MC13783_ADC_16CHANS is provided in driver data */ 142static struct attribute *mc13783_attr_16chans[] = { 143 &sensor_dev_attr_in8_input.dev_attr.attr, 144 &sensor_dev_attr_in9_input.dev_attr.attr, 145 &sensor_dev_attr_in10_input.dev_attr.attr, 146 &sensor_dev_attr_in11_input.dev_attr.attr, 147 NULL 148}; 149 150static const struct attribute_group mc13783_group_16chans = { 151 .attrs = mc13783_attr_16chans, 152}; 153 154/* last four channels may be occupied by the touchscreen */ 155static struct attribute *mc13783_attr_ts[] = { 156 &sensor_dev_attr_in12_input.dev_attr.attr, 157 &sensor_dev_attr_in13_input.dev_attr.attr, 158 &sensor_dev_attr_in14_input.dev_attr.attr, 159 &sensor_dev_attr_in15_input.dev_attr.attr, 160 NULL 161}; 162 163static const struct attribute_group mc13783_group_ts = { 164 .attrs = mc13783_attr_ts, 165}; 166 167static int mc13783_adc_use_touchscreen(struct platform_device *pdev) 168{ 169 struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); 170 unsigned flags = mc13xxx_get_flags(priv->mc13xxx); 171 172 return flags & MC13XXX_USE_TOUCHSCREEN; 173} 174 175static int __init mc13783_adc_probe(struct platform_device *pdev) 176{ 177 struct mc13783_adc_priv *priv; 178 int ret; 179 const struct platform_device_id *id = platform_get_device_id(pdev); 180 char *dash; 181 182 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 183 if (!priv) 184 return -ENOMEM; 185 186 priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); 187 snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name); 188 dash = strchr(priv->name, '-'); 189 if (dash) 190 *dash = '\0'; 191 192 platform_set_drvdata(pdev, priv); 193 194 /* Register sysfs hooks */ 195 ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base); 196 if (ret) 197 return ret; 198 199 if (id->driver_data & MC13783_ADC_16CHANS) { 200 ret = sysfs_create_group(&pdev->dev.kobj, 201 &mc13783_group_16chans); 202 if (ret) 203 goto out_err_create_16chans; 204 } 205 206 if (!mc13783_adc_use_touchscreen(pdev)) { 207 ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts); 208 if (ret) 209 goto out_err_create_ts; 210 } 211 212 priv->hwmon_dev = hwmon_device_register(&pdev->dev); 213 if (IS_ERR(priv->hwmon_dev)) { 214 ret = PTR_ERR(priv->hwmon_dev); 215 dev_err(&pdev->dev, 216 "hwmon_device_register failed with %d.\n", ret); 217 goto out_err_register; 218 } 219 220 return 0; 221 222out_err_register: 223 224 if (!mc13783_adc_use_touchscreen(pdev)) 225 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); 226out_err_create_ts: 227 228 if (id->driver_data & MC13783_ADC_16CHANS) 229 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); 230out_err_create_16chans: 231 232 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); 233 return ret; 234} 235 236static int mc13783_adc_remove(struct platform_device *pdev) 237{ 238 struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); 239 kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; 240 241 hwmon_device_unregister(priv->hwmon_dev); 242 243 if (!mc13783_adc_use_touchscreen(pdev)) 244 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); 245 246 if (driver_data & MC13783_ADC_16CHANS) 247 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); 248 249 sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); 250 251 return 0; 252} 253 254static const struct platform_device_id mc13783_adc_idtable[] = { 255 { 256 .name = "mc13783-adc", 257 .driver_data = MC13783_ADC_16CHANS, 258 }, { 259 .name = "mc13892-adc", 260 .driver_data = MC13783_ADC_BPDIV2, 261 }, { 262 /* sentinel */ 263 } 264}; 265MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); 266 267static struct platform_driver mc13783_adc_driver = { 268 .remove = mc13783_adc_remove, 269 .driver = { 270 .name = DRIVER_NAME, 271 }, 272 .id_table = mc13783_adc_idtable, 273}; 274 275module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe); 276 277MODULE_DESCRIPTION("MC13783 ADC driver"); 278MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>"); 279MODULE_LICENSE("GPL");