0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/device.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/of.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/thermal.h>
0018
0019 #define MD_FACTOR 1000
0020
0021
0022 struct spear_thermal_dev {
0023
0024 void __iomem *thermal_base;
0025
0026 struct clk *clk;
0027
0028 unsigned int flags;
0029 };
0030
0031 static inline int thermal_get_temp(struct thermal_zone_device *thermal,
0032 int *temp)
0033 {
0034 struct spear_thermal_dev *stdev = thermal->devdata;
0035
0036
0037
0038
0039
0040 *temp = (readl_relaxed(stdev->thermal_base) & 0x7F) * MD_FACTOR;
0041 return 0;
0042 }
0043
0044 static struct thermal_zone_device_ops ops = {
0045 .get_temp = thermal_get_temp,
0046 };
0047
0048 static int __maybe_unused spear_thermal_suspend(struct device *dev)
0049 {
0050 struct thermal_zone_device *spear_thermal = dev_get_drvdata(dev);
0051 struct spear_thermal_dev *stdev = spear_thermal->devdata;
0052 unsigned int actual_mask = 0;
0053
0054
0055 actual_mask = readl_relaxed(stdev->thermal_base);
0056 writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
0057
0058 clk_disable(stdev->clk);
0059 dev_info(dev, "Suspended.\n");
0060
0061 return 0;
0062 }
0063
0064 static int __maybe_unused spear_thermal_resume(struct device *dev)
0065 {
0066 struct thermal_zone_device *spear_thermal = dev_get_drvdata(dev);
0067 struct spear_thermal_dev *stdev = spear_thermal->devdata;
0068 unsigned int actual_mask = 0;
0069 int ret = 0;
0070
0071 ret = clk_enable(stdev->clk);
0072 if (ret) {
0073 dev_err(dev, "Can't enable clock\n");
0074 return ret;
0075 }
0076
0077
0078 actual_mask = readl_relaxed(stdev->thermal_base);
0079 writel_relaxed(actual_mask | stdev->flags, stdev->thermal_base);
0080
0081 dev_info(dev, "Resumed.\n");
0082
0083 return 0;
0084 }
0085
0086 static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
0087 spear_thermal_resume);
0088
0089 static int spear_thermal_probe(struct platform_device *pdev)
0090 {
0091 struct thermal_zone_device *spear_thermal = NULL;
0092 struct spear_thermal_dev *stdev;
0093 struct device_node *np = pdev->dev.of_node;
0094 struct resource *res;
0095 int ret = 0, val;
0096
0097 if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
0098 dev_err(&pdev->dev, "Failed: DT Pdata not passed\n");
0099 return -EINVAL;
0100 }
0101
0102 stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
0103 if (!stdev)
0104 return -ENOMEM;
0105
0106
0107 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0108 stdev->thermal_base = devm_ioremap_resource(&pdev->dev, res);
0109 if (IS_ERR(stdev->thermal_base))
0110 return PTR_ERR(stdev->thermal_base);
0111
0112 stdev->clk = devm_clk_get(&pdev->dev, NULL);
0113 if (IS_ERR(stdev->clk)) {
0114 dev_err(&pdev->dev, "Can't get clock\n");
0115 return PTR_ERR(stdev->clk);
0116 }
0117
0118 ret = clk_enable(stdev->clk);
0119 if (ret) {
0120 dev_err(&pdev->dev, "Can't enable clock\n");
0121 return ret;
0122 }
0123
0124 stdev->flags = val;
0125 writel_relaxed(stdev->flags, stdev->thermal_base);
0126
0127 spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0,
0128 stdev, &ops, NULL, 0, 0);
0129 if (IS_ERR(spear_thermal)) {
0130 dev_err(&pdev->dev, "thermal zone device is NULL\n");
0131 ret = PTR_ERR(spear_thermal);
0132 goto disable_clk;
0133 }
0134 ret = thermal_zone_device_enable(spear_thermal);
0135 if (ret) {
0136 dev_err(&pdev->dev, "Cannot enable thermal zone\n");
0137 goto unregister_tzd;
0138 }
0139
0140 platform_set_drvdata(pdev, spear_thermal);
0141
0142 dev_info(&spear_thermal->device, "Thermal Sensor Loaded at: 0x%p.\n",
0143 stdev->thermal_base);
0144
0145 return 0;
0146
0147 unregister_tzd:
0148 thermal_zone_device_unregister(spear_thermal);
0149 disable_clk:
0150 clk_disable(stdev->clk);
0151
0152 return ret;
0153 }
0154
0155 static int spear_thermal_exit(struct platform_device *pdev)
0156 {
0157 unsigned int actual_mask = 0;
0158 struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
0159 struct spear_thermal_dev *stdev = spear_thermal->devdata;
0160
0161 thermal_zone_device_unregister(spear_thermal);
0162
0163
0164 actual_mask = readl_relaxed(stdev->thermal_base);
0165 writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
0166
0167 clk_disable(stdev->clk);
0168
0169 return 0;
0170 }
0171
0172 static const struct of_device_id spear_thermal_id_table[] = {
0173 { .compatible = "st,thermal-spear1340" },
0174 {}
0175 };
0176 MODULE_DEVICE_TABLE(of, spear_thermal_id_table);
0177
0178 static struct platform_driver spear_thermal_driver = {
0179 .probe = spear_thermal_probe,
0180 .remove = spear_thermal_exit,
0181 .driver = {
0182 .name = "spear_thermal",
0183 .pm = &spear_thermal_pm_ops,
0184 .of_match_table = spear_thermal_id_table,
0185 },
0186 };
0187
0188 module_platform_driver(spear_thermal_driver);
0189
0190 MODULE_AUTHOR("Vincenzo Frascino <vincenzo.frascino@st.com>");
0191 MODULE_DESCRIPTION("SPEAr thermal driver");
0192 MODULE_LICENSE("GPL");