0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/kernel.h>
0011 #include <linux/of.h>
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/thermal.h>
0015
0016 #define KIRKWOOD_THERMAL_VALID_OFFSET 9
0017 #define KIRKWOOD_THERMAL_VALID_MASK 0x1
0018 #define KIRKWOOD_THERMAL_TEMP_OFFSET 10
0019 #define KIRKWOOD_THERMAL_TEMP_MASK 0x1FF
0020
0021
0022 struct kirkwood_thermal_priv {
0023 void __iomem *sensor;
0024 };
0025
0026 static int kirkwood_get_temp(struct thermal_zone_device *thermal,
0027 int *temp)
0028 {
0029 unsigned long reg;
0030 struct kirkwood_thermal_priv *priv = thermal->devdata;
0031
0032 reg = readl_relaxed(priv->sensor);
0033
0034
0035 if (!((reg >> KIRKWOOD_THERMAL_VALID_OFFSET) &
0036 KIRKWOOD_THERMAL_VALID_MASK)) {
0037 dev_err(&thermal->device,
0038 "Temperature sensor reading not valid\n");
0039 return -EIO;
0040 }
0041
0042
0043
0044
0045
0046
0047 reg = (reg >> KIRKWOOD_THERMAL_TEMP_OFFSET) &
0048 KIRKWOOD_THERMAL_TEMP_MASK;
0049 *temp = ((3220000000UL - (10000000UL * reg)) / 13625);
0050
0051 return 0;
0052 }
0053
0054 static struct thermal_zone_device_ops ops = {
0055 .get_temp = kirkwood_get_temp,
0056 };
0057
0058 static const struct of_device_id kirkwood_thermal_id_table[] = {
0059 { .compatible = "marvell,kirkwood-thermal" },
0060 {}
0061 };
0062
0063 static int kirkwood_thermal_probe(struct platform_device *pdev)
0064 {
0065 struct thermal_zone_device *thermal = NULL;
0066 struct kirkwood_thermal_priv *priv;
0067 struct resource *res;
0068 int ret;
0069
0070 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0071 if (!priv)
0072 return -ENOMEM;
0073
0074 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0075 priv->sensor = devm_ioremap_resource(&pdev->dev, res);
0076 if (IS_ERR(priv->sensor))
0077 return PTR_ERR(priv->sensor);
0078
0079 thermal = thermal_zone_device_register("kirkwood_thermal", 0, 0,
0080 priv, &ops, NULL, 0, 0);
0081 if (IS_ERR(thermal)) {
0082 dev_err(&pdev->dev,
0083 "Failed to register thermal zone device\n");
0084 return PTR_ERR(thermal);
0085 }
0086 ret = thermal_zone_device_enable(thermal);
0087 if (ret) {
0088 thermal_zone_device_unregister(thermal);
0089 dev_err(&pdev->dev, "Failed to enable thermal zone device\n");
0090 return ret;
0091 }
0092
0093 platform_set_drvdata(pdev, thermal);
0094
0095 return 0;
0096 }
0097
0098 static int kirkwood_thermal_exit(struct platform_device *pdev)
0099 {
0100 struct thermal_zone_device *kirkwood_thermal =
0101 platform_get_drvdata(pdev);
0102
0103 thermal_zone_device_unregister(kirkwood_thermal);
0104
0105 return 0;
0106 }
0107
0108 MODULE_DEVICE_TABLE(of, kirkwood_thermal_id_table);
0109
0110 static struct platform_driver kirkwood_thermal_driver = {
0111 .probe = kirkwood_thermal_probe,
0112 .remove = kirkwood_thermal_exit,
0113 .driver = {
0114 .name = "kirkwood_thermal",
0115 .of_match_table = kirkwood_thermal_id_table,
0116 },
0117 };
0118
0119 module_platform_driver(kirkwood_thermal_driver);
0120
0121 MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
0122 MODULE_DESCRIPTION("kirkwood thermal driver");
0123 MODULE_LICENSE("GPL");