cregit-Linux how code gets into the kernel

Release 4.10 drivers/thermal/hisi_thermal.c

Directory: drivers/thermal
/*
 * Hisilicon thermal sensor driver
 *
 * Copyright (c) 2014-2015 Hisilicon Limited.
 * Copyright (c) 2014-2015 Linaro Limited.
 *
 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
 * Leo Yan <leo.yan@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>

#include "thermal_core.h"


#define TEMP0_TH			(0x4)

#define TEMP0_RST_TH			(0x8)

#define TEMP0_CFG			(0xC)

#define TEMP0_EN			(0x10)

#define TEMP0_INT_EN			(0x14)

#define TEMP0_INT_CLR			(0x18)

#define TEMP0_RST_MSK			(0x1C)

#define TEMP0_VALUE			(0x28)


#define HISI_TEMP_BASE			(-60)

#define HISI_TEMP_RESET			(100000)


#define HISI_MAX_SENSORS		4


struct hisi_thermal_sensor {
	
struct hisi_thermal_data *thermal;
	
struct thermal_zone_device *tzd;

	
long sensor_temp;
	
uint32_t id;
	
uint32_t thres_temp;
};


struct hisi_thermal_data {
	
struct mutex thermal_lock;    /* protects register data */
	
struct platform_device *pdev;
	
struct clk *clk;
	
struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];

	

int irq, irq_bind_sensor;
	
bool irq_enabled;

	
void __iomem *regs;
};

/* in millicelsius */

static inline int _step_to_temp(int step) { /* * Every step equals (1 * 200) / 255 celsius, and finally * need convert to millicelsius. */ return (HISI_TEMP_BASE * 1000 + (step * 200000 / 255)); }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei2388.46%150.00%
leo yanleo yan311.54%150.00%
Total26100.00%2100.00%


static inline long _temp_to_step(long temp) { return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei2184.00%150.00%
leo yanleo yan416.00%150.00%
Total25100.00%2100.00%


static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data, struct hisi_thermal_sensor *sensor) { long val; mutex_lock(&data->thermal_lock); /* disable interrupt */ writel(0x0, data->regs + TEMP0_INT_EN); writel(0x1, data->regs + TEMP0_INT_CLR); /* disable module firstly */ writel(0x0, data->regs + TEMP0_EN); /* select sensor id */ writel((sensor->id << 12), data->regs + TEMP0_CFG); /* enable module */ writel(0x1, data->regs + TEMP0_EN); usleep_range(3000, 5000); val = readl(data->regs + TEMP0_VALUE); val = _step_to_temp(val); mutex_unlock(&data->thermal_lock); return val; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei128100.00%1100.00%
Total128100.00%1100.00%


static void hisi_thermal_enable_bind_irq_sensor (struct hisi_thermal_data *data) { struct hisi_thermal_sensor *sensor; mutex_lock(&data->thermal_lock); sensor = &data->sensors[data->irq_bind_sensor]; /* setting the hdak time */ writel(0x0, data->regs + TEMP0_CFG); /* disable module firstly */ writel(0x0, data->regs + TEMP0_RST_MSK); writel(0x0, data->regs + TEMP0_EN); /* select sensor id */ writel((sensor->id << 12), data->regs + TEMP0_CFG); /* enable for interrupt */ writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00, data->regs + TEMP0_TH); writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH); /* enable module */ writel(0x1, data->regs + TEMP0_RST_MSK); writel(0x1, data->regs + TEMP0_EN); writel(0x0, data->regs + TEMP0_INT_CLR); writel(0x1, data->regs + TEMP0_INT_EN); usleep_range(3000, 5000); mutex_unlock(&data->thermal_lock); }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei182100.00%1100.00%
Total182100.00%1100.00%


static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data) { mutex_lock(&data->thermal_lock); /* disable sensor module */ writel(0x0, data->regs + TEMP0_INT_EN); writel(0x0, data->regs + TEMP0_RST_MSK); writel(0x0, data->regs + TEMP0_EN); mutex_unlock(&data->thermal_lock); }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei61100.00%1100.00%
Total61100.00%1100.00%


