diff options
author | Samin Guo <samin.guo@starfivetech.com> | 2021-02-05 06:29:44 +0300 |
---|---|---|
committer | Fu Wei <fu.wei@linaro.org> | 2021-02-24 22:46:57 +0300 |
commit | b6b0e571705ba82560f604780646d24993aa56c0 (patch) | |
tree | 780c74b895a1cc741c5e66ffada05c6056bef31c | |
parent | d97261f965f82feec963b8cdf8689389e9cac0c0 (diff) | |
download | linux-b6b0e571705ba82560f604780646d24993aa56c0.tar.xz |
add tempsensor hwmon driver
-rw-r--r-- | drivers/hwmon/Kconfig | 8 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/hwmon.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/sfctmp.c | 211 |
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 |