17f2958e8SEmil Renner Berthing // SPDX-License-Identifier: GPL-2.0 27f2958e8SEmil Renner Berthing /* 37f2958e8SEmil Renner Berthing * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk> 47f2958e8SEmil Renner Berthing * Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com> 57f2958e8SEmil Renner Berthing */ 67f2958e8SEmil Renner Berthing 77f2958e8SEmil Renner Berthing #include <linux/bits.h> 87f2958e8SEmil Renner Berthing #include <linux/clk.h> 97f2958e8SEmil Renner Berthing #include <linux/delay.h> 107f2958e8SEmil Renner Berthing #include <linux/hwmon.h> 117f2958e8SEmil Renner Berthing #include <linux/io.h> 127f2958e8SEmil Renner Berthing #include <linux/module.h> 137f2958e8SEmil Renner Berthing #include <linux/mutex.h> 147f2958e8SEmil Renner Berthing #include <linux/of.h> 157f2958e8SEmil Renner Berthing #include <linux/platform_device.h> 167f2958e8SEmil Renner Berthing #include <linux/reset.h> 177f2958e8SEmil Renner Berthing 187f2958e8SEmil Renner Berthing /* 197f2958e8SEmil Renner Berthing * TempSensor reset. The RSTN can be de-asserted once the analog core has 207f2958e8SEmil Renner Berthing * powered up. Trst(min 100ns) 217f2958e8SEmil Renner Berthing * 0:reset 1:de-assert 227f2958e8SEmil Renner Berthing */ 237f2958e8SEmil Renner Berthing #define SFCTEMP_RSTN BIT(0) 247f2958e8SEmil Renner Berthing 257f2958e8SEmil Renner Berthing /* 267f2958e8SEmil Renner Berthing * TempSensor analog core power down. The analog core will be powered up 277f2958e8SEmil Renner Berthing * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the 287f2958e8SEmil Renner Berthing * analog core is powered up. 297f2958e8SEmil Renner Berthing * 0:power up 1:power down 307f2958e8SEmil Renner Berthing */ 317f2958e8SEmil Renner Berthing #define SFCTEMP_PD BIT(1) 327f2958e8SEmil Renner Berthing 337f2958e8SEmil Renner Berthing /* 347f2958e8SEmil Renner Berthing * TempSensor start conversion enable. 357f2958e8SEmil Renner Berthing * 0:disable 1:enable 367f2958e8SEmil Renner Berthing */ 377f2958e8SEmil Renner Berthing #define SFCTEMP_RUN BIT(2) 387f2958e8SEmil Renner Berthing 397f2958e8SEmil Renner Berthing /* 407f2958e8SEmil Renner Berthing * TempSensor conversion value output. 417f2958e8SEmil Renner Berthing * Temp(C)=DOUT*Y/4094 - K 427f2958e8SEmil Renner Berthing */ 437f2958e8SEmil Renner Berthing #define SFCTEMP_DOUT_POS 16 447f2958e8SEmil Renner Berthing #define SFCTEMP_DOUT_MSK GENMASK(27, 16) 457f2958e8SEmil Renner Berthing 467f2958e8SEmil Renner Berthing /* DOUT to Celcius conversion constants */ 477f2958e8SEmil Renner Berthing #define SFCTEMP_Y1000 237500L 487f2958e8SEmil Renner Berthing #define SFCTEMP_Z 4094L 497f2958e8SEmil Renner Berthing #define SFCTEMP_K1000 81100L 507f2958e8SEmil Renner Berthing 517f2958e8SEmil Renner Berthing struct sfctemp { 527f2958e8SEmil Renner Berthing /* serialize access to hardware register and enabled below */ 537f2958e8SEmil Renner Berthing struct mutex lock; 547f2958e8SEmil Renner Berthing void __iomem *regs; 557f2958e8SEmil Renner Berthing struct clk *clk_sense; 567f2958e8SEmil Renner Berthing struct clk *clk_bus; 577f2958e8SEmil Renner Berthing struct reset_control *rst_sense; 587f2958e8SEmil Renner Berthing struct reset_control *rst_bus; 597f2958e8SEmil Renner Berthing bool enabled; 607f2958e8SEmil Renner Berthing }; 617f2958e8SEmil Renner Berthing 627f2958e8SEmil Renner Berthing static void sfctemp_power_up(struct sfctemp *sfctemp) 637f2958e8SEmil Renner Berthing { 647f2958e8SEmil Renner Berthing /* make sure we're powered down first */ 657f2958e8SEmil Renner Berthing writel(SFCTEMP_PD, sfctemp->regs); 667f2958e8SEmil Renner Berthing udelay(1); 677f2958e8SEmil Renner Berthing 687f2958e8SEmil Renner Berthing writel(0, sfctemp->regs); 697f2958e8SEmil Renner Berthing /* wait t_pu(50us) + t_rst(100ns) */ 707f2958e8SEmil Renner Berthing usleep_range(60, 200); 717f2958e8SEmil Renner Berthing 727f2958e8SEmil Renner Berthing /* de-assert reset */ 737f2958e8SEmil Renner Berthing writel(SFCTEMP_RSTN, sfctemp->regs); 747f2958e8SEmil Renner Berthing udelay(1); /* wait t_su(500ps) */ 757f2958e8SEmil Renner Berthing } 767f2958e8SEmil Renner Berthing 777f2958e8SEmil Renner Berthing static void sfctemp_power_down(struct sfctemp *sfctemp) 787f2958e8SEmil Renner Berthing { 797f2958e8SEmil Renner Berthing writel(SFCTEMP_PD, sfctemp->regs); 807f2958e8SEmil Renner Berthing } 817f2958e8SEmil Renner Berthing 827f2958e8SEmil Renner Berthing static void sfctemp_run(struct sfctemp *sfctemp) 837f2958e8SEmil Renner Berthing { 847f2958e8SEmil Renner Berthing writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs); 857f2958e8SEmil Renner Berthing udelay(1); 867f2958e8SEmil Renner Berthing } 877f2958e8SEmil Renner Berthing 887f2958e8SEmil Renner Berthing static void sfctemp_stop(struct sfctemp *sfctemp) 897f2958e8SEmil Renner Berthing { 907f2958e8SEmil Renner Berthing writel(SFCTEMP_RSTN, sfctemp->regs); 917f2958e8SEmil Renner Berthing } 927f2958e8SEmil Renner Berthing 937f2958e8SEmil Renner Berthing static int sfctemp_enable(struct sfctemp *sfctemp) 947f2958e8SEmil Renner Berthing { 957f2958e8SEmil Renner Berthing int ret = 0; 967f2958e8SEmil Renner Berthing 977f2958e8SEmil Renner Berthing mutex_lock(&sfctemp->lock); 987f2958e8SEmil Renner Berthing if (sfctemp->enabled) 997f2958e8SEmil Renner Berthing goto done; 1007f2958e8SEmil Renner Berthing 1017f2958e8SEmil Renner Berthing ret = clk_prepare_enable(sfctemp->clk_bus); 1027f2958e8SEmil Renner Berthing if (ret) 1037f2958e8SEmil Renner Berthing goto err; 1047f2958e8SEmil Renner Berthing ret = reset_control_deassert(sfctemp->rst_bus); 1057f2958e8SEmil Renner Berthing if (ret) 1067f2958e8SEmil Renner Berthing goto err_disable_bus; 1077f2958e8SEmil Renner Berthing 1087f2958e8SEmil Renner Berthing ret = clk_prepare_enable(sfctemp->clk_sense); 1097f2958e8SEmil Renner Berthing if (ret) 1107f2958e8SEmil Renner Berthing goto err_assert_bus; 1117f2958e8SEmil Renner Berthing ret = reset_control_deassert(sfctemp->rst_sense); 1127f2958e8SEmil Renner Berthing if (ret) 1137f2958e8SEmil Renner Berthing goto err_disable_sense; 1147f2958e8SEmil Renner Berthing 1157f2958e8SEmil Renner Berthing sfctemp_power_up(sfctemp); 1167f2958e8SEmil Renner Berthing sfctemp_run(sfctemp); 1177f2958e8SEmil Renner Berthing sfctemp->enabled = true; 1187f2958e8SEmil Renner Berthing done: 1197f2958e8SEmil Renner Berthing mutex_unlock(&sfctemp->lock); 1207f2958e8SEmil Renner Berthing return ret; 1217f2958e8SEmil Renner Berthing 1227f2958e8SEmil Renner Berthing err_disable_sense: 1237f2958e8SEmil Renner Berthing clk_disable_unprepare(sfctemp->clk_sense); 1247f2958e8SEmil Renner Berthing err_assert_bus: 1257f2958e8SEmil Renner Berthing reset_control_assert(sfctemp->rst_bus); 1267f2958e8SEmil Renner Berthing err_disable_bus: 1277f2958e8SEmil Renner Berthing clk_disable_unprepare(sfctemp->clk_bus); 1287f2958e8SEmil Renner Berthing err: 1297f2958e8SEmil Renner Berthing mutex_unlock(&sfctemp->lock); 1307f2958e8SEmil Renner Berthing return ret; 1317f2958e8SEmil Renner Berthing } 1327f2958e8SEmil Renner Berthing 1337f2958e8SEmil Renner Berthing static int sfctemp_disable(struct sfctemp *sfctemp) 1347f2958e8SEmil Renner Berthing { 1357f2958e8SEmil Renner Berthing mutex_lock(&sfctemp->lock); 1367f2958e8SEmil Renner Berthing if (!sfctemp->enabled) 1377f2958e8SEmil Renner Berthing goto done; 1387f2958e8SEmil Renner Berthing 1397f2958e8SEmil Renner Berthing sfctemp_stop(sfctemp); 1407f2958e8SEmil Renner Berthing sfctemp_power_down(sfctemp); 1417f2958e8SEmil Renner Berthing reset_control_assert(sfctemp->rst_sense); 1427f2958e8SEmil Renner Berthing clk_disable_unprepare(sfctemp->clk_sense); 1437f2958e8SEmil Renner Berthing reset_control_assert(sfctemp->rst_bus); 1447f2958e8SEmil Renner Berthing clk_disable_unprepare(sfctemp->clk_bus); 1457f2958e8SEmil Renner Berthing sfctemp->enabled = false; 1467f2958e8SEmil Renner Berthing done: 1477f2958e8SEmil Renner Berthing mutex_unlock(&sfctemp->lock); 1487f2958e8SEmil Renner Berthing return 0; 1497f2958e8SEmil Renner Berthing } 1507f2958e8SEmil Renner Berthing 1517f2958e8SEmil Renner Berthing static void sfctemp_disable_action(void *data) 1527f2958e8SEmil Renner Berthing { 1537f2958e8SEmil Renner Berthing sfctemp_disable(data); 1547f2958e8SEmil Renner Berthing } 1557f2958e8SEmil Renner Berthing 1567f2958e8SEmil Renner Berthing static int sfctemp_convert(struct sfctemp *sfctemp, long *val) 1577f2958e8SEmil Renner Berthing { 1587f2958e8SEmil Renner Berthing int ret; 1597f2958e8SEmil Renner Berthing 1607f2958e8SEmil Renner Berthing mutex_lock(&sfctemp->lock); 1617f2958e8SEmil Renner Berthing if (!sfctemp->enabled) { 1627f2958e8SEmil Renner Berthing ret = -ENODATA; 1637f2958e8SEmil Renner Berthing goto out; 1647f2958e8SEmil Renner Berthing } 1657f2958e8SEmil Renner Berthing 1667f2958e8SEmil Renner Berthing /* calculate temperature in milli Celcius */ 1677f2958e8SEmil Renner Berthing *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) 1687f2958e8SEmil Renner Berthing * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; 1697f2958e8SEmil Renner Berthing 1707f2958e8SEmil Renner Berthing ret = 0; 1717f2958e8SEmil Renner Berthing out: 1727f2958e8SEmil Renner Berthing mutex_unlock(&sfctemp->lock); 1737f2958e8SEmil Renner Berthing return ret; 1747f2958e8SEmil Renner Berthing } 1757f2958e8SEmil Renner Berthing 1767f2958e8SEmil Renner Berthing static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, 1777f2958e8SEmil Renner Berthing u32 attr, int channel) 1787f2958e8SEmil Renner Berthing { 1797f2958e8SEmil Renner Berthing switch (type) { 1807f2958e8SEmil Renner Berthing case hwmon_temp: 1817f2958e8SEmil Renner Berthing switch (attr) { 1827f2958e8SEmil Renner Berthing case hwmon_temp_enable: 1837f2958e8SEmil Renner Berthing return 0644; 1847f2958e8SEmil Renner Berthing case hwmon_temp_input: 1857f2958e8SEmil Renner Berthing return 0444; 1867f2958e8SEmil Renner Berthing default: 1877f2958e8SEmil Renner Berthing return 0; 1887f2958e8SEmil Renner Berthing } 1897f2958e8SEmil Renner Berthing default: 1907f2958e8SEmil Renner Berthing return 0; 1917f2958e8SEmil Renner Berthing } 1927f2958e8SEmil Renner Berthing } 1937f2958e8SEmil Renner Berthing 1947f2958e8SEmil Renner Berthing static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type, 1957f2958e8SEmil Renner Berthing u32 attr, int channel, long *val) 1967f2958e8SEmil Renner Berthing { 1977f2958e8SEmil Renner Berthing struct sfctemp *sfctemp = dev_get_drvdata(dev); 1987f2958e8SEmil Renner Berthing 1997f2958e8SEmil Renner Berthing switch (type) { 2007f2958e8SEmil Renner Berthing case hwmon_temp: 2017f2958e8SEmil Renner Berthing switch (attr) { 2027f2958e8SEmil Renner Berthing case hwmon_temp_enable: 2037f2958e8SEmil Renner Berthing *val = sfctemp->enabled; 2047f2958e8SEmil Renner Berthing return 0; 2057f2958e8SEmil Renner Berthing case hwmon_temp_input: 2067f2958e8SEmil Renner Berthing return sfctemp_convert(sfctemp, val); 2077f2958e8SEmil Renner Berthing default: 2087f2958e8SEmil Renner Berthing return -EINVAL; 2097f2958e8SEmil Renner Berthing } 2107f2958e8SEmil Renner Berthing default: 2117f2958e8SEmil Renner Berthing return -EINVAL; 2127f2958e8SEmil Renner Berthing } 2137f2958e8SEmil Renner Berthing } 2147f2958e8SEmil Renner Berthing 2157f2958e8SEmil Renner Berthing static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type, 2167f2958e8SEmil Renner Berthing u32 attr, int channel, long val) 2177f2958e8SEmil Renner Berthing { 2187f2958e8SEmil Renner Berthing struct sfctemp *sfctemp = dev_get_drvdata(dev); 2197f2958e8SEmil Renner Berthing 2207f2958e8SEmil Renner Berthing switch (type) { 2217f2958e8SEmil Renner Berthing case hwmon_temp: 2227f2958e8SEmil Renner Berthing switch (attr) { 2237f2958e8SEmil Renner Berthing case hwmon_temp_enable: 2247f2958e8SEmil Renner Berthing if (val == 0) 2257f2958e8SEmil Renner Berthing return sfctemp_disable(sfctemp); 2267f2958e8SEmil Renner Berthing if (val == 1) 2277f2958e8SEmil Renner Berthing return sfctemp_enable(sfctemp); 2287f2958e8SEmil Renner Berthing return -EINVAL; 2297f2958e8SEmil Renner Berthing default: 2307f2958e8SEmil Renner Berthing return -EINVAL; 2317f2958e8SEmil Renner Berthing } 2327f2958e8SEmil Renner Berthing default: 2337f2958e8SEmil Renner Berthing return -EINVAL; 2347f2958e8SEmil Renner Berthing } 2357f2958e8SEmil Renner Berthing } 2367f2958e8SEmil Renner Berthing 2377f2958e8SEmil Renner Berthing static const struct hwmon_channel_info *sfctemp_info[] = { 2387f2958e8SEmil Renner Berthing HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), 2397f2958e8SEmil Renner Berthing HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT), 2407f2958e8SEmil Renner Berthing NULL 2417f2958e8SEmil Renner Berthing }; 2427f2958e8SEmil Renner Berthing 2437f2958e8SEmil Renner Berthing static const struct hwmon_ops sfctemp_hwmon_ops = { 2447f2958e8SEmil Renner Berthing .is_visible = sfctemp_is_visible, 2457f2958e8SEmil Renner Berthing .read = sfctemp_read, 2467f2958e8SEmil Renner Berthing .write = sfctemp_write, 2477f2958e8SEmil Renner Berthing }; 2487f2958e8SEmil Renner Berthing 2497f2958e8SEmil Renner Berthing static const struct hwmon_chip_info sfctemp_chip_info = { 2507f2958e8SEmil Renner Berthing .ops = &sfctemp_hwmon_ops, 2517f2958e8SEmil Renner Berthing .info = sfctemp_info, 2527f2958e8SEmil Renner Berthing }; 2537f2958e8SEmil Renner Berthing 2547f2958e8SEmil Renner Berthing static int sfctemp_probe(struct platform_device *pdev) 2557f2958e8SEmil Renner Berthing { 2567f2958e8SEmil Renner Berthing struct device *dev = &pdev->dev; 2577f2958e8SEmil Renner Berthing struct device *hwmon_dev; 2587f2958e8SEmil Renner Berthing struct sfctemp *sfctemp; 2597f2958e8SEmil Renner Berthing int ret; 2607f2958e8SEmil Renner Berthing 2617f2958e8SEmil Renner Berthing sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL); 2627f2958e8SEmil Renner Berthing if (!sfctemp) 2637f2958e8SEmil Renner Berthing return -ENOMEM; 2647f2958e8SEmil Renner Berthing 2657f2958e8SEmil Renner Berthing dev_set_drvdata(dev, sfctemp); 2667f2958e8SEmil Renner Berthing mutex_init(&sfctemp->lock); 2677f2958e8SEmil Renner Berthing 2687f2958e8SEmil Renner Berthing sfctemp->regs = devm_platform_ioremap_resource(pdev, 0); 2697f2958e8SEmil Renner Berthing if (IS_ERR(sfctemp->regs)) 2707f2958e8SEmil Renner Berthing return PTR_ERR(sfctemp->regs); 2717f2958e8SEmil Renner Berthing 2727f2958e8SEmil Renner Berthing sfctemp->clk_sense = devm_clk_get(dev, "sense"); 2737f2958e8SEmil Renner Berthing if (IS_ERR(sfctemp->clk_sense)) 2747f2958e8SEmil Renner Berthing return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense), 2757f2958e8SEmil Renner Berthing "error getting sense clock\n"); 2767f2958e8SEmil Renner Berthing 2777f2958e8SEmil Renner Berthing sfctemp->clk_bus = devm_clk_get(dev, "bus"); 2787f2958e8SEmil Renner Berthing if (IS_ERR(sfctemp->clk_bus)) 2797f2958e8SEmil Renner Berthing return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus), 2807f2958e8SEmil Renner Berthing "error getting bus clock\n"); 2817f2958e8SEmil Renner Berthing 2827f2958e8SEmil Renner Berthing sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense"); 2837f2958e8SEmil Renner Berthing if (IS_ERR(sfctemp->rst_sense)) 2847f2958e8SEmil Renner Berthing return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense), 2857f2958e8SEmil Renner Berthing "error getting sense reset\n"); 2867f2958e8SEmil Renner Berthing 2877f2958e8SEmil Renner Berthing sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus"); 2887f2958e8SEmil Renner Berthing if (IS_ERR(sfctemp->rst_bus)) 2897f2958e8SEmil Renner Berthing return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus), 2907f2958e8SEmil Renner Berthing "error getting busreset\n"); 2917f2958e8SEmil Renner Berthing 2927f2958e8SEmil Renner Berthing ret = reset_control_assert(sfctemp->rst_sense); 2937f2958e8SEmil Renner Berthing if (ret) 2947f2958e8SEmil Renner Berthing return dev_err_probe(dev, ret, "error asserting sense reset\n"); 2957f2958e8SEmil Renner Berthing 2967f2958e8SEmil Renner Berthing ret = reset_control_assert(sfctemp->rst_bus); 2977f2958e8SEmil Renner Berthing if (ret) 2987f2958e8SEmil Renner Berthing return dev_err_probe(dev, ret, "error asserting bus reset\n"); 2997f2958e8SEmil Renner Berthing 3007f2958e8SEmil Renner Berthing ret = devm_add_action(dev, sfctemp_disable_action, sfctemp); 3017f2958e8SEmil Renner Berthing if (ret) 3027f2958e8SEmil Renner Berthing return ret; 3037f2958e8SEmil Renner Berthing 3047f2958e8SEmil Renner Berthing ret = sfctemp_enable(sfctemp); 3057f2958e8SEmil Renner Berthing if (ret) 306*fb23f230SChristophe JAILLET return dev_err_probe(dev, ret, "error enabling temperature sensor\n"); 3077f2958e8SEmil Renner Berthing 3087f2958e8SEmil Renner Berthing hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp, 3097f2958e8SEmil Renner Berthing &sfctemp_chip_info, NULL); 3107f2958e8SEmil Renner Berthing return PTR_ERR_OR_ZERO(hwmon_dev); 3117f2958e8SEmil Renner Berthing } 3127f2958e8SEmil Renner Berthing 3137f2958e8SEmil Renner Berthing static const struct of_device_id sfctemp_of_match[] = { 3147f2958e8SEmil Renner Berthing { .compatible = "starfive,jh7100-temp" }, 3157f2958e8SEmil Renner Berthing { .compatible = "starfive,jh7110-temp" }, 3167f2958e8SEmil Renner Berthing { /* sentinel */ } 3177f2958e8SEmil Renner Berthing }; 3187f2958e8SEmil Renner Berthing MODULE_DEVICE_TABLE(of, sfctemp_of_match); 3197f2958e8SEmil Renner Berthing 3207f2958e8SEmil Renner Berthing static struct platform_driver sfctemp_driver = { 3217f2958e8SEmil Renner Berthing .probe = sfctemp_probe, 3227f2958e8SEmil Renner Berthing .driver = { 3237f2958e8SEmil Renner Berthing .name = "sfctemp", 3247f2958e8SEmil Renner Berthing .of_match_table = sfctemp_of_match, 3257f2958e8SEmil Renner Berthing }, 3267f2958e8SEmil Renner Berthing }; 3277f2958e8SEmil Renner Berthing module_platform_driver(sfctemp_driver); 3287f2958e8SEmil Renner Berthing 3297f2958e8SEmil Renner Berthing MODULE_AUTHOR("Emil Renner Berthing"); 3307f2958e8SEmil Renner Berthing MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver"); 3317f2958e8SEmil Renner Berthing MODULE_LICENSE("GPL"); 332