blob: 8e352523accff8fd8fc65f436afa9494c58ee014 [file] [log] [blame]
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001/*
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -08002 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * Qualcomm's PM8921/PM8018 ADC Arbiter driver
14 */
15#define pr_fmt(fmt) "%s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/mutex.h>
23#include <linux/hwmon.h>
24#include <linux/module.h>
25#include <linux/debugfs.h>
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -070026#include <linux/interrupt.h>
27#include <linux/completion.h>
28#include <linux/hwmon-sysfs.h>
29#include <linux/mfd/pm8xxx/mpp.h>
30#include <linux/platform_device.h>
31#include <linux/mfd/pm8xxx/core.h>
32#include <linux/regulator/consumer.h>
33#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
34
35/* User Bank register set */
36#define PM8XXX_ADC_ARB_USRP_CNTRL1 0x197
37#define PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB BIT(0)
38#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV1 BIT(1)
39#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV2 BIT(2)
40#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV3 BIT(3)
41#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV4 BIT(4)
42#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV5 BIT(5)
43#define PM8XXX_ADC_ARB_USRP_CNTRL1_EOC BIT(6)
44#define PM8XXX_ADC_ARB_USRP_CNTRL1_REQ BIT(7)
45
46#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL 0x198
47#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV0 BIT(0)
48#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV1 BIT(1)
49#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX0 BIT(2)
50#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX1 BIT(3)
51#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL0 BIT(4)
52#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL1 BIT(5)
53#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL2 BIT(6)
54#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL3 BIT(7)
55
56#define PM8XXX_ADC_ARB_USRP_ANA_PARAM 0x199
57#define PM8XXX_ADC_ARB_USRP_DIG_PARAM 0x19A
58#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 BIT(0)
59#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 BIT(1)
60#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE0 BIT(2)
61#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE1 BIT(3)
62#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EOC BIT(4)
63#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0 BIT(5)
64#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1 BIT(6)
65#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EN BIT(7)
66
67#define PM8XXX_ADC_ARB_USRP_RSV 0x19B
68#define PM8XXX_ADC_ARB_USRP_RSV_RST BIT(0)
69#define PM8XXX_ADC_ARB_USRP_RSV_DTEST0 BIT(1)
70#define PM8XXX_ADC_ARB_USRP_RSV_DTEST1 BIT(2)
71#define PM8XXX_ADC_ARB_USRP_RSV_OP BIT(3)
72#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL0 BIT(4)
73#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL1 BIT(5)
74#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL2 BIT(6)
75#define PM8XXX_ADC_ARB_USRP_RSV_TRM BIT(7)
76
77#define PM8XXX_ADC_ARB_USRP_DATA0 0x19D
78#define PM8XXX_ADC_ARB_USRP_DATA1 0x19C
79
80#define PM8XXX_ADC_ARB_BTM_CNTRL1 0x17e
81#define PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM BIT(0)
82#define PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE BIT(1)
83#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1 BIT(2)
84#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2 BIT(3)
85#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3 BIT(4)
86#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4 BIT(5)
87#define PM8XXX_ADC_ARB_BTM_CNTRL1_EOC BIT(6)
88#define PM8XXX_ADC_ARB_BTM_CNTRL1_REQ BIT(7)
89
90#define PM8XXX_ADC_ARB_BTM_CNTRL2 0x18c
91#define PM8XXX_ADC_ARB_BTM_AMUX_CNTRL 0x17f
92#define PM8XXX_ADC_ARB_BTM_ANA_PARAM 0x180
93#define PM8XXX_ADC_ARB_BTM_DIG_PARAM 0x181
94#define PM8XXX_ADC_ARB_BTM_RSV 0x182
95#define PM8XXX_ADC_ARB_BTM_DATA1 0x183
96#define PM8XXX_ADC_ARB_BTM_DATA0 0x184
97#define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1 0x185
98#define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0 0x186
99#define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1 0x187
100#define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0 0x188
101
102#define PM8XXX_ADC_ARB_ANA_DIG 0xa0
103#define PM8XXX_ADC_BTM_RSV 0x10
104#define PM8XXX_ADC_AMUX_MPP_SEL 2
105#define PM8XXX_ADC_AMUX_SEL 4
106#define PM8XXX_ADC_RSV_IP_SEL 4
107#define PM8XXX_ADC_BTM_CHANNEL_SEL 4
108#define PM8XXX_MAX_CHANNEL_PROPERTIES 2
109#define PM8XXX_ADC_IRQ_0 0
110#define PM8XXX_ADC_IRQ_1 1
111#define PM8XXX_ADC_IRQ_2 2
112#define PM8XXX_ADC_BTM_INTERVAL_SEL_MASK 0xF
113#define PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT 2
114#define PM8XXX_ADC_BTM_DECIMATION_SEL 5
115#define PM8XXX_ADC_MUL 10
116#define PM8XXX_ADC_CONV_TIME_MIN 2000
117#define PM8XXX_ADC_CONV_TIME_MAX 2100
118#define PM8XXX_ADC_MPP_SETTLE_TIME_MIN 200
119#define PM8XXX_ADC_MPP_SETTLE_TIME_MAX 200
120#define PM8XXX_ADC_PA_THERM_VREG_UV_MIN 1800000
121#define PM8XXX_ADC_PA_THERM_VREG_UV_MAX 1800000
122#define PM8XXX_ADC_PA_THERM_VREG_UA_LOAD 100000
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800123#define PM8XXX_ADC_HWMON_NAME_LENGTH 32
Siddartha Mohanadoss68ceac12011-12-09 16:04:41 -0800124#define PM8XXX_ADC_BTM_INTERVAL_MAX 0x14
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700125#define PM8XXX_ADC_COMPLETION_TIMEOUT (2 * HZ)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700126
127struct pm8xxx_adc {
128 struct device *dev;
129 struct pm8xxx_adc_properties *adc_prop;
130 int adc_irq;
131 struct mutex adc_lock;
132 struct mutex mpp_adc_lock;
133 spinlock_t btm_lock;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700134 uint32_t adc_num_board_channel;
135 struct completion adc_rslt_completion;
136 struct pm8xxx_adc_amux *adc_channel;
137 int btm_warm_irq;
138 int btm_cool_irq;
139 struct dentry *dent;
140 struct work_struct warm_work;
141 struct work_struct cool_work;
142 uint32_t mpp_base;
143 struct device *hwmon;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700144 int msm_suspend_check;
145 struct pm8xxx_adc_amux_properties *conv;
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800146 struct pm8xxx_adc_arb_btm_param batt;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700147 struct sensor_device_attribute sens_attr[0];
148};
149
150struct pm8xxx_adc_amux_properties {
151 uint32_t amux_channel;
152 uint32_t decimation;
153 uint32_t amux_ip_rsv;
154 uint32_t amux_mpp_channel;
155 struct pm8xxx_adc_chan_properties chan_prop[0];
156};
157
158static const struct pm8xxx_adc_scaling_ratio pm8xxx_amux_scaling_ratio[] = {
159 {1, 1},
160 {1, 3},
161 {1, 4},
162 {1, 6}
163};
164
165static struct pm8xxx_adc *pmic_adc;
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800166static struct regulator *pa_therm;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700167
168static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
169 [ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
170 [ADC_SCALE_BATT_THERM] = {pm8xxx_adc_scale_batt_therm},
171 [ADC_SCALE_PA_THERM] = {pm8xxx_adc_scale_pa_therm},
172 [ADC_SCALE_PMIC_THERM] = {pm8xxx_adc_scale_pmic_therm},
173 [ADC_SCALE_XOTHERM] = {pm8xxx_adc_tdkntcg_therm},
174};
175
176/* On PM8921 ADC the MPP needs to first be configured
177as an analog input to the AMUX pre-mux channel before
178issuing a read request. PM8921 MPP 8 is mapped to AMUX8
179and is common between remote processor's.
180On PM8018 ADC the MPP is directly connected to the AMUX
181pre-mux. Therefore clients of the PM8018 MPP do not need
182to configure the MPP as an analog input to the pre-mux.
183Clients can directly issue request on the pre-mux AMUX
184channel to read the ADC on the MPP */
185static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_config = {
186 .type = PM8XXX_MPP_TYPE_A_INPUT,
187 /* AMUX6 is dedicated to be used for apps processor */
188 .level = PM8XXX_MPP_AIN_AMUX_CH6,
189 .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
190};
191
192/* MPP Configuration for default settings */
193static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_unconfig = {
194 .type = PM8XXX_MPP_TYPE_SINK,
195 .level = PM8XXX_MPP_AIN_AMUX_CH5,
196 .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
197};
198
199static bool pm8xxx_adc_calib_first_adc;
200static bool pm8xxx_adc_initialized, pm8xxx_adc_calib_device_init;
201
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700202static int32_t pm8xxx_adc_check_channel_valid(uint32_t channel)
203{
204 if (channel < CHANNEL_VCOIN ||
205 (channel > CHANNEL_MUXOFF && channel < ADC_MPP_1_ATEST_8) ||
206 (channel > ADC_MPP_1_ATEST_7 && channel < ADC_MPP_2_ATEST_8)
207 || (channel >= ADC_CHANNEL_MAX_NUM))
208 return -EBADF;
209 else
210 return 0;
211}
212
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700213static int32_t pm8xxx_adc_arb_cntrl(uint32_t arb_cntrl,
214 uint32_t channel)
215{
216 struct pm8xxx_adc *adc_pmic = pmic_adc;
217 int i, rc;
218 u8 data_arb_cntrl = 0;
219
220 if (arb_cntrl) {
221 if (adc_pmic->msm_suspend_check)
222 pr_err("PM8xxx ADC request made after suspend_noirq "
223 "with channel: %d\n", channel);
224 data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700225 }
226
227 /* Write twice to the CNTRL register for the arbiter settings
228 to take into effect */
229 for (i = 0; i < 2; i++) {
230 rc = pm8xxx_writeb(adc_pmic->dev->parent,
231 PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
232 if (rc < 0) {
233 pr_err("PM8xxx arb cntrl write failed with %d\n", rc);
234 return rc;
235 }
236 }
237
238 if (arb_cntrl) {
239 data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_REQ;
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700240 INIT_COMPLETION(adc_pmic->adc_rslt_completion);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700241 rc = pm8xxx_writeb(adc_pmic->dev->parent,
242 PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700243 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700244
245 return 0;
246}
247
248static int32_t pm8xxx_adc_patherm_power(bool on)
249{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700250 int rc = 0;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700251
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800252 if (!pa_therm) {
253 pr_err("pm8xxx adc pa_therm not valid\n");
254 return -EINVAL;
255 }
256
257 if (on) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700258 rc = regulator_set_voltage(pa_therm,
259 PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
260 PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
261 if (rc < 0) {
262 pr_err("failed to set the voltage for "
263 "pa_therm with error %d\n", rc);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800264 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700265 }
266
267 rc = regulator_set_optimum_mode(pa_therm,
268 PM8XXX_ADC_PA_THERM_VREG_UA_LOAD);
269 if (rc < 0) {
270 pr_err("failed to set optimum mode for "
271 "pa_therm with error %d\n", rc);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800272 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700273 }
274
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800275 rc = regulator_enable(pa_therm);
276 if (rc < 0) {
277 pr_err("failed to enable pa_therm vreg "
278 "with error %d\n", rc);
279 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700280 }
281 } else {
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800282 rc = regulator_disable(pa_therm);
283 if (rc < 0) {
284 pr_err("failed to disable pa_therm vreg "
285 "with error %d\n", rc);
286 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700287 }
288 }
289
290 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700291}
292
293static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
294 bool power_cntrl)
295{
296 int rc = 0;
297
298 switch (channel)
299 case ADC_MPP_1_AMUX8:
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800300 rc = pm8xxx_adc_patherm_power(power_cntrl);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700301
302 return rc;
303}
304
305
306static uint32_t pm8xxx_adc_read_reg(uint32_t reg, u8 *data)
307{
308 struct pm8xxx_adc *adc_pmic = pmic_adc;
309 int rc;
310
311 rc = pm8xxx_readb(adc_pmic->dev->parent, reg, data);
312 if (rc < 0) {
313 pr_err("PM8xxx adc read reg %d failed with %d\n", reg, rc);
314 return rc;
315 }
316
317 return 0;
318}
319
320static uint32_t pm8xxx_adc_write_reg(uint32_t reg, u8 data)
321{
322 struct pm8xxx_adc *adc_pmic = pmic_adc;
323 int rc;
324
325 rc = pm8xxx_writeb(adc_pmic->dev->parent, reg, data);
326 if (rc < 0) {
327 pr_err("PM8xxx adc write reg %d failed with %d\n", reg, rc);
328 return rc;
329 }
330
331 return 0;
332}
333
334static int32_t pm8xxx_adc_configure(
335 struct pm8xxx_adc_amux_properties *chan_prop)
336{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700337 u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
338 int rc;
339
340 data_amux_chan |= chan_prop->amux_channel << PM8XXX_ADC_AMUX_SEL;
341
342 if (chan_prop->amux_mpp_channel)
343 data_amux_chan |= chan_prop->amux_mpp_channel <<
344 PM8XXX_ADC_AMUX_MPP_SEL;
345
346 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_AMUX_CNTRL,
347 data_amux_chan);
348 if (rc < 0)
349 return rc;
350
Siddartha Mohanadoss866fe9f2011-12-13 23:01:40 -0800351 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_RSV, &data_arb_rsv);
352 if (rc < 0)
353 return rc;
354
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700355 data_arb_rsv &= (PM8XXX_ADC_ARB_USRP_RSV_RST |
356 PM8XXX_ADC_ARB_USRP_RSV_DTEST0 |
357 PM8XXX_ADC_ARB_USRP_RSV_DTEST1 |
Siddartha Mohanadoss866fe9f2011-12-13 23:01:40 -0800358 PM8XXX_ADC_ARB_USRP_RSV_OP);
359 data_arb_rsv |= (chan_prop->amux_ip_rsv << PM8XXX_ADC_RSV_IP_SEL |
360 PM8XXX_ADC_ARB_USRP_RSV_TRM);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700361
362 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_RSV, data_arb_rsv);
363 if (rc < 0)
364 return rc;
365
366 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
367 &data_dig_param);
368 if (rc < 0)
369 return rc;
370
371 /* Default 2.4Mhz clock rate */
372 /* Client chooses the decimation */
373 switch (chan_prop->decimation) {
374 case ADC_DECIMATION_TYPE1:
375 data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
376 break;
377 case ADC_DECIMATION_TYPE2:
378 data_dig_param |= (PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0
379 | PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1);
380 break;
381 default:
382 data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
383 break;
384 }
385 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
386 PM8XXX_ADC_ARB_ANA_DIG);
387 if (rc < 0)
388 return rc;
389
390 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_ANA_PARAM,
391 PM8XXX_ADC_ARB_ANA_DIG);
392 if (rc < 0)
393 return rc;
394
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700395 rc = pm8xxx_adc_arb_cntrl(1, data_amux_chan);
396 if (rc < 0) {
397 pr_err("Configuring ADC Arbiter"
398 "enable failed with %d\n", rc);
399 return rc;
400 }
401
402 return 0;
403}
404
405static uint32_t pm8xxx_adc_read_adc_code(int32_t *data)
406{
407 struct pm8xxx_adc *adc_pmic = pmic_adc;
408 uint8_t rslt_lsb, rslt_msb;
409 int32_t rc, max_ideal_adc_code = 1 << adc_pmic->adc_prop->bitresolution;
410
411 rc = pm8xxx_readb(adc_pmic->dev->parent,
412 PM8XXX_ADC_ARB_USRP_DATA0, &rslt_lsb);
413 if (rc < 0) {
414 pr_err("PM8xxx adc result read failed with %d\n", rc);
415 return rc;
416 }
417
418 rc = pm8xxx_readb(adc_pmic->dev->parent,
419 PM8XXX_ADC_ARB_USRP_DATA1, &rslt_msb);
420 if (rc < 0) {
421 pr_err("PM8xxx adc result read failed with %d\n", rc);
422 return rc;
423 }
424
425 *data = (rslt_msb << 8) | rslt_lsb;
426
427 /* Use the midpoint to determine underflow or overflow */
428 if (*data > max_ideal_adc_code + (max_ideal_adc_code >> 1))
429 *data |= ((1 << (8 * sizeof(*data) -
430 adc_pmic->adc_prop->bitresolution)) - 1) <<
431 adc_pmic->adc_prop->bitresolution;
432
433 /* Default value for switching off the arbiter after reading
434 the ADC value. Bit 0 set to 0. */
435 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
436 if (rc < 0) {
437 pr_err("%s: Configuring ADC Arbiter disable"
438 "failed\n", __func__);
439 return rc;
440 }
441
442 return 0;
443}
444
445static void pm8xxx_adc_btm_warm_scheduler_fn(struct work_struct *work)
446{
447 struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
448 warm_work);
449 unsigned long flags = 0;
450 bool warm_status;
451
452 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
453 warm_status = irq_read_line(adc_pmic->btm_warm_irq);
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800454 if (adc_pmic->batt.btm_warm_fn != NULL)
455 adc_pmic->batt.btm_warm_fn(warm_status);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700456 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
457}
458
459static void pm8xxx_adc_btm_cool_scheduler_fn(struct work_struct *work)
460{
461 struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
462 cool_work);
463 unsigned long flags = 0;
464 bool cool_status;
465
466 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
467 cool_status = irq_read_line(adc_pmic->btm_cool_irq);
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800468 if (adc_pmic->batt.btm_cool_fn != NULL)
469 adc_pmic->batt.btm_cool_fn(cool_status);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700470 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
471}
472
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700473void trigger_completion(struct work_struct *work)
474{
475 struct pm8xxx_adc *adc_8xxx = pmic_adc;
476
477 complete(&adc_8xxx->adc_rslt_completion);
478}
479DECLARE_WORK(trigger_completion_work, trigger_completion);
480
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700481static irqreturn_t pm8xxx_adc_isr(int irq, void *dev_id)
482{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700483
484 if (pm8xxx_adc_calib_first_adc)
485 return IRQ_HANDLED;
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700486
487 schedule_work(&trigger_completion_work);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700488
489 return IRQ_HANDLED;
490}
491
492static irqreturn_t pm8xxx_btm_warm_isr(int irq, void *dev_id)
493{
494 struct pm8xxx_adc *btm_8xxx = dev_id;
495
496 schedule_work(&btm_8xxx->warm_work);
497
498 return IRQ_HANDLED;
499}
500
501static irqreturn_t pm8xxx_btm_cool_isr(int irq, void *dev_id)
502{
503 struct pm8xxx_adc *btm_8xxx = dev_id;
504
505 schedule_work(&btm_8xxx->cool_work);
506
507 return IRQ_HANDLED;
508}
509
510static uint32_t pm8xxx_adc_calib_device(void)
511{
512 struct pm8xxx_adc *adc_pmic = pmic_adc;
513 struct pm8xxx_adc_amux_properties conv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800514 int rc, calib_read_1, calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700515 u8 data_arb_usrp_cntrl1 = 0;
516
517 conv.amux_channel = CHANNEL_125V;
518 conv.decimation = ADC_DECIMATION_TYPE2;
519 conv.amux_ip_rsv = AMUX_RSV1;
520 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
521 pm8xxx_adc_calib_first_adc = true;
522 rc = pm8xxx_adc_configure(&conv);
523 if (rc) {
524 pr_err("pm8xxx_adc configure failed with %d\n", rc);
525 goto calib_fail;
526 }
527
528 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
529 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
530 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
531 &data_arb_usrp_cntrl1);
532 if (rc < 0)
533 return rc;
534 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
535 PM8XXX_ADC_CONV_TIME_MAX);
536 }
537 data_arb_usrp_cntrl1 = 0;
538
539 rc = pm8xxx_adc_read_adc_code(&calib_read_1);
540 if (rc) {
541 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
542 pm8xxx_adc_calib_first_adc = false;
543 goto calib_fail;
544 }
545 pm8xxx_adc_calib_first_adc = false;
546
547 conv.amux_channel = CHANNEL_625MV;
548 conv.decimation = ADC_DECIMATION_TYPE2;
549 conv.amux_ip_rsv = AMUX_RSV1;
550 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
551 pm8xxx_adc_calib_first_adc = true;
552 rc = pm8xxx_adc_configure(&conv);
553 if (rc) {
554 pr_err("pm8xxx_adc configure failed with %d\n", rc);
555 goto calib_fail;
556 }
557
558 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
559 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
560 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
561 &data_arb_usrp_cntrl1);
562 if (rc < 0)
563 return rc;
564 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
565 PM8XXX_ADC_CONV_TIME_MAX);
566 }
567 data_arb_usrp_cntrl1 = 0;
568
569 rc = pm8xxx_adc_read_adc_code(&calib_read_2);
570 if (rc) {
571 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
572 pm8xxx_adc_calib_first_adc = false;
573 goto calib_fail;
574 }
575 pm8xxx_adc_calib_first_adc = false;
576
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700577 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dy =
578 (calib_read_1 - calib_read_2);
579 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dx
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800580 = PM8XXX_CHANNEL_ADC_625_UV;
581 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_vref =
582 calib_read_1;
583 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd =
584 calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700585 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
586 if (rc < 0) {
587 pr_err("%s: Configuring ADC Arbiter disable"
588 "failed\n", __func__);
589 return rc;
590 }
591 /* Ratiometric Calibration */
592 conv.amux_channel = CHANNEL_MUXOFF;
593 conv.decimation = ADC_DECIMATION_TYPE2;
594 conv.amux_ip_rsv = AMUX_RSV5;
595 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
596 pm8xxx_adc_calib_first_adc = true;
597 rc = pm8xxx_adc_configure(&conv);
598 if (rc) {
599 pr_err("pm8xxx_adc configure failed with %d\n", rc);
600 goto calib_fail;
601 }
602
603 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
604 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
605 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
606 &data_arb_usrp_cntrl1);
607 if (rc < 0)
608 return rc;
609 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
610 PM8XXX_ADC_CONV_TIME_MAX);
611 }
612 data_arb_usrp_cntrl1 = 0;
613
614 rc = pm8xxx_adc_read_adc_code(&calib_read_1);
615 if (rc) {
616 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
617 pm8xxx_adc_calib_first_adc = false;
618 goto calib_fail;
619 }
620 pm8xxx_adc_calib_first_adc = false;
621
622 conv.amux_channel = CHANNEL_MUXOFF;
623 conv.decimation = ADC_DECIMATION_TYPE2;
624 conv.amux_ip_rsv = AMUX_RSV4;
625 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
626 pm8xxx_adc_calib_first_adc = true;
627 rc = pm8xxx_adc_configure(&conv);
628 if (rc) {
629 pr_err("pm8xxx_adc configure failed with %d\n", rc);
630 goto calib_fail;
631 }
632
633 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
634 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
635 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
636 &data_arb_usrp_cntrl1);
637 if (rc < 0)
638 return rc;
639 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
640 PM8XXX_ADC_CONV_TIME_MAX);
641 }
642 data_arb_usrp_cntrl1 = 0;
643
644 rc = pm8xxx_adc_read_adc_code(&calib_read_2);
645 if (rc) {
646 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
647 pm8xxx_adc_calib_first_adc = false;
648 goto calib_fail;
649 }
650 pm8xxx_adc_calib_first_adc = false;
651
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700652 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dy =
653 (calib_read_1 - calib_read_2);
654 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dx =
655 adc_pmic->adc_prop->adc_vdd_reference;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800656 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_vref =
657 calib_read_1;
658 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd =
659 calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700660calib_fail:
661 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
662 if (rc < 0) {
663 pr_err("%s: Configuring ADC Arbiter disable"
664 "failed\n", __func__);
665 }
666
667 return rc;
668}
669
670uint32_t pm8xxx_adc_read(enum pm8xxx_adc_channels channel,
671 struct pm8xxx_adc_chan_result *result)
672{
673 struct pm8xxx_adc *adc_pmic = pmic_adc;
674 int i = 0, rc = 0, rc_fail, amux_prescaling, scale_type;
675 enum pm8xxx_adc_premux_mpp_scale_type mpp_scale;
676
677 if (!pm8xxx_adc_initialized)
678 return -ENODEV;
679
680 if (!pm8xxx_adc_calib_device_init) {
681 if (pm8xxx_adc_calib_device() == 0)
682 pm8xxx_adc_calib_device_init = true;
683 }
684
685 mutex_lock(&adc_pmic->adc_lock);
686
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700687 for (i = 0; i < adc_pmic->adc_num_board_channel; i++) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700688 if (channel == adc_pmic->adc_channel[i].channel_name)
689 break;
690 }
691
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700692 if (i == adc_pmic->adc_num_board_channel ||
693 (pm8xxx_adc_check_channel_valid(channel) != 0)) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700694 rc = -EBADF;
695 goto fail_unlock;
696 }
697
698 if (channel < PM8XXX_CHANNEL_MPP_SCALE1_IDX) {
699 mpp_scale = PREMUX_MPP_SCALE_0;
700 adc_pmic->conv->amux_channel = channel;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800701 } else if (channel >= PM8XXX_CHANNEL_MPP_SCALE1_IDX &&
702 channel < PM8XXX_CHANNEL_MPP_SCALE3_IDX) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700703 mpp_scale = PREMUX_MPP_SCALE_1;
704 adc_pmic->conv->amux_channel = channel %
705 PM8XXX_CHANNEL_MPP_SCALE1_IDX;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800706 } else {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700707 mpp_scale = PREMUX_MPP_SCALE_1_DIV3;
708 adc_pmic->conv->amux_channel = channel %
709 PM8XXX_CHANNEL_MPP_SCALE3_IDX;
710 }
711
712 adc_pmic->conv->amux_mpp_channel = mpp_scale;
713 adc_pmic->conv->amux_ip_rsv = adc_pmic->adc_channel[i].adc_rsv;
714 adc_pmic->conv->decimation = adc_pmic->adc_channel[i].adc_decimation;
715 amux_prescaling = adc_pmic->adc_channel[i].chan_path_prescaling;
716
717 adc_pmic->conv->chan_prop->offset_gain_numerator =
718 pm8xxx_amux_scaling_ratio[amux_prescaling].num;
719 adc_pmic->conv->chan_prop->offset_gain_denominator =
720 pm8xxx_amux_scaling_ratio[amux_prescaling].den;
721
722 rc = pm8xxx_adc_channel_power_enable(channel, true);
723 if (rc) {
724 rc = -EINVAL;
725 goto fail_unlock;
726 }
727
728 rc = pm8xxx_adc_configure(adc_pmic->conv);
729 if (rc) {
730 rc = -EINVAL;
731 goto fail;
732 }
733
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700734 rc = wait_for_completion_timeout(&adc_pmic->adc_rslt_completion,
735 PM8XXX_ADC_COMPLETION_TIMEOUT);
736 if (!rc) {
737 u8 data_arb_usrp_cntrl1 = 0;
738 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
739 &data_arb_usrp_cntrl1);
740 if (rc < 0)
741 goto fail;
742 if (data_arb_usrp_cntrl1 == (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
743 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB))
744 pr_debug("End of conversion status set\n");
745 else {
746 pr_err("EOC interrupt not received\n");
747 rc = -EINVAL;
748 goto fail;
749 }
750 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700751
752 rc = pm8xxx_adc_read_adc_code(&result->adc_code);
753 if (rc) {
754 rc = -EINVAL;
755 goto fail;
756 }
757
758 scale_type = adc_pmic->adc_channel[i].adc_scale_fn;
759 if (scale_type >= ADC_SCALE_NONE) {
760 rc = -EBADF;
761 goto fail;
762 }
763
764 adc_scale_fn[scale_type].chan(result->adc_code,
765 adc_pmic->adc_prop, adc_pmic->conv->chan_prop, result);
766
767 rc = pm8xxx_adc_channel_power_enable(channel, false);
768 if (rc) {
769 rc = -EINVAL;
770 goto fail_unlock;
771 }
772
773 mutex_unlock(&adc_pmic->adc_lock);
774
775 return 0;
776fail:
777 rc_fail = pm8xxx_adc_channel_power_enable(channel, false);
778 if (rc_fail)
779 pr_err("pm8xxx adc power disable failed\n");
780fail_unlock:
781 mutex_unlock(&adc_pmic->adc_lock);
782 pr_err("pm8xxx adc error with %d\n", rc);
783 return rc;
784}
785EXPORT_SYMBOL_GPL(pm8xxx_adc_read);
786
787uint32_t pm8xxx_adc_mpp_config_read(uint32_t mpp_num,
788 enum pm8xxx_adc_channels channel,
789 struct pm8xxx_adc_chan_result *result)
790{
791 struct pm8xxx_adc *adc_pmic = pmic_adc;
792 int rc = 0;
793
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800794 if (!pm8xxx_adc_initialized)
795 return -ENODEV;
796
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700797 if (!adc_pmic->mpp_base) {
798 rc = -EINVAL;
799 pr_info("PM8xxx MPP base invalid with error %d\n", rc);
800 return rc;
801 }
802
803 if (mpp_num == PM8XXX_AMUX_MPP_8) {
804 rc = -EINVAL;
805 pr_info("PM8xxx MPP8 is already configured "
806 "to AMUX8. Use pm8xxx_adc_read() instead.\n");
807 return rc;
808 }
809
810 mutex_lock(&adc_pmic->mpp_adc_lock);
811
812 rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
813 &pm8xxx_adc_mpp_config);
814 if (rc < 0) {
815 pr_err("pm8xxx adc mpp config error with %d\n", rc);
816 goto fail;
817 }
818
819 usleep_range(PM8XXX_ADC_MPP_SETTLE_TIME_MIN,
820 PM8XXX_ADC_MPP_SETTLE_TIME_MAX);
821
822 rc = pm8xxx_adc_read(channel, result);
823 if (rc < 0)
824 pr_err("pm8xxx adc read error with %d\n", rc);
825
826 rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
827 &pm8xxx_adc_mpp_unconfig);
828 if (rc < 0)
829 pr_err("pm8xxx adc mpp config error with %d\n", rc);
830fail:
831 mutex_unlock(&adc_pmic->mpp_adc_lock);
832
833 return rc;
834}
835EXPORT_SYMBOL_GPL(pm8xxx_adc_mpp_config_read);
836
837uint32_t pm8xxx_adc_btm_configure(struct pm8xxx_adc_arb_btm_param *btm_param)
838{
839 struct pm8xxx_adc *adc_pmic = pmic_adc;
840 u8 data_btm_cool_thr0, data_btm_cool_thr1;
841 u8 data_btm_warm_thr0, data_btm_warm_thr1;
842 u8 arb_btm_cntrl1;
843 unsigned long flags = 0;
844 int rc;
845
846 if (adc_pmic == NULL) {
847 pr_err("PMIC ADC not valid\n");
848 return -EINVAL;
849 }
850
851 if ((btm_param->btm_cool_fn == NULL) &&
852 (btm_param->btm_warm_fn == NULL)) {
853 pr_err("No BTM warm/cool notification??\n");
854 return -EINVAL;
855 }
856
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800857 rc = pm8xxx_adc_batt_scaler(btm_param, adc_pmic->adc_prop,
858 adc_pmic->conv->chan_prop);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700859 if (rc < 0) {
860 pr_err("Failed to lookup the BTM thresholds\n");
861 return rc;
862 }
863
Siddartha Mohanadoss68ceac12011-12-09 16:04:41 -0800864 if (btm_param->interval > PM8XXX_ADC_BTM_INTERVAL_MAX) {
865 pr_info("Bug in PMIC BTM interval time and cannot set"
866 " a value greater than 0x14 %x\n", btm_param->interval);
867 btm_param->interval = PM8XXX_ADC_BTM_INTERVAL_MAX;
868 }
869
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700870 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
871
872 data_btm_cool_thr0 = ((btm_param->low_thr_voltage << 24) >> 24);
873 data_btm_cool_thr1 = ((btm_param->low_thr_voltage << 16) >> 24);
874 data_btm_warm_thr0 = ((btm_param->high_thr_voltage << 24) >> 24);
875 data_btm_warm_thr1 = ((btm_param->high_thr_voltage << 16) >> 24);
876
877 if (btm_param->btm_cool_fn != NULL) {
878 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0,
879 data_btm_cool_thr0);
880 if (rc < 0)
881 goto write_err;
882
883 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1,
884 data_btm_cool_thr1);
885 if (rc < 0)
886 goto write_err;
887
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800888 adc_pmic->batt.btm_cool_fn = btm_param->btm_cool_fn;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700889 }
890
891 if (btm_param->btm_warm_fn != NULL) {
892 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0,
893 data_btm_warm_thr0);
894 if (rc < 0)
895 goto write_err;
896
897 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1,
898 data_btm_warm_thr1);
899 if (rc < 0)
900 goto write_err;
901
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800902 adc_pmic->batt.btm_warm_fn = btm_param->btm_warm_fn;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700903 }
904
905 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, &arb_btm_cntrl1);
906 if (rc < 0)
907 goto bail_out;
908
909 btm_param->interval &= PM8XXX_ADC_BTM_INTERVAL_SEL_MASK;
910 arb_btm_cntrl1 |=
911 btm_param->interval << PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT;
912
913 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, arb_btm_cntrl1);
914 if (rc < 0)
915 goto write_err;
916
917 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
918
919 return rc;
920bail_out:
921write_err:
922 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
923 pr_debug("%s: with error code %d\n", __func__, rc);
924 return rc;
925}
926EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_configure);
927
928static uint32_t pm8xxx_adc_btm_read(uint32_t channel)
929{
930 struct pm8xxx_adc *adc_pmic = pmic_adc;
931 int rc, i;
932 u8 arb_btm_dig_param, arb_btm_ana_param, arb_btm_rsv;
933 u8 arb_btm_amux_cntrl, data_arb_btm_cntrl = 0;
934 unsigned long flags;
935
936 arb_btm_amux_cntrl = channel << PM8XXX_ADC_BTM_CHANNEL_SEL;
937 arb_btm_rsv = adc_pmic->adc_channel[channel].adc_rsv;
938 arb_btm_dig_param = arb_btm_ana_param = PM8XXX_ADC_ARB_ANA_DIG;
939
940 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
941
942 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_AMUX_CNTRL,
943 arb_btm_amux_cntrl);
944 if (rc < 0)
945 goto write_err;
946
947 arb_btm_rsv = PM8XXX_ADC_BTM_RSV;
948
949 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_RSV, arb_btm_rsv);
950 if (rc < 0)
951 goto write_err;
952
953 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_DIG_PARAM,
954 arb_btm_dig_param);
955 if (rc < 0)
956 goto write_err;
957
958 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_ANA_PARAM,
959 arb_btm_ana_param);
960 if (rc < 0)
961 goto write_err;
962
963 data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM;
964
965 for (i = 0; i < 2; i++) {
966 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
967 data_arb_btm_cntrl);
968 if (rc < 0)
969 goto write_err;
970 }
971
972 data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_REQ
973 | PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE;
974
975 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
976 data_arb_btm_cntrl);
977 if (rc < 0)
978 goto write_err;
979
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800980 if (pmic_adc->batt.btm_warm_fn != NULL)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700981 enable_irq(adc_pmic->btm_warm_irq);
982
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800983 if (pmic_adc->batt.btm_cool_fn != NULL)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700984 enable_irq(adc_pmic->btm_cool_irq);
985
986write_err:
987 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
988 return rc;
989}
990
991uint32_t pm8xxx_adc_btm_start(void)
992{
993 return pm8xxx_adc_btm_read(CHANNEL_BATT_THERM);
994}
995EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_start);
996
997uint32_t pm8xxx_adc_btm_end(void)
998{
999 struct pm8xxx_adc *adc_pmic = pmic_adc;
1000 int i, rc;
Siddartha Mohanadoss6217da02011-12-13 20:23:05 -08001001 u8 data_arb_btm_cntrl = 0;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001002 unsigned long flags;
1003
1004 disable_irq_nosync(adc_pmic->btm_warm_irq);
1005 disable_irq_nosync(adc_pmic->btm_cool_irq);
1006
1007 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001008
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001009 /* Write twice to the CNTRL register for the arbiter settings
1010 to take into effect */
1011 for (i = 0; i < 2; i++) {
1012 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
1013 data_arb_btm_cntrl);
1014 if (rc < 0) {
1015 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
1016 return rc;
1017 }
1018 }
1019
1020 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
1021
1022 return rc;
1023}
1024EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_end);
1025
1026static ssize_t pm8xxx_adc_show(struct device *dev,
1027 struct device_attribute *devattr, char *buf)
1028{
1029 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001030 struct pm8xxx_adc_chan_result result;
1031 int rc = -1;
1032
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001033 rc = pm8xxx_adc_read(attr->index, &result);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001034
1035 if (rc)
1036 return 0;
1037
Siddartha Mohanadossae39c902011-11-09 17:54:31 -08001038 return snprintf(buf, PM8XXX_ADC_HWMON_NAME_LENGTH,
1039 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001040}
1041
1042static int get_adc(void *data, u64 *val)
1043{
1044 struct pm8xxx_adc_chan_result result;
1045 int i = (int)data;
1046 int rc;
1047
1048 rc = pm8xxx_adc_read(i, &result);
1049 if (!rc)
1050 pr_info("ADC value raw:%x physical:%lld\n",
1051 result.adc_code, result.physical);
1052 *val = result.physical;
1053
1054 return 0;
1055}
1056DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%llu\n");
1057
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001058#ifdef CONFIG_DEBUG_FS
1059static void create_debugfs_entries(void)
1060{
1061 int i = 0;
1062 pmic_adc->dent = debugfs_create_dir("pm8xxx_adc", NULL);
1063
1064 if (IS_ERR(pmic_adc->dent)) {
1065 pr_err("pmic adc debugfs dir not created\n");
1066 return;
1067 }
1068
1069 for (i = 0; i < pmic_adc->adc_num_board_channel; i++)
1070 debugfs_create_file(pmic_adc->adc_channel[i].name,
1071 0644, pmic_adc->dent,
1072 (void *)pmic_adc->adc_channel[i].channel_name,
1073 &reg_fops);
1074}
1075#else
1076static inline void create_debugfs_entries(void)
1077{
1078}
1079#endif
1080static struct sensor_device_attribute pm8xxx_adc_attr =
1081 SENSOR_ATTR(NULL, S_IRUGO, pm8xxx_adc_show, NULL, 0);
1082
1083static int32_t pm8xxx_adc_init_hwmon(struct platform_device *pdev)
1084{
1085 struct pm8xxx_adc *adc_pmic = pmic_adc;
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001086 int rc = 0, i, channel;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001087
1088 for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001089 channel = adc_pmic->adc_channel[i].channel_name;
1090 if (pm8xxx_adc_check_channel_valid(channel)) {
1091 pr_err("Invalid ADC init HWMON channel: %d\n", channel);
1092 continue;
1093 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001094 pm8xxx_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
1095 pm8xxx_adc_attr.dev_attr.attr.name =
1096 adc_pmic->adc_channel[i].name;
1097 memcpy(&adc_pmic->sens_attr[i], &pm8xxx_adc_attr,
1098 sizeof(pm8xxx_adc_attr));
Stephen Boyd388d5cf2012-07-03 14:33:25 -07001099 sysfs_attr_init(&adc_pmic->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001100 rc = device_create_file(&pdev->dev,
1101 &adc_pmic->sens_attr[i].dev_attr);
1102 if (rc) {
1103 dev_err(&pdev->dev, "device_create_file failed for "
1104 "dev %s\n",
1105 adc_pmic->adc_channel[i].name);
1106 goto hwmon_err_sens;
1107 }
1108 }
1109
1110 return 0;
1111hwmon_err_sens:
1112 pr_info("Init HWMON failed for pm8xxx_adc with %d\n", rc);
1113 return rc;
1114}
1115
1116#ifdef CONFIG_PM
1117static int pm8xxx_adc_suspend_noirq(struct device *dev)
1118{
1119 struct pm8xxx_adc *adc_pmic = pmic_adc;
1120
1121 adc_pmic->msm_suspend_check = 1;
1122
1123 return 0;
1124}
1125
1126static int pm8xxx_adc_resume_noirq(struct device *dev)
1127{
1128 struct pm8xxx_adc *adc_pmic = pmic_adc;
1129
1130 adc_pmic->msm_suspend_check = 0;
1131
1132 return 0;
1133}
1134
1135static const struct dev_pm_ops pm8xxx_adc_dev_pm_ops = {
1136 .suspend_noirq = pm8xxx_adc_suspend_noirq,
1137 .resume_noirq = pm8xxx_adc_resume_noirq,
1138};
1139
1140#define PM8XXX_ADC_DEV_PM_OPS (&pm8xxx_adc_dev_pm_ops)
1141#else
1142#define PM8XXX_ADC_DEV_PM_OPS NULL
1143#endif
1144
1145static int __devexit pm8xxx_adc_teardown(struct platform_device *pdev)
1146{
1147 struct pm8xxx_adc *adc_pmic = pmic_adc;
1148 int i;
1149
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001150 platform_set_drvdata(pdev, NULL);
1151 pmic_adc = NULL;
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -08001152 if (!pa_therm) {
1153 regulator_put(pa_therm);
1154 pa_therm = NULL;
1155 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001156 for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
1157 device_remove_file(adc_pmic->dev,
1158 &adc_pmic->sens_attr[i].dev_attr);
1159 pm8xxx_adc_initialized = false;
1160
1161 return 0;
1162}
1163
1164static int __devinit pm8xxx_adc_probe(struct platform_device *pdev)
1165{
1166 const struct pm8xxx_adc_platform_data *pdata = pdev->dev.platform_data;
1167 struct pm8xxx_adc *adc_pmic;
1168 struct pm8xxx_adc_amux_properties *adc_amux_prop;
1169 int rc = 0;
1170
1171 if (!pdata) {
1172 dev_err(&pdev->dev, "no platform data?\n");
1173 return -EINVAL;
1174 }
1175
1176 adc_pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8xxx_adc) +
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001177 (sizeof(struct sensor_device_attribute) *
1178 pdata->adc_num_board_channel), GFP_KERNEL);
1179 if (!adc_pmic) {
1180 dev_err(&pdev->dev, "Unable to allocate memory\n");
1181 return -ENOMEM;
1182 }
1183
1184 adc_amux_prop = devm_kzalloc(&pdev->dev,
1185 sizeof(struct pm8xxx_adc_amux_properties) +
1186 sizeof(struct pm8xxx_adc_chan_properties)
1187 , GFP_KERNEL);
1188 if (!adc_amux_prop) {
1189 dev_err(&pdev->dev, "Unable to allocate memory\n");
1190 return -ENOMEM;
1191 }
1192
1193 adc_pmic->dev = &pdev->dev;
1194 adc_pmic->adc_prop = pdata->adc_prop;
1195 adc_pmic->conv = adc_amux_prop;
1196 init_completion(&adc_pmic->adc_rslt_completion);
1197 adc_pmic->adc_channel = pdata->adc_channel;
1198 adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001199 adc_pmic->mpp_base = pdata->adc_mpp_base;
1200
1201 mutex_init(&adc_pmic->adc_lock);
1202 mutex_init(&adc_pmic->mpp_adc_lock);
1203 spin_lock_init(&adc_pmic->btm_lock);
1204
1205 adc_pmic->adc_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_0);
1206 if (adc_pmic->adc_irq < 0)
1207 return adc_pmic->adc_irq;
1208
1209 rc = devm_request_irq(&pdev->dev, adc_pmic->adc_irq,
1210 pm8xxx_adc_isr,
1211 IRQF_TRIGGER_RISING, "pm8xxx_adc_interrupt", adc_pmic);
1212 if (rc) {
1213 dev_err(&pdev->dev, "failed to request adc irq "
1214 "with error %d\n", rc);
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -07001215 } else {
1216 enable_irq_wake(adc_pmic->adc_irq);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001217 }
1218
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001219 adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_1);
1220 if (adc_pmic->btm_warm_irq < 0)
1221 return adc_pmic->btm_warm_irq;
1222
1223 rc = devm_request_irq(&pdev->dev, adc_pmic->btm_warm_irq,
1224 pm8xxx_btm_warm_isr,
1225 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1226 "pm8xxx_btm_warm_interrupt", adc_pmic);
1227 if (rc) {
1228 pr_err("btm warm irq failed %d with interrupt number %d\n",
1229 rc, adc_pmic->btm_warm_irq);
1230 dev_err(&pdev->dev, "failed to request btm irq\n");
1231 }
1232
1233 disable_irq_nosync(adc_pmic->btm_warm_irq);
1234
1235 adc_pmic->btm_cool_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_2);
1236 if (adc_pmic->btm_cool_irq < 0)
1237 return adc_pmic->btm_cool_irq;
1238
1239 rc = devm_request_irq(&pdev->dev, adc_pmic->btm_cool_irq,
1240 pm8xxx_btm_cool_isr,
1241 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1242 "pm8xxx_btm_cool_interrupt", adc_pmic);
1243 if (rc) {
1244 pr_err("btm cool irq failed with return %d and number %d\n",
1245 rc, adc_pmic->btm_cool_irq);
1246 dev_err(&pdev->dev, "failed to request btm irq\n");
1247 }
1248
1249 disable_irq_nosync(adc_pmic->btm_cool_irq);
1250 platform_set_drvdata(pdev, adc_pmic);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001251 adc_pmic->msm_suspend_check = 0;
1252 pmic_adc = adc_pmic;
1253
1254 INIT_WORK(&adc_pmic->warm_work, pm8xxx_adc_btm_warm_scheduler_fn);
1255 INIT_WORK(&adc_pmic->cool_work, pm8xxx_adc_btm_cool_scheduler_fn);
1256 create_debugfs_entries();
1257 pm8xxx_adc_calib_first_adc = false;
1258 pm8xxx_adc_calib_device_init = false;
1259 pm8xxx_adc_initialized = true;
1260
1261 rc = pm8xxx_adc_init_hwmon(pdev);
1262 if (rc) {
1263 pr_err("pm8xxx adc init hwmon failed with %d\n", rc);
1264 dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
1265 }
1266 adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -08001267
1268 pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
1269 if (IS_ERR(pa_therm)) {
1270 rc = PTR_ERR(pa_therm);
1271 pr_err("failed to request pa_therm vreg with error %d\n", rc);
1272 pa_therm = NULL;
1273 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001274 return 0;
1275}
1276
1277static struct platform_driver pm8xxx_adc_driver = {
1278 .probe = pm8xxx_adc_probe,
1279 .remove = __devexit_p(pm8xxx_adc_teardown),
1280 .driver = {
1281 .name = PM8XXX_ADC_DEV_NAME,
1282 .owner = THIS_MODULE,
1283 .pm = PM8XXX_ADC_DEV_PM_OPS,
1284 },
1285};
1286
1287static int __init pm8xxx_adc_init(void)
1288{
1289 return platform_driver_register(&pm8xxx_adc_driver);
1290}
1291module_init(pm8xxx_adc_init);
1292
1293static void __exit pm8xxx_adc_exit(void)
1294{
1295 platform_driver_unregister(&pm8xxx_adc_driver);
1296}
1297module_exit(pm8xxx_adc_exit);
1298
1299MODULE_ALIAS("platform:" PM8XXX_ADC_DEV_NAME);
1300MODULE_DESCRIPTION("PMIC8921/8018 ADC driver");
1301MODULE_LICENSE("GPL v2");