summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamin Guo <samin.guo@starfivetech.com>2021-02-05 06:29:44 +0300
committerFu Wei <fu.wei@linaro.org>2021-02-24 22:46:57 +0300
commitb6b0e571705ba82560f604780646d24993aa56c0 (patch)
tree780c74b895a1cc741c5e66ffada05c6056bef31c
parentd97261f965f82feec963b8cdf8689389e9cac0c0 (diff)
downloadlinux-b6b0e571705ba82560f604780646d24993aa56c0.tar.xz
add tempsensor hwmon driver
-rw-r--r--drivers/hwmon/Kconfig8
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/hwmon.c2
-rw-r--r--drivers/hwmon/sfctmp.c211
4 files changed, 221 insertions, 1 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a850e4f0e0bd..ecd83a7f77fc 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1872,6 +1872,14 @@ config SENSORS_TMP513
This driver can also be built as a module. If so, the module
will be called tmp513.
+config SENSORS_SFCTMP
+ tristate "SFC temperature sensor and compatible"
+ help
+ If you say yes here you get support for SFC tmperature sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called sfc_temp.
+
config SENSORS_VEXPRESS
tristate "Versatile Express"
depends on VEXPRESS_CONFIG
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 9db2903b61e5..8f1e1faf2c41 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -193,6 +193,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
+obj-$(CONFIG_SENSORS_SFCTMP) += sfctmp.o
obj-$(CONFIG_SENSORS_OCC) += occ/
obj-$(CONFIG_PMBUS) += pmbus/
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 6c684058bfdf..7157d22eb650 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -855,7 +855,7 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
*/
struct device *hwmon_device_register(struct device *dev)
{
- dev_warn(dev,
+ dev_dbg(dev,
"hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n");
return __hwmon_device_register(dev, NULL, NULL, NULL, NULL);
diff --git a/drivers/hwmon/sfctmp.c b/drivers/hwmon/sfctmp.c
new file mode 100644
index 000000000000..901f92f8dd2d
--- /dev/null
+++ b/drivers/hwmon/sfctmp.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 samin.guo <samin.guo@starfivetech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <asm-generic/io.h>
+#include <linux/regmap.h>
+
+typedef union
+{
+ uint32_t v;
+ struct {
+ uint32_t rstn : 1; /* TempSensor reset.The RSTN can be de-asserted once the analog core has powered up. Trst(min 100ns) 0: reset 1: de-assert */
+ uint32_t pd : 1; /* TempSensor analog core power down.the analog core will be power up when PD de-asserted after Tpu(min 50us) has elapsed. the RSTN should be held low until the analog core is powered up. 0:power up 1: power down */
+ uint32_t run : 1; /* TempSensor start conversion enable
+ 0:disable 1:enable */
+ uint32_t rsvd_0 : 1;
+ uint32_t cal : 1; /* TempSensor calibration mode enable
+ 0:disable 1:enable */
+ uint32_t sgn : 1; /* TempSensor signature enable,generate a toggle value outputting on DOUT for test purposes.
+ 0:disable 1:enable */
+ uint32_t rsvd_1 : 6;
+ uint32_t tm : 4; /* TempSensor test access control
+ 0000:normal 0001:Test 1 0010:Test 2 0011:Test 3
+ 0100:Test4 1000:Test 8 1001:Test 9 */
+ uint32_t dout : 12; /* TempSensor conversion value output
+ Temp(c)=DOUT/4094*Y-K */
+ uint32_t rsvd_2 : 3;
+ uint32_t digo : 1; /* TempSensor digital test output */
+ } bits;
+} sfc_temp_sensor_reg_t;
+
+static uint32_t s_temp_sensor_dout;
+
+struct sfc_temp{
+ const char *name;
+ void __iomem *regs;
+ int irq;
+ int clk;
+};
+
+static ssize_t sfctmp_get_temp(struct device *dev, struct device_attribute *devattr,char *buf)
+{
+ long temp,temp_z,temp_x;
+ const long Y100 = 23750, K100 = 8110,Z100 = 409400;
+
+ temp = ((long)s_temp_sensor_dout*100)*Y100/Z100-K100;
+ temp_z = temp/100;
+ temp_x = temp%100;
+ return sprintf(buf, "%ld.%ld\n", temp_z,temp_x);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sfctmp_get_temp, NULL, 0);
+
+static ssize_t sfctmp_temp_show(void)
+{
+ char buf[10];
+ sfctmp_get_temp(NULL, NULL, buf);
+ printk("temp(c): %s",buf);
+ return 0;
+}
+
+static irqreturn_t sfc_temp_isr(int irq, void *priv)
+{
+ struct sfc_temp *sfc_temp = (struct sfc_temp *)priv;
+ sfc_temp_sensor_reg_t reg;
+
+ reg.v = readl(sfc_temp->regs);
+ s_temp_sensor_dout = reg.bits.dout;
+ return IRQ_HANDLED;
+}
+
+static void temp_sensor_power_up(struct sfc_temp *sfc_temp)
+{
+ sfc_temp_sensor_reg_t init;
+ init.v = 0;
+ init.bits.pd = 1;
+ writel(init.v, sfc_temp->regs);
+ udelay(1);
+
+ init.bits.pd = 0;
+ writel(init.v, sfc_temp->regs);
+ // wait t_pu(50us) + t_rst(100ns)
+ udelay(60);
+
+ init.bits.rstn = 1;
+ writel(init.v, sfc_temp->regs);
+ // wait t_su(500ps)
+ udelay(1);
+
+ init.bits.run = 1;
+ writel(init.v, sfc_temp->regs);
+ // wait 1st sample (8192 temp_sense clk: ~2MHz)
+ mdelay(10);
+}
+
+static void temp_sensor_power_down(struct sfc_temp *sfc_temp)
+{
+ sfc_temp_sensor_reg_t init;
+
+ init.v = readl(sfc_temp->regs);
+ init.bits.run = 0;
+ writel(init.v, sfc_temp->regs);
+ udelay(1);
+
+ init.bits.pd = 1;
+ init.bits.rstn = 0;
+ writel(init.v, sfc_temp->regs);
+ udelay(1);
+}
+
+int temp_sensor_deinit(struct sfc_temp *sfc_temp)
+{
+ temp_sensor_power_down(sfc_temp);
+ return 0;
+}
+
+static int sfc_temp_probe(struct platform_device *pdev)
+{
+ struct device *temp_dev = &pdev->dev;
+ struct device *hwmon_dev;
+ struct resource *mem;
+ struct sfc_temp *sfc_temp;
+ int ret;
+
+ dev_info(temp_dev,"probe\n");
+ sfc_temp = devm_kzalloc(&pdev->dev, sizeof(*sfc_temp), GFP_KERNEL);
+ if (!sfc_temp)
+ return -ENOMEM;
+
+ temp_dev->driver_data = (void *)sfc_temp;
+
+ sfc_temp->irq = platform_get_irq(pdev, 0);
+ if (sfc_temp->irq < 0)
+ return sfc_temp->irq;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sfc_temp->regs = devm_ioremap_resource(temp_dev, mem);
+ if(IS_ERR(sfc_temp->regs)){
+ return PTR_ERR(sfc_temp->regs);
+ }
+
+ sfc_temp->name = "sfc_tempsnsor";
+
+ ret = devm_request_irq(temp_dev, sfc_temp->irq, sfc_temp_isr,
+ IRQF_SHARED, sfc_temp->name, sfc_temp);
+ if(ret){
+ printk("request_irq failed.\n");
+ return ret;
+ }
+
+ temp_sensor_power_up(sfc_temp);
+ sfctmp_temp_show();
+
+ ret = device_create_file(temp_dev, &sensor_dev_attr_temp1_input.dev_attr);
+ if (ret){
+ return ret;
+ }
+ hwmon_device_register(temp_dev);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static int sfc_temp_remove(struct platform_device *pdev)
+{
+ struct device *tmp_dev = &pdev->dev;
+ struct sfc_temp *sfc_temp = (struct sfc_temp *)tmp_dev->driver_data;
+ hwmon_device_unregister(tmp_dev);
+ temp_sensor_deinit(sfc_temp);
+ return 0;
+}
+
+static const struct of_device_id sfc_temp_of_match[] = {
+ { .compatible = "sfc,tempsensor" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, sfc_temp_of_match);
+
+static struct platform_driver sfc_temp_sensor_driver = {
+ .driver = {
+ .name = "sfc_temp_sensor",
+ .of_match_table = of_match_ptr(sfc_temp_of_match),
+ },
+ .probe = sfc_temp_probe,
+ .remove = sfc_temp_remove,
+};
+module_platform_driver(sfc_temp_sensor_driver);
+
+MODULE_AUTHOR("samin.guo");
+MODULE_DESCRIPTION("SFC temperature sensor driver");
+MODULE_LICENSE("GPL"); \ No newline at end of file