Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc7 109 lines 2.8 kB view raw
1#include <linux/io.h> 2#include <linux/delay.h> 3#include <linux/module.h> 4#include <linux/thermal.h> 5#include <linux/platform_device.h> 6 7/* 8 * According to a data sheet draft, "this temperature sensor uses a bandgap 9 * type of circuit to compare a voltage which has a negative temperature 10 * coefficient with a voltage that is proportional to absolute temperature. 11 * A resistor bank allows 41 different temperature thresholds to be selected 12 * and the logic output will then indicate whether the actual die temperature 13 * lies above or below the selected threshold." 14 */ 15 16#define TEMPSI_CMD 0 17#define TEMPSI_RES 4 18#define TEMPSI_CFG 8 19 20#define CMD_OFF 0 21#define CMD_ON 1 22#define CMD_READ 2 23 24#define IDX_MIN 15 25#define IDX_MAX 40 26 27struct tango_thermal_priv { 28 void __iomem *base; 29 int thresh_idx; 30}; 31 32static bool temp_above_thresh(void __iomem *base, int thresh_idx) 33{ 34 writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD); 35 usleep_range(10, 20); 36 writel(CMD_READ | thresh_idx << 8, base + TEMPSI_CMD); 37 38 return readl(base + TEMPSI_RES); 39} 40 41static int tango_get_temp(void *arg, int *res) 42{ 43 struct tango_thermal_priv *priv = arg; 44 int idx = priv->thresh_idx; 45 46 if (temp_above_thresh(priv->base, idx)) { 47 /* Search upward by incrementing thresh_idx */ 48 while (idx < IDX_MAX && temp_above_thresh(priv->base, ++idx)) 49 cpu_relax(); 50 idx = idx - 1; /* always return lower bound */ 51 } else { 52 /* Search downward by decrementing thresh_idx */ 53 while (idx > IDX_MIN && !temp_above_thresh(priv->base, --idx)) 54 cpu_relax(); 55 } 56 57 *res = (idx * 9 / 2 - 38) * 1000; /* millidegrees Celsius */ 58 priv->thresh_idx = idx; 59 60 return 0; 61} 62 63static const struct thermal_zone_of_device_ops ops = { 64 .get_temp = tango_get_temp, 65}; 66 67static int tango_thermal_probe(struct platform_device *pdev) 68{ 69 struct resource *res; 70 struct tango_thermal_priv *priv; 71 struct thermal_zone_device *tzdev; 72 73 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 74 if (!priv) 75 return -ENOMEM; 76 77 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 78 priv->base = devm_ioremap_resource(&pdev->dev, res); 79 if (IS_ERR(priv->base)) 80 return PTR_ERR(priv->base); 81 82 priv->thresh_idx = IDX_MIN; 83 writel(0, priv->base + TEMPSI_CFG); 84 writel(CMD_ON, priv->base + TEMPSI_CMD); 85 86 tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &ops); 87 return PTR_ERR_OR_ZERO(tzdev); 88} 89 90static const struct of_device_id tango_sensor_ids[] = { 91 { 92 .compatible = "sigma,smp8758-thermal", 93 }, 94 { /* sentinel */ } 95}; 96 97static struct platform_driver tango_thermal_driver = { 98 .probe = tango_thermal_probe, 99 .driver = { 100 .name = "tango-thermal", 101 .of_match_table = tango_sensor_ids, 102 }, 103}; 104 105module_platform_driver(tango_thermal_driver); 106 107MODULE_LICENSE("GPL"); 108MODULE_AUTHOR("Sigma Designs"); 109MODULE_DESCRIPTION("Tango temperature sensor");