193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu/*
20c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu *
493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * Copyright (C) 2009 Sascha Hauer, Pengutronix
693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu *
793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * This program is free software; you can redistribute it and/or
893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * modify it under the terms of the GNU General Public License
993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * as published by the Free Software Foundation; either version 2
1093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * of the License, or (at your option) any later version.
1193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * This program is distributed in the hope that it will be useful,
1293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * but WITHOUT ANY WARRANTY; without even the implied warranty of
1393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * GNU General Public License for more details.
1593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu *
1693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * You should have received a copy of the GNU General Public License along with
1793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * this program; if not, write to the Free Software Foundation, Inc., 51
1893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu */
2093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
210c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig#include <linux/mfd/mc13xxx.h>
2293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/platform_device.h>
2393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/hwmon-sysfs.h>
2493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/kernel.h>
2593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/module.h>
2693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/hwmon.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/init.h>
2993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu#include <linux/err.h>
3093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
310c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig#define DRIVER_NAME	"mc13783-adc"
320c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
330c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig/* platform device id driver data */
340c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig#define MC13783_ADC_16CHANS	1
350c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig#define MC13783_ADC_BPDIV2	2
3693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
3793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustruct mc13783_adc_priv {
38613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König	struct mc13xxx *mc13xxx;
3993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	struct device *hwmon_dev;
400c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	char name[10];
4193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
4293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
4393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
4493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu			      *devattr, char *buf)
4593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
460c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
470c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
480c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	return sprintf(buf, "%s\n", priv->name);
4993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
5093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
5193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic int mc13783_adc_read(struct device *dev,
5293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		struct device_attribute *devattr, unsigned int *val)
5393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
540c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
5593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
5693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	unsigned int channel = attr->index;
5793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	unsigned int sample[4];
5893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	int ret;
5993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
60613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
61613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König			MC13XXX_ADC_MODE_MULT_CHAN,
621039d762d03b573de4d46603c8583051c6d79094Michael Thalmeier			channel, 0, 0, sample);
6393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (ret)
6493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		return ret;
6593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
6693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	channel &= 0x7;
6793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
6893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	*val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
6993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
7093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return 0;
7193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
7293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
7393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic ssize_t mc13783_adc_read_bp(struct device *dev,
7493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		struct device_attribute *devattr, char *buf)
7593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
7693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	unsigned val;
770c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	struct platform_device *pdev = to_platform_device(dev);
780c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
7993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	int ret = mc13783_adc_read(dev, devattr, &val);
8093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
8193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (ret)
8293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		return ret;
8393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
840c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	if (driver_data & MC13783_ADC_BPDIV2)
850c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		val = DIV_ROUND_CLOSEST(val * 9, 2);
860c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	else
870c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		/*
880c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		 * BP (channel 2) reports with offset 2.4V to the actual value
890c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
900c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		 */
910c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
9293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
9393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return sprintf(buf, "%u\n", val);
9493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
9593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
9693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic ssize_t mc13783_adc_read_gp(struct device *dev,
9793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		struct device_attribute *devattr, char *buf)
9893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
9993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	unsigned val;
10093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	int ret = mc13783_adc_read(dev, devattr, &val);
10193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
10293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (ret)
10393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		return ret;
10493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
10593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	/*
10693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	 * input range is [0, 2.3V], val has 10 bits, so each bit
10793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	 * is worth 9/4 mV.
10893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	 */
10993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	val = DIV_ROUND_CLOSEST(val * 9, 4);
11093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
11193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return sprintf(buf, "%u\n", val);
11293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
11393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
11493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
11593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
11693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
11793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
11893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
11993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
12093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
12193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
12293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
12393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
12493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
12593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
12693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
12793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
1280c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigstatic struct attribute *mc13783_attr_base[] = {
12993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&dev_attr_name.attr,
13093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in2_input.dev_attr.attr,
13193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in5_input.dev_attr.attr,
13293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in6_input.dev_attr.attr,
13393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in7_input.dev_attr.attr,
1340c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	NULL
1350c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig};
1360c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
1370c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigstatic const struct attribute_group mc13783_group_base = {
1380c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	.attrs = mc13783_attr_base,
1390c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig};
1400c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
1410c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
1420c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigstatic struct attribute *mc13783_attr_16chans[] = {
14393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in8_input.dev_attr.attr,
14493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in9_input.dev_attr.attr,
14593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in10_input.dev_attr.attr,
14693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in11_input.dev_attr.attr,
14793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	NULL
14893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
14993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
1500c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigstatic const struct attribute_group mc13783_group_16chans = {
1510c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	.attrs = mc13783_attr_16chans,
15293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
15393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
15493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu/* last four channels may be occupied by the touchscreen */
15593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic struct attribute *mc13783_attr_ts[] = {
15693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in12_input.dev_attr.attr,
15793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in13_input.dev_attr.attr,
15893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in14_input.dev_attr.attr,
15993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	&sensor_dev_attr_in15_input.dev_attr.attr,
16093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	NULL
16193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
16293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
16393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic const struct attribute_group mc13783_group_ts = {
16493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	.attrs = mc13783_attr_ts,
16593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
16693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
167eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-Königstatic int mc13783_adc_use_touchscreen(struct platform_device *pdev)
168eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König{
169eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
170613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König	unsigned flags = mc13xxx_get_flags(priv->mc13xxx);
171eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König
172613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König	return flags & MC13XXX_USE_TOUCHSCREEN;
173eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König}
174eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König
17593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic int __init mc13783_adc_probe(struct platform_device *pdev)
17693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
17793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	struct mc13783_adc_priv *priv;
17893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	int ret;
1790c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	const struct platform_device_id *id = platform_get_device_id(pdev);
1800c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	char *dash;
18193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
18293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
18393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (!priv)
18493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		return -ENOMEM;
18593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
186613c27ab98dd2242bd9d62b0ab00b440bdf3259fUwe Kleine-König	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
1870c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
1880c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	dash = strchr(priv->name, '-');
1890c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	if (dash)
1900c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		*dash = '\0';
19193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
19293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	platform_set_drvdata(pdev, priv);
19393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
19493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	/* Register sysfs hooks */
1950c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
19693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (ret)
1970c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		goto out_err_create_base;
1980c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
1990c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	if (id->driver_data & MC13783_ADC_16CHANS) {
2000c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		ret = sysfs_create_group(&pdev->dev.kobj,
2010c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig				&mc13783_group_16chans);
2020c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		if (ret)
2030c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig			goto out_err_create_16chans;
2040c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	}
20593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
206eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König	if (!mc13783_adc_use_touchscreen(pdev)) {
20793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
20893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		if (ret)
2090c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig			goto out_err_create_ts;
210eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König	}
21193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
21293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
21393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	if (IS_ERR(priv->hwmon_dev)) {
21493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		ret = PTR_ERR(priv->hwmon_dev);
21593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		dev_err(&pdev->dev,
21693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu				"hwmon_device_register failed with %d.\n", ret);
21793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		goto out_err_register;
21893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	}
21993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
22093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return 0;
22193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
22293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fuout_err_register:
22393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
224eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König	if (!mc13783_adc_use_touchscreen(pdev))
22593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
2260c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigout_err_create_ts:
22793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
2280c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	if (id->driver_data & MC13783_ADC_16CHANS)
2290c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
2300c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigout_err_create_16chans:
2310c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
2320c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
2330c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigout_err_create_base:
23493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
23593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	platform_set_drvdata(pdev, NULL);
23693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	kfree(priv);
23793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
23893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return ret;
23993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
24093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
24193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic int __devexit mc13783_adc_remove(struct platform_device *pdev)
24293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
24393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
2440c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
24593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
24693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	hwmon_device_unregister(priv->hwmon_dev);
24793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
248eaf06ee22594ac90cdd0279483b06c1db1667e01Uwe Kleine-König	if (!mc13783_adc_use_touchscreen(pdev))
24993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
25093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
2510c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	if (driver_data & MC13783_ADC_16CHANS)
2520c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
2530c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
2540c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
25593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
25693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	platform_set_drvdata(pdev, NULL);
25793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	kfree(priv);
25893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
25993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return 0;
26093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
26193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
2620c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenigstatic const struct platform_device_id mc13783_adc_idtable[] = {
2630c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	{
2640c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		.name = "mc13783-adc",
2650c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		.driver_data = MC13783_ADC_16CHANS,
2660c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	}, {
2670c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		.name = "mc13892-adc",
2680c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		.driver_data = MC13783_ADC_BPDIV2,
2690c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	}, {
2700c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		/* sentinel */
2710c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	}
2720c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig};
2730c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-KoenigMODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
2740c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig
27593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic struct platform_driver mc13783_adc_driver = {
276cb88200490d723048994753ed59dc0abddc51e77Frans Meulenbroeks	.remove		= __devexit_p(mc13783_adc_remove),
27793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	.driver		= {
27893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu		.owner	= THIS_MODULE,
2790c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig		.name	= DRIVER_NAME,
28093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	},
2810c2732152a5813a870d0b96f0844f4dfe1436519Uwe Kleine-Koenig	.id_table	= mc13783_adc_idtable,
28293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu};
28393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
28493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic int __init mc13783_adc_init(void)
28593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
28693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
28793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
28893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
28993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fustatic void __exit mc13783_adc_exit(void)
29093ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu{
29193ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu	platform_driver_unregister(&mc13783_adc_driver);
29293ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu}
29393ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
29493ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fumodule_init(mc13783_adc_init);
29593ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fumodule_exit(mc13783_adc_exit);
29693ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao Fu
29793ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao FuMODULE_DESCRIPTION("MC13783 ADC driver");
29893ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao FuMODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
29993ee0a75f6e4b2c7ec20fd8f4ace87f88ba785b9Luotao FuMODULE_LICENSE("GPL");
300