diff options
author | Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | 2012-03-23 05:02:19 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-03-23 05:02:19 -0400 |
commit | 0c2732152a5813a870d0b96f0844f4dfe1436519 (patch) | |
tree | e9ba0ad606d58085217b9a179b9bb508fc4d1d0a /drivers/hwmon | |
parent | cb88200490d723048994753ed59dc0abddc51e77 (diff) |
hwmon: (mc13783-adc) Add support for the MC13892 PMIC
Based on a patch by David Jander that mostly did s/mc13783/mc13xxx/ .
Additionally use dev_get_drvdata instead of to_platform_device +
platform_get_drvdata in mc13783_adc_read (spotted by Jean Delvare).
Cc: David Jander <david.jander@protonic.nl>
Signed-off-by: Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 6 | ||||
-rw-r--r-- | drivers/hwmon/mc13783-adc.c | 101 |
2 files changed, 80 insertions, 27 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index fc3f4e1cad2c..7190a3f4a827 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1360,10 +1360,10 @@ config SENSORS_APPLESMC | |||
1360 | the awesome power of applesmc. | 1360 | the awesome power of applesmc. |
1361 | 1361 | ||
1362 | config SENSORS_MC13783_ADC | 1362 | config SENSORS_MC13783_ADC |
1363 | tristate "Freescale MC13783 ADC" | 1363 | tristate "Freescale MC13783/MC13892 ADC" |
1364 | depends on MFD_MC13783 | 1364 | depends on MFD_MC13XXX |
1365 | help | 1365 | help |
1366 | Support for the A/D converter on MC13783 PMIC. | 1366 | Support for the A/D converter on MC13783 and MC13892 PMIC. |
1367 | 1367 | ||
1368 | if ACPI | 1368 | if ACPI |
1369 | 1369 | ||
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 04d13b31aacd..6c6b240a782e 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the Freescale Semiconductor MC13783 adc. | 2 | * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs. |
3 | * | 3 | * |
4 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | 4 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. |
5 | * Copyright (C) 2009 Sascha Hauer, Pengutronix | 5 | * Copyright (C) 2009 Sascha Hauer, Pengutronix |
@@ -18,7 +18,7 @@ | |||
18 | * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 18 | * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/mfd/mc13783.h> | 21 | #include <linux/mfd/mc13xxx.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/hwmon-sysfs.h> | 23 | #include <linux/hwmon-sysfs.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
@@ -28,24 +28,30 @@ | |||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/err.h> | 29 | #include <linux/err.h> |
30 | 30 | ||
31 | #define MC13783_ADC_NAME "mc13783-adc" | 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 | ||
32 | 36 | ||
33 | struct mc13783_adc_priv { | 37 | struct mc13783_adc_priv { |
34 | struct mc13xxx *mc13xxx; | 38 | struct mc13xxx *mc13xxx; |
35 | struct device *hwmon_dev; | 39 | struct device *hwmon_dev; |
40 | char name[10]; | ||
36 | }; | 41 | }; |
37 | 42 | ||
38 | static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute | 43 | static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute |
39 | *devattr, char *buf) | 44 | *devattr, char *buf) |
40 | { | 45 | { |
41 | return sprintf(buf, "mc13783_adc\n"); | 46 | struct mc13783_adc_priv *priv = dev_get_drvdata(dev); |
47 | |||
48 | return sprintf(buf, "%s\n", priv->name); | ||
42 | } | 49 | } |
43 | 50 | ||
44 | static int mc13783_adc_read(struct device *dev, | 51 | static int mc13783_adc_read(struct device *dev, |
45 | struct device_attribute *devattr, unsigned int *val) | 52 | struct device_attribute *devattr, unsigned int *val) |
46 | { | 53 | { |
47 | struct platform_device *pdev = to_platform_device(dev); | 54 | struct mc13783_adc_priv *priv = dev_get_drvdata(dev); |
48 | struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); | ||
49 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 55 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
50 | unsigned int channel = attr->index; | 56 | unsigned int channel = attr->index; |
51 | unsigned int sample[4]; | 57 | unsigned int sample[4]; |
@@ -68,16 +74,21 @@ static ssize_t mc13783_adc_read_bp(struct device *dev, | |||
68 | struct device_attribute *devattr, char *buf) | 74 | struct device_attribute *devattr, char *buf) |
69 | { | 75 | { |
70 | unsigned val; | 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; | ||
71 | int ret = mc13783_adc_read(dev, devattr, &val); | 79 | int ret = mc13783_adc_read(dev, devattr, &val); |
72 | 80 | ||
73 | if (ret) | 81 | if (ret) |
74 | return ret; | 82 | return ret; |
75 | 83 | ||
76 | /* | 84 | if (driver_data & MC13783_ADC_BPDIV2) |
77 | * BP (channel 2) reports with offset 2.4V to the actual value to fit | 85 | val = DIV_ROUND_CLOSEST(val * 9, 2); |
78 | * the input range of the ADC. unit = 2.25mV = 9/4 mV. | 86 | else |
79 | */ | 87 | /* |
80 | val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400; | 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; | ||
81 | 92 | ||
82 | return sprintf(buf, "%u\n", val); | 93 | return sprintf(buf, "%u\n", val); |
83 | } | 94 | } |
@@ -114,12 +125,21 @@ static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13); | |||
114 | static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); | 125 | static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); |
115 | static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); | 126 | static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); |
116 | 127 | ||
117 | static struct attribute *mc13783_attr[] = { | 128 | static struct attribute *mc13783_attr_base[] = { |
118 | &dev_attr_name.attr, | 129 | &dev_attr_name.attr, |
119 | &sensor_dev_attr_in2_input.dev_attr.attr, | 130 | &sensor_dev_attr_in2_input.dev_attr.attr, |
120 | &sensor_dev_attr_in5_input.dev_attr.attr, | 131 | &sensor_dev_attr_in5_input.dev_attr.attr, |
121 | &sensor_dev_attr_in6_input.dev_attr.attr, | 132 | &sensor_dev_attr_in6_input.dev_attr.attr, |
122 | &sensor_dev_attr_in7_input.dev_attr.attr, | 133 | &sensor_dev_attr_in7_input.dev_attr.attr, |
134 | NULL | ||
135 | }; | ||
136 | |||
137 | static 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 */ | ||
142 | static struct attribute *mc13783_attr_16chans[] = { | ||
123 | &sensor_dev_attr_in8_input.dev_attr.attr, | 143 | &sensor_dev_attr_in8_input.dev_attr.attr, |
124 | &sensor_dev_attr_in9_input.dev_attr.attr, | 144 | &sensor_dev_attr_in9_input.dev_attr.attr, |
125 | &sensor_dev_attr_in10_input.dev_attr.attr, | 145 | &sensor_dev_attr_in10_input.dev_attr.attr, |
@@ -127,8 +147,8 @@ static struct attribute *mc13783_attr[] = { | |||
127 | NULL | 147 | NULL |
128 | }; | 148 | }; |
129 | 149 | ||
130 | static const struct attribute_group mc13783_group = { | 150 | static const struct attribute_group mc13783_group_16chans = { |
131 | .attrs = mc13783_attr, | 151 | .attrs = mc13783_attr_16chans, |
132 | }; | 152 | }; |
133 | 153 | ||
134 | /* last four channels may be occupied by the touchscreen */ | 154 | /* last four channels may be occupied by the touchscreen */ |
@@ -156,24 +176,37 @@ static int __init mc13783_adc_probe(struct platform_device *pdev) | |||
156 | { | 176 | { |
157 | struct mc13783_adc_priv *priv; | 177 | struct mc13783_adc_priv *priv; |
158 | int ret; | 178 | int ret; |
179 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
180 | char *dash; | ||
159 | 181 | ||
160 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 182 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
161 | if (!priv) | 183 | if (!priv) |
162 | return -ENOMEM; | 184 | return -ENOMEM; |
163 | 185 | ||
164 | priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); | 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'; | ||
165 | 191 | ||
166 | platform_set_drvdata(pdev, priv); | 192 | platform_set_drvdata(pdev, priv); |
167 | 193 | ||
168 | /* Register sysfs hooks */ | 194 | /* Register sysfs hooks */ |
169 | ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group); | 195 | ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base); |
170 | if (ret) | 196 | if (ret) |
171 | goto out_err_create1; | 197 | goto out_err_create_base; |
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 | } | ||
172 | 205 | ||
173 | if (!mc13783_adc_use_touchscreen(pdev)) { | 206 | if (!mc13783_adc_use_touchscreen(pdev)) { |
174 | ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts); | 207 | ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts); |
175 | if (ret) | 208 | if (ret) |
176 | goto out_err_create2; | 209 | goto out_err_create_ts; |
177 | } | 210 | } |
178 | 211 | ||
179 | priv->hwmon_dev = hwmon_device_register(&pdev->dev); | 212 | priv->hwmon_dev = hwmon_device_register(&pdev->dev); |
@@ -184,17 +217,20 @@ static int __init mc13783_adc_probe(struct platform_device *pdev) | |||
184 | goto out_err_register; | 217 | goto out_err_register; |
185 | } | 218 | } |
186 | 219 | ||
187 | |||
188 | return 0; | 220 | return 0; |
189 | 221 | ||
190 | out_err_register: | 222 | out_err_register: |
191 | 223 | ||
192 | if (!mc13783_adc_use_touchscreen(pdev)) | 224 | if (!mc13783_adc_use_touchscreen(pdev)) |
193 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); | 225 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); |
194 | out_err_create2: | 226 | out_err_create_ts: |
195 | 227 | ||
196 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group); | 228 | if (id->driver_data & MC13783_ADC_16CHANS) |
197 | out_err_create1: | 229 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); |
230 | out_err_create_16chans: | ||
231 | |||
232 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); | ||
233 | out_err_create_base: | ||
198 | 234 | ||
199 | platform_set_drvdata(pdev, NULL); | 235 | platform_set_drvdata(pdev, NULL); |
200 | kfree(priv); | 236 | kfree(priv); |
@@ -205,13 +241,17 @@ out_err_create1: | |||
205 | static int __devexit mc13783_adc_remove(struct platform_device *pdev) | 241 | static int __devexit mc13783_adc_remove(struct platform_device *pdev) |
206 | { | 242 | { |
207 | struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); | 243 | struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); |
244 | kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; | ||
208 | 245 | ||
209 | hwmon_device_unregister(priv->hwmon_dev); | 246 | hwmon_device_unregister(priv->hwmon_dev); |
210 | 247 | ||
211 | if (!mc13783_adc_use_touchscreen(pdev)) | 248 | if (!mc13783_adc_use_touchscreen(pdev)) |
212 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); | 249 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts); |
213 | 250 | ||
214 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group); | 251 | if (driver_data & MC13783_ADC_16CHANS) |
252 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); | ||
253 | |||
254 | sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); | ||
215 | 255 | ||
216 | platform_set_drvdata(pdev, NULL); | 256 | platform_set_drvdata(pdev, NULL); |
217 | kfree(priv); | 257 | kfree(priv); |
@@ -219,12 +259,26 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev) | |||
219 | return 0; | 259 | return 0; |
220 | } | 260 | } |
221 | 261 | ||
262 | static const struct platform_device_id mc13783_adc_idtable[] = { | ||
263 | { | ||
264 | .name = "mc13783-adc", | ||
265 | .driver_data = MC13783_ADC_16CHANS, | ||
266 | }, { | ||
267 | .name = "mc13892-adc", | ||
268 | .driver_data = MC13783_ADC_BPDIV2, | ||
269 | }, { | ||
270 | /* sentinel */ | ||
271 | } | ||
272 | }; | ||
273 | MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); | ||
274 | |||
222 | static struct platform_driver mc13783_adc_driver = { | 275 | static struct platform_driver mc13783_adc_driver = { |
223 | .remove = __devexit_p(mc13783_adc_remove), | 276 | .remove = __devexit_p(mc13783_adc_remove), |
224 | .driver = { | 277 | .driver = { |
225 | .owner = THIS_MODULE, | 278 | .owner = THIS_MODULE, |
226 | .name = MC13783_ADC_NAME, | 279 | .name = DRIVER_NAME, |
227 | }, | 280 | }, |
281 | .id_table = mc13783_adc_idtable, | ||
228 | }; | 282 | }; |
229 | 283 | ||
230 | static int __init mc13783_adc_init(void) | 284 | static int __init mc13783_adc_init(void) |
@@ -243,4 +297,3 @@ module_exit(mc13783_adc_exit); | |||
243 | MODULE_DESCRIPTION("MC13783 ADC driver"); | 297 | MODULE_DESCRIPTION("MC13783 ADC driver"); |
244 | MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>"); | 298 | MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>"); |
245 | MODULE_LICENSE("GPL"); | 299 | MODULE_LICENSE("GPL"); |
246 | MODULE_ALIAS("platform:" MC13783_ADC_NAME); | ||