Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * Driver for the Freescale Semiconductor MC13783 adc.
  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/mc13783.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 MC13783_ADC_NAME	"mc13783-adc"
 
 
 
 
 32
 33struct mc13783_adc_priv {
 34	struct mc13783 *mc13783;
 35	struct device *hwmon_dev;
 
 36};
 37
 38static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
 39			      *devattr, char *buf)
 40{
 41	return sprintf(buf, "mc13783_adc\n");
 
 
 42}
 43
 44static int mc13783_adc_read(struct device *dev,
 45		struct device_attribute *devattr, unsigned int *val)
 46{
 47	struct platform_device *pdev = to_platform_device(dev);
 48	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 49	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 50	unsigned int channel = attr->index;
 51	unsigned int sample[4];
 52	int ret;
 53
 54	ret = mc13783_adc_do_conversion(priv->mc13783,
 55			MC13783_ADC_MODE_MULT_CHAN,
 56			channel, sample);
 57	if (ret)
 58		return ret;
 59
 
 
 
 
 60	channel &= 0x7;
 61
 62	*val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
 63
 64	return 0;
 65}
 66
 67static ssize_t mc13783_adc_read_bp(struct device *dev,
 68		struct device_attribute *devattr, char *buf)
 
 69{
 70	unsigned val;
 
 
 71	int ret = mc13783_adc_read(dev, devattr, &val);
 72
 73	if (ret)
 74		return ret;
 75
 76	/*
 77	 * BP (channel 2) reports with offset 2.4V to the actual value to fit
 78	 * the input range of the ADC.  unit = 2.25mV = 9/4 mV.
 79	 */
 80	val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
 
 
 
 81
 82	return sprintf(buf, "%u\n", val);
 83}
 84
 85static ssize_t mc13783_adc_read_gp(struct device *dev,
 86		struct device_attribute *devattr, char *buf)
 
 87{
 88	unsigned val;
 89	int ret = mc13783_adc_read(dev, devattr, &val);
 90
 91	if (ret)
 92		return ret;
 93
 94	/*
 95	 * input range is [0, 2.3V], val has 10 bits, so each bit
 96	 * is worth 9/4 mV.
 97	 */
 98	val = DIV_ROUND_CLOSEST(val * 9, 4);
 99
100	return sprintf(buf, "%u\n", val);
101}
102
103static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
104static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
105static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
106static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
107static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
108static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
109static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
110static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
111static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
112static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
113static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
114static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
115static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
117static struct attribute *mc13783_attr[] = {
118	&dev_attr_name.attr,
119	&sensor_dev_attr_in2_input.dev_attr.attr,
120	&sensor_dev_attr_in5_input.dev_attr.attr,
121	&sensor_dev_attr_in6_input.dev_attr.attr,
122	&sensor_dev_attr_in7_input.dev_attr.attr,
 
 
 
 
 
 
 
 
 
 
 
123	&sensor_dev_attr_in8_input.dev_attr.attr,
124	&sensor_dev_attr_in9_input.dev_attr.attr,
125	&sensor_dev_attr_in10_input.dev_attr.attr,
126	&sensor_dev_attr_in11_input.dev_attr.attr,
127	NULL
128};
129
130static const struct attribute_group mc13783_group = {
131	.attrs = mc13783_attr,
132};
133
134/* last four channels may be occupied by the touchscreen */
135static struct attribute *mc13783_attr_ts[] = {
136	&sensor_dev_attr_in12_input.dev_attr.attr,
137	&sensor_dev_attr_in13_input.dev_attr.attr,
138	&sensor_dev_attr_in14_input.dev_attr.attr,
139	&sensor_dev_attr_in15_input.dev_attr.attr,
140	NULL
141};
142
143static const struct attribute_group mc13783_group_ts = {
144	.attrs = mc13783_attr_ts,
145};
146
147static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
148{
149	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
150	unsigned flags = mc13783_get_flags(priv->mc13783);
151
152	return flags & MC13783_USE_TOUCHSCREEN;
153}
154
155static int __init mc13783_adc_probe(struct platform_device *pdev)
156{
157	struct mc13783_adc_priv *priv;
158	int ret;
 
 
159
160	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
161	if (!priv)
162		return -ENOMEM;
163
164	priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
 
 
 
 
165
166	platform_set_drvdata(pdev, priv);
167
168	/* Register sysfs hooks */
169	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
170	if (ret)
171		goto out_err_create1;
 
 
 
 
 
 
 
172
173	if (!mc13783_adc_use_touchscreen(pdev)) {
174		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
175		if (ret)
176			goto out_err_create2;
177	}
178
179	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
180	if (IS_ERR(priv->hwmon_dev)) {
181		ret = PTR_ERR(priv->hwmon_dev);
182		dev_err(&pdev->dev,
183				"hwmon_device_register failed with %d.\n", ret);
184		goto out_err_register;
185	}
186
187
188	return 0;
189
190out_err_register:
191
192	if (!mc13783_adc_use_touchscreen(pdev))
193		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
194out_err_create2:
195
196	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
197out_err_create1:
198
199	platform_set_drvdata(pdev, NULL);
200	kfree(priv);
 
201
 
202	return ret;
203}
204
205static int __devexit mc13783_adc_remove(struct platform_device *pdev)
206{
207	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 
208
209	hwmon_device_unregister(priv->hwmon_dev);
210
211	if (!mc13783_adc_use_touchscreen(pdev))
212		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
213
214	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
 
215
216	platform_set_drvdata(pdev, NULL);
217	kfree(priv);
218
219	return 0;
220}
221
 
 
 
 
 
 
 
 
 
 
 
 
 
