/* * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* IADC register and bit definition */ #define IADC_REVISION2 0x1 #define IADC_REVISION2_SUPPORTED_IADC 1 #define IADC_PERPH_TYPE 0x4 #define IADC_PERPH_TYPE_ADC 8 #define IADC_PERPH_SUBTYPE 0x5 #define IADC_PERPH_SUBTYPE_IADC 3 #define IADC_STATUS1 0x8 #define IADC_STATUS1_OP_MODE 4 #define IADC_STATUS1_REQ_STS BIT(1) #define IADC_STATUS1_EOC BIT(0) #define IADC_STATUS1_REQ_STS_EOC_MASK 0x3 #define IADC_MODE_CTL 0x40 #define IADC_OP_MODE_SHIFT 3 #define IADC_OP_MODE_NORMAL 0 #define IADC_TRIM_EN BIT(0) #define IADC_EN_CTL1 0x46 #define IADC_EN_CTL1_SET BIT(7) #define IADC_CH_SEL_CTL 0x48 #define IADC_DIG_PARAM 0x50 #define IADC_DIG_DEC_RATIO_SEL_SHIFT 2 #define IADC_HW_SETTLE_DELAY 0x51 #define IADC_CONV_REQ 0x52 #define IADC_CONV_REQ_SET BIT(7) #define IADC_FAST_AVG_CTL 0x5a #define IADC_FAST_AVG_EN 0x5b #define IADC_FAST_AVG_EN_SET BIT(7) #define IADC_PERH_RESET_CTL3 0xda #define IADC_FOLLOW_WARM_RB BIT(2) #define IADC_DATA 0x60 /* 16 bits */ #define IADC_SEC_ACCESS 0xd0 #define IADC_SEC_ACCESS_DATA 0xa5 #define IADC_NOMINAL_RSENSE 0xf4 #define IADC_NOMINAL_RSENSE_SIGN_MASK BIT(7) #define IADC_REF_GAIN_MICRO_VOLTS 17857 #define IADC_INT_RSENSE_DEVIATION 15625 /* nano Ohms per bit */ #define IADC_INT_RSENSE_IDEAL_VALUE 10000 /* micro Ohms */ #define IADC_INT_RSENSE_DEFAULT_VALUE 7800 /* micro Ohms */ #define IADC_INT_RSENSE_DEFAULT_GF 9000 /* micro Ohms */ #define IADC_INT_RSENSE_DEFAULT_SMIC 9700 /* micro Ohms */ #define IADC_CONV_TIME_MIN_US 2000 #define IADC_CONV_TIME_MAX_US 2100 #define IADC_DEF_PRESCALING 0 /* 1:1 */ #define IADC_DEF_DECIMATION 0 /* 512 */ #define IADC_DEF_HW_SETTLE_TIME 0 /* 0 us */ #define IADC_DEF_AVG_SAMPLES 0 /* 1 sample */ /* IADC channel list */ #define IADC_INT_RSENSE 0 #define IADC_EXT_RSENSE 1 #define IADC_GAIN_17P857MV 3 #define IADC_EXT_OFFSET_CSP_CSN 5 #define IADC_INT_OFFSET_CSP2_CSN2 6 /** * struct iadc_chip - IADC Current ADC device structure. * @regmap: regmap for register read/write. * @dev: This device pointer. * @base: base offset for the ADC peripheral. * @rsense: Values of the internal and external sense resister in micro Ohms. * @poll_eoc: Poll for end of conversion instead of waiting for IRQ. * @offset: Raw offset values for the internal and external channels. * @gain: Raw gain of the channels. * @lock: ADC lock for access to the peripheral. * @complete: ADC notification after end of conversion interrupt is received. */ struct iadc_chip { struct regmap *regmap; struct device *dev; u16 base; bool poll_eoc; u32 rsense[2]; u16 offset[2]; u16 gain; struct mutex lock; struct completion complete; }; static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data) { unsigned int val; int ret; ret = regmap_read(iadc->regmap, iadc->base + offset, &val); if (ret < 0) return ret; *data = val; return 0; } static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data) { return regmap_write(iadc->regmap, iadc->base + offset, data); } static int iadc_reset(struct iadc_chip *iadc) { u8 data; int ret; ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA); if (ret < 0) return ret; ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data); if (ret < 0) return ret; ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA); if (ret < 0) return ret; data |= IADC_FOLLOW_WARM_RB; return iadc_write(iadc, IADC_PERH_RESET_CTL3, data); } static int iadc_set_state(struct iadc_chip *iadc, bool state) { return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0); } static void iadc_status_show(struct iadc_chip *iadc) { u8 mode, sta1, chan, dig, en, req; int ret; ret = iadc_read(iadc, IADC_MODE_CTL, &mode); if (ret < 0) return; ret = iadc_read(iadc, IADC_DIG_PARAM, &dig); if (ret < 0) return; ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan); if (ret < 0) return; ret = iadc_read(iadc, IADC_CONV_REQ, &req); if (ret < 0) return; ret = iadc_read(iadc, IADC_STATUS1, &sta1); if (ret < 0) return; ret = iadc_read(iadc, IADC_EN_CTL1, &en); if (ret
resource_registry