Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
  3 *
  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
 14#include <linux/delay.h>
 15#include <linux/err.h>
 16#include <linux/iio/consumer.h>
 17#include <linux/interrupt.h>
 18#include <linux/module.h>
 19#include <linux/of.h>
 20#include <linux/of_device.h>
 21#include <linux/platform_device.h>
 22#include <linux/regmap.h>
 23#include <linux/thermal.h>
 24
 25#define QPNP_TM_REG_TYPE		0x04
 26#define QPNP_TM_REG_SUBTYPE		0x05
 27#define QPNP_TM_REG_STATUS		0x08
 28#define QPNP_TM_REG_SHUTDOWN_CTRL1	0x40
 29#define QPNP_TM_REG_ALARM_CTRL		0x46
 30
 31#define QPNP_TM_TYPE			0x09
 32#define QPNP_TM_SUBTYPE			0x08
 33
 34#define STATUS_STAGE_MASK		0x03
 35
 36#define SHUTDOWN_CTRL1_THRESHOLD_MASK	0x03
 37
 38#define ALARM_CTRL_FORCE_ENABLE		0x80
 39
 40/*
 41 * Trip point values based on threshold control
 42 * 0 = {105 C, 125 C, 145 C}
 43 * 1 = {110 C, 130 C, 150 C}
 44 * 2 = {115 C, 135 C, 155 C}
 45 * 3 = {120 C, 140 C, 160 C}
 46*/
 47#define TEMP_STAGE_STEP			20000	/* Stage step: 20.000 C */
 48#define TEMP_STAGE_HYSTERESIS		2000
 49
 50#define TEMP_THRESH_MIN			105000	/* Threshold Min: 105 C */
 51#define TEMP_THRESH_STEP		5000	/* Threshold step: 5 C */
 52
 53#define THRESH_MIN			0
 54
 55/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
 56#define DEFAULT_TEMP			37000
 57
 58struct qpnp_tm_chip {
 59	struct regmap			*map;
 60	struct thermal_zone_device	*tz_dev;
 61	long				temp;
 62	unsigned int			thresh;
 63	unsigned int			stage;
 64	unsigned int			prev_stage;
 65	unsigned int			base;
 66	struct iio_channel		*adc;
 67};
 68
 69static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data)
 70{
 71	unsigned int val;
 72	int ret;
 73
 74	ret = regmap_read(chip->map, chip->base + addr, &val);
 75	if (ret < 0)
 76		return ret;
 77
 78	*data = val;
 79	return 0;
 80}
 81
 82static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
 83{
 84	return regmap_write(chip->map, chip->base + addr, data);
 85}
 86
 87/*
 88 * This function updates the internal temp value based on the
 89 * current thermal stage and threshold as well as the previous stage
 90 */
 91static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
 92{
 93	unsigned int stage;
 94	int ret;
 95	u8 reg = 0;
 96
 97	ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
 98	if (ret < 0)
 99		return ret;
100
101	stage = reg & STATUS_STAGE_MASK;
102
103	if (stage > chip->stage) {
104		/* increasing stage, use lower bound */
105		chip->temp = (stage - 1) * TEMP_STAGE_STEP +
106			     chip->thresh * TEMP_THRESH_STEP +
107			     TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
108	} else if (stage < chip->stage) {
109		/* decreasing stage, use upper bound */
110		chip->temp = stage * TEMP_STAGE_STEP +
111			     chip->thresh * TEMP_THRESH_STEP -
112			     TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
113	}
114
115	chip->stage = stage;
116
117	return 0;
118}
119
120static int qpnp_tm_get_temp(void *data, int *temp)
121{
122	struct qpnp_tm_chip *chip = data;
123	int ret, mili_celsius;
124
125	if (!temp)
126		return -EINVAL;
127
128	if (!chip->adc) {
129		ret = qpnp_tm_update_temp_no_adc(chip);
130		if (ret < 0)
131			return ret;
132	} else {
133		ret = iio_read_channel_processed(chip->adc, &mili_celsius);
134		if (ret < 0)
135			return ret;
136
137		chip->temp = mili_celsius;
138	}
139
140	*temp = chip->temp < 0 ? 0 : chip->temp;
141
142	return 0;
143}
144
145static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = {
146	.get_temp = qpnp_tm_get_temp,
147};
148
149static irqreturn_t qpnp_tm_isr(int irq, void *data)
150{
151	struct qpnp_tm_chip *chip = data;
152
153	thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED);
154
155	return IRQ_HANDLED;
156}
157
158/*
159 * This function initializes the internal temp value based on only the
160 * current thermal stage and threshold. Setup threshold control and
161 * disable shutdown override.
162 */
163static int qpnp_tm_init(struct qpnp_tm_chip *chip)
164{
165	int ret;
166	u8 reg;
167
168	chip->thresh = THRESH_MIN;
169	chip->temp = DEFAULT_TEMP;
170
171	ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
172	if (ret < 0)
173		return ret;
174
175	chip->stage = reg & STATUS_STAGE_MASK;
176
177	if (chip->stage)
178		chip->temp = chip->thresh * TEMP_THRESH_STEP +
179			     (chip->stage - 1) * TEMP_STAGE_STEP +
180			     TEMP_THRESH_MIN;
181
182	/*
183	 * Set threshold and disable software override of stage 2 and 3
184	 * shutdowns.
185	 */
186	reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
187	ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
188	if (ret < 0)
189		return ret;
190
191	/* Enable the thermal alarm PMIC module in always-on mode. */
192	reg = ALARM_CTRL_FORCE_ENABLE;
193	ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg);
194
195	return ret;
196}
197
198static int qpnp_tm_probe(struct platform_device *pdev)
199{
200	struct qpnp_tm_chip *chip;
201	struct device_node *node;
202	u8 type, subtype;
203	u32 res;
204	int ret, irq;
205
206	node = pdev->dev.of_node;
207
208	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
209	if (!chip)
210		return -ENOMEM;
211
212	dev_set_drvdata(&pdev->dev, chip);
213
214	chip->map = dev_get_regmap(pdev->dev.parent, NULL);
215	if (!chip->map)
216		return -ENXIO;
217
218	ret = of_property_read_u32(node, "reg", &res);
219	if (ret < 0)
220		return ret;
221
222	irq = platform_get_irq(pdev, 0);
223	if (irq < 0)
224		return irq;
225
226	/* ADC based measurements are optional */
227	chip->adc = devm_iio_channel_get(&pdev->dev, "thermal");
228	if (IS_ERR(chip->adc)) {
229		ret = PTR_ERR(chip->adc);
230		chip->adc = NULL;
231		if (ret == -EPROBE_DEFER)
232			return ret;
233	}
234
235	chip->base = res;
236
237	ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
238	if (ret < 0) {
239		dev_err(&pdev->dev, "could not read type\n");
240		return ret;
241	}
242
243	ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);
244	if (ret < 0) {
245		dev_err(&pdev->dev, "could not read subtype\n");
246		return ret;
247	}
248
249	if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
250		dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
251			type, subtype);
252		return -ENODEV;
253	}
254
255	ret = qpnp_tm_init(chip);
256	if (ret < 0) {
257		dev_err(&pdev->dev, "init failed\n");
258		return ret;
259	}
260
261	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
262					IRQF_ONESHOT, node->name, chip);
263	if (ret < 0)
264		return ret;
265
266	chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
267							&qpnp_tm_sensor_ops);
268	if (IS_ERR(chip->tz_dev)) {
269		dev_err(&pdev->dev, "failed to register sensor\n");
270		return PTR_ERR(chip->tz_dev);
271	}
272
273	return 0;
274}
275
276static const struct of_device_id qpnp_tm_match_table[] = {
277	{ .compatible = "qcom,spmi-temp-alarm" },
278	{ }
279};
280MODULE_DEVICE_TABLE(of, qpnp_tm_match_table);
281
282static struct platform_driver qpnp_tm_driver = {
283	.driver = {
284		.name = "spmi-temp-alarm",
285		.of_match_table = qpnp_tm_match_table,
286	},
287	.probe  = qpnp_tm_probe,
288};
289module_platform_driver(qpnp_tm_driver);
290
291MODULE_ALIAS("platform:spmi-temp-alarm");
292MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver");
293MODULE_LICENSE("GPL v2");