222static struct platform_driver mc13783_adc_driver = {
223	.remove 	= __devexit_p(mc13783_adc_remove),
224	.driver		= {
225		.owner	= THIS_MODULE,
226		.name	= MC13783_ADC_NAME,
227	},
 
228};
229
230static int __init mc13783_adc_init(void)
231{
232	return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
233}
234
235static void __exit mc13783_adc_exit(void)
236{
237	platform_driver_unregister(&mc13783_adc_driver);
238}
239
240module_init(mc13783_adc_init);
241module_exit(mc13783_adc_exit);
242
243MODULE_DESCRIPTION("MC13783 ADC driver");
244MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
245MODULE_LICENSE("GPL");
246MODULE_ALIAS("platform:" MC13783_ADC_NAME);
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
  4 *
  5 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  6 * Copyright (C) 2009 Sascha Hauer, Pengutronix
 
 
 
 
 
 
 
 
 
 
 
 
 
  7 */
  8
  9#include <linux/mfd/mc13xxx.h>
 10#include <linux/platform_device.h>
 11#include <linux/hwmon-sysfs.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/mod_devicetable.h>
 15#include <linux/hwmon.h>
 16#include <linux/slab.h>
 17#include <linux/init.h>
 18#include <linux/err.h>
 19
 20#define DRIVER_NAME	"mc13783-adc"
 21
 22/* platform device id driver data */
 23#define MC13783_ADC_16CHANS	1
 24#define MC13783_ADC_BPDIV2	2
 25
 26struct mc13783_adc_priv {
 27	struct mc13xxx *mc13xxx;
 28	struct device *hwmon_dev;
 29	char name[PLATFORM_NAME_SIZE];
 30};
 31
 32static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
 33			 char *buf)
 34{
 35	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
 36
 37	return sprintf(buf, "%s\n", priv->name);
 38}
 39
 40static int mc13783_adc_read(struct device *dev,
 41		struct device_attribute *devattr, unsigned int *val)
 42{
 43	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
 
 44	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 45	unsigned int channel = attr->index;
 46	unsigned int sample[4];
 47	int ret;
 48
 49	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
 50			MC13XXX_ADC_MODE_MULT_CHAN,
 51			channel, 0, 0, sample);
 52	if (ret)
 53		return ret;
 54
 55	/* ADIN7 subchannels */
 56	if (channel >= 16)
 57		channel = 7;
 58
 59	channel &= 0x7;
 60
 61	*val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
 62
 63	return 0;
 64}
 65
 66static ssize_t mc13783_adc_bp_show(struct device *dev,
 67				   struct device_attribute *devattr,
 68				   char *buf)
 69{
 70	unsigned val;
 71	struct platform_device *pdev = to_platform_device(dev);
 72	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
 73	int ret = mc13783_adc_read(dev, devattr, &val);
 74
 75	if (ret)
 76		return ret;
 77
 78	if (driver_data & MC13783_ADC_BPDIV2)
 79		val = DIV_ROUND_CLOSEST(val * 9, 2);
 80	else
 81		/*
 82		 * BP (channel 2) reports with offset 2.4V to the actual value
 83		 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
 84		 */
 85		val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
 86
 87	return sprintf(buf, "%u\n", val);
 88}
 89
 90static ssize_t mc13783_adc_gp_show(struct device *dev,
 91				   struct device_attribute *devattr,
 92				   char *buf)
 93{
 94	unsigned val;
 95	int ret = mc13783_adc_read(dev, devattr, &val);
 96
 97	if (ret)
 98		return ret;
 99
100	/*
101	 * input range is [0, 2.3V], val has 10 bits, so each bit
102	 * is worth 9/4 mV.
103	 */
104	val = DIV_ROUND_CLOSEST(val * 9, 4);
105
106	return sprintf(buf, "%u\n", val);
107}
108
109static ssize_t mc13783_adc_uid_show(struct device *dev,
110				    struct device_attribute *devattr,
111				    char *buf)
112{
113	unsigned int val;
114	struct platform_device *pdev = to_platform_device(dev);
115	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
116	int ret = mc13783_adc_read(dev, devattr, &val);
117
118	if (ret)
119		return ret;
120
121	if (driver_data & MC13783_ADC_BPDIV2)
122		/* MC13892 have 1/2 divider, input range is [0, 4.800V] */
123		val = DIV_ROUND_CLOSEST(val * 4800, 1024);
124	else
125		/* MC13783 have 0.9 divider, input range is [0, 2.555V] */
126		val = DIV_ROUND_CLOSEST(val * 2555, 1024);
127
128	return sprintf(buf, "%u\n", val);
129}
130
131static ssize_t mc13783_adc_temp_show(struct device *dev,
132				     struct device_attribute *devattr,
133				     char *buf)
134{
135	unsigned int val;
136	struct platform_device *pdev = to_platform_device(dev);
137	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
138	int ret = mc13783_adc_read(dev, devattr, &val);
139
140	if (ret)
141		return ret;
142
143	if (driver_data & MC13783_ADC_BPDIV2) {
144		/*
145		 * MC13892:
146		 * Die Temperature Read Out Code at 25C 680
147		 * Temperature change per LSB +0.4244C
148		 */
149		ret = DIV_ROUND_CLOSEST(-2635920 + val * 4244, 10);
150	} else {
151		/*
152		 * MC13783:
153		 * Die Temperature Read Out Code at 25C 282
154		 * Temperature change per LSB -1.14C
155		 */
156		ret = 346480 - 1140 * val;
157	}
158
159	return sprintf(buf, "%d\n", ret);
160}
161
162static DEVICE_ATTR_RO(name);
163static SENSOR_DEVICE_ATTR_RO(in2_input, mc13783_adc_bp, 2);
164static SENSOR_DEVICE_ATTR_RO(in5_input, mc13783_adc_gp, 5);
165static SENSOR_DEVICE_ATTR_RO(in6_input, mc13783_adc_gp, 6);
166static SENSOR_DEVICE_ATTR_RO(in7_input, mc13783_adc_gp, 7);
167static SENSOR_DEVICE_ATTR_RO(in8_input, mc13783_adc_gp, 8);
168static SENSOR_DEVICE_ATTR_RO(in9_input, mc13783_adc_gp, 9);
169static SENSOR_DEVICE_ATTR_RO(in10_input, mc13783_adc_gp, 10);
170static SENSOR_DEVICE_ATTR_RO(in11_input, mc13783_adc_gp, 11);
171static SENSOR_DEVICE_ATTR_RO(in12_input, mc13783_adc_gp, 12);
172static SENSOR_DEVICE_ATTR_RO(in13_input, mc13783_adc_gp, 13);
173static SENSOR_DEVICE_ATTR_RO(in14_input, mc13783_adc_gp, 14);
174static SENSOR_DEVICE_ATTR_RO(in15_input, mc13783_adc_gp, 15);
175static SENSOR_DEVICE_ATTR_RO(in16_input, mc13783_adc_uid, 16);
176static SENSOR_DEVICE_ATTR_RO(temp1_input, mc13783_adc_temp, 17);
177
178static struct attribute *mc13783_attr_base[] = {
179	&dev_attr_name.attr,
180	&sensor_dev_attr_in2_input.dev_attr.attr,
181	&sensor_dev_attr_in5_input.dev_attr.attr,
182	&sensor_dev_attr_in6_input.dev_attr.attr,
183	&sensor_dev_attr_in7_input.dev_attr.attr,
184	&sensor_dev_attr_in16_input.dev_attr.attr,
185	&sensor_dev_attr_temp1_input.dev_attr.attr,
186	NULL
187};
188
189static const struct attribute_group mc13783_group_base = {
190	.attrs = mc13783_attr_base,
191};
192
193/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
194static struct attribute *mc13783_attr_16chans[] = {
195	&sensor_dev_attr_in8_input.dev_attr.attr,
196	&sensor_dev_attr_in9_input.dev_attr.attr,
197	&sensor_dev_attr_in10_input.dev_attr.attr,
198	&sensor_dev_attr_in11_input.dev_attr.attr,
199	NULL
200};
201
202static const struct attribute_group mc13783_group_16chans = {
203	.attrs = mc13783_attr_16chans,
204};
205
206/* last four channels may be occupied by the touchscreen */
207static struct attribute *mc13783_attr_ts[] = {
208	&sensor_dev_attr_in12_input.dev_attr.attr,
209	&sensor_dev_attr_in13_input.dev_attr.attr,
210	&sensor_dev_attr_in14_input.dev_attr.attr,
211	&sensor_dev_attr_in15_input.dev_attr.attr,
212	NULL
213};
214
215static const struct attribute_group mc13783_group_ts = {
216	.attrs = mc13783_attr_ts,
217};
218
219static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
220{
221	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
222	unsigned flags = mc13xxx_get_flags(priv->mc13xxx);
223
224	return flags & MC13XXX_USE_TOUCHSCREEN;
225}
226
227static int __init mc13783_adc_probe(struct platform_device *pdev)
228{
229	struct mc13783_adc_priv *priv;
230	int ret;
231	const struct platform_device_id *id = platform_get_device_id(pdev);
232	char *dash;
233
234	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
235	if (!priv)
236		return -ENOMEM;
237
238	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
239	snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
240	dash = strchr(priv->name, '-');
241	if (dash)
242		*dash = '\0';
243
244	platform_set_drvdata(pdev, priv);
245
246	/* Register sysfs hooks */
247	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
248	if (ret)
249		return ret;
250
251	if (id->driver_data & MC13783_ADC_16CHANS) {
252		ret = sysfs_create_group(&pdev->dev.kobj,
253				&mc13783_group_16chans);
254		if (ret)
255			goto out_err_create_16chans;
256	}
257
258	if (!mc13783_adc_use_touchscreen(pdev)) {
259		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
260		if (ret)
261			goto out_err_create_ts;
262	}
263
264	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
265	if (IS_ERR(priv->hwmon_dev)) {
266		ret = PTR_ERR(priv->hwmon_dev);
267		dev_err(&pdev->dev,
268				"hwmon_device_register failed with %d.\n", ret);
269		goto out_err_register;
270	}
271
 
272	return 0;
273
274out_err_register:
275
276	if (!mc13783_adc_use_touchscreen(pdev))
277		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
278out_err_create_ts:
 
 
 
279
280	if (id->driver_data & MC13783_ADC_16CHANS)
281		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
282out_err_create_16chans:
283
284	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
285	return ret;
286}
287
288static void mc13783_adc_remove(struct platform_device *pdev)
289{
290	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
291	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
292
293	hwmon_device_unregister(priv->hwmon_dev);
294
295	if (!mc13783_adc_use_touchscreen(pdev))
296		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
297
298	if (driver_data & MC13783_ADC_16CHANS)
299		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
300
301	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 
 
 
302}
303
304static const struct platform_device_id mc13783_adc_idtable[] = {
305	{
306		.name = "mc13783-adc",
307		.driver_data = MC13783_ADC_16CHANS,
308	}, {
309		.name = "mc13892-adc",
310		.driver_data = MC13783_ADC_BPDIV2,
311	}, {
312		/* sentinel */
313	}
314};
315MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
316
317static struct platform_driver mc13783_adc_driver = {
318	.remove		= mc13783_adc_remove,
319	.driver		= {
320		.name	= DRIVER_NAME,
 
321	},
322	.id_table	= mc13783_adc_idtable,
323};
324
325module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
 
 
 
 
 
 
 
 
 
 
 
326
327MODULE_DESCRIPTION("MC13783 ADC driver");
328MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
329MODULE_LICENSE("GPL");