xref: /linux/drivers/thermal/qcom/qcom-spmi-adc-tm5-gen3.c (revision b81e34131907d2c243c51117a4aff8dbe22ccc9c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4  */
5 
6 #include <linux/auxiliary_bus.h>
7 #include <linux/bitfield.h>
8 #include <linux/bits.h>
9 #include <linux/cleanup.h>
10 #include <linux/container_of.h>
11 #include <linux/device/devres.h>
12 #include <linux/dev_printk.h>
13 #include <linux/err.h>
14 #include <linux/iio/adc/qcom-adc5-gen3-common.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/thermal.h>
18 #include <linux/types.h>
19 #include <linux/unaligned.h>
20 
21 #include "../thermal_hwmon.h"
22 
23 #define ADC_TM5_GEN3_CONFIG_REGS 12
24 
25 struct device;
26 struct adc_tm5_gen3_chip;
27 
28 /**
29  * struct adc_tm5_gen3_channel_props - ADC_TM channel structure
30  * @common_props: structure with common ADC channel properties.
31  * @chip: ADC TM device.
32  * @tzd: pointer to thermal device corresponding to TM channel.
33  * @sdam_index: SDAM on which this TM channel lies.
34  * @timer: time period of recurring TM measurement.
35  * @tm_chan_index: TM channel number used.
36  * @high_thr_en: TM high threshold crossing detection enabled.
37  * @low_thr_en: TM low threshold crossing detection enabled.
38  */
39 struct adc_tm5_gen3_channel_props {
40 	struct adc5_channel_common_prop common_props;
41 	struct adc_tm5_gen3_chip *chip;
42 	struct thermal_zone_device *tzd;
43 	unsigned int sdam_index;
44 	unsigned int timer;
45 	unsigned int tm_chan_index;
46 	bool high_thr_en;
47 	bool low_thr_en;
48 };
49 
50 /**
51  * struct adc_tm5_gen3_chip - ADC Thermal Monitoring device structure
52  * @dev_data: Top-level ADC device data.
53  * @chan_props: Array of ADC_TM channel structures.
54  * @dev: SPMI ADC5 Gen3 device.
55  * @nchannels: number of TM channels allocated
56  */
57 struct adc_tm5_gen3_chip {
58 	struct adc5_device_data *dev_data;
59 	struct adc_tm5_gen3_channel_props *chan_props;
60 	struct device *dev;
61 	unsigned int nchannels;
62 };
63 
64 DEFINE_GUARD(adc5_gen3, struct adc_tm5_gen3_chip *,
65 	     adc5_gen3_mutex_lock(_T->dev), adc5_gen3_mutex_unlock(_T->dev))
66 
get_sdam_from_irq(struct adc_tm5_gen3_chip * adc_tm5,int irq)67 static int get_sdam_from_irq(struct adc_tm5_gen3_chip *adc_tm5, int irq)
68 {
69 	for (int i = 0; i < adc_tm5->dev_data->num_sdams; i++) {
70 		if (adc_tm5->dev_data->base[i].irq == irq)
71 			return i;
72 	}
73 	return -ENOENT;
74 }
75 
adctm5_gen3_isr(int irq,void * dev_id)76 static irqreturn_t adctm5_gen3_isr(int irq, void *dev_id)
77 {
78 	struct adc_tm5_gen3_chip *adc_tm5 = dev_id;
79 	int ret, sdam_num;
80 	u8 tm_status[2];
81 	u8 status, val;
82 
83 	sdam_num = get_sdam_from_irq(adc_tm5, irq);
84 	if (sdam_num < 0)
85 		return IRQ_NONE;
86 
87 	ret = adc5_gen3_read(adc_tm5->dev_data, sdam_num, ADC5_GEN3_STATUS1,
88 			     &status, sizeof(status));
89 	if (ret)
90 		return IRQ_NONE;
91 
92 	if (status & ADC5_GEN3_STATUS1_CONV_FAULT) {
93 		val = ADC5_GEN3_CONV_ERR_CLR_REQ;
94 		adc5_gen3_status_clear(adc_tm5->dev_data, sdam_num,
95 				       ADC5_GEN3_CONV_ERR_CLR, &val, 1);
96 		return IRQ_HANDLED;
97 	}
98 
99 	ret = adc5_gen3_read(adc_tm5->dev_data, sdam_num, ADC5_GEN3_TM_HIGH_STS,
100 			     tm_status, sizeof(tm_status));
101 	if (ret)
102 		return IRQ_NONE;
103 
104 	if (tm_status[0] || tm_status[1])
105 		return IRQ_WAKE_THREAD;
106 
107 	return IRQ_NONE;
108 }
109 
adctm5_gen3_isr_thread(int irq,void * dev_id)110 static irqreturn_t adctm5_gen3_isr_thread(int irq, void *dev_id)
111 {
112 	struct adc_tm5_gen3_chip *adc_tm5 = dev_id;
113 	u8 tm_status[2];
114 	int sdam_index;
115 
116 	sdam_index = get_sdam_from_irq(adc_tm5, irq);
117 	if (sdam_index < 0)
118 		return IRQ_NONE;
119 
120 	scoped_guard(adc5_gen3, adc_tm5) {
121 		int ret;
122 
123 		ret = adc5_gen3_read(adc_tm5->dev_data, sdam_index, ADC5_GEN3_TM_HIGH_STS,
124 				     tm_status, sizeof(tm_status));
125 		if (ret)
126 			return IRQ_NONE;
127 
128 		ret = adc5_gen3_status_clear(adc_tm5->dev_data, sdam_index,
129 					     ADC5_GEN3_TM_HIGH_STS_CLR, tm_status,
130 					     sizeof(tm_status));
131 		if (ret)
132 			return IRQ_NONE;
133 	}
134 
135 	for (int i = 0; i < adc_tm5->nchannels; i++) {
136 		struct adc_tm5_gen3_channel_props *chan_prop = &adc_tm5->chan_props[i];
137 		int offset = chan_prop->tm_chan_index;
138 		bool upper_set, lower_set;
139 
140 		if (chan_prop->sdam_index != sdam_index)
141 			continue;
142 
143 		upper_set = ((tm_status[0] & BIT(offset)) && chan_prop->high_thr_en);
144 		lower_set = ((tm_status[1] & BIT(offset)) && chan_prop->low_thr_en);
145 
146 		if (!(upper_set || lower_set))
147 			continue;
148 
149 		thermal_zone_device_update(chan_prop->tzd, THERMAL_TRIP_VIOLATED);
150 	}
151 
152 	return IRQ_HANDLED;
153 }
154 
adc_tm5_gen3_get_temp(struct thermal_zone_device * tz,int * temp)155 static int adc_tm5_gen3_get_temp(struct thermal_zone_device *tz, int *temp)
156 {
157 	struct adc_tm5_gen3_channel_props *prop = thermal_zone_device_priv(tz);
158 	struct adc_tm5_gen3_chip *adc_tm5;
159 
160 	if (!prop || !prop->chip)
161 		return -EINVAL;
162 
163 	adc_tm5 = prop->chip;
164 
165 	return adc5_gen3_get_scaled_reading(adc_tm5->dev, &prop->common_props, temp);
166 }
167 
adc_tm5_gen3_disable_channel(struct adc_tm5_gen3_channel_props * prop)168 static int adc_tm5_gen3_disable_channel(struct adc_tm5_gen3_channel_props *prop)
169 {
170 	struct adc_tm5_gen3_chip *adc_tm5 = prop->chip;
171 	int ret;
172 	u8 val;
173 
174 	prop->high_thr_en = false;
175 	prop->low_thr_en = false;
176 
177 	ret = adc5_gen3_poll_wait_hs(adc_tm5->dev_data, prop->sdam_index);
178 	if (ret)
179 		return ret;
180 
181 	val = BIT(prop->tm_chan_index);
182 	ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
183 			      ADC5_GEN3_TM_HIGH_STS_CLR, &val, sizeof(val));
184 	if (ret)
185 		return ret;
186 
187 	ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
188 			      ADC5_GEN3_TM_LOW_STS_CLR, &val, sizeof(val));
189 	if (ret)
190 		return ret;
191 
192 	val = MEAS_INT_DISABLE;
193 	ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
194 			      ADC5_GEN3_TIMER_SEL, &val, sizeof(val));
195 	if (ret)
196 		return ret;
197 
198 	/* To indicate there is an actual conversion request */
199 	val = ADC5_GEN3_CHAN_CONV_REQ | prop->tm_chan_index;
200 	ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
201 			      ADC5_GEN3_PERPH_CH, &val, sizeof(val));
202 	if (ret)
203 		return ret;
204 
205 	val = ADC5_GEN3_CONV_REQ_REQ;
206 	return adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
207 			       ADC5_GEN3_CONV_REQ, &val, sizeof(val));
208 }
209 
adc_tm5_gen3_configure(struct adc_tm5_gen3_channel_props * prop,int low_temp,int high_temp)210 static int adc_tm5_gen3_configure(struct adc_tm5_gen3_channel_props *prop,
211 				  int low_temp, int high_temp)
212 {
213 	struct adc_tm5_gen3_chip *adc_tm5 = prop->chip;
214 	u8 buf[ADC_TM5_GEN3_CONFIG_REGS];
215 	u8 conv_req;
216 	u16 adc_code;
217 	int ret;
218 
219 	ret = adc5_gen3_poll_wait_hs(adc_tm5->dev_data, prop->sdam_index);
220 	if (ret < 0)
221 		return ret;
222 
223 	ret = adc5_gen3_read(adc_tm5->dev_data, prop->sdam_index,
224 			     ADC5_GEN3_SID, buf, sizeof(buf));
225 	if (ret < 0)
226 		return ret;
227 
228 	/* Write SID */
229 	buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->common_props.sid);
230 
231 	/* Select TM channel and indicate there is an actual conversion request */
232 	buf[1] = ADC5_GEN3_CHAN_CONV_REQ | prop->tm_chan_index;
233 
234 	buf[2] = prop->timer;
235 
236 	/* Digital param selection */
237 	adc5_gen3_update_dig_param(&prop->common_props, &buf[3]);
238 
239 	/* Update fast average sample value */
240 	buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK,
241 			    prop->common_props.avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN;
242 
243 	/* Select ADC channel */
244 	buf[5] = prop->common_props.channel;
245 
246 	/* Select HW settle delay for channel */
247 	buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK,
248 			    prop->common_props.hw_settle_time_us);
249 
250 	buf[7] = 0;
251 
252 	/* High temperature corresponds to low voltage threshold */
253 	prop->low_thr_en = (high_temp != INT_MAX);
254 	if (prop->low_thr_en) {
255 		adc_code = qcom_adc_tm5_gen2_temp_res_scale(high_temp);
256 		put_unaligned_le16(adc_code, &buf[8]);
257 		buf[7] |= ADC5_GEN3_LOW_THR_INT_EN;
258 	}
259 
260 	/* Low temperature corresponds to high voltage threshold */
261 	prop->high_thr_en = (low_temp != -INT_MAX);
262 	if (prop->high_thr_en) {
263 		adc_code = qcom_adc_tm5_gen2_temp_res_scale(low_temp);
264 		put_unaligned_le16(adc_code, &buf[10]);
265 		buf[7] |= ADC5_GEN3_HIGH_THR_INT_EN;
266 	}
267 
268 	ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index, ADC5_GEN3_SID,
269 			      buf, sizeof(buf));
270 	if (ret < 0)
271 		return ret;
272 
273 	conv_req = ADC5_GEN3_CONV_REQ_REQ;
274 	return adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
275 			       ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req));
276 }
277 
adc_tm5_gen3_set_trip_temp(struct thermal_zone_device * tz,int low_temp,int high_temp)278 static int adc_tm5_gen3_set_trip_temp(struct thermal_zone_device *tz,
279 				      int low_temp, int high_temp)
280 {
281 	struct adc_tm5_gen3_channel_props *prop = thermal_zone_device_priv(tz);
282 	struct adc_tm5_gen3_chip *adc_tm5;
283 
284 	if (!prop || !prop->chip)
285 		return -EINVAL;
286 
287 	adc_tm5 = prop->chip;
288 
289 	dev_dbg(adc_tm5->dev, "channel:%s, low_temp(mdegC):%d, high_temp(mdegC):%d\n",
290 		prop->common_props.label, low_temp, high_temp);
291 
292 	guard(adc5_gen3)(adc_tm5);
293 
294 	return adc_tm5_gen3_configure(prop, low_temp, high_temp);
295 }
296 
297 static const struct thermal_zone_device_ops adc_tm_ops = {
298 	.get_temp = adc_tm5_gen3_get_temp,
299 	.set_trips = adc_tm5_gen3_set_trip_temp,
300 };
301 
adc_tm5_register_tzd(struct adc_tm5_gen3_chip * adc_tm5)302 static int adc_tm5_register_tzd(struct adc_tm5_gen3_chip *adc_tm5)
303 {
304 	struct thermal_zone_device *tzd;
305 	unsigned int channel;
306 	int ret;
307 
308 	for (int i = 0; i < adc_tm5->nchannels; i++) {
309 		channel = ADC5_GEN3_V_CHAN(adc_tm5->chan_props[i].common_props);
310 		tzd = devm_thermal_of_zone_register(adc_tm5->dev, channel,
311 						    &adc_tm5->chan_props[i],
312 						    &adc_tm_ops);
313 		if (IS_ERR(tzd)) {
314 			if (PTR_ERR(tzd) == -ENODEV) {
315 				dev_dbg(adc_tm5->dev,
316 					"thermal sensor on channel %d is not used\n",
317 					channel);
318 				continue;
319 			}
320 			return PTR_ERR(tzd);
321 		}
322 		adc_tm5->chan_props[i].tzd = tzd;
323 		ret = devm_thermal_add_hwmon_sysfs(adc_tm5->dev, tzd);
324 		if (ret)
325 			return ret;
326 	}
327 
328 	return 0;
329 }
330 
adc5_gen3_disable(void * data)331 static void adc5_gen3_disable(void *data)
332 {
333 	struct adc_tm5_gen3_chip *adc_tm5 = data;
334 
335 	guard(adc5_gen3)(adc_tm5);
336 
337 	/* Disable all available TM channels */
338 	for (int i = 0; i < adc_tm5->nchannels; i++)
339 		adc_tm5_gen3_disable_channel(&adc_tm5->chan_props[i]);
340 }
341 
adc_tm5_probe(struct auxiliary_device * aux_dev,const struct auxiliary_device_id * id)342 static int adc_tm5_probe(struct auxiliary_device *aux_dev,
343 			 const struct auxiliary_device_id *id)
344 {
345 	struct adc_tm5_gen3_chip *adc_tm5;
346 	struct tm5_aux_dev_wrapper *aux_dev_wrapper;
347 	struct device *dev = &aux_dev->dev;
348 	int ret;
349 
350 	adc_tm5 = devm_kzalloc(dev, sizeof(*adc_tm5), GFP_KERNEL);
351 	if (!adc_tm5)
352 		return -ENOMEM;
353 
354 	aux_dev_wrapper = container_of(aux_dev, struct tm5_aux_dev_wrapper, aux_dev);
355 
356 	adc_tm5->dev = dev;
357 	adc_tm5->dev_data = aux_dev_wrapper->dev_data;
358 	adc_tm5->nchannels = aux_dev_wrapper->n_tm_channels;
359 	adc_tm5->chan_props = devm_kcalloc(dev, aux_dev_wrapper->n_tm_channels,
360 					   sizeof(*adc_tm5->chan_props), GFP_KERNEL);
361 	if (!adc_tm5->chan_props)
362 		return -ENOMEM;
363 
364 	for (int i = 0; i < adc_tm5->nchannels; i++) {
365 		/*
366 		 * Since the first channel of the first SDAM is reserved for
367 		 * immediate ADC conversions, TM channel count must start from
368 		 * the channel just after it. The variable tm_count is used to
369 		 * calculate SDAM and TM channel index on that SDAM correctly
370 		 * for each TM channel.
371 		 */
372 		int tm_count = i + 1;
373 
374 		adc_tm5->chan_props[i].common_props = aux_dev_wrapper->tm_props[i];
375 		adc_tm5->chan_props[i].timer = MEAS_INT_1S;
376 		adc_tm5->chan_props[i].sdam_index = tm_count / 8;
377 		adc_tm5->chan_props[i].tm_chan_index = tm_count % 8;
378 		adc_tm5->chan_props[i].chip = adc_tm5;
379 	}
380 
381 	/*
382 	 * ADC_TM channels are enabled in the loop in adc_tm5_register_tzd() as
383 	 * part of the set_trips calls during thermal zone registration. This
384 	 * action is to disable them all in case of probe failure.
385 	 */
386 	ret = devm_add_action(dev, adc5_gen3_disable, adc_tm5);
387 	if (ret)
388 		return ret;
389 
390 	ret = adc_tm5_register_tzd(adc_tm5);
391 	if (ret)
392 		return ret;
393 
394 	for (int i = 0; i < adc_tm5->dev_data->num_sdams; i++) {
395 		u32 irq_flags = IRQF_ONESHOT;
396 
397 		/*
398 		 * First SDAM's interrupt is shared between main ADC driver and
399 		 * auxiliary TM driver, so its flags must include IRQF_SHARED.
400 		 * This is not needed for other SDAMs as they will be used only
401 		 * for TM functionality.
402 		 */
403 		if (i == 0)
404 			irq_flags |= IRQF_SHARED;
405 
406 		ret = devm_request_threaded_irq(dev,
407 						adc_tm5->dev_data->base[i].irq,
408 						adctm5_gen3_isr,
409 						adctm5_gen3_isr_thread,
410 						irq_flags,
411 						adc_tm5->dev_data->base[i].irq_name,
412 						adc_tm5);
413 		if (ret < 0)
414 			return ret;
415 	}
416 
417 	return 0;
418 }
419 
420 static const struct auxiliary_device_id adctm5_auxiliary_id_table[] = {
421 	{ .name = "qcom_spmi_adc5_gen3.adc5_tm_gen3" },
422 	{ }
423 };
424 MODULE_DEVICE_TABLE(auxiliary, adctm5_auxiliary_id_table);
425 
426 static struct auxiliary_driver adctm5gen3_auxiliary_driver = {
427 	.id_table = adctm5_auxiliary_id_table,
428 	.probe = adc_tm5_probe,
429 };
430 module_auxiliary_driver(adctm5gen3_auxiliary_driver);
431 
432 MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver");
433 MODULE_LICENSE("GPL");
434 MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3");
435