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, ®, 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 ®val, 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 ®val, 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 ®val, 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, ®val, 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