static int hisi_thermal_get_temp(void *_sensor, int *temp) { struct hisi_thermal_sensor *sensor = _sensor; struct hisi_thermal_data *data = sensor->thermal; int sensor_id = -1, i; long max_temp = 0; *temp = hisi_thermal_get_sensor_temp(data, sensor); sensor->sensor_temp = *temp; for (i = 0; i < HISI_MAX_SENSORS; i++) { if (!data->sensors[i].tzd) continue; if (data->sensors[i].sensor_temp >= max_temp) { max_temp = data->sensors[i].sensor_temp; sensor_id = i; } } /* If no sensor has been enabled, then skip to enable irq */ if (sensor_id == -1) return 0; mutex_lock(&data->thermal_lock); data->irq_bind_sensor = sensor_id; mutex_unlock(&data->thermal_lock); dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n", sensor->id, data->irq_enabled, *temp, sensor->thres_temp); /* * Bind irq to sensor for two cases: * Reenable alarm IRQ if temperature below threshold; * if irq has been enabled, always set it; */ if (data->irq_enabled) { hisi_thermal_enable_bind_irq_sensor(data); return 0; } if (max_temp < sensor->thres_temp) { data->irq_enabled = true; hisi_thermal_enable_bind_irq_sensor(data); enable_irq(data->irq); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei19887.61%133.33%
leo yanleo yan2611.50%133.33%
sascha hauersascha hauer20.88%133.33%
Total226100.00%3100.00%

static struct thermal_zone_of_device_ops hisi_of_thermal_ops = { .get_temp = hisi_thermal_get_temp, };
static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev) { struct hisi_thermal_data *data = dev; disable_irq_nosync(irq); data->irq_enabled = false; return IRQ_WAKE_THREAD; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei34100.00%1100.00%
Total34100.00%1100.00%


static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) { struct hisi_thermal_data *data = dev; struct hisi_thermal_sensor *sensor; int i; mutex_lock(&data->thermal_lock); sensor = &data->sensors[data->irq_bind_sensor]; dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n", sensor->thres_temp / 1000); mutex_unlock(&data->thermal_lock); for (i = 0; i < HISI_MAX_SENSORS; i++) { if (!data->sensors[i].tzd) continue; thermal_zone_device_update(data->sensors[i].tzd, THERMAL_EVENT_UNSPECIFIED); } return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei10285.71%133.33%
leo yanleo yan1512.61%133.33%
srinivas pandruvadasrinivas pandruvada21.68%133.33%
Total119100.00%3100.00%


static int hisi_thermal_register_sensor(struct platform_device *pdev, struct hisi_thermal_data *data, struct hisi_thermal_sensor *sensor, int index) { int ret, i; const struct thermal_trip *trip; sensor->id = index; sensor->thermal = data; sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, sensor->id, sensor, &hisi_of_thermal_ops); if (IS_ERR(sensor->tzd)) { ret = PTR_ERR(sensor->tzd); sensor->tzd = NULL; dev_err(&pdev->dev, "failed to register sensor id %d: %d\n", sensor->id, ret); return ret; } trip = of_thermal_get_trip_points(sensor->tzd); for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) { if (trip[i].type == THERMAL_TRIP_PASSIVE) { sensor->thres_temp = trip[i].temperature; break; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei16395.88%133.33%
leo yanleo yan63.53%133.33%
eduardo valentineduardo valentin10.59%133.33%
Total170100.00%3100.00%

static const struct of_device_id of_hisi_thermal_match[] = { { .compatible = "hisilicon,tsensor" }, { /* end */ } }; MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor, bool on) { struct thermal_zone_device *tzd = sensor->tzd; tzd->ops->set_mode(tzd, on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei38100.00%1100.00%
Total38100.00%1100.00%


static int hisi_thermal_probe(struct platform_device *pdev) { struct hisi_thermal_data *data; struct resource *res; int i; int ret; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; mutex_init(&data->thermal_lock); data->pdev = pdev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(data->regs)) { dev_err(&pdev->dev, "failed to get io address\n"); return PTR_ERR(data->regs); } data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) return data->irq; ret = devm_request_threaded_irq(&pdev->dev, data->irq, hisi_thermal_alarm_irq, hisi_thermal_alarm_irq_thread, 0, "hisi_thermal", data); if (ret < 0) { dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); return ret; } platform_set_drvdata(pdev, data); data->clk = devm_clk_get(&pdev->dev, "thermal_clk"); if (IS_ERR(data->clk)) { ret = PTR_ERR(data->clk); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "failed to get thermal clk: %d\n", ret); return ret; } /* enable clock for thermal */ ret = clk_prepare_enable(data->clk); if (ret) { dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret); return ret; } hisi_thermal_enable_bind_irq_sensor(data); irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED, &data->irq_enabled); for (i = 0; i < HISI_MAX_SENSORS; ++i) { ret = hisi_thermal_register_sensor(pdev, data, &data->sensors[i], i); if (ret) dev_err(&pdev->dev, "failed to register thermal sensor: %d\n", ret); else hisi_thermal_toggle_sensor(&data->sensors[i], true); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei35194.10%133.33%
leo yanleo yan225.90%266.67%
Total373100.00%3100.00%


static int hisi_thermal_remove(struct platform_device *pdev) { struct hisi_thermal_data *data = platform_get_drvdata(pdev); int i; for (i = 0; i < HISI_MAX_SENSORS; i++) { struct hisi_thermal_sensor *sensor = &data->sensors[i]; if (!sensor->tzd) continue; hisi_thermal_toggle_sensor(sensor, false); } hisi_thermal_disable_sensor(data); clk_disable_unprepare(data->clk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei7490.24%150.00%
leo yanleo yan89.76%150.00%
Total82100.00%2100.00%

#ifdef CONFIG_PM_SLEEP
static int hisi_thermal_suspend(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); hisi_thermal_disable_sensor(data); data->irq_enabled = false; clk_disable_unprepare(data->clk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei42100.00%1100.00%
Total42100.00%1100.00%


static int hisi_thermal_resume(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); clk_prepare_enable(data->clk); data->irq_enabled = true; hisi_thermal_enable_bind_irq_sensor(data); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei42100.00%1100.00%
Total42100.00%1100.00%

#endif static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops, hisi_thermal_suspend, hisi_thermal_resume); static struct platform_driver hisi_thermal_driver = { .driver = { .name = "hisi_thermal", .pm = &hisi_thermal_pm_ops, .of_match_table = of_hisi_thermal_match, }, .probe = hisi_thermal_probe, .remove = hisi_thermal_remove, }; module_platform_driver(hisi_thermal_driver); MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); MODULE_DESCRIPTION("Hisilicon thermal driver"); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
kong xinweikong xinwei170795.04%114.29%
leo yanleo yan844.68%342.86%
srinivas pandruvadasrinivas pandruvada20.11%114.29%
sascha hauersascha hauer20.11%114.29%
eduardo valentineduardo valentin10.06%114.29%
Total1796100.00%7100.00%
Directory: drivers/thermal
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.