Lines Matching +full:trim +full:- +full:data +full:- +full:valid

1 // SPDX-License-Identifier: GPL-2.0-only
9 * Baikal-T1 Process, Voltage, Temperature sensor driver
18 #include <linux/hwmon-sysfs.h>
34 #include "bt1-pvt.h"
44 PVT_SENSOR_INFO(1, "CPU Core Low-Vt", hwmon_in, LVT, LTHRES),
45 PVT_SENSOR_INFO(2, "CPU Core High-Vt", hwmon_in, HVT, HTHRES),
46 PVT_SENSOR_INFO(3, "CPU Core Standard-Vt", hwmon_in, SVT, STHRES),
51 * to PVT data and vice-versa are following:
52 * N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) +
54 * T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) +
55 * 3.1020e-1*(N^1) - 4.838e1,
56 * where T = [-48.380, 147.438]C and N = [0, 1023].
63 * N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T +
65 * T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D -
67 * where T = [-48380, 147438] mC and N = [0, 1023].
83 {4, -16743, 1000, 1},
85 {2, -182010, 1000, 1},
87 {0, -48380, 1, 1}
94 * N = 1.8658e3*V - 1.1572e3,
98 * N = (18658e-3*V - 11572) / 10,
105 {0, -11572, 1, 1}
117 static inline u32 pvt_update(void __iomem *reg, u32 mask, u32 data) in pvt_update() argument
122 writel((old & ~mask) | (data & mask), reg); in pvt_update()
128 * Baikal-T1 PVT mode can be updated only when the controller is disabled.
130 * getting back enabled. The same concerns the temperature trim and
140 old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_set_mode()
141 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_MODE_MASK | PVT_CTRL_EN, in pvt_set_mode()
152 static inline void pvt_set_trim(struct pvt_hwmon *pvt, u32 trim) in pvt_set_trim() argument
156 trim = FIELD_PREP(PVT_CTRL_TRIM_MASK, trim); in pvt_set_trim()
158 old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_set_trim()
159 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_TRIM_MASK | PVT_CTRL_EN, in pvt_set_trim()
160 trim | old); in pvt_set_trim()
167 old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_set_tout()
168 writel(tout, pvt->regs + PVT_TTIMEOUT); in pvt_set_tout()
169 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, old); in pvt_set_tout()
174 * controller supports. The alarms functionality is made compile-time
178 * IRQs being periodically raised to get the data cache/alarms status up to
181 * Baikal-T1 PVT embedded controller is based on the Analog Bits PVT sensor,
183 * sub-block registers space via the APB3 bus. In addition the wrapper provides
187 * thresholds comparator is enabled right after the data conversion is
193 * data conversion completion. The best driver design would be to have the
195 * driver data cache. This solution is implemented if hwmon alarms are enabled
204 static irqreturn_t pvt_soft_isr(int irq, void *data) in pvt_soft_isr() argument
207 struct pvt_hwmon *pvt = data; in pvt_soft_isr()
212 * DVALID bit will be cleared by reading the data. We need to save the in pvt_soft_isr()
216 thres_sts = readl(pvt->regs + PVT_RAW_INTR_STAT); in pvt_soft_isr()
220 * Lock the interface mutex to serialize trim, timeouts and alarm in pvt_soft_isr()
223 cache = &pvt->cache[pvt->sensor]; in pvt_soft_isr()
224 info = &pvt_info[pvt->sensor]; in pvt_soft_isr()
225 pvt->sensor = (pvt->sensor == PVT_SENSOR_LAST) ? in pvt_soft_isr()
226 PVT_SENSOR_FIRST : (pvt->sensor + 1); in pvt_soft_isr()
232 * corresponds to one. Then we read the data. By doing so we also in pvt_soft_isr()
233 * recharge the data conversion. After this the mode corresponding in pvt_soft_isr()
237 mutex_lock(&pvt->iface_mtx); in pvt_soft_isr()
239 old = pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, in pvt_soft_isr()
242 val = readl(pvt->regs + PVT_DATA); in pvt_soft_isr()
244 pvt_set_mode(pvt, pvt_info[pvt->sensor].mode); in pvt_soft_isr()
246 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, old); in pvt_soft_isr()
248 mutex_unlock(&pvt->iface_mtx); in pvt_soft_isr()
251 * We can now update the data cache with data just retrieved from the in pvt_soft_isr()
252 * sensor. Lock write-seqlock to make sure the reader has a coherent in pvt_soft_isr()
253 * data. in pvt_soft_isr()
255 write_seqlock(&cache->data_seqlock); in pvt_soft_isr()
257 cache->data = FIELD_GET(PVT_DATA_DATA_MASK, val); in pvt_soft_isr()
259 write_sequnlock(&cache->data_seqlock); in pvt_soft_isr()
262 * While PVT core is doing the next mode data conversion, we'll check in pvt_soft_isr()
265 * set at a time, that's why if-else statement is utilized. in pvt_soft_isr()
267 if ((thres_sts & info->thres_sts_lo) ^ cache->thres_sts_lo) { in pvt_soft_isr()
268 WRITE_ONCE(cache->thres_sts_lo, thres_sts & info->thres_sts_lo); in pvt_soft_isr()
269 hwmon_notify_event(pvt->hwmon, info->type, info->attr_min_alarm, in pvt_soft_isr()
270 info->channel); in pvt_soft_isr()
271 } else if ((thres_sts & info->thres_sts_hi) ^ cache->thres_sts_hi) { in pvt_soft_isr()
272 WRITE_ONCE(cache->thres_sts_hi, thres_sts & info->thres_sts_hi); in pvt_soft_isr()
273 hwmon_notify_event(pvt->hwmon, info->type, info->attr_max_alarm, in pvt_soft_isr()
274 info->channel); in pvt_soft_isr()
293 struct pvt_cache *cache = &pvt->cache[type]; in pvt_read_data()
295 u32 data; in pvt_read_data() local
298 seq = read_seqbegin(&cache->data_seqlock); in pvt_read_data()
299 data = cache->data; in pvt_read_data()
300 } while (read_seqretry(&cache->data_seqlock, seq)); in pvt_read_data()
303 *val = polynomial_calc(&poly_N_to_temp, data); in pvt_read_data()
305 *val = polynomial_calc(&poly_N_to_volt, data); in pvt_read_data()
313 u32 data; in pvt_read_limit() local
316 data = readl(pvt->regs + pvt_info[type].thres_base); in pvt_read_limit()
319 data = FIELD_GET(PVT_THRES_LO_MASK, data); in pvt_read_limit()
321 data = FIELD_GET(PVT_THRES_HI_MASK, data); in pvt_read_limit()
324 *val = polynomial_calc(&poly_N_to_temp, data); in pvt_read_limit()
326 *val = polynomial_calc(&poly_N_to_volt, data); in pvt_read_limit()
334 u32 data, limit, mask; in pvt_write_limit() local
339 data = polynomial_calc(&poly_temp_to_N, val); in pvt_write_limit()
342 data = polynomial_calc(&poly_volt_to_N, val); in pvt_write_limit()
346 ret = mutex_lock_interruptible(&pvt->iface_mtx); in pvt_write_limit()
351 limit = readl(pvt->regs + pvt_info[type].thres_base); in pvt_write_limit()
354 data = clamp_val(data, PVT_DATA_MIN, limit); in pvt_write_limit()
355 data = FIELD_PREP(PVT_THRES_LO_MASK, data); in pvt_write_limit()
359 data = clamp_val(data, limit, PVT_DATA_MAX); in pvt_write_limit()
360 data = FIELD_PREP(PVT_THRES_HI_MASK, data); in pvt_write_limit()
364 pvt_update(pvt->regs + pvt_info[type].thres_base, mask, data); in pvt_write_limit()
366 mutex_unlock(&pvt->iface_mtx); in pvt_write_limit()
375 *val = !!READ_ONCE(pvt->cache[type].thres_sts_lo); in pvt_read_alarm()
377 *val = !!READ_ONCE(pvt->cache[type].thres_sts_hi); in pvt_read_alarm()
408 static irqreturn_t pvt_hard_isr(int irq, void *data) in pvt_hard_isr() argument
410 struct pvt_hwmon *pvt = data; in pvt_hard_isr()
418 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, in pvt_hard_isr()
422 * Nothing special for alarm-less driver. Just read the data, update in pvt_hard_isr()
425 val = readl(pvt->regs + PVT_DATA); in pvt_hard_isr()
427 dev_err(pvt->dev, "Got IRQ when data isn't valid\n"); in pvt_hard_isr()
431 cache = &pvt->cache[pvt->sensor]; in pvt_hard_isr()
433 WRITE_ONCE(cache->data, FIELD_GET(PVT_DATA_DATA_MASK, val)); in pvt_hard_isr()
435 complete(&cache->conversion); in pvt_hard_isr()
455 struct pvt_cache *cache = &pvt->cache[type]; in pvt_read_data()
457 u32 data; in pvt_read_data() local
461 * Lock PVT conversion interface until data cache is updated. The in pvt_read_data()
462 * data read procedure is following: set the requested PVT sensor in pvt_read_data()
464 * then disable conversion and IRQ, and read the cached data. in pvt_read_data()
466 ret = mutex_lock_interruptible(&pvt->iface_mtx); in pvt_read_data()
470 pvt->sensor = type; in pvt_read_data()
477 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0); in pvt_read_data()
478 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); in pvt_read_data()
486 timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout)); in pvt_read_data()
487 ret = wait_for_completion_timeout(&cache->conversion, timeout); in pvt_read_data()
489 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_read_data()
490 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, in pvt_read_data()
493 data = READ_ONCE(cache->data); in pvt_read_data()
495 mutex_unlock(&pvt->iface_mtx); in pvt_read_data()
498 return -ETIMEDOUT; in pvt_read_data()
501 *val = polynomial_calc(&poly_N_to_temp, data); in pvt_read_data()
503 *val = polynomial_calc(&poly_N_to_volt, data); in pvt_read_data()
511 return -EOPNOTSUPP; in pvt_read_limit()
517 return -EOPNOTSUPP; in pvt_write_limit()
523 return -EOPNOTSUPP; in pvt_read_alarm()
562 static umode_t pvt_hwmon_is_visible(const void *data, in pvt_hwmon_is_visible() argument
614 u32 data; in pvt_read_trim() local
616 data = readl(pvt->regs + PVT_CTRL); in pvt_read_trim()
617 *val = FIELD_GET(PVT_CTRL_TRIM_MASK, data) * PVT_TRIM_STEP; in pvt_read_trim()
624 u32 trim; in pvt_write_trim() local
628 * Serialize trim update, since a part of the register is changed and in pvt_write_trim()
631 ret = mutex_lock_interruptible(&pvt->iface_mtx); in pvt_write_trim()
635 trim = pvt_calc_trim(val); in pvt_write_trim()
636 pvt_set_trim(pvt, trim); in pvt_write_trim()
638 mutex_unlock(&pvt->iface_mtx); in pvt_write_trim()
647 ret = mutex_lock_interruptible(&pvt->iface_mtx); in pvt_read_timeout()
652 *val = ktime_to_ms(pvt->timeout); in pvt_read_timeout()
654 mutex_unlock(&pvt->iface_mtx); in pvt_read_timeout()
663 u32 data; in pvt_write_timeout() local
666 rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); in pvt_write_timeout()
668 return -ENODEV; in pvt_write_timeout()
692 data = ktime_divns(kt * rate, NSEC_PER_SEC); in pvt_write_timeout()
699 ret = mutex_lock_interruptible(&pvt->iface_mtx); in pvt_write_timeout()
703 pvt_set_tout(pvt, data); in pvt_write_timeout()
704 pvt->timeout = cache; in pvt_write_timeout()
706 mutex_unlock(&pvt->iface_mtx); in pvt_write_timeout()
717 return -EINVAL; in pvt_hwmon_read()
763 return -EOPNOTSUPP; in pvt_hwmon_read()
771 return -EINVAL; in pvt_hwmon_read_string()
792 return -EOPNOTSUPP; in pvt_hwmon_read_string()
801 return -EINVAL; in pvt_hwmon_write()
832 return -EOPNOTSUPP; in pvt_hwmon_write()
847 static void pvt_clear_data(void *data) in pvt_clear_data() argument
849 struct pvt_hwmon *pvt = data; in pvt_clear_data()
854 complete_all(&pvt->cache[idx].conversion); in pvt_clear_data()
857 mutex_destroy(&pvt->iface_mtx); in pvt_clear_data()
862 struct device *dev = &pdev->dev; in pvt_create_data()
868 return ERR_PTR(-ENOMEM); in pvt_create_data()
872 dev_err(dev, "Can't add PVT data clear action\n"); in pvt_create_data()
876 pvt->dev = dev; in pvt_create_data()
877 pvt->sensor = PVT_SENSOR_FIRST; in pvt_create_data()
878 mutex_init(&pvt->iface_mtx); in pvt_create_data()
882 seqlock_init(&pvt->cache[idx].data_seqlock); in pvt_create_data()
885 init_completion(&pvt->cache[idx].conversion); in pvt_create_data()
893 struct platform_device *pdev = to_platform_device(pvt->dev); in pvt_request_regs()
895 pvt->regs = devm_platform_ioremap_resource(pdev, 0); in pvt_request_regs()
896 if (IS_ERR(pvt->regs)) in pvt_request_regs()
897 return PTR_ERR(pvt->regs); in pvt_request_regs()
902 static void pvt_disable_clks(void *data) in pvt_disable_clks() argument
904 struct pvt_hwmon *pvt = data; in pvt_disable_clks()
906 clk_bulk_disable_unprepare(PVT_CLOCK_NUM, pvt->clks); in pvt_disable_clks()
913 pvt->clks[PVT_CLOCK_APB].id = "pclk"; in pvt_request_clks()
914 pvt->clks[PVT_CLOCK_REF].id = "ref"; in pvt_request_clks()
916 ret = devm_clk_bulk_get(pvt->dev, PVT_CLOCK_NUM, pvt->clks); in pvt_request_clks()
918 dev_err(pvt->dev, "Couldn't get PVT clocks descriptors\n"); in pvt_request_clks()
922 ret = clk_bulk_prepare_enable(PVT_CLOCK_NUM, pvt->clks); in pvt_request_clks()
924 dev_err(pvt->dev, "Couldn't enable the PVT clocks\n"); in pvt_request_clks()
928 ret = devm_add_action_or_reset(pvt->dev, pvt_disable_clks, pvt); in pvt_request_clks()
930 dev_err(pvt->dev, "Can't add PVT clocks disable action\n"); in pvt_request_clks()
941 u32 data; in pvt_check_pwr() local
948 * data read procedure will either return -ETIMEDOUT (for the in pvt_check_pwr()
949 * alarm-less driver configuration) or just stop the repeated in pvt_check_pwr()
953 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL); in pvt_check_pwr()
954 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); in pvt_check_pwr()
956 readl(pvt->regs + PVT_DATA); in pvt_check_pwr()
961 data = readl(pvt->regs + PVT_DATA); in pvt_check_pwr()
962 if (!(data & PVT_DATA_VALID)) { in pvt_check_pwr()
963 ret = -ENODEV; in pvt_check_pwr()
964 dev_err(pvt->dev, "Sensor is powered down\n"); in pvt_check_pwr()
967 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_check_pwr()
975 u32 trim, temp; in pvt_init_iface() local
977 rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); in pvt_init_iface()
979 dev_err(pvt->dev, "Invalid reference clock rate\n"); in pvt_init_iface()
980 return -ENODEV; in pvt_init_iface()
985 * accidentally have ISR executed before the driver data is fully in pvt_init_iface()
988 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL); in pvt_init_iface()
989 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_init_iface()
990 readl(pvt->regs + PVT_CLR_INTR); in pvt_init_iface()
991 readl(pvt->regs + PVT_DATA); in pvt_init_iface()
993 /* Setup default sensor mode, timeout and temperature trim. */ in pvt_init_iface()
994 pvt_set_mode(pvt, pvt_info[pvt->sensor].mode); in pvt_init_iface()
998 * Preserve the current ref-clock based delay (Ttotal) between the in pvt_init_iface()
999 * sensors data samples in the driver data so not to recalculate it in pvt_init_iface()
1000 * each time on the data requests and timeout reads. It consists of the in pvt_init_iface()
1001 * delay introduced by the internal ref-clock timer (N / Fclk) and the in pvt_init_iface()
1011 pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0); in pvt_init_iface()
1012 pvt->timeout = ktime_divns(pvt->timeout, rate); in pvt_init_iface()
1013 pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN); in pvt_init_iface()
1015 pvt->timeout = ktime_set(PVT_TOUT_DEF, 0); in pvt_init_iface()
1016 pvt->timeout = ktime_divns(pvt->timeout, rate); in pvt_init_iface()
1017 pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN); in pvt_init_iface()
1020 trim = PVT_TRIM_DEF; in pvt_init_iface()
1021 if (!of_property_read_u32(pvt->dev->of_node, in pvt_init_iface()
1022 "baikal,pvt-temp-offset-millicelsius", &temp)) in pvt_init_iface()
1023 trim = pvt_calc_trim(temp); in pvt_init_iface()
1025 pvt_set_trim(pvt, trim); in pvt_init_iface()
1032 struct platform_device *pdev = to_platform_device(pvt->dev); in pvt_request_irq()
1035 pvt->irq = platform_get_irq(pdev, 0); in pvt_request_irq()
1036 if (pvt->irq < 0) in pvt_request_irq()
1037 return pvt->irq; in pvt_request_irq()
1039 ret = devm_request_threaded_irq(pvt->dev, pvt->irq, in pvt_request_irq()
1049 dev_err(pvt->dev, "Couldn't request PVT IRQ\n"); in pvt_request_irq()
1058 pvt->hwmon = devm_hwmon_device_register_with_info(pvt->dev, "pvt", pvt, in pvt_create_hwmon()
1060 if (IS_ERR(pvt->hwmon)) { in pvt_create_hwmon()
1061 dev_err(pvt->dev, "Couldn't create hwmon device\n"); in pvt_create_hwmon()
1062 return PTR_ERR(pvt->hwmon); in pvt_create_hwmon()
1070 static void pvt_disable_iface(void *data) in pvt_disable_iface() argument
1072 struct pvt_hwmon *pvt = data; in pvt_disable_iface()
1074 mutex_lock(&pvt->iface_mtx); in pvt_disable_iface()
1075 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); in pvt_disable_iface()
1076 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, in pvt_disable_iface()
1078 mutex_unlock(&pvt->iface_mtx); in pvt_disable_iface()
1085 ret = devm_add_action(pvt->dev, pvt_disable_iface, pvt); in pvt_enable_iface()
1087 dev_err(pvt->dev, "Can't add PVT disable interface action\n"); in pvt_enable_iface()
1092 * Enable sensors data conversion and IRQ. We need to lock the in pvt_enable_iface()
1094 * corresponding sysfs files are accessible from user-space, in pvt_enable_iface()
1097 mutex_lock(&pvt->iface_mtx); in pvt_enable_iface()
1098 pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0); in pvt_enable_iface()
1099 pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); in pvt_enable_iface()
1100 mutex_unlock(&pvt->iface_mtx); in pvt_enable_iface()
1155 { .compatible = "baikal,bt1-pvt" },
1163 .name = "bt1-pvt",
1170 MODULE_DESCRIPTION("Baikal-T1 PVT driver");