^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Thermal device driver for DA9062 and DA9061
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Dialog Semiconductor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /* When over-temperature is reached, an interrupt from the device will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * triggered. Following this event the interrupt will be disabled and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * periodic transmission of uevents (HOT trip point) should define the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * first level of temperature supervision. It is expected that any final
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * implementation of the thermal driver will include a .notify() function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * to implement these uevents to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * These uevents are intended to indicate non-invasive temperature control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * of the system, where the necessary measures for cooling are the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * responsibility of the host software. Once the temperature falls again,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * the IRQ is re-enabled so the start of a new over-temperature event can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * be detected without constant software monitoring.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mfd/da9062/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/mfd/da9062/registers.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* Minimum, maximum and default polling millisecond periods are provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * here as an example. It is expected that any final implementation to also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * include a modification of these settings to match the required
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * application.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define DA9062_DEFAULT_POLLING_MS_PERIOD 3000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define DA9062_MAX_POLLING_MS_PERIOD 10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define DA9062_MIN_POLLING_MS_PERIOD 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define DA9062_MILLI_CELSIUS(t) ((t) * 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct da9062_thermal_config {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct da9062_thermal {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct da9062 *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct delayed_work work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct thermal_zone_device *zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct mutex lock; /* protection for da9062_thermal temperature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) const struct da9062_thermal_config *config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void da9062_thermal_poll_on(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct da9062_thermal *thermal = container_of(work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct da9062_thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* clear E_TEMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ret = regmap_write(thermal->hw->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) DA9062AA_EVENT_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) DA9062AA_E_TEMP_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) dev_err(thermal->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) "Cannot clear the TJUNC temperature status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) goto err_enable_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Now read E_TEMP again: it is acting like a status bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * If over-temperature, then this status will be true.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * If not over-temperature, this status will be false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ret = regmap_read(thermal->hw->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) DA9062AA_EVENT_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) dev_err(thermal->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "Cannot check the TJUNC temperature status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) goto err_enable_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (val & DA9062AA_E_TEMP_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) mutex_lock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) thermal->temperature = DA9062_MILLI_CELSIUS(125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) mutex_unlock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) thermal_zone_device_update(thermal->zone,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) THERMAL_EVENT_UNSPECIFIED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) delay = msecs_to_jiffies(thermal->zone->passive_delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) queue_delayed_work(system_freezable_wq, &thermal->work, delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) mutex_lock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) thermal->temperature = DA9062_MILLI_CELSIUS(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mutex_unlock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) thermal_zone_device_update(thermal->zone,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) THERMAL_EVENT_UNSPECIFIED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) err_enable_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) enable_irq(thermal->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct da9062_thermal *thermal = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) disable_irq_nosync(thermal->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) queue_delayed_work(system_freezable_wq, &thermal->work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) int trip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) enum thermal_trip_type *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct da9062_thermal *thermal = z->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) switch (trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *type = THERMAL_TRIP_HOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev_err(thermal->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) "Driver does not support more than 1 trip-wire\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int trip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct da9062_thermal *thermal = z->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) switch (trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) *temp = DA9062_MILLI_CELSIUS(125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dev_err(thermal->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) "Driver does not support more than 1 trip-wire\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int da9062_thermal_get_temp(struct thermal_zone_device *z,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct da9062_thermal *thermal = z->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) mutex_lock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *temp = thermal->temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) mutex_unlock(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static struct thermal_zone_device_ops da9062_thermal_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .get_temp = da9062_thermal_get_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .get_trip_type = da9062_thermal_get_trip_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .get_trip_temp = da9062_thermal_get_trip_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static const struct da9062_thermal_config da9062_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .name = "da9062-thermal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static const struct of_device_id da9062_compatible_reg_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int da9062_thermal_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct da9062_thermal *thermal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) match = of_match_node(da9062_compatible_reg_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) pdev->dev.of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (pdev->dev.of_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (!of_property_read_u32(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) "polling-delay-passive",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) &pp_tmp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) pp_tmp > DA9062_MAX_POLLING_MS_PERIOD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) dev_warn(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) "Out-of-range polling period %d ms\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pp_tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!thermal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) thermal->config = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) thermal->hw = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) thermal->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) mutex_init(&thermal->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) thermal->zone = thermal_zone_device_register(thermal->config->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 1, 0, thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) &da9062_thermal_ops, NULL, pp_tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (IS_ERR(thermal->zone)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) dev_err(&pdev->dev, "Cannot register thermal zone device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ret = PTR_ERR(thermal->zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ret = thermal_zone_device_enable(thermal->zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dev_err(&pdev->dev, "Cannot enable thermal zone device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) goto err_zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) "TJUNC temperature polling period set at %d ms\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) thermal->zone->passive_delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ret = platform_get_irq_byname(pdev, "THERMAL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(&pdev->dev, "Failed to get platform IRQ.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto err_zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) thermal->irq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) ret = request_threaded_irq(thermal->irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) da9062_thermal_irq_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) IRQF_TRIGGER_LOW | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) "THERMAL", thermal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) "Failed to request thermal device IRQ.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) goto err_zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) platform_set_drvdata(pdev, thermal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) err_zone:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) thermal_zone_device_unregister(thermal->zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static int da9062_thermal_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct da9062_thermal *thermal = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) free_irq(thermal->irq, thermal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) cancel_delayed_work_sync(&thermal->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) thermal_zone_device_unregister(thermal->zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static struct platform_driver da9062_thermal_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .probe = da9062_thermal_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .remove = da9062_thermal_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .name = "da9062-thermal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) .of_match_table = da9062_compatible_reg_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) module_platform_driver(da9062_thermal_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) MODULE_AUTHOR("Steve Twiss");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) MODULE_ALIAS("platform:da9062-thermal");