332 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>4 * Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com>5 */6 7#include <linux/bits.h>8#include <linux/clk.h>9#include <linux/delay.h>10#include <linux/hwmon.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/reset.h>17 18/*19 * TempSensor reset. The RSTN can be de-asserted once the analog core has20 * powered up. Trst(min 100ns)21 * 0:reset 1:de-assert22 */23#define SFCTEMP_RSTN BIT(0)24 25/*26 * TempSensor analog core power down. The analog core will be powered up27 * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the28 * analog core is powered up.29 * 0:power up 1:power down30 */31#define SFCTEMP_PD BIT(1)32 33/*34 * TempSensor start conversion enable.35 * 0:disable 1:enable36 */37#define SFCTEMP_RUN BIT(2)38 39/*40 * TempSensor conversion value output.41 * Temp(C)=DOUT*Y/4094 - K42 */43#define SFCTEMP_DOUT_POS 1644#define SFCTEMP_DOUT_MSK GENMASK(27, 16)45 46/* DOUT to Celcius conversion constants */47#define SFCTEMP_Y1000 237500L48#define SFCTEMP_Z 4094L49#define SFCTEMP_K1000 81100L50 51struct sfctemp {52 /* serialize access to hardware register and enabled below */53 struct mutex lock;54 void __iomem *regs;55 struct clk *clk_sense;56 struct clk *clk_bus;57 struct reset_control *rst_sense;58 struct reset_control *rst_bus;59 bool enabled;60};61 62static void sfctemp_power_up(struct sfctemp *sfctemp)63{64 /* make sure we're powered down first */65 writel(SFCTEMP_PD, sfctemp->regs);66 udelay(1);67 68 writel(0, sfctemp->regs);69 /* wait t_pu(50us) + t_rst(100ns) */70 usleep_range(60, 200);71 72 /* de-assert reset */73 writel(SFCTEMP_RSTN, sfctemp->regs);74 udelay(1); /* wait t_su(500ps) */75}76 77static void sfctemp_power_down(struct sfctemp *sfctemp)78{79 writel(SFCTEMP_PD, sfctemp->regs);80}81 82static void sfctemp_run(struct sfctemp *sfctemp)83{84 writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);85 udelay(1);86}87 88static void sfctemp_stop(struct sfctemp *sfctemp)89{90 writel(SFCTEMP_RSTN, sfctemp->regs);91}92 93static int sfctemp_enable(struct sfctemp *sfctemp)94{95 int ret = 0;96 97 mutex_lock(&sfctemp->lock);98 if (sfctemp->enabled)99 goto done;100 101 ret = clk_prepare_enable(sfctemp->clk_bus);102 if (ret)103 goto err;104 ret = reset_control_deassert(sfctemp->rst_bus);105 if (ret)106 goto err_disable_bus;107 108 ret = clk_prepare_enable(sfctemp->clk_sense);109 if (ret)110 goto err_assert_bus;111 ret = reset_control_deassert(sfctemp->rst_sense);112 if (ret)113 goto err_disable_sense;114 115 sfctemp_power_up(sfctemp);116 sfctemp_run(sfctemp);117 sfctemp->enabled = true;118done:119 mutex_unlock(&sfctemp->lock);120 return ret;121 122err_disable_sense:123 clk_disable_unprepare(sfctemp->clk_sense);124err_assert_bus:125 reset_control_assert(sfctemp->rst_bus);126err_disable_bus:127 clk_disable_unprepare(sfctemp->clk_bus);128err:129 mutex_unlock(&sfctemp->lock);130 return ret;131}132 133static int sfctemp_disable(struct sfctemp *sfctemp)134{135 mutex_lock(&sfctemp->lock);136 if (!sfctemp->enabled)137 goto done;138 139 sfctemp_stop(sfctemp);140 sfctemp_power_down(sfctemp);141 reset_control_assert(sfctemp->rst_sense);142 clk_disable_unprepare(sfctemp->clk_sense);143 reset_control_assert(sfctemp->rst_bus);144 clk_disable_unprepare(sfctemp->clk_bus);145 sfctemp->enabled = false;146done:147 mutex_unlock(&sfctemp->lock);148 return 0;149}150 151static void sfctemp_disable_action(void *data)152{153 sfctemp_disable(data);154}155 156static int sfctemp_convert(struct sfctemp *sfctemp, long *val)157{158 int ret;159 160 mutex_lock(&sfctemp->lock);161 if (!sfctemp->enabled) {162 ret = -ENODATA;163 goto out;164 }165 166 /* calculate temperature in milli Celcius */167 *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS)168 * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000;169 170 ret = 0;171out:172 mutex_unlock(&sfctemp->lock);173 return ret;174}175 176static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,177 u32 attr, int channel)178{179 switch (type) {180 case hwmon_temp:181 switch (attr) {182 case hwmon_temp_enable:183 return 0644;184 case hwmon_temp_input:185 return 0444;186 default:187 return 0;188 }189 default:190 return 0;191 }192}193 194static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,195 u32 attr, int channel, long *val)196{197 struct sfctemp *sfctemp = dev_get_drvdata(dev);198 199 switch (type) {200 case hwmon_temp:201 switch (attr) {202 case hwmon_temp_enable:203 *val = sfctemp->enabled;204 return 0;205 case hwmon_temp_input:206 return sfctemp_convert(sfctemp, val);207 default:208 return -EINVAL;209 }210 default:211 return -EINVAL;212 }213}214 215static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type,216 u32 attr, int channel, long val)217{218 struct sfctemp *sfctemp = dev_get_drvdata(dev);219 220 switch (type) {221 case hwmon_temp:222 switch (attr) {223 case hwmon_temp_enable:224 if (val == 0)225 return sfctemp_disable(sfctemp);226 if (val == 1)227 return sfctemp_enable(sfctemp);228 return -EINVAL;229 default:230 return -EINVAL;231 }232 default:233 return -EINVAL;234 }235}236 237static const struct hwmon_channel_info *sfctemp_info[] = {238 HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),239 HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT),240 NULL241};242 243static const struct hwmon_ops sfctemp_hwmon_ops = {244 .is_visible = sfctemp_is_visible,245 .read = sfctemp_read,246 .write = sfctemp_write,247};248 249static const struct hwmon_chip_info sfctemp_chip_info = {250 .ops = &sfctemp_hwmon_ops,251 .info = sfctemp_info,252};253 254static int sfctemp_probe(struct platform_device *pdev)255{256 struct device *dev = &pdev->dev;257 struct device *hwmon_dev;258 struct sfctemp *sfctemp;259 int ret;260 261 sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL);262 if (!sfctemp)263 return -ENOMEM;264 265 dev_set_drvdata(dev, sfctemp);266 mutex_init(&sfctemp->lock);267 268 sfctemp->regs = devm_platform_ioremap_resource(pdev, 0);269 if (IS_ERR(sfctemp->regs))270 return PTR_ERR(sfctemp->regs);271 272 sfctemp->clk_sense = devm_clk_get(dev, "sense");273 if (IS_ERR(sfctemp->clk_sense))274 return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense),275 "error getting sense clock\n");276 277 sfctemp->clk_bus = devm_clk_get(dev, "bus");278 if (IS_ERR(sfctemp->clk_bus))279 return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus),280 "error getting bus clock\n");281 282 sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense");283 if (IS_ERR(sfctemp->rst_sense))284 return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense),285 "error getting sense reset\n");286 287 sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus");288 if (IS_ERR(sfctemp->rst_bus))289 return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus),290 "error getting busreset\n");291 292 ret = reset_control_assert(sfctemp->rst_sense);293 if (ret)294 return dev_err_probe(dev, ret, "error asserting sense reset\n");295 296 ret = reset_control_assert(sfctemp->rst_bus);297 if (ret)298 return dev_err_probe(dev, ret, "error asserting bus reset\n");299 300 ret = devm_add_action(dev, sfctemp_disable_action, sfctemp);301 if (ret)302 return ret;303 304 ret = sfctemp_enable(sfctemp);305 if (ret)306 return dev_err_probe(dev, ret, "error enabling temperature sensor\n");307 308 hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp,309 &sfctemp_chip_info, NULL);310 return PTR_ERR_OR_ZERO(hwmon_dev);311}312 313static const struct of_device_id sfctemp_of_match[] = {314 { .compatible = "starfive,jh7100-temp" },315 { .compatible = "starfive,jh7110-temp" },316 { /* sentinel */ }317};318MODULE_DEVICE_TABLE(of, sfctemp_of_match);319 320static struct platform_driver sfctemp_driver = {321 .probe = sfctemp_probe,322 .driver = {323 .name = "sfctemp",324 .of_match_table = sfctemp_of_match,325 },326};327module_platform_driver(sfctemp_driver);328 329MODULE_AUTHOR("Emil Renner Berthing");330MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver");331MODULE_LICENSE("GPL");332