1f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
2f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
3f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * TWL4030 MADC module driver-This driver monitors the real time
4f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * conversion of analog signals like battery temperature,
5f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * battery type, battery level etc.
6f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
7f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
8f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * J Keerthy <j-keerthy@ti.com>
9f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
10f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Based on twl4030-madc.c
11f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Copyright (C) 2008 Nokia Corporation
12f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Mikko Ylinen <mikko.k.ylinen@nokia.com>
13f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
14f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Amit Kucheria <amit.kucheria@canonical.com>
15f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
16f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * This program is free software; you can redistribute it and/or
17f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * modify it under the terms of the GNU General Public License
18f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * version 2 as published by the Free Software Foundation.
19f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
20f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * This program is distributed in the hope that it will be useful, but
21f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * WITHOUT ANY WARRANTY; without even the implied warranty of
22f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * General Public License for more details.
24f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
25f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * You should have received a copy of the GNU General Public License
26f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * along with this program; if not, write to the Free Software
27f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * 02110-1301 USA
29f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy *
30f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
31f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
32f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/init.h>
33f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/device.h>
34f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/interrupt.h>
35f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/kernel.h>
36f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/delay.h>
37f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/platform_device.h>
38f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/slab.h>
39f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/i2c/twl.h>
40f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/i2c/twl4030-madc.h>
41f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/module.h>
42f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/stddef.h>
43f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/mutex.h>
44f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/bitops.h>
45f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/jiffies.h>
46f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/types.h>
47f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/gfp.h>
48f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy#include <linux/err.h>
49f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
50f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
51f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * struct twl4030_madc_data - a container for madc info
52f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @dev - pointer to device structure for madc
53f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @lock - mutex protecting this data structure
54f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @requests - Array of request struct corresponding to SW1, SW2 and RT
55f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @imr - Interrupt mask register of MADC
56f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @isr - Interrupt status register of MADC
57f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
58f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystruct twl4030_madc_data {
59f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct device *dev;
60f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct mutex lock;	/* mutex protecting this data structure */
61f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
62f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int imr;
63f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int isr;
64f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
65f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
66f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic struct twl4030_madc_data *twl4030_madc;
67f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
68f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystruct twl4030_prescale_divider_ratios {
69f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	s16 numerator;
70f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	s16 denominator;
71f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
72f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
73f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic const struct twl4030_prescale_divider_ratios
74f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthytwl4030_divider_ratios[16] = {
75f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 1},		/* CHANNEL 0 No Prescaler */
76f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 1},		/* CHANNEL 1 No Prescaler */
77f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 2 */
78f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 3 */
79f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 4 */
80f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 5 */
81f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 6 */
82f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{6, 10},	/* CHANNEL 7 */
83f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{3, 14},	/* CHANNEL 8 */
84f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 3},		/* CHANNEL 9 */
85f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 1},		/* CHANNEL 10 No Prescaler */
86f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{15, 100},	/* CHANNEL 11 */
87f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 4},		/* CHANNEL 12 */
88f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 1},		/* CHANNEL 13 Reserved channels */
89f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{1, 1},		/* CHANNEL 14 Reseved channels */
90f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	{5, 11},	/* CHANNEL 15 */
91f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
92f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
93f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
94f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
95f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Conversion table from -3 to 55 degree Celcius
96f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
97f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int therm_tbl[] = {
98f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy30800,	29500,	28300,	27100,
99f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy26000,	24900,	23900,	22900,	22000,	21100,	20300,	19400,	18700,	17900,
100f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy17200,	16500,	15900,	15300,	14700,	14100,	13600,	13100,	12600,	12100,
101f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy11600,	11200,	10800,	10400,	10000,	9630,	9280,	8950,	8620,	8310,
102f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy8020,	7730,	7460,	7200,	6950,	6710,	6470,	6250,	6040,	5830,
103f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy5640,	5450,	5260,	5090,	4920,	4760,	4600,	4450,	4310,	4170,
104f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy4040,	3910,	3790,	3670,	3550
105f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
106f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
107f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
108f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Structure containing the registers
109f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * of different conversion methods supported by MADC.
110f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Hardware or RT real time conversion request initiated by external host
111f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * processor for RT Signal conversions.
112f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * External host processors can also request for non RT conversions
113f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * SW1 and SW2 software conversions also called asynchronous or GPC request.
114f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
115f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic
116f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyconst struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
117f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	[TWL4030_MADC_RT] = {
118f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			     .sel = TWL4030_MADC_RTSELECT_LSB,
119f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			     .avg = TWL4030_MADC_RTAVERAGE_LSB,
120f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			     .rbase = TWL4030_MADC_RTCH0_LSB,
121f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			     },
122f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	[TWL4030_MADC_SW1] = {
123f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .sel = TWL4030_MADC_SW1SELECT_LSB,
124f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .avg = TWL4030_MADC_SW1AVERAGE_LSB,
125f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .rbase = TWL4030_MADC_GPCH0_LSB,
126f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .ctrl = TWL4030_MADC_CTRL_SW1,
127f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      },
128f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	[TWL4030_MADC_SW2] = {
129f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .sel = TWL4030_MADC_SW2SELECT_LSB,
130f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .avg = TWL4030_MADC_SW2AVERAGE_LSB,
131f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .rbase = TWL4030_MADC_GPCH0_LSB,
132f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      .ctrl = TWL4030_MADC_CTRL_SW2,
133f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      },
134f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
135f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
136f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
137f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function to read a particular channel value.
138f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to struct twl4030_madc_data
139f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @reg - lsb of ADC Channel
140f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * If the i2c read fails it returns an error else returns 0.
141f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
142f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
143f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
144f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 msb, lsb;
145f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
146f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/*
147f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * For each ADC channel, we have MSB and LSB register pair. MSB address
148f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * is always LSB address+1. reg parameter is the address of LSB register
149f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 */
150f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
151f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
152f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read MSB register 0x%X\n",
153f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			reg + 1);
154f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
155f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
156f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
157f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
158f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
159f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
160f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
161f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
162f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return (int)(((msb << 8) | lsb) >> 6);
163f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
164f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
165f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
166f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Return battery temperature
167f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Or < 0 on failure.
168f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
169f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030battery_temperature(int raw_volt)
170f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
171f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 val;
172f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int temp, curr, volt, res, ret;
173f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
174f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
175f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Getting and calculating the supply current in micro ampers */
176f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
177f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		REG_BCICTL2);
178f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0)
179f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
180f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
181f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Getting and calculating the thermistor resistance in ohms */
182f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	res = volt * 1000 / curr;
183f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* calculating temperature */
184f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	for (temp = 58; temp >= 0; temp--) {
185f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		int actual = therm_tbl[temp];
186f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
187f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if ((actual - res) >= 0)
188f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			break;
189f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
190f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
191f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return temp + 1;
192f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
193f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
194f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030battery_current(int raw_volt)
195f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
196f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
197f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 val;
198f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
199f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
200f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		TWL4030_BCI_BCICTL1);
201f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret)
202f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
203f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
204f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
205f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	else /* slope of 0.88 mV/mA */
206f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
207f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
208f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
209f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function to read channel values
210f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
211f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @reg_base - Base address of the first channel
212f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @Channels - 16 bit bitmap. If the bit is set, channel value is read
213f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @buf - The channel values are stored here. if read fails error
214f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * value is stored
215f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Returns the number of successfully read channels.
216f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
217f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
218f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				      u8 reg_base, unsigned
219f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy						long channels, int *buf)
220f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
221f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int count = 0, count_req = 0, i;
222f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 reg;
223f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
224f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
225f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		reg = reg_base + 2 * i;
226f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		buf[i] = twl4030_madc_channel_raw_read(madc, reg);
227f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (buf[i] < 0) {
228f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_err(madc->dev,
229f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				"Unable to read register 0x%X\n", reg);
230f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			count_req++;
231f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			continue;
232f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
233f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		switch (i) {
234f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		case 10:
235f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			buf[i] = twl4030battery_current(buf[i]);
236f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			if (buf[i] < 0) {
237f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				dev_err(madc->dev, "err reading current\n");
238f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				count_req++;
239f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			} else {
240f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				count++;
241f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				buf[i] = buf[i] - 750;
242f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			}
243f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			break;
244f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		case 1:
245f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			buf[i] = twl4030battery_temperature(buf[i]);
246f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			if (buf[i] < 0) {
247f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				dev_err(madc->dev, "err reading temperature\n");
248f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				count_req++;
249f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			} else {
250f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				buf[i] -= 3;
251f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				count++;
252f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			}
253f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			break;
254f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		default:
255f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			count++;
256f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			/* Analog Input (V) = conv_result * step_size / R
257f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 * conv_result = decimal value of 10-bit conversion
258f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 *		 result
259f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 * step size = 1.5 / (2 ^ 10 -1)
260f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 * R = Prescaler ratio for input channels.
261f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 * Result given in mV hence multiplied by 1000.
262f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			 */
263f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			buf[i] = (buf[i] * 3 * 1000 *
264f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				 twl4030_divider_ratios[i].denominator)
265f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				/ (2 * 1023 *
266f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				twl4030_divider_ratios[i].numerator);
267f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
268f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
269f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (count_req)
270f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "%d channel conversion failed\n", count_req);
271f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
272f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return count;
273f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
274f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
275f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
276f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Enables irq.
277f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
278f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @id - irq number to be enabled
279f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
280f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * corresponding to RT, SW1, SW2 conversion requests.
281f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * If the i2c read fails it returns an error else returns 0.
282f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
283f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
284f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
285f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 val;
286f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
287f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
288f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
289f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
290f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read imr register 0x%X\n",
291f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			madc->imr);
292f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
293f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
294f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	val &= ~(1 << id);
295f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
296f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
297f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev,
298f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			"unable to write imr register 0x%X\n", madc->imr);
299f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
300f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
301f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
302f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
303f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
304f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
305f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
306f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
307f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Disables irq.
308f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
309f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @id - irq number to be disabled
310f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
311f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * corresponding to RT, SW1, SW2 conversion requests.
312f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Returns error if i2c read/write fails.
313f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
314f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
315f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
316f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 val;
317f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
318f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
319f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
320f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
321f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read imr register 0x%X\n",
322f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			madc->imr);
323f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
324f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
325f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	val |= (1 << id);
326f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
327f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
328f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev,
329f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			"unable to write imr register 0x%X\n", madc->imr);
330f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
331f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
332f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
333f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
334f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
335f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
336f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
337f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
338f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_data *madc = _madc;
339f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	const struct twl4030_madc_conversion_method *method;
340f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 isr_val, imr_val;
341f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int i, len, ret;
342f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_request *r;
343f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
344f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_lock(&madc->lock);
345f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
346f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
347f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read isr register 0x%X\n",
348f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			madc->isr);
349f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_i2c;
350f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
351f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
352f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
353f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read imr register 0x%X\n",
354f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			madc->imr);
355f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_i2c;
356f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
357f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	isr_val &= ~imr_val;
358f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
359f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (!(isr_val & (1 << i)))
360f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			continue;
361f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl4030_madc_disable_irq(madc, i);
362f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret < 0)
363f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
364f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		madc->requests[i].result_pending = 1;
365f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
366f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
367f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r = &madc->requests[i];
368f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* No pending results for this method, move to next one */
369f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (!r->result_pending)
370f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			continue;
371f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		method = &twl4030_conversion_methods[r->method];
372f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Read results */
373f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		len = twl4030_madc_read_channels(madc, method->rbase,
374f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy						 r->channels, r->rbuf);
375f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Return results to caller */
376f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (r->func_cb != NULL) {
377f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			r->func_cb(len, r->channels, r->rbuf);
378f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			r->func_cb = NULL;
379f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
380f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Free request */
381f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r->result_pending = 0;
382f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r->active = 0;
383f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
384f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_unlock(&madc->lock);
385f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
386f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return IRQ_HANDLED;
387f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
388f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyerr_i2c:
389f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/*
390f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * In case of error check whichever request is active
391f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * and service the same.
392f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 */
393f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
394f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r = &madc->requests[i];
395f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (r->active == 0)
396f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			continue;
397f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		method = &twl4030_conversion_methods[r->method];
398f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Read results */
399f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		len = twl4030_madc_read_channels(madc, method->rbase,
400f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy						 r->channels, r->rbuf);
401f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Return results to caller */
402f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (r->func_cb != NULL) {
403f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			r->func_cb(len, r->channels, r->rbuf);
404f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			r->func_cb = NULL;
405f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
406f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		/* Free request */
407f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r->result_pending = 0;
408f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		r->active = 0;
409f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
410f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_unlock(&madc->lock);
411f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
412f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return IRQ_HANDLED;
413f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
414f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
415f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
416f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				struct twl4030_madc_request *req)
417f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
418f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_request *p;
419f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
420f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
421f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	p = &madc->requests[req->method];
422f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	memcpy(p, req, sizeof(*req));
423f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_enable_irq(madc, req->method);
424f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0) {
425f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "enable irq failed!!\n");
426f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
427f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
428f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
429f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
430f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
431f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
432f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
433f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function which enables the madc conversion
434f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * by writing to the control register.
435f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
436f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
437f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * corresponding to RT SW1 or SW2 conversion methods.
438f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Returns 0 if succeeds else a negative error value
439f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
440f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
441f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy					 int conv_method)
442f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
443f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	const struct twl4030_madc_conversion_method *method;
444f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret = 0;
445f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	method = &twl4030_conversion_methods[conv_method];
446f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	switch (conv_method) {
447f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	case TWL4030_MADC_SW1:
448f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	case TWL4030_MADC_SW2:
449f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
450f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				       TWL4030_MADC_SW_START, method->ctrl);
451f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret) {
452f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_err(madc->dev,
453f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				"unable to write ctrl register 0x%X\n",
454f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				method->ctrl);
455f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			return ret;
456f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
457f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		break;
458f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	default:
459f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		break;
460f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
461f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
462f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
463f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
464f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
465f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
466f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function that waits for conversion to be ready
467f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
468f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @timeout_ms - timeout value in milliseconds
469f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @status_reg - ctrl register
470f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * returns 0 if succeeds else a negative error value
471f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
472f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
473f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy					      unsigned int timeout_ms,
474f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy					      u8 status_reg)
475f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
476f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	unsigned long timeout;
477f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
478f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
479f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	timeout = jiffies + msecs_to_jiffies(timeout_ms);
480f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	do {
481f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		u8 reg;
482f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
483f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
484f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret) {
485f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_err(madc->dev,
486f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				"unable to read status register 0x%X\n",
487f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				status_reg);
488f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			return ret;
489f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
490f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
491f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			return 0;
492f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		usleep_range(500, 2000);
493f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	} while (!time_after(jiffies, timeout));
494f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	dev_err(madc->dev, "conversion timeout!\n");
495f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
496f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return -EAGAIN;
497f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
498f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
499f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
500f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * An exported function which can be called from other kernel drivers.
501f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @req twl4030_madc_request structure
502f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * req->rbuf will be filled with read values of channels based on the
503f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * channel index. If a particular channel reading fails there will
504f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * be a negative error value in the corresponding array element.
505f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * returns 0 if succeeds else error value
506f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
507f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyint twl4030_madc_conversion(struct twl4030_madc_request *req)
508f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
509f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	const struct twl4030_madc_conversion_method *method;
510f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 ch_msb, ch_lsb;
511f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
512f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
513d0e84caeb4cd535923884735906e5730329505b4Kyle Manna	if (!req || !twl4030_madc)
514f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return -EINVAL;
515d0e84caeb4cd535923884735906e5730329505b4Kyle Manna
516f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_lock(&twl4030_madc->lock);
517f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
518f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = -EINVAL;
519f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
520f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
521f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Do we have a conversion request ongoing */
522f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (twl4030_madc->requests[req->method].active) {
523f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = -EBUSY;
524f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
525f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
526f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ch_msb = (req->channels >> 8) & 0xff;
527f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ch_lsb = req->channels & 0xff;
528f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	method = &twl4030_conversion_methods[req->method];
529f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Select channels to be converted */
530f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
531f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
532f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(twl4030_madc->dev,
533f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			"unable to write sel register 0x%X\n", method->sel + 1);
534e178ccb33569da17dc897a08a3865441b813bdfbSanjeev Premi		goto out;
535f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
536f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
537f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
538f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(twl4030_madc->dev,
539f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			"unable to write sel register 0x%X\n", method->sel + 1);
540e178ccb33569da17dc897a08a3865441b813bdfbSanjeev Premi		goto out;
541f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
542f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Select averaging for all channels if do_avg is set */
543f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (req->do_avg) {
544f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
545f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				       ch_msb, method->avg + 1);
546f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret) {
547f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_err(twl4030_madc->dev,
548f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				"unable to write avg register 0x%X\n",
549f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				method->avg + 1);
550e178ccb33569da17dc897a08a3865441b813bdfbSanjeev Premi			goto out;
551f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
552f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
553f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				       ch_lsb, method->avg);
554f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret) {
555f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			dev_err(twl4030_madc->dev,
556f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				"unable to write sel reg 0x%X\n",
557f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				method->sel + 1);
558e178ccb33569da17dc897a08a3865441b813bdfbSanjeev Premi			goto out;
559f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		}
560f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
561f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
562f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl4030_madc_set_irq(twl4030_madc, req);
563f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret < 0)
564f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			goto out;
565f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
566f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		if (ret < 0)
567f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			goto out;
568f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		twl4030_madc->requests[req->method].active = 1;
569f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = 0;
570f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
571f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
572f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* With RT method we should not be here anymore */
573f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (req->method == TWL4030_MADC_RT) {
574f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		ret = -EINVAL;
575f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
576f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
577f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
578f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0)
579f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
580f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc->requests[req->method].active = 1;
581f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/* Wait until conversion is ready (ctrl register returns EOC) */
582f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
583f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
584f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		twl4030_madc->requests[req->method].active = 0;
585f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto out;
586f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
587f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
588f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy					 req->channels, req->rbuf);
589f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc->requests[req->method].active = 0;
590f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
591f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyout:
592f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_unlock(&twl4030_madc->lock);
593f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
594f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return ret;
595f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
596f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyEXPORT_SYMBOL_GPL(twl4030_madc_conversion);
597f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
598f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
599f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Return channel value
600f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Or < 0 on failure.
601f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
602f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyint twl4030_get_madc_conversion(int channel_no)
603f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
604f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_request req;
605f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int temp = 0;
606f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
607f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
608f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	req.channels = (1 << channel_no);
609f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	req.method = TWL4030_MADC_SW2;
610f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	req.active = 0;
611f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	req.func_cb = NULL;
612f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_conversion(&req);
613f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0)
614f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
615f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (req.rbuf[channel_no] > 0)
616f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		temp = req.rbuf[channel_no];
617f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
618f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return temp;
619f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
620f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyEXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
621f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
622f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
623f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function to enable or disable bias current for
624f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * main battery type reading or temperature sensing
625f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
626f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @chan - can be one of the two values
627f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
628f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
629f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * sensing
630f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @on - enable or disable chan.
631f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
632f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
633f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy					      int chan, int on)
634f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
635f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
636f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 regval;
637f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
638f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
639f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      &regval, TWL4030_BCI_BCICTL1);
640f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
641f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
642f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_BCI_BCICTL1);
643f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
644f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
645f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (on)
646f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
647f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	else
648f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
649f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
650f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			       regval, TWL4030_BCI_BCICTL1);
651f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
652f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
653f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_BCI_BCICTL1);
654f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
655f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
656f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
657f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
658f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
659f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
660f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
661f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Function that sets MADC software power on bit to enable MADC
662f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @madc - pointer to twl4030_madc_data struct
663f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * @on - Enable or disable MADC software powen on bit.
664f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * returns error if i2c read/write fails else 0
665f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
666f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
667f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
668f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 regval;
669f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
670f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
671f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
672f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      &regval, TWL4030_MADC_CTRL1);
673f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
674f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
675f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_MADC_CTRL1);
676f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
677f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
678f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (on)
679f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		regval |= TWL4030_MADC_MADCON;
680f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	else
681f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		regval &= ~TWL4030_MADC_MADCON;
682f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
683f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
684f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
685f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_MADC_CTRL1);
686f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return ret;
687f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
688f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
689f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
690f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
691f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
692f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy/*
693f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy * Initialize MADC and request for threaded irq
694f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy */
695f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int __devinit twl4030_madc_probe(struct platform_device *pdev)
696f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
697f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_data *madc;
698f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
699f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	int ret;
700f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	u8 regval;
701f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
702f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (!pdata) {
703f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(&pdev->dev, "platform_data not available\n");
704f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return -EINVAL;
705f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
706f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	madc = kzalloc(sizeof(*madc), GFP_KERNEL);
707f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (!madc)
708f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		return -ENOMEM;
709f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
71066cc5b8e50af87b0bbd0f179d76d2826f4549c13Kyle Manna	madc->dev = &pdev->dev;
71166cc5b8e50af87b0bbd0f179d76d2826f4549c13Kyle Manna
712f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	/*
713f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * Phoenix provides 2 interrupt lines. The first one is connected to
714f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * the OMAP. The other one can be connected to the other processor such
715f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 * as modem. Hence two separate ISR and IMR registers.
716f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	 */
717f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	madc->imr = (pdata->irq_line == 1) ?
718f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	    TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
719f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	madc->isr = (pdata->irq_line == 1) ?
720f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	    TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
721f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_set_power(madc, 1);
722f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0)
723f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_power;
724f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl4030_madc_set_current_generator(madc, 0, 1);
725f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret < 0)
726f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_current_generator;
727f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
728f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
729f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			      &regval, TWL4030_BCI_BCICTL1);
730f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
731f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
732f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_BCI_BCICTL1);
733f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_i2c;
734f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
735f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	regval |= TWL4030_BCI_MESBAT;
736f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
737f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			       regval, TWL4030_BCI_BCICTL1);
738f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
739f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
740f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy			TWL4030_BCI_BCICTL1);
741f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_i2c;
742f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
7433d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna
7443d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	/* Check that MADC clock is on */
7453d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
7463d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	if (ret) {
7473d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
7483d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna				TWL4030_REG_GPBR1);
7493d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		goto err_i2c;
7503d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	}
7513d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna
7523d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	/* If MADC clk is not on, turn it on */
7533d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
7543d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		dev_info(&pdev->dev, "clk disabled, enabling\n");
7553d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
7563d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
7573d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna				       TWL4030_REG_GPBR1);
7583d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		if (ret) {
7593d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna			dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
7603d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna					TWL4030_REG_GPBR1);
7613d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna			goto err_i2c;
7623d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna		}
7633d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna	}
7643d6271f92e98094584fd1e609a9969cd33e61122Kyle Manna
765f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	platform_set_drvdata(pdev, madc);
766f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	mutex_init(&madc->lock);
767f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
768f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				   twl4030_madc_threaded_irq_handler,
769f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy				   IRQF_TRIGGER_RISING, "twl4030_madc", madc);
770f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	if (ret) {
771f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		dev_dbg(&pdev->dev, "could not request irq\n");
772f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		goto err_irq;
773f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	}
774f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc = madc;
775f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
776f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyerr_irq:
777f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	platform_set_drvdata(pdev, NULL);
778f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyerr_i2c:
779f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc_set_current_generator(madc, 0, 0);
780f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyerr_current_generator:
781f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc_set_power(madc, 0);
782f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyerr_power:
783f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	kfree(madc);
784f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
785f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return ret;
786f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
787f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
788f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic int __devexit twl4030_madc_remove(struct platform_device *pdev)
789f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy{
790f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
791f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
792f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	free_irq(platform_get_irq(pdev, 0), madc);
793f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	platform_set_drvdata(pdev, NULL);
794f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc_set_current_generator(madc, 0, 0);
795f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	twl4030_madc_set_power(madc, 0);
796f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	kfree(madc);
797f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
798f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	return 0;
799f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy}
800f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
801f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthystatic struct platform_driver twl4030_madc_driver = {
802f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	.probe = twl4030_madc_probe,
803f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	.remove = __exit_p(twl4030_madc_remove),
804f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy	.driver = {
805f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		   .name = "twl4030_madc",
806f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		   .owner = THIS_MODULE,
807f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy		   },
808f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy};
809f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
81065349d60d27e850c94544567c91ab1be3e4c0777Mark Brownmodule_platform_driver(twl4030_madc_driver);
811f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthy
812f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyMODULE_DESCRIPTION("TWL4030 ADC driver");
813f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyMODULE_LICENSE("GPL");
814f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668ebKeerthyMODULE_AUTHOR("J Keerthy");
8150ea3e83bd8d198f2a18e0066542f8670b2883890Axel LinMODULE_ALIAS("platform:twl4030_madc");
816