0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/errno.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/module.h>
0024 #include <linux/of.h>
0025 #include <linux/platform_device.h>
0026 #include <linux/regmap.h>
0027 #include <linux/thermal.h>
0028 #include <linux/workqueue.h>
0029
0030 #include <linux/mfd/da9062/core.h>
0031 #include <linux/mfd/da9062/registers.h>
0032
0033
0034
0035
0036
0037
0038 #define DA9062_DEFAULT_POLLING_MS_PERIOD 3000
0039 #define DA9062_MAX_POLLING_MS_PERIOD 10000
0040 #define DA9062_MIN_POLLING_MS_PERIOD 1000
0041
0042 #define DA9062_MILLI_CELSIUS(t) ((t) * 1000)
0043
0044 struct da9062_thermal_config {
0045 const char *name;
0046 };
0047
0048 struct da9062_thermal {
0049 struct da9062 *hw;
0050 struct delayed_work work;
0051 struct thermal_zone_device *zone;
0052 struct mutex lock;
0053 int temperature;
0054 int irq;
0055 const struct da9062_thermal_config *config;
0056 struct device *dev;
0057 };
0058
0059 static void da9062_thermal_poll_on(struct work_struct *work)
0060 {
0061 struct da9062_thermal *thermal = container_of(work,
0062 struct da9062_thermal,
0063 work.work);
0064 unsigned long delay;
0065 unsigned int val;
0066 int ret;
0067
0068
0069 ret = regmap_write(thermal->hw->regmap,
0070 DA9062AA_EVENT_B,
0071 DA9062AA_E_TEMP_MASK);
0072 if (ret < 0) {
0073 dev_err(thermal->dev,
0074 "Cannot clear the TJUNC temperature status\n");
0075 goto err_enable_irq;
0076 }
0077
0078
0079
0080
0081
0082 ret = regmap_read(thermal->hw->regmap,
0083 DA9062AA_EVENT_B,
0084 &val);
0085 if (ret < 0) {
0086 dev_err(thermal->dev,
0087 "Cannot check the TJUNC temperature status\n");
0088 goto err_enable_irq;
0089 }
0090
0091 if (val & DA9062AA_E_TEMP_MASK) {
0092 mutex_lock(&thermal->lock);
0093 thermal->temperature = DA9062_MILLI_CELSIUS(125);
0094 mutex_unlock(&thermal->lock);
0095 thermal_zone_device_update(thermal->zone,
0096 THERMAL_EVENT_UNSPECIFIED);
0097
0098 delay = thermal->zone->passive_delay_jiffies;
0099 queue_delayed_work(system_freezable_wq, &thermal->work, delay);
0100 return;
0101 }
0102
0103 mutex_lock(&thermal->lock);
0104 thermal->temperature = DA9062_MILLI_CELSIUS(0);
0105 mutex_unlock(&thermal->lock);
0106 thermal_zone_device_update(thermal->zone,
0107 THERMAL_EVENT_UNSPECIFIED);
0108
0109 err_enable_irq:
0110 enable_irq(thermal->irq);
0111 }
0112
0113 static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
0114 {
0115 struct da9062_thermal *thermal = data;
0116
0117 disable_irq_nosync(thermal->irq);
0118 queue_delayed_work(system_freezable_wq, &thermal->work, 0);
0119
0120 return IRQ_HANDLED;
0121 }
0122
0123 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
0124 int trip,
0125 enum thermal_trip_type *type)
0126 {
0127 struct da9062_thermal *thermal = z->devdata;
0128
0129 switch (trip) {
0130 case 0:
0131 *type = THERMAL_TRIP_HOT;
0132 break;
0133 default:
0134 dev_err(thermal->dev,
0135 "Driver does not support more than 1 trip-wire\n");
0136 return -EINVAL;
0137 }
0138
0139 return 0;
0140 }
0141
0142 static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
0143 int trip,
0144 int *temp)
0145 {
0146 struct da9062_thermal *thermal = z->devdata;
0147
0148 switch (trip) {
0149 case 0:
0150 *temp = DA9062_MILLI_CELSIUS(125);
0151 break;
0152 default:
0153 dev_err(thermal->dev,
0154 "Driver does not support more than 1 trip-wire\n");
0155 return -EINVAL;
0156 }
0157
0158 return 0;
0159 }
0160
0161 static int da9062_thermal_get_temp(struct thermal_zone_device *z,
0162 int *temp)
0163 {
0164 struct da9062_thermal *thermal = z->devdata;
0165
0166 mutex_lock(&thermal->lock);
0167 *temp = thermal->temperature;
0168 mutex_unlock(&thermal->lock);
0169
0170 return 0;
0171 }
0172
0173 static struct thermal_zone_device_ops da9062_thermal_ops = {
0174 .get_temp = da9062_thermal_get_temp,
0175 .get_trip_type = da9062_thermal_get_trip_type,
0176 .get_trip_temp = da9062_thermal_get_trip_temp,
0177 };
0178
0179 static const struct da9062_thermal_config da9062_config = {
0180 .name = "da9062-thermal",
0181 };
0182
0183 static const struct of_device_id da9062_compatible_reg_id_table[] = {
0184 { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
0185 { },
0186 };
0187
0188 MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
0189
0190 static int da9062_thermal_probe(struct platform_device *pdev)
0191 {
0192 struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
0193 struct da9062_thermal *thermal;
0194 unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
0195 const struct of_device_id *match;
0196 int ret = 0;
0197
0198 match = of_match_node(da9062_compatible_reg_id_table,
0199 pdev->dev.of_node);
0200 if (!match)
0201 return -ENXIO;
0202
0203 if (pdev->dev.of_node) {
0204 if (!of_property_read_u32(pdev->dev.of_node,
0205 "polling-delay-passive",
0206 &pp_tmp)) {
0207 if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
0208 pp_tmp > DA9062_MAX_POLLING_MS_PERIOD) {
0209 dev_warn(&pdev->dev,
0210 "Out-of-range polling period %d ms\n",
0211 pp_tmp);
0212 pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
0213 }
0214 }
0215 }
0216
0217 thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
0218 GFP_KERNEL);
0219 if (!thermal) {
0220 ret = -ENOMEM;
0221 goto err;
0222 }
0223
0224 thermal->config = match->data;
0225 thermal->hw = chip;
0226 thermal->dev = &pdev->dev;
0227
0228 INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
0229 mutex_init(&thermal->lock);
0230
0231 thermal->zone = thermal_zone_device_register(thermal->config->name,
0232 1, 0, thermal,
0233 &da9062_thermal_ops, NULL, pp_tmp,
0234 0);
0235 if (IS_ERR(thermal->zone)) {
0236 dev_err(&pdev->dev, "Cannot register thermal zone device\n");
0237 ret = PTR_ERR(thermal->zone);
0238 goto err;
0239 }
0240 ret = thermal_zone_device_enable(thermal->zone);
0241 if (ret) {
0242 dev_err(&pdev->dev, "Cannot enable thermal zone device\n");
0243 goto err_zone;
0244 }
0245
0246 dev_dbg(&pdev->dev,
0247 "TJUNC temperature polling period set at %d ms\n",
0248 jiffies_to_msecs(thermal->zone->passive_delay_jiffies));
0249
0250 ret = platform_get_irq_byname(pdev, "THERMAL");
0251 if (ret < 0) {
0252 dev_err(&pdev->dev, "Failed to get platform IRQ.\n");
0253 goto err_zone;
0254 }
0255 thermal->irq = ret;
0256
0257 ret = request_threaded_irq(thermal->irq, NULL,
0258 da9062_thermal_irq_handler,
0259 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
0260 "THERMAL", thermal);
0261 if (ret) {
0262 dev_err(&pdev->dev,
0263 "Failed to request thermal device IRQ.\n");
0264 goto err_zone;
0265 }
0266
0267 platform_set_drvdata(pdev, thermal);
0268 return 0;
0269
0270 err_zone:
0271 thermal_zone_device_unregister(thermal->zone);
0272 err:
0273 return ret;
0274 }
0275
0276 static int da9062_thermal_remove(struct platform_device *pdev)
0277 {
0278 struct da9062_thermal *thermal = platform_get_drvdata(pdev);
0279
0280 free_irq(thermal->irq, thermal);
0281 cancel_delayed_work_sync(&thermal->work);
0282 thermal_zone_device_unregister(thermal->zone);
0283 return 0;
0284 }
0285
0286 static struct platform_driver da9062_thermal_driver = {
0287 .probe = da9062_thermal_probe,
0288 .remove = da9062_thermal_remove,
0289 .driver = {
0290 .name = "da9062-thermal",
0291 .of_match_table = da9062_compatible_reg_id_table,
0292 },
0293 };
0294
0295 module_platform_driver(da9062_thermal_driver);
0296
0297 MODULE_AUTHOR("Steve Twiss");
0298 MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");
0299 MODULE_LICENSE("GPL");
0300 MODULE_ALIAS("platform:da9062-thermal");