1*baff4517SJishnu Prakash // SPDX-License-Identifier: GPL-2.0-only
2*baff4517SJishnu Prakash /*
3*baff4517SJishnu Prakash * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4*baff4517SJishnu Prakash */
5*baff4517SJishnu Prakash
6*baff4517SJishnu Prakash #include <linux/auxiliary_bus.h>
7*baff4517SJishnu Prakash #include <linux/bitfield.h>
8*baff4517SJishnu Prakash #include <linux/bits.h>
9*baff4517SJishnu Prakash #include <linux/cleanup.h>
10*baff4517SJishnu Prakash #include <linux/completion.h>
11*baff4517SJishnu Prakash #include <linux/container_of.h>
12*baff4517SJishnu Prakash #include <linux/delay.h>
13*baff4517SJishnu Prakash #include <linux/device.h>
14*baff4517SJishnu Prakash #include <linux/device/devres.h>
15*baff4517SJishnu Prakash #include <linux/dev_printk.h>
16*baff4517SJishnu Prakash #include <linux/err.h>
17*baff4517SJishnu Prakash #include <linux/export.h>
18*baff4517SJishnu Prakash #include <linux/iio/adc/qcom-adc5-gen3-common.h>
19*baff4517SJishnu Prakash #include <linux/iio/iio.h>
20*baff4517SJishnu Prakash #include <linux/interrupt.h>
21*baff4517SJishnu Prakash #include <linux/kernel.h>
22*baff4517SJishnu Prakash #include <linux/module.h>
23*baff4517SJishnu Prakash #include <linux/mod_devicetable.h>
24*baff4517SJishnu Prakash #include <linux/mutex.h>
25*baff4517SJishnu Prakash #include <linux/platform_device.h>
26*baff4517SJishnu Prakash #include <linux/property.h>
27*baff4517SJishnu Prakash #include <linux/regmap.h>
28*baff4517SJishnu Prakash #include <linux/types.h>
29*baff4517SJishnu Prakash #include <linux/unaligned.h>
30*baff4517SJishnu Prakash
31*baff4517SJishnu Prakash #define ADC5_GEN3_VADC_SDAM 0x0
32*baff4517SJishnu Prakash
33*baff4517SJishnu Prakash struct adc5_chip;
34*baff4517SJishnu Prakash
35*baff4517SJishnu Prakash /**
36*baff4517SJishnu Prakash * struct adc5_channel_prop - ADC channel structure
37*baff4517SJishnu Prakash * @common_props: structure with ADC channel properties (common to TM usage).
38*baff4517SJishnu Prakash * @adc_tm: indicates TM type if the channel is used for TM measurements.
39*baff4517SJishnu Prakash * @chip: pointer to top-level ADC device structure.
40*baff4517SJishnu Prakash */
41*baff4517SJishnu Prakash struct adc5_channel_prop {
42*baff4517SJishnu Prakash struct adc5_channel_common_prop common_props;
43*baff4517SJishnu Prakash int adc_tm;
44*baff4517SJishnu Prakash struct adc5_chip *chip;
45*baff4517SJishnu Prakash };
46*baff4517SJishnu Prakash
47*baff4517SJishnu Prakash /**
48*baff4517SJishnu Prakash * struct adc5_chip - ADC private structure.
49*baff4517SJishnu Prakash * @dev: SPMI ADC5 Gen3 device.
50*baff4517SJishnu Prakash * @dev_data: Top-level ADC device data.
51*baff4517SJishnu Prakash * @nchannels: number of ADC channels.
52*baff4517SJishnu Prakash * @chan_props: array of ADC channel properties.
53*baff4517SJishnu Prakash * @iio_chans: array of IIO channels specification.
54*baff4517SJishnu Prakash * @complete: ADC result notification after interrupt is received.
55*baff4517SJishnu Prakash * @lock: ADC lock for access to the peripheral, to prevent concurrent
56*baff4517SJishnu Prakash * requests from multiple clients.
57*baff4517SJishnu Prakash * @data: software configuration data.
58*baff4517SJishnu Prakash * @n_tm_channels: number of ADC channels used for TM measurements.
59*baff4517SJishnu Prakash * @handler: TM callback to be called for threshold violation interrupt
60*baff4517SJishnu Prakash * on first SDAM.
61*baff4517SJishnu Prakash * @tm_aux: pointer to auxiliary TM device.
62*baff4517SJishnu Prakash */
63*baff4517SJishnu Prakash struct adc5_chip {
64*baff4517SJishnu Prakash struct device *dev;
65*baff4517SJishnu Prakash struct adc5_device_data dev_data;
66*baff4517SJishnu Prakash unsigned int nchannels;
67*baff4517SJishnu Prakash struct adc5_channel_prop *chan_props;
68*baff4517SJishnu Prakash struct iio_chan_spec *iio_chans;
69*baff4517SJishnu Prakash struct completion complete;
70*baff4517SJishnu Prakash struct mutex lock;
71*baff4517SJishnu Prakash const struct adc5_data *data;
72*baff4517SJishnu Prakash unsigned int n_tm_channels;
73*baff4517SJishnu Prakash void (*handler)(struct auxiliary_device *tm_aux);
74*baff4517SJishnu Prakash struct auxiliary_device *tm_aux;
75*baff4517SJishnu Prakash };
76*baff4517SJishnu Prakash
adc5_gen3_read(struct adc5_device_data * adc,unsigned int sdam_index,u16 offset,u8 * data,int len)77*baff4517SJishnu Prakash int adc5_gen3_read(struct adc5_device_data *adc, unsigned int sdam_index,
78*baff4517SJishnu Prakash u16 offset, u8 *data, int len)
79*baff4517SJishnu Prakash {
80*baff4517SJishnu Prakash return regmap_bulk_read(adc->regmap,
81*baff4517SJishnu Prakash adc->base[sdam_index].base_addr + offset,
82*baff4517SJishnu Prakash data, len);
83*baff4517SJishnu Prakash }
84*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_read, "QCOM_SPMI_ADC5_GEN3");
85*baff4517SJishnu Prakash
adc5_gen3_write(struct adc5_device_data * adc,unsigned int sdam_index,u16 offset,u8 * data,int len)86*baff4517SJishnu Prakash int adc5_gen3_write(struct adc5_device_data *adc, unsigned int sdam_index,
87*baff4517SJishnu Prakash u16 offset, u8 *data, int len)
88*baff4517SJishnu Prakash {
89*baff4517SJishnu Prakash return regmap_bulk_write(adc->regmap,
90*baff4517SJishnu Prakash adc->base[sdam_index].base_addr + offset,
91*baff4517SJishnu Prakash data, len);
92*baff4517SJishnu Prakash }
93*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_write, "QCOM_SPMI_ADC5_GEN3");
94*baff4517SJishnu Prakash
adc5_gen3_read_voltage_data(struct adc5_chip * adc,u16 * data)95*baff4517SJishnu Prakash static int adc5_gen3_read_voltage_data(struct adc5_chip *adc, u16 *data)
96*baff4517SJishnu Prakash {
97*baff4517SJishnu Prakash u8 rslt[2];
98*baff4517SJishnu Prakash int ret;
99*baff4517SJishnu Prakash
100*baff4517SJishnu Prakash ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
101*baff4517SJishnu Prakash ADC5_GEN3_CH_DATA0(0), rslt, sizeof(rslt));
102*baff4517SJishnu Prakash if (ret)
103*baff4517SJishnu Prakash return ret;
104*baff4517SJishnu Prakash
105*baff4517SJishnu Prakash *data = get_unaligned_le16(rslt);
106*baff4517SJishnu Prakash
107*baff4517SJishnu Prakash if (*data == ADC5_USR_DATA_CHECK) {
108*baff4517SJishnu Prakash dev_err(adc->dev, "Invalid data:%#x\n", *data);
109*baff4517SJishnu Prakash return -EINVAL;
110*baff4517SJishnu Prakash }
111*baff4517SJishnu Prakash
112*baff4517SJishnu Prakash dev_dbg(adc->dev, "voltage raw code:%#x\n", *data);
113*baff4517SJishnu Prakash
114*baff4517SJishnu Prakash return 0;
115*baff4517SJishnu Prakash }
116*baff4517SJishnu Prakash
adc5_gen3_update_dig_param(struct adc5_channel_common_prop * prop,u8 * data)117*baff4517SJishnu Prakash void adc5_gen3_update_dig_param(struct adc5_channel_common_prop *prop, u8 *data)
118*baff4517SJishnu Prakash {
119*baff4517SJishnu Prakash /* Update calibration select and decimation ratio select */
120*baff4517SJishnu Prakash *data &= ~(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK | ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK);
121*baff4517SJishnu Prakash *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK, prop->cal_method);
122*baff4517SJishnu Prakash *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK, prop->decimation);
123*baff4517SJishnu Prakash }
124*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_update_dig_param, "QCOM_SPMI_ADC5_GEN3");
125*baff4517SJishnu Prakash
126*baff4517SJishnu Prakash #define ADC5_GEN3_READ_CONFIG_REGS 7
127*baff4517SJishnu Prakash
adc5_gen3_configure(struct adc5_chip * adc,struct adc5_channel_common_prop * prop)128*baff4517SJishnu Prakash static int adc5_gen3_configure(struct adc5_chip *adc,
129*baff4517SJishnu Prakash struct adc5_channel_common_prop *prop)
130*baff4517SJishnu Prakash {
131*baff4517SJishnu Prakash u8 buf[ADC5_GEN3_READ_CONFIG_REGS];
132*baff4517SJishnu Prakash u8 conv_req = 0;
133*baff4517SJishnu Prakash int ret;
134*baff4517SJishnu Prakash
135*baff4517SJishnu Prakash ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
136*baff4517SJishnu Prakash buf, sizeof(buf));
137*baff4517SJishnu Prakash if (ret)
138*baff4517SJishnu Prakash return ret;
139*baff4517SJishnu Prakash
140*baff4517SJishnu Prakash /* Write SID */
141*baff4517SJishnu Prakash buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->sid);
142*baff4517SJishnu Prakash
143*baff4517SJishnu Prakash /*
144*baff4517SJishnu Prakash * Use channel 0 by default for immediate conversion and to indicate
145*baff4517SJishnu Prakash * there is an actual conversion request
146*baff4517SJishnu Prakash */
147*baff4517SJishnu Prakash buf[1] = ADC5_GEN3_CHAN_CONV_REQ | 0;
148*baff4517SJishnu Prakash
149*baff4517SJishnu Prakash buf[2] = ADC5_GEN3_TIME_IMMEDIATE;
150*baff4517SJishnu Prakash
151*baff4517SJishnu Prakash /* Digital param selection */
152*baff4517SJishnu Prakash adc5_gen3_update_dig_param(prop, &buf[3]);
153*baff4517SJishnu Prakash
154*baff4517SJishnu Prakash /* Update fast average sample value */
155*baff4517SJishnu Prakash buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK,
156*baff4517SJishnu Prakash prop->avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN;
157*baff4517SJishnu Prakash
158*baff4517SJishnu Prakash /* Select ADC channel */
159*baff4517SJishnu Prakash buf[5] = prop->channel;
160*baff4517SJishnu Prakash
161*baff4517SJishnu Prakash /* Select HW settle delay for channel */
162*baff4517SJishnu Prakash buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK,
163*baff4517SJishnu Prakash prop->hw_settle_time_us);
164*baff4517SJishnu Prakash
165*baff4517SJishnu Prakash reinit_completion(&adc->complete);
166*baff4517SJishnu Prakash
167*baff4517SJishnu Prakash ret = adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
168*baff4517SJishnu Prakash buf, sizeof(buf));
169*baff4517SJishnu Prakash if (ret)
170*baff4517SJishnu Prakash return ret;
171*baff4517SJishnu Prakash
172*baff4517SJishnu Prakash conv_req = ADC5_GEN3_CONV_REQ_REQ;
173*baff4517SJishnu Prakash return adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
174*baff4517SJishnu Prakash ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req));
175*baff4517SJishnu Prakash }
176*baff4517SJishnu Prakash
177*baff4517SJishnu Prakash /*
178*baff4517SJishnu Prakash * Worst case delay from PBS in readying handshake bit can be up to 15ms, when
179*baff4517SJishnu Prakash * PBS is busy running other simultaneous transactions, while in the best case,
180*baff4517SJishnu Prakash * it is already ready at this point. Assigning polling delay and retry count
181*baff4517SJishnu Prakash * accordingly.
182*baff4517SJishnu Prakash */
183*baff4517SJishnu Prakash
184*baff4517SJishnu Prakash #define ADC5_GEN3_HS_DELAY_US 100
185*baff4517SJishnu Prakash #define ADC5_GEN3_HS_RETRY_COUNT 150
186*baff4517SJishnu Prakash
adc5_gen3_poll_wait_hs(struct adc5_device_data * adc,unsigned int sdam_index)187*baff4517SJishnu Prakash int adc5_gen3_poll_wait_hs(struct adc5_device_data *adc,
188*baff4517SJishnu Prakash unsigned int sdam_index)
189*baff4517SJishnu Prakash {
190*baff4517SJishnu Prakash u8 conv_req = ADC5_GEN3_CONV_REQ_REQ;
191*baff4517SJishnu Prakash int ret, count;
192*baff4517SJishnu Prakash u8 status = 0;
193*baff4517SJishnu Prakash
194*baff4517SJishnu Prakash for (count = 0; count < ADC5_GEN3_HS_RETRY_COUNT; count++) {
195*baff4517SJishnu Prakash ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_HS, &status, sizeof(status));
196*baff4517SJishnu Prakash if (ret)
197*baff4517SJishnu Prakash return ret;
198*baff4517SJishnu Prakash
199*baff4517SJishnu Prakash if (status == ADC5_GEN3_HS_READY) {
200*baff4517SJishnu Prakash ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_CONV_REQ,
201*baff4517SJishnu Prakash &conv_req, sizeof(conv_req));
202*baff4517SJishnu Prakash if (ret)
203*baff4517SJishnu Prakash return ret;
204*baff4517SJishnu Prakash
205*baff4517SJishnu Prakash if (!conv_req)
206*baff4517SJishnu Prakash return 0;
207*baff4517SJishnu Prakash }
208*baff4517SJishnu Prakash
209*baff4517SJishnu Prakash fsleep(ADC5_GEN3_HS_DELAY_US);
210*baff4517SJishnu Prakash }
211*baff4517SJishnu Prakash
212*baff4517SJishnu Prakash pr_err("Setting HS ready bit timed out, sdam_index:%d, status:%#x\n",
213*baff4517SJishnu Prakash sdam_index, status);
214*baff4517SJishnu Prakash return -ETIMEDOUT;
215*baff4517SJishnu Prakash }
216*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_poll_wait_hs, "QCOM_SPMI_ADC5_GEN3");
217*baff4517SJishnu Prakash
adc5_gen3_status_clear(struct adc5_device_data * adc,int sdam_index,u16 offset,u8 * val,int len)218*baff4517SJishnu Prakash int adc5_gen3_status_clear(struct adc5_device_data *adc,
219*baff4517SJishnu Prakash int sdam_index, u16 offset, u8 *val, int len)
220*baff4517SJishnu Prakash {
221*baff4517SJishnu Prakash u8 value;
222*baff4517SJishnu Prakash int ret;
223*baff4517SJishnu Prakash
224*baff4517SJishnu Prakash ret = adc5_gen3_write(adc, sdam_index, offset, val, len);
225*baff4517SJishnu Prakash if (ret)
226*baff4517SJishnu Prakash return ret;
227*baff4517SJishnu Prakash
228*baff4517SJishnu Prakash /* To indicate conversion request is only to clear a status */
229*baff4517SJishnu Prakash value = 0;
230*baff4517SJishnu Prakash ret = adc5_gen3_write(adc, sdam_index, ADC5_GEN3_PERPH_CH, &value,
231*baff4517SJishnu Prakash sizeof(value));
232*baff4517SJishnu Prakash if (ret)
233*baff4517SJishnu Prakash return ret;
234*baff4517SJishnu Prakash
235*baff4517SJishnu Prakash value = ADC5_GEN3_CONV_REQ_REQ;
236*baff4517SJishnu Prakash return adc5_gen3_write(adc, sdam_index, ADC5_GEN3_CONV_REQ, &value,
237*baff4517SJishnu Prakash sizeof(value));
238*baff4517SJishnu Prakash }
239*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_status_clear, "QCOM_SPMI_ADC5_GEN3");
240*baff4517SJishnu Prakash
241*baff4517SJishnu Prakash /*
242*baff4517SJishnu Prakash * Worst case delay from PBS for conversion time can be up to 500ms, when PBS
243*baff4517SJishnu Prakash * has timed out twice, once for the initial attempt and once for a retry of
244*baff4517SJishnu Prakash * the same transaction.
245*baff4517SJishnu Prakash */
246*baff4517SJishnu Prakash
247*baff4517SJishnu Prakash #define ADC5_GEN3_CONV_TIMEOUT_MS 501
248*baff4517SJishnu Prakash
adc5_gen3_do_conversion(struct adc5_chip * adc,struct adc5_channel_common_prop * prop,u16 * data_volt)249*baff4517SJishnu Prakash static int adc5_gen3_do_conversion(struct adc5_chip *adc,
250*baff4517SJishnu Prakash struct adc5_channel_common_prop *prop,
251*baff4517SJishnu Prakash u16 *data_volt)
252*baff4517SJishnu Prakash {
253*baff4517SJishnu Prakash unsigned long rc;
254*baff4517SJishnu Prakash int ret;
255*baff4517SJishnu Prakash u8 val;
256*baff4517SJishnu Prakash
257*baff4517SJishnu Prakash guard(mutex)(&adc->lock);
258*baff4517SJishnu Prakash ret = adc5_gen3_poll_wait_hs(&adc->dev_data, ADC5_GEN3_VADC_SDAM);
259*baff4517SJishnu Prakash if (ret)
260*baff4517SJishnu Prakash return ret;
261*baff4517SJishnu Prakash
262*baff4517SJishnu Prakash ret = adc5_gen3_configure(adc, prop);
263*baff4517SJishnu Prakash if (ret) {
264*baff4517SJishnu Prakash dev_err(adc->dev, "ADC configure failed with %d\n", ret);
265*baff4517SJishnu Prakash return ret;
266*baff4517SJishnu Prakash }
267*baff4517SJishnu Prakash
268*baff4517SJishnu Prakash /* No support for polling mode at present */
269*baff4517SJishnu Prakash rc = wait_for_completion_timeout(&adc->complete,
270*baff4517SJishnu Prakash msecs_to_jiffies(ADC5_GEN3_CONV_TIMEOUT_MS));
271*baff4517SJishnu Prakash if (!rc) {
272*baff4517SJishnu Prakash dev_err(adc->dev, "Reading ADC channel %s timed out\n",
273*baff4517SJishnu Prakash prop->label);
274*baff4517SJishnu Prakash return -ETIMEDOUT;
275*baff4517SJishnu Prakash }
276*baff4517SJishnu Prakash
277*baff4517SJishnu Prakash ret = adc5_gen3_read_voltage_data(adc, data_volt);
278*baff4517SJishnu Prakash if (ret)
279*baff4517SJishnu Prakash return ret;
280*baff4517SJishnu Prakash
281*baff4517SJishnu Prakash val = BIT(0);
282*baff4517SJishnu Prakash return adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
283*baff4517SJishnu Prakash ADC5_GEN3_EOC_CLR, &val, 1);
284*baff4517SJishnu Prakash }
285*baff4517SJishnu Prakash
adc5_gen3_isr(int irq,void * dev_id)286*baff4517SJishnu Prakash static irqreturn_t adc5_gen3_isr(int irq, void *dev_id)
287*baff4517SJishnu Prakash {
288*baff4517SJishnu Prakash struct adc5_chip *adc = dev_id;
289*baff4517SJishnu Prakash struct device *dev = adc->dev;
290*baff4517SJishnu Prakash struct auxiliary_device *adev;
291*baff4517SJishnu Prakash u8 status, eoc_status, val;
292*baff4517SJishnu Prakash u8 tm_status[2];
293*baff4517SJishnu Prakash int ret;
294*baff4517SJishnu Prakash
295*baff4517SJishnu Prakash ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
296*baff4517SJishnu Prakash ADC5_GEN3_STATUS1, &status, sizeof(status));
297*baff4517SJishnu Prakash if (ret) {
298*baff4517SJishnu Prakash dev_err(dev, "adc read status1 failed with %d\n", ret);
299*baff4517SJishnu Prakash return IRQ_HANDLED;
300*baff4517SJishnu Prakash }
301*baff4517SJishnu Prakash
302*baff4517SJishnu Prakash ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
303*baff4517SJishnu Prakash ADC5_GEN3_EOC_STS, &eoc_status, sizeof(eoc_status));
304*baff4517SJishnu Prakash if (ret) {
305*baff4517SJishnu Prakash dev_err(dev, "adc read eoc status failed with %d\n", ret);
306*baff4517SJishnu Prakash return IRQ_HANDLED;
307*baff4517SJishnu Prakash }
308*baff4517SJishnu Prakash
309*baff4517SJishnu Prakash if (status & ADC5_GEN3_STATUS1_CONV_FAULT) {
310*baff4517SJishnu Prakash dev_err_ratelimited(dev,
311*baff4517SJishnu Prakash "Unexpected conversion fault, status:%#x, eoc_status:%#x\n",
312*baff4517SJishnu Prakash status, eoc_status);
313*baff4517SJishnu Prakash val = ADC5_GEN3_CONV_ERR_CLR_REQ;
314*baff4517SJishnu Prakash adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
315*baff4517SJishnu Prakash ADC5_GEN3_CONV_ERR_CLR, &val, 1);
316*baff4517SJishnu Prakash return IRQ_HANDLED;
317*baff4517SJishnu Prakash }
318*baff4517SJishnu Prakash
319*baff4517SJishnu Prakash /* CHAN0 is the preconfigured channel for immediate conversion */
320*baff4517SJishnu Prakash if (eoc_status & ADC5_GEN3_EOC_CHAN_0)
321*baff4517SJishnu Prakash complete(&adc->complete);
322*baff4517SJishnu Prakash
323*baff4517SJishnu Prakash ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
324*baff4517SJishnu Prakash ADC5_GEN3_TM_HIGH_STS, tm_status, sizeof(tm_status));
325*baff4517SJishnu Prakash if (ret) {
326*baff4517SJishnu Prakash dev_err(dev, "adc read TM status failed with %d\n", ret);
327*baff4517SJishnu Prakash return IRQ_HANDLED;
328*baff4517SJishnu Prakash }
329*baff4517SJishnu Prakash
330*baff4517SJishnu Prakash dev_dbg(dev, "Interrupt status:%#x, EOC status:%#x, high:%#x, low:%#x\n",
331*baff4517SJishnu Prakash status, eoc_status, tm_status[0], tm_status[1]);
332*baff4517SJishnu Prakash
333*baff4517SJishnu Prakash if (tm_status[0] || tm_status[1]) {
334*baff4517SJishnu Prakash adev = adc->tm_aux;
335*baff4517SJishnu Prakash if (!adev || !adev->dev.driver) {
336*baff4517SJishnu Prakash dev_err(dev, "adc_tm auxiliary device not initialized\n");
337*baff4517SJishnu Prakash return IRQ_HANDLED;
338*baff4517SJishnu Prakash }
339*baff4517SJishnu Prakash
340*baff4517SJishnu Prakash adc->handler(adev);
341*baff4517SJishnu Prakash }
342*baff4517SJishnu Prakash
343*baff4517SJishnu Prakash return IRQ_HANDLED;
344*baff4517SJishnu Prakash }
345*baff4517SJishnu Prakash
adc5_gen3_fwnode_xlate(struct iio_dev * indio_dev,const struct fwnode_reference_args * iiospec)346*baff4517SJishnu Prakash static int adc5_gen3_fwnode_xlate(struct iio_dev *indio_dev,
347*baff4517SJishnu Prakash const struct fwnode_reference_args *iiospec)
348*baff4517SJishnu Prakash {
349*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
350*baff4517SJishnu Prakash int i, v_channel;
351*baff4517SJishnu Prakash
352*baff4517SJishnu Prakash for (i = 0; i < adc->nchannels; i++) {
353*baff4517SJishnu Prakash v_channel = ADC5_GEN3_V_CHAN(adc->chan_props[i].common_props);
354*baff4517SJishnu Prakash if (v_channel == iiospec->args[0])
355*baff4517SJishnu Prakash return i;
356*baff4517SJishnu Prakash }
357*baff4517SJishnu Prakash
358*baff4517SJishnu Prakash return -ENOENT;
359*baff4517SJishnu Prakash }
360*baff4517SJishnu Prakash
adc5_gen3_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)361*baff4517SJishnu Prakash static int adc5_gen3_read_raw(struct iio_dev *indio_dev,
362*baff4517SJishnu Prakash struct iio_chan_spec const *chan, int *val,
363*baff4517SJishnu Prakash int *val2, long mask)
364*baff4517SJishnu Prakash {
365*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
366*baff4517SJishnu Prakash struct adc5_channel_common_prop *prop;
367*baff4517SJishnu Prakash u16 adc_code_volt;
368*baff4517SJishnu Prakash int ret;
369*baff4517SJishnu Prakash
370*baff4517SJishnu Prakash prop = &adc->chan_props[chan->address].common_props;
371*baff4517SJishnu Prakash
372*baff4517SJishnu Prakash switch (mask) {
373*baff4517SJishnu Prakash case IIO_CHAN_INFO_PROCESSED:
374*baff4517SJishnu Prakash ret = adc5_gen3_do_conversion(adc, prop, &adc_code_volt);
375*baff4517SJishnu Prakash if (ret)
376*baff4517SJishnu Prakash return ret;
377*baff4517SJishnu Prakash
378*baff4517SJishnu Prakash ret = qcom_adc5_hw_scale(prop->scale_fn_type, prop->prescale,
379*baff4517SJishnu Prakash adc->data, adc_code_volt, val);
380*baff4517SJishnu Prakash if (ret)
381*baff4517SJishnu Prakash return ret;
382*baff4517SJishnu Prakash
383*baff4517SJishnu Prakash return IIO_VAL_INT;
384*baff4517SJishnu Prakash default:
385*baff4517SJishnu Prakash return -EINVAL;
386*baff4517SJishnu Prakash }
387*baff4517SJishnu Prakash }
388*baff4517SJishnu Prakash
adc5_gen3_read_label(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,char * label)389*baff4517SJishnu Prakash static int adc5_gen3_read_label(struct iio_dev *indio_dev,
390*baff4517SJishnu Prakash const struct iio_chan_spec *chan, char *label)
391*baff4517SJishnu Prakash {
392*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
393*baff4517SJishnu Prakash struct adc5_channel_prop *prop;
394*baff4517SJishnu Prakash
395*baff4517SJishnu Prakash prop = &adc->chan_props[chan->address];
396*baff4517SJishnu Prakash return sprintf(label, "%s\n", prop->common_props.label);
397*baff4517SJishnu Prakash }
398*baff4517SJishnu Prakash
399*baff4517SJishnu Prakash static const struct iio_info adc5_gen3_info = {
400*baff4517SJishnu Prakash .read_raw = adc5_gen3_read_raw,
401*baff4517SJishnu Prakash .read_label = adc5_gen3_read_label,
402*baff4517SJishnu Prakash .fwnode_xlate = adc5_gen3_fwnode_xlate,
403*baff4517SJishnu Prakash };
404*baff4517SJishnu Prakash
405*baff4517SJishnu Prakash struct adc5_channels {
406*baff4517SJishnu Prakash unsigned int prescale_index;
407*baff4517SJishnu Prakash enum iio_chan_type type;
408*baff4517SJishnu Prakash long info_mask;
409*baff4517SJishnu Prakash enum vadc_scale_fn_type scale_fn_type;
410*baff4517SJishnu Prakash };
411*baff4517SJishnu Prakash
412*baff4517SJishnu Prakash /* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
413*baff4517SJishnu Prakash #define ADC5_CHAN(_type, _mask, _pre, _scale) \
414*baff4517SJishnu Prakash { \
415*baff4517SJishnu Prakash .prescale_index = _pre, \
416*baff4517SJishnu Prakash .type = _type, \
417*baff4517SJishnu Prakash .info_mask = _mask, \
418*baff4517SJishnu Prakash .scale_fn_type = _scale, \
419*baff4517SJishnu Prakash }, \
420*baff4517SJishnu Prakash
421*baff4517SJishnu Prakash #define ADC5_CHAN_TEMP(_pre, _scale) \
422*baff4517SJishnu Prakash ADC5_CHAN(IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
423*baff4517SJishnu Prakash
424*baff4517SJishnu Prakash #define ADC5_CHAN_VOLT(_pre, _scale) \
425*baff4517SJishnu Prakash ADC5_CHAN(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
426*baff4517SJishnu Prakash
427*baff4517SJishnu Prakash #define ADC5_CHAN_CUR(_pre, _scale) \
428*baff4517SJishnu Prakash ADC5_CHAN(IIO_CURRENT, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
429*baff4517SJishnu Prakash
430*baff4517SJishnu Prakash static const struct adc5_channels adc5_gen3_chans_pmic[ADC5_MAX_CHANNEL] = {
431*baff4517SJishnu Prakash [ADC5_GEN3_REF_GND] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
432*baff4517SJishnu Prakash [ADC5_GEN3_1P25VREF] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
433*baff4517SJishnu Prakash [ADC5_GEN3_VPH_PWR] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
434*baff4517SJishnu Prakash [ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
435*baff4517SJishnu Prakash [ADC5_GEN3_USB_SNS_V_16] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
436*baff4517SJishnu Prakash [ADC5_GEN3_VIN_DIV16_MUX] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
437*baff4517SJishnu Prakash [ADC5_GEN3_DIE_TEMP] = ADC5_CHAN_TEMP(0,
438*baff4517SJishnu Prakash SCALE_HW_CALIB_PMIC_THERM_PM7)
439*baff4517SJishnu Prakash [ADC5_GEN3_AMUX1_THM_100K_PU] = ADC5_CHAN_TEMP(0,
440*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
441*baff4517SJishnu Prakash [ADC5_GEN3_AMUX2_THM_100K_PU] = ADC5_CHAN_TEMP(0,
442*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
443*baff4517SJishnu Prakash [ADC5_GEN3_AMUX3_THM_100K_PU] = ADC5_CHAN_TEMP(0,
444*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
445*baff4517SJishnu Prakash [ADC5_GEN3_AMUX4_THM_100K_PU] = ADC5_CHAN_TEMP(0,
446*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
447*baff4517SJishnu Prakash [ADC5_GEN3_AMUX5_THM_100K_PU] = ADC5_CHAN_TEMP(0,
448*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
449*baff4517SJishnu Prakash [ADC5_GEN3_AMUX6_THM_100K_PU] = ADC5_CHAN_TEMP(0,
450*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
451*baff4517SJishnu Prakash [ADC5_GEN3_AMUX1_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
452*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
453*baff4517SJishnu Prakash [ADC5_GEN3_AMUX2_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
454*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
455*baff4517SJishnu Prakash [ADC5_GEN3_AMUX3_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
456*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
457*baff4517SJishnu Prakash [ADC5_GEN3_AMUX4_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
458*baff4517SJishnu Prakash SCALE_HW_CALIB_THERM_100K_PU_PM7)
459*baff4517SJishnu Prakash };
460*baff4517SJishnu Prakash
adc5_gen3_get_fw_channel_data(struct adc5_chip * adc,struct adc5_channel_prop * prop,struct fwnode_handle * fwnode)461*baff4517SJishnu Prakash static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc,
462*baff4517SJishnu Prakash struct adc5_channel_prop *prop,
463*baff4517SJishnu Prakash struct fwnode_handle *fwnode)
464*baff4517SJishnu Prakash {
465*baff4517SJishnu Prakash const char *name = fwnode_get_name(fwnode);
466*baff4517SJishnu Prakash const struct adc5_data *data = adc->data;
467*baff4517SJishnu Prakash struct device *dev = adc->dev;
468*baff4517SJishnu Prakash const char *channel_name;
469*baff4517SJishnu Prakash u32 chan, value, sid;
470*baff4517SJishnu Prakash u32 varr[2];
471*baff4517SJishnu Prakash int ret;
472*baff4517SJishnu Prakash
473*baff4517SJishnu Prakash ret = fwnode_property_read_u32(fwnode, "reg", &chan);
474*baff4517SJishnu Prakash if (ret < 0)
475*baff4517SJishnu Prakash return dev_err_probe(dev, ret, "invalid channel number %s\n",
476*baff4517SJishnu Prakash name);
477*baff4517SJishnu Prakash
478*baff4517SJishnu Prakash /*
479*baff4517SJishnu Prakash * Value read from "reg" is virtual channel number
480*baff4517SJishnu Prakash * virtual channel number = sid << 8 | channel number
481*baff4517SJishnu Prakash */
482*baff4517SJishnu Prakash sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan);
483*baff4517SJishnu Prakash chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan);
484*baff4517SJishnu Prakash
485*baff4517SJishnu Prakash if (chan > ADC5_MAX_CHANNEL)
486*baff4517SJishnu Prakash return dev_err_probe(dev, -EINVAL,
487*baff4517SJishnu Prakash "%s invalid channel number %d\n",
488*baff4517SJishnu Prakash name, chan);
489*baff4517SJishnu Prakash
490*baff4517SJishnu Prakash prop->common_props.channel = chan;
491*baff4517SJishnu Prakash prop->common_props.sid = sid;
492*baff4517SJishnu Prakash
493*baff4517SJishnu Prakash if (!adc->data->adc_chans[chan].info_mask)
494*baff4517SJishnu Prakash return dev_err_probe(dev, -EINVAL, "Channel %#x not supported\n", chan);
495*baff4517SJishnu Prakash
496*baff4517SJishnu Prakash channel_name = name;
497*baff4517SJishnu Prakash fwnode_property_read_string(fwnode, "label", &channel_name);
498*baff4517SJishnu Prakash prop->common_props.label = channel_name;
499*baff4517SJishnu Prakash
500*baff4517SJishnu Prakash value = data->decimation[ADC5_DECIMATION_DEFAULT];
501*baff4517SJishnu Prakash fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
502*baff4517SJishnu Prakash ret = qcom_adc5_decimation_from_dt(value, data->decimation);
503*baff4517SJishnu Prakash if (ret < 0)
504*baff4517SJishnu Prakash return dev_err_probe(dev, ret, "%#x invalid decimation %d\n",
505*baff4517SJishnu Prakash chan, value);
506*baff4517SJishnu Prakash prop->common_props.decimation = ret;
507*baff4517SJishnu Prakash
508*baff4517SJishnu Prakash prop->common_props.prescale = adc->data->adc_chans[chan].prescale_index;
509*baff4517SJishnu Prakash ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2);
510*baff4517SJishnu Prakash if (!ret) {
511*baff4517SJishnu Prakash ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
512*baff4517SJishnu Prakash if (ret < 0)
513*baff4517SJishnu Prakash return dev_err_probe(dev, ret,
514*baff4517SJishnu Prakash "%#x invalid pre-scaling <%d %d>\n",
515*baff4517SJishnu Prakash chan, varr[0], varr[1]);
516*baff4517SJishnu Prakash prop->common_props.prescale = ret;
517*baff4517SJishnu Prakash }
518*baff4517SJishnu Prakash
519*baff4517SJishnu Prakash value = data->hw_settle_1[VADC_DEF_HW_SETTLE_TIME];
520*baff4517SJishnu Prakash fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
521*baff4517SJishnu Prakash ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1);
522*baff4517SJishnu Prakash if (ret < 0)
523*baff4517SJishnu Prakash return dev_err_probe(dev, ret,
524*baff4517SJishnu Prakash "%#x invalid hw-settle-time %d us\n",
525*baff4517SJishnu Prakash chan, value);
526*baff4517SJishnu Prakash prop->common_props.hw_settle_time_us = ret;
527*baff4517SJishnu Prakash
528*baff4517SJishnu Prakash value = BIT(VADC_DEF_AVG_SAMPLES);
529*baff4517SJishnu Prakash fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value);
530*baff4517SJishnu Prakash ret = qcom_adc5_avg_samples_from_dt(value);
531*baff4517SJishnu Prakash if (ret < 0)
532*baff4517SJishnu Prakash return dev_err_probe(dev, ret, "%#x invalid avg-samples %d\n",
533*baff4517SJishnu Prakash chan, value);
534*baff4517SJishnu Prakash prop->common_props.avg_samples = ret;
535*baff4517SJishnu Prakash
536*baff4517SJishnu Prakash if (fwnode_property_read_bool(fwnode, "qcom,ratiometric"))
537*baff4517SJishnu Prakash prop->common_props.cal_method = ADC5_RATIOMETRIC_CAL;
538*baff4517SJishnu Prakash else
539*baff4517SJishnu Prakash prop->common_props.cal_method = ADC5_ABSOLUTE_CAL;
540*baff4517SJishnu Prakash
541*baff4517SJishnu Prakash prop->adc_tm = fwnode_property_read_bool(fwnode, "qcom,adc-tm");
542*baff4517SJishnu Prakash if (prop->adc_tm) {
543*baff4517SJishnu Prakash adc->n_tm_channels++;
544*baff4517SJishnu Prakash if (adc->n_tm_channels > (adc->dev_data.num_sdams * 8 - 1))
545*baff4517SJishnu Prakash return dev_err_probe(dev, -EINVAL,
546*baff4517SJishnu Prakash "Number of TM nodes %u greater than channels supported:%u\n",
547*baff4517SJishnu Prakash adc->n_tm_channels,
548*baff4517SJishnu Prakash adc->dev_data.num_sdams * 8 - 1);
549*baff4517SJishnu Prakash }
550*baff4517SJishnu Prakash
551*baff4517SJishnu Prakash return 0;
552*baff4517SJishnu Prakash }
553*baff4517SJishnu Prakash
554*baff4517SJishnu Prakash static const struct adc5_data adc5_gen3_data_pmic = {
555*baff4517SJishnu Prakash .full_scale_code_volt = 0x70e4,
556*baff4517SJishnu Prakash .adc_chans = adc5_gen3_chans_pmic,
557*baff4517SJishnu Prakash .info = &adc5_gen3_info,
558*baff4517SJishnu Prakash .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
559*baff4517SJishnu Prakash { 85, 340, 1360 },
560*baff4517SJishnu Prakash .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
561*baff4517SJishnu Prakash { 15, 100, 200, 300,
562*baff4517SJishnu Prakash 400, 500, 600, 700,
563*baff4517SJishnu Prakash 1000, 2000, 4000, 8000,
564*baff4517SJishnu Prakash 16000, 32000, 64000, 128000 },
565*baff4517SJishnu Prakash };
566*baff4517SJishnu Prakash
567*baff4517SJishnu Prakash static const struct of_device_id adc5_match_table[] = {
568*baff4517SJishnu Prakash {
569*baff4517SJishnu Prakash .compatible = "qcom,spmi-adc5-gen3",
570*baff4517SJishnu Prakash .data = &adc5_gen3_data_pmic,
571*baff4517SJishnu Prakash },
572*baff4517SJishnu Prakash { }
573*baff4517SJishnu Prakash };
574*baff4517SJishnu Prakash MODULE_DEVICE_TABLE(of, adc5_match_table);
575*baff4517SJishnu Prakash
adc5_get_fw_data(struct adc5_chip * adc)576*baff4517SJishnu Prakash static int adc5_get_fw_data(struct adc5_chip *adc)
577*baff4517SJishnu Prakash {
578*baff4517SJishnu Prakash const struct adc5_channels *adc_chan;
579*baff4517SJishnu Prakash struct adc5_channel_prop *chan_props;
580*baff4517SJishnu Prakash struct iio_chan_spec *iio_chan;
581*baff4517SJishnu Prakash struct device *dev = adc->dev;
582*baff4517SJishnu Prakash unsigned int index = 0;
583*baff4517SJishnu Prakash int ret;
584*baff4517SJishnu Prakash
585*baff4517SJishnu Prakash adc->nchannels = device_get_child_node_count(dev);
586*baff4517SJishnu Prakash if (!adc->nchannels)
587*baff4517SJishnu Prakash return dev_err_probe(dev, -EINVAL, "No ADC channels found\n");
588*baff4517SJishnu Prakash
589*baff4517SJishnu Prakash adc->iio_chans = devm_kcalloc(dev, adc->nchannels,
590*baff4517SJishnu Prakash sizeof(*adc->iio_chans), GFP_KERNEL);
591*baff4517SJishnu Prakash if (!adc->iio_chans)
592*baff4517SJishnu Prakash return -ENOMEM;
593*baff4517SJishnu Prakash
594*baff4517SJishnu Prakash adc->chan_props = devm_kcalloc(dev, adc->nchannels,
595*baff4517SJishnu Prakash sizeof(*adc->chan_props), GFP_KERNEL);
596*baff4517SJishnu Prakash if (!adc->chan_props)
597*baff4517SJishnu Prakash return -ENOMEM;
598*baff4517SJishnu Prakash
599*baff4517SJishnu Prakash chan_props = adc->chan_props;
600*baff4517SJishnu Prakash adc->n_tm_channels = 0;
601*baff4517SJishnu Prakash iio_chan = adc->iio_chans;
602*baff4517SJishnu Prakash adc->data = device_get_match_data(dev);
603*baff4517SJishnu Prakash
604*baff4517SJishnu Prakash device_for_each_child_node_scoped(dev, child) {
605*baff4517SJishnu Prakash ret = adc5_gen3_get_fw_channel_data(adc, chan_props, child);
606*baff4517SJishnu Prakash if (ret)
607*baff4517SJishnu Prakash return ret;
608*baff4517SJishnu Prakash
609*baff4517SJishnu Prakash chan_props->chip = adc;
610*baff4517SJishnu Prakash adc_chan = &adc->data->adc_chans[chan_props->common_props.channel];
611*baff4517SJishnu Prakash chan_props->common_props.scale_fn_type = adc_chan->scale_fn_type;
612*baff4517SJishnu Prakash
613*baff4517SJishnu Prakash iio_chan->channel = ADC5_GEN3_V_CHAN(chan_props->common_props);
614*baff4517SJishnu Prakash iio_chan->info_mask_separate = adc_chan->info_mask;
615*baff4517SJishnu Prakash iio_chan->type = adc_chan->type;
616*baff4517SJishnu Prakash iio_chan->address = index;
617*baff4517SJishnu Prakash iio_chan->indexed = 1;
618*baff4517SJishnu Prakash iio_chan++;
619*baff4517SJishnu Prakash chan_props++;
620*baff4517SJishnu Prakash index++;
621*baff4517SJishnu Prakash }
622*baff4517SJishnu Prakash
623*baff4517SJishnu Prakash return 0;
624*baff4517SJishnu Prakash }
625*baff4517SJishnu Prakash
adc5_gen3_uninit_aux(void * data)626*baff4517SJishnu Prakash static void adc5_gen3_uninit_aux(void *data)
627*baff4517SJishnu Prakash {
628*baff4517SJishnu Prakash auxiliary_device_uninit(data);
629*baff4517SJishnu Prakash }
630*baff4517SJishnu Prakash
adc5_gen3_delete_aux(void * data)631*baff4517SJishnu Prakash static void adc5_gen3_delete_aux(void *data)
632*baff4517SJishnu Prakash {
633*baff4517SJishnu Prakash auxiliary_device_delete(data);
634*baff4517SJishnu Prakash }
635*baff4517SJishnu Prakash
adc5_gen3_aux_device_release(struct device * dev)636*baff4517SJishnu Prakash static void adc5_gen3_aux_device_release(struct device *dev) {}
637*baff4517SJishnu Prakash
adc5_gen3_add_aux_tm_device(struct adc5_chip * adc)638*baff4517SJishnu Prakash static int adc5_gen3_add_aux_tm_device(struct adc5_chip *adc)
639*baff4517SJishnu Prakash {
640*baff4517SJishnu Prakash struct tm5_aux_dev_wrapper *aux_device;
641*baff4517SJishnu Prakash int i, ret, i_tm = 0;
642*baff4517SJishnu Prakash
643*baff4517SJishnu Prakash aux_device = devm_kzalloc(adc->dev, sizeof(*aux_device), GFP_KERNEL);
644*baff4517SJishnu Prakash if (!aux_device)
645*baff4517SJishnu Prakash return -ENOMEM;
646*baff4517SJishnu Prakash
647*baff4517SJishnu Prakash aux_device->aux_dev.name = "adc5_tm_gen3";
648*baff4517SJishnu Prakash aux_device->aux_dev.dev.parent = adc->dev;
649*baff4517SJishnu Prakash aux_device->aux_dev.dev.release = adc5_gen3_aux_device_release;
650*baff4517SJishnu Prakash
651*baff4517SJishnu Prakash aux_device->tm_props = devm_kcalloc(adc->dev, adc->n_tm_channels,
652*baff4517SJishnu Prakash sizeof(*aux_device->tm_props),
653*baff4517SJishnu Prakash GFP_KERNEL);
654*baff4517SJishnu Prakash if (!aux_device->tm_props)
655*baff4517SJishnu Prakash return -ENOMEM;
656*baff4517SJishnu Prakash
657*baff4517SJishnu Prakash aux_device->dev_data = &adc->dev_data;
658*baff4517SJishnu Prakash
659*baff4517SJishnu Prakash for (i = 0; i < adc->nchannels; i++) {
660*baff4517SJishnu Prakash if (!adc->chan_props[i].adc_tm)
661*baff4517SJishnu Prakash continue;
662*baff4517SJishnu Prakash aux_device->tm_props[i_tm] = adc->chan_props[i].common_props;
663*baff4517SJishnu Prakash i_tm++;
664*baff4517SJishnu Prakash }
665*baff4517SJishnu Prakash
666*baff4517SJishnu Prakash device_set_of_node_from_dev(&aux_device->aux_dev.dev, adc->dev);
667*baff4517SJishnu Prakash
668*baff4517SJishnu Prakash aux_device->n_tm_channels = adc->n_tm_channels;
669*baff4517SJishnu Prakash
670*baff4517SJishnu Prakash ret = auxiliary_device_init(&aux_device->aux_dev);
671*baff4517SJishnu Prakash if (ret)
672*baff4517SJishnu Prakash return ret;
673*baff4517SJishnu Prakash
674*baff4517SJishnu Prakash ret = devm_add_action_or_reset(adc->dev, adc5_gen3_uninit_aux,
675*baff4517SJishnu Prakash &aux_device->aux_dev);
676*baff4517SJishnu Prakash if (ret)
677*baff4517SJishnu Prakash return ret;
678*baff4517SJishnu Prakash
679*baff4517SJishnu Prakash ret = auxiliary_device_add(&aux_device->aux_dev);
680*baff4517SJishnu Prakash if (ret)
681*baff4517SJishnu Prakash return ret;
682*baff4517SJishnu Prakash ret = devm_add_action_or_reset(adc->dev, adc5_gen3_delete_aux,
683*baff4517SJishnu Prakash &aux_device->aux_dev);
684*baff4517SJishnu Prakash if (ret)
685*baff4517SJishnu Prakash return ret;
686*baff4517SJishnu Prakash
687*baff4517SJishnu Prakash adc->tm_aux = &aux_device->aux_dev;
688*baff4517SJishnu Prakash
689*baff4517SJishnu Prakash return 0;
690*baff4517SJishnu Prakash }
691*baff4517SJishnu Prakash
adc5_gen3_mutex_lock(struct device * dev)692*baff4517SJishnu Prakash void adc5_gen3_mutex_lock(struct device *dev)
693*baff4517SJishnu Prakash __acquires(&adc->lock)
694*baff4517SJishnu Prakash {
695*baff4517SJishnu Prakash struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
696*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
697*baff4517SJishnu Prakash
698*baff4517SJishnu Prakash mutex_lock(&adc->lock);
699*baff4517SJishnu Prakash }
700*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_lock, "QCOM_SPMI_ADC5_GEN3");
701*baff4517SJishnu Prakash
adc5_gen3_mutex_unlock(struct device * dev)702*baff4517SJishnu Prakash void adc5_gen3_mutex_unlock(struct device *dev)
703*baff4517SJishnu Prakash __releases(&adc->lock)
704*baff4517SJishnu Prakash {
705*baff4517SJishnu Prakash struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
706*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
707*baff4517SJishnu Prakash
708*baff4517SJishnu Prakash mutex_unlock(&adc->lock);
709*baff4517SJishnu Prakash }
710*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_unlock, "QCOM_SPMI_ADC5_GEN3");
711*baff4517SJishnu Prakash
adc5_gen3_get_scaled_reading(struct device * dev,struct adc5_channel_common_prop * common_props,int * val)712*baff4517SJishnu Prakash int adc5_gen3_get_scaled_reading(struct device *dev,
713*baff4517SJishnu Prakash struct adc5_channel_common_prop *common_props,
714*baff4517SJishnu Prakash int *val)
715*baff4517SJishnu Prakash {
716*baff4517SJishnu Prakash struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
717*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
718*baff4517SJishnu Prakash u16 adc_code_volt;
719*baff4517SJishnu Prakash int ret;
720*baff4517SJishnu Prakash
721*baff4517SJishnu Prakash ret = adc5_gen3_do_conversion(adc, common_props, &adc_code_volt);
722*baff4517SJishnu Prakash if (ret)
723*baff4517SJishnu Prakash return ret;
724*baff4517SJishnu Prakash
725*baff4517SJishnu Prakash return qcom_adc5_hw_scale(common_props->scale_fn_type,
726*baff4517SJishnu Prakash common_props->prescale,
727*baff4517SJishnu Prakash adc->data, adc_code_volt, val);
728*baff4517SJishnu Prakash }
729*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_get_scaled_reading, "QCOM_SPMI_ADC5_GEN3");
730*baff4517SJishnu Prakash
adc5_gen3_therm_code_to_temp(struct device * dev,struct adc5_channel_common_prop * common_props,u16 code,int * val)731*baff4517SJishnu Prakash int adc5_gen3_therm_code_to_temp(struct device *dev,
732*baff4517SJishnu Prakash struct adc5_channel_common_prop *common_props,
733*baff4517SJishnu Prakash u16 code, int *val)
734*baff4517SJishnu Prakash {
735*baff4517SJishnu Prakash struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
736*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
737*baff4517SJishnu Prakash
738*baff4517SJishnu Prakash return qcom_adc5_hw_scale(common_props->scale_fn_type,
739*baff4517SJishnu Prakash common_props->prescale,
740*baff4517SJishnu Prakash adc->data, code, val);
741*baff4517SJishnu Prakash }
742*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_therm_code_to_temp, "QCOM_SPMI_ADC5_GEN3");
743*baff4517SJishnu Prakash
adc5_gen3_register_tm_event_notifier(struct device * dev,void (* handler)(struct auxiliary_device *))744*baff4517SJishnu Prakash void adc5_gen3_register_tm_event_notifier(struct device *dev,
745*baff4517SJishnu Prakash void (*handler)(struct auxiliary_device *))
746*baff4517SJishnu Prakash {
747*baff4517SJishnu Prakash struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
748*baff4517SJishnu Prakash struct adc5_chip *adc = iio_priv(indio_dev);
749*baff4517SJishnu Prakash
750*baff4517SJishnu Prakash adc->handler = handler;
751*baff4517SJishnu Prakash }
752*baff4517SJishnu Prakash EXPORT_SYMBOL_NS_GPL(adc5_gen3_register_tm_event_notifier, "QCOM_SPMI_ADC5_GEN3");
753*baff4517SJishnu Prakash
adc5_gen3_probe(struct platform_device * pdev)754*baff4517SJishnu Prakash static int adc5_gen3_probe(struct platform_device *pdev)
755*baff4517SJishnu Prakash {
756*baff4517SJishnu Prakash struct device *dev = &pdev->dev;
757*baff4517SJishnu Prakash struct iio_dev *indio_dev;
758*baff4517SJishnu Prakash struct adc5_chip *adc;
759*baff4517SJishnu Prakash struct regmap *regmap;
760*baff4517SJishnu Prakash int ret, i;
761*baff4517SJishnu Prakash u32 *reg;
762*baff4517SJishnu Prakash
763*baff4517SJishnu Prakash regmap = dev_get_regmap(dev->parent, NULL);
764*baff4517SJishnu Prakash if (!regmap)
765*baff4517SJishnu Prakash return -ENODEV;
766*baff4517SJishnu Prakash
767*baff4517SJishnu Prakash indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
768*baff4517SJishnu Prakash if (!indio_dev)
769*baff4517SJishnu Prakash return -ENOMEM;
770*baff4517SJishnu Prakash
771*baff4517SJishnu Prakash adc = iio_priv(indio_dev);
772*baff4517SJishnu Prakash adc->dev_data.regmap = regmap;
773*baff4517SJishnu Prakash adc->dev = dev;
774*baff4517SJishnu Prakash
775*baff4517SJishnu Prakash ret = device_property_count_u32(dev, "reg");
776*baff4517SJishnu Prakash if (ret < 0)
777*baff4517SJishnu Prakash return ret;
778*baff4517SJishnu Prakash
779*baff4517SJishnu Prakash adc->dev_data.num_sdams = ret;
780*baff4517SJishnu Prakash
781*baff4517SJishnu Prakash reg = devm_kcalloc(dev, adc->dev_data.num_sdams, sizeof(u32),
782*baff4517SJishnu Prakash GFP_KERNEL);
783*baff4517SJishnu Prakash if (!reg)
784*baff4517SJishnu Prakash return -ENOMEM;
785*baff4517SJishnu Prakash
786*baff4517SJishnu Prakash ret = device_property_read_u32_array(dev, "reg", reg,
787*baff4517SJishnu Prakash adc->dev_data.num_sdams);
788*baff4517SJishnu Prakash if (ret)
789*baff4517SJishnu Prakash return dev_err_probe(dev, ret,
790*baff4517SJishnu Prakash "Failed to read reg property\n");
791*baff4517SJishnu Prakash
792*baff4517SJishnu Prakash adc->dev_data.base = devm_kcalloc(dev, adc->dev_data.num_sdams,
793*baff4517SJishnu Prakash sizeof(*adc->dev_data.base),
794*baff4517SJishnu Prakash GFP_KERNEL);
795*baff4517SJishnu Prakash if (!adc->dev_data.base)
796*baff4517SJishnu Prakash return -ENOMEM;
797*baff4517SJishnu Prakash
798*baff4517SJishnu Prakash platform_set_drvdata(pdev, indio_dev);
799*baff4517SJishnu Prakash init_completion(&adc->complete);
800*baff4517SJishnu Prakash ret = devm_mutex_init(dev, &adc->lock);
801*baff4517SJishnu Prakash if (ret)
802*baff4517SJishnu Prakash return ret;
803*baff4517SJishnu Prakash
804*baff4517SJishnu Prakash for (i = 0; i < adc->dev_data.num_sdams; i++) {
805*baff4517SJishnu Prakash adc->dev_data.base[i].base_addr = reg[i];
806*baff4517SJishnu Prakash
807*baff4517SJishnu Prakash ret = platform_get_irq(pdev, i);
808*baff4517SJishnu Prakash if (ret < 0)
809*baff4517SJishnu Prakash return dev_err_probe(dev, ret,
810*baff4517SJishnu Prakash "Getting IRQ %d failed\n", i);
811*baff4517SJishnu Prakash
812*baff4517SJishnu Prakash adc->dev_data.base[i].irq = ret;
813*baff4517SJishnu Prakash
814*baff4517SJishnu Prakash adc->dev_data.base[i].irq_name = devm_kasprintf(dev, GFP_KERNEL,
815*baff4517SJishnu Prakash "sdam%d", i);
816*baff4517SJishnu Prakash if (!adc->dev_data.base[i].irq_name)
817*baff4517SJishnu Prakash return -ENOMEM;
818*baff4517SJishnu Prakash }
819*baff4517SJishnu Prakash
820*baff4517SJishnu Prakash ret = devm_request_irq(dev, adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq,
821*baff4517SJishnu Prakash adc5_gen3_isr, 0,
822*baff4517SJishnu Prakash adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq_name,
823*baff4517SJishnu Prakash adc);
824*baff4517SJishnu Prakash if (ret)
825*baff4517SJishnu Prakash return dev_err_probe(dev, ret,
826*baff4517SJishnu Prakash "Failed to request SDAM%d irq\n",
827*baff4517SJishnu Prakash ADC5_GEN3_VADC_SDAM);
828*baff4517SJishnu Prakash
829*baff4517SJishnu Prakash ret = adc5_get_fw_data(adc);
830*baff4517SJishnu Prakash if (ret)
831*baff4517SJishnu Prakash return ret;
832*baff4517SJishnu Prakash
833*baff4517SJishnu Prakash if (adc->n_tm_channels > 0) {
834*baff4517SJishnu Prakash ret = adc5_gen3_add_aux_tm_device(adc);
835*baff4517SJishnu Prakash if (ret)
836*baff4517SJishnu Prakash dev_err_probe(dev, ret,
837*baff4517SJishnu Prakash "Failed to add auxiliary TM device\n");
838*baff4517SJishnu Prakash }
839*baff4517SJishnu Prakash
840*baff4517SJishnu Prakash indio_dev->name = "spmi-adc5-gen3";
841*baff4517SJishnu Prakash indio_dev->modes = INDIO_DIRECT_MODE;
842*baff4517SJishnu Prakash indio_dev->info = &adc5_gen3_info;
843*baff4517SJishnu Prakash indio_dev->channels = adc->iio_chans;
844*baff4517SJishnu Prakash indio_dev->num_channels = adc->nchannels;
845*baff4517SJishnu Prakash
846*baff4517SJishnu Prakash return devm_iio_device_register(dev, indio_dev);
847*baff4517SJishnu Prakash }
848*baff4517SJishnu Prakash
849*baff4517SJishnu Prakash static struct platform_driver adc5_gen3_driver = {
850*baff4517SJishnu Prakash .driver = {
851*baff4517SJishnu Prakash .name = "qcom-spmi-adc5-gen3",
852*baff4517SJishnu Prakash .of_match_table = adc5_match_table,
853*baff4517SJishnu Prakash },
854*baff4517SJishnu Prakash .probe = adc5_gen3_probe,
855*baff4517SJishnu Prakash };
856*baff4517SJishnu Prakash module_platform_driver(adc5_gen3_driver);
857*baff4517SJishnu Prakash
858*baff4517SJishnu Prakash MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 Gen3 ADC driver");
859*baff4517SJishnu Prakash MODULE_LICENSE("GPL");
860*baff4517SJishnu Prakash MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3");
861