blob: a4b3a829a0792e8845fcd3b0ab4f78412ae6b571 [file] [log] [blame]
Channagoud Kadabid091f702013-01-07 16:17:37 -08001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <bits.h>
30#include <debug.h>
31#include <reg.h>
32#include <spmi.h>
33#include <platform/timer.h>
34#include <pm8x41_adc.h>
35#include <pm8x41_hw.h>
36
37/*
38 * This is the predefined adc configuration values for the supported
39 * channels
40 */
41static struct adc_conf adc_data[] = {
42 CHAN_INIT(VADC_USR1_BASE, VADC_BAT_CHAN_ID, VADC_MODE_NORMAL, VADC_DECIM_RATIO_VAL, HW_SET_DELAY_100US, FAST_AVG_SAMP_1, CALIB_RATIO),
43 CHAN_INIT(VADC_USR1_BASE, VADC_BAT_VOL_CHAN_ID, VADC_MODE_NORMAL, VADC_DECIM_RATIO_VAL, HW_SET_DELAY_100US, FAST_AVG_SAMP_1, CALIB_ABS),
Jie Cheng182e5ed2013-07-16 18:24:37 +080044 CHAN_INIT(VADC_USR1_BASE, MPP_8_CHAN_ID, VADC_MODE_NORMAL, VADC_DECIM_RATIO_VAL, HW_SET_DELAY_100US, FAST_AVG_SAMP_1, CALIB_ABS),
Channagoud Kadabid091f702013-01-07 16:17:37 -080045};
46
47
48static struct adc_conf* get_channel_prop(uint16_t ch_num)
49{
50 struct adc_conf *chan_data = NULL;
51 uint8_t i;
52
53 for(i = 0; i < ARRAY_SIZE(adc_data) ; i++) {
54 chan_data = &adc_data[i];
55 if (chan_data->chan == ch_num)
56 break;
57 }
58
59 return chan_data;
60}
61
62static void adc_limit_result_range(uint16_t *result)
63{
64 if (*result < VADC_MIN_VAL)
65 *result = VADC_MIN_VAL;
66 else if(*result > VADC_MAX_VAL)
67 *result = VADC_MAX_VAL;
68}
69
70static void adc_read_conv_result(struct adc_conf *adc, uint16_t *result)
71{
72 uint8_t val = 0;
73
74 /* Read the MSB part */
75 val = REG_READ(adc->base + VADC_REG_DATA_MSB);
76 *result = val;
77
78 /* Read the LSB part */
79 val = REG_READ(adc->base + VADC_REG_DATA_LSB);
80 *result = ((*result) << 8) | val;
81
82 adc_limit_result_range(result);
83}
84
85static void adc_enable(struct adc_conf *adc, uint8_t enable)
86{
87 if (enable)
88 REG_WRITE((adc->base + VADC_EN_CTL), VADC_CTL_EN_BIT);
89 else
90 REG_WRITE((adc->base + VADC_EN_CTL), (uint8_t) (~VADC_CTL_EN_BIT));
91}
92
93static void adc_measure(struct adc_conf *adc, uint16_t *result)
94{
95 uint8_t status;
96
97 /* Request conversion */
98 REG_WRITE((adc->base + VADC_CONV_REQ), VADC_CON_REQ_BIT);
99
100 /* Poll for the conversion to complete */
101 do {
102 status = REG_READ(adc->base + VADC_STATUS);
103 status &= VADC_STATUS_MASK;
104 if (status == VADC_STATUS_EOC) {
105 dprintf(SPEW, "ADC conversion is complete\n");
106 break;
107 }
108 /* Wait for sometime before polling for the status again */
109 udelay(10);
110 } while(1);
111
112 /* Now read the conversion result */
113 adc_read_conv_result(adc, result);
114}
115
116/*
117 * This function configures adc & requests for conversion
118 */
119static uint16_t adc_configure(struct adc_conf *adc)
120{
121 uint8_t mode;
122 uint8_t adc_p;
123 uint16_t result;
124
125 /* Mode Selection */
126 mode = (adc->mode << VADC_MODE_BIT_NORMAL);
127 REG_WRITE((adc->base + VADC_MODE_CTRL), mode);
128
129 /* Select Channel */
130 REG_WRITE((adc->base + VADC_CHAN_SEL), adc->chan);
131
132 /* ADC digital param setup */
133 adc_p = (adc->adc_param << VADC_DECIM_RATIO_SEL);
134 REG_WRITE((adc->base + VADC_DIG_ADC_PARAM), adc_p);
135
136 /* hardware settling time */
137 REG_WRITE((adc->base + VADC_HW_SETTLE_TIME), adc->hw_set_time);
138
139 /* For normal mode set the fast avg */
140 REG_WRITE((adc->base + VADC_FAST_AVG), adc->fast_avg);
141
142 /* Enable Vadc */
143 adc_enable(adc, true);
144
145 /* Measure the result */
146 adc_measure(adc, &result);
147
148 /* Disable vadc */
149 adc_enable(adc, false);
150
151 return result;
152}
153
154static uint32_t vadc_calibrate(uint16_t result, uint8_t calib_type)
155{
156 struct adc_conf calib;
157 uint16_t calib1;
158 uint16_t calib2;
159 uint32_t calib_result = 0;
160 uint32_t mul;
161
162 if(calib_type == CALIB_ABS) {
163 /*
164 * Measure the calib data for 1.25 V ref
165 */
166 calib.base = VADC_USR1_BASE;
167 calib.chan = VREF_125_CHAN_ID;
168 calib.mode = VADC_MODE_NORMAL;
169 calib.adc_param = VADC_DECIM_RATIO_VAL;
170 calib.hw_set_time = 0x0;
171 calib.fast_avg = 0x0;
172
173 calib1 = adc_configure(&calib);
174
175 /*
176 * Measure the calib data for 0.625 V ref
177 */
178 calib.base = VADC_USR1_BASE;
179 calib.chan = VREF_625_CHAN_ID;
180 calib.mode = VADC_MODE_NORMAL;
181 calib.adc_param = VADC_DECIM_RATIO_VAL;
182 calib.hw_set_time = 0x0;
183 calib.fast_avg = 0x0;
184
185 calib2 = adc_configure(&calib);
186
187 mul = VREF_625_MV / (calib1 - calib2);
188 calib_result = (result - calib2) * mul;
189 calib_result += VREF_625_MV;
190 calib_result *= OFFSET_GAIN_DNOM;
191 calib_result /= OFFSET_GAIN_NUME;
192 } else if(calib_type == CALIB_RATIO) {
193 /*
194 * Measure the calib data for VDD_ADC ref
195 */
196 calib.base = VADC_USR1_BASE;
197 calib.chan = VDD_VADC_CHAN_ID;
198 calib.mode = VADC_MODE_NORMAL;
199 calib.adc_param = VADC_DECIM_RATIO_VAL;
200 calib.hw_set_time = 0;
201 calib.fast_avg = 0;
202
203 calib1 = adc_configure(&calib);
204
205 /*
206 * Measure the calib data for ADC_GND
207 */
208 calib.base = VADC_USR1_BASE;
209 calib.chan = GND_REF_CHAN_ID;
210 calib.mode = VADC_MODE_NORMAL;
211 calib.adc_param = VADC_DECIM_RATIO_VAL;
212 calib.hw_set_time = 0;
213 calib.fast_avg = 0;
214
215 calib2 = adc_configure(&calib);
216
217 mul = VREF_18_V / (calib1 - calib2);
218 calib_result = (result - calib2) * mul;
219 }
220
221 return calib_result;
222}
223
224/*
225 * This API takes channel number as input
226 * & returns the calibrated voltage as output
227 * The calibrated result is the voltage in uVs
228 */
229uint32_t pm8x41_adc_channel_read(uint16_t ch_num)
230{
231 struct adc_conf *adc;
232 uint16_t result;
233 uint32_t calib_result;
234
235 adc = get_channel_prop(ch_num);
236 if (!adc) {
237 dprintf(CRITICAL, "Error: requested channel is not supported: %u\n", ch_num);
Channagoud Kadabib9f58c42013-05-17 12:30:42 -0700238 return 0;
Channagoud Kadabid091f702013-01-07 16:17:37 -0800239 }
240
241 result = adc_configure(adc);
242
243 calib_result = vadc_calibrate(result, adc->calib_type);
244
Channagoud Kadabibdc83772013-09-05 11:21:21 -0700245 dprintf(SPEW, "Result: Raw %u\tCalibrated:%u\n", result, calib_result);
Channagoud Kadabid091f702013-01-07 16:17:37 -0800246
247 return calib_result;
248}
249
250/*
251 * This function configures the maximum
252 * current for USB in uA
253 */
254int pm8x41_iusb_max_config(uint32_t current)
255{
256 uint32_t mul;
257
258 if(current < IUSB_MIN_UA || current > IUSB_MAX_UA) {
259 dprintf(CRITICAL, "Error: Current value for USB are not in permissible range\n");
260 return -1;
261 }
262
263 if (current == USB_CUR_100UA)
264 mul = 0x0;
265 else if (current == USB_CUR_150UA)
266 mul = 0x1;
267 else
268 mul = current / USB_CUR_100UA;
269
270 REG_WRITE(IUSB_MAX_REG, mul);
271
272 return 0;
273}
274
275/*
276 * This function configures the maximum
277 * current for battery in uA
278 */
279int pm8x41_ibat_max_config(uint32_t current)
280{
281 uint32_t mul;
282
283 if(current < IBAT_MIN_UA || current > IBAT_MAX_UA) {
284 dprintf(CRITICAL, "Error: Current value for BAT are not in permissible range\n");
285 return -1;
286 }
287
288 mul = (current - BAT_CUR_100UA) / BAT_CUR_STEP;
289
290 REG_WRITE(IBAT_MAX_REG, mul);
291
292 return 0;
293}
Channagoud Kadabib9f58c42013-05-17 12:30:42 -0700294
295/*
296 * API: pm8x41_chgr_vdd_max_config
297 * Configure the VDD max to i/p value
298 */
299int pm8x41_chgr_vdd_max_config(uint32_t vol)
300{
301 uint8_t mul;
302
303 /* Check for permissible range of i/p */
304 if (vol < VDD_MIN_UA || vol > VDD_MAX_UA)
305 {
306 dprintf(CRITICAL, "Error: Voltage values are not in permissible range\n");
307 return -1;
308 }
309
310 /* Calculate the multiplier */
311 mul = (vol - VDD_MIN_UA) / VDD_VOL_STEP;
312
313 /* Write to VDD_MAX register */
314 REG_WRITE(CHGR_VDD_MAX, mul);
315
316 return 0;
317}
318
319/*
320 * API: pm8x41_chgr_ctl_enable
321 * Enable FSM-controlled autonomous charging
322 */
323int pm8x41_chgr_ctl_enable(uint8_t enable)
324{
325 /* If charging has to be enabled?
326 * 1. Enable charging in charge control
327 * 2. Enable boot done to enable charging
328 */
329 if (enable)
330 {
331 REG_WRITE(CHGR_CHG_CTRL, (CHGR_ENABLE << CHGR_EN_BIT));
332 REG_WRITE(MISC_BOOT_DONE, (BOOT_DONE << BOOT_DONE_BIT));
333 }
334 else
335 REG_WRITE(CHGR_CHG_CTRL, CHGR_DISABLE);
336
337 return 0;
338}
339
340/*
341 * API: pm8x41_get_batt_voltage
342 * Get calibrated battery voltage from VADC, in UV
343 */
344uint32_t pm8x41_get_batt_voltage()
345{
346 uint32_t voltage;
347
348 voltage = pm8x41_adc_channel_read(VADC_BAT_VOL_CHAN_ID);
349
350 if(!voltage)
351 {
352 dprintf(CRITICAL, "Error getting battery Voltage\n");
353 return 0;
354 }
355
356 return voltage;
357}
358
359/*
360 * API: pm8x41_get_voltage_based_soc
361 * Get voltage based State Of Charge, this takes vdd max & battery cutoff
362 * voltage as i/p in uV
363 */
364uint32_t pm8x41_get_voltage_based_soc(uint32_t cutoff_vol, uint32_t vdd_max)
365{
366 uint32_t vol_soc;
367 uint32_t batt_vol;
368
369 batt_vol = pm8x41_get_batt_voltage();
370
371 if(!batt_vol)
372 {
373 dprintf(CRITICAL, "Error: Getting battery voltage based Soc\n");
374 return 0;
375 }
376
377 if (cutoff_vol >= vdd_max)
378 {
379 dprintf(CRITICAL, "Cutoff is greater than VDD max, Voltage based soc can't be calculated\n");
380 return 0;
381 }
382
383 vol_soc = ((batt_vol - cutoff_vol) * 100) / (vdd_max - cutoff_vol);
384
385 return vol_soc;
386}
Jie Cheng182e5ed2013-07-16 18:24:37 +0800387
388/*
389 * API: pm8x41_enable_mpp_as_adc
390 * Configurate the MPP pin as the ADC feature.
391 */
392void pm8x41_enable_mpp_as_adc(uint16_t mpp_num)
393{
394 uint32_t val;
395 if(mpp_num > MPP_MAX_NUM)
396 {
397 dprintf(CRITICAL, "Error: The MPP pin number is unavailable\n");
398 return;
399 }
400 /* set the MPP mode as AIN */
401 val = (MPP_MODE_AIN << Q_REG_MODE_SEL_SHIFT) \
402 | (0x1 << Q_REG_OUT_INVERT_SHIFT) \
403 | (0x0 << Q_REG_SRC_SEL_SHIFT);
404 REG_WRITE((MPP_REG_BASE + mpp_num * MPP_REG_RANGE + Q_REG_MODE_CTL), val);
405
406 /* Enable the MPP */
407 val = (MPP_MASTER_ENABLE << Q_REG_MASTER_EN_SHIFT);
408 REG_WRITE((MPP_REG_BASE + mpp_num * MPP_REG_RANGE + Q_REG_EN_CTL), val);
409
410 /* AIN route to AMUX8 */
411 val = (MPP_AIN_ROUTE_AMUX3 << Q_REG_AIN_ROUTE_SHIFT);
412 REG_WRITE((MPP_REG_BASE + mpp_num * MPP_REG_RANGE + Q_REG_AIN_CTL), val);
413
414}