* [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC
@ 2026-02-20 14:35 Andy Shevchenko
2026-02-20 14:49 ` Guenter Roeck
0 siblings, 1 reply; 5+ messages in thread
From: Andy Shevchenko @ 2026-02-20 14:35 UTC (permalink / raw)
To: linux-hwmon, devicetree, linux-kernel, linux-doc
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Corbet, Shuah Khan, Andy Shevchenko
As noticed in the discussion [1] the Baikal SoC and platforms
are not going to be finalized, hence remove stale code.
Link: https://lore.kernel.org/lkml/22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org/ [1]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
.../bindings/hwmon/baikal,bt1-pvt.yaml | 105 --
Documentation/hwmon/bt1-pvt.rst | 117 --
Documentation/hwmon/index.rst | 1 -
drivers/hwmon/Kconfig | 26 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/bt1-pvt.c | 1171 -----------------
drivers/hwmon/bt1-pvt.h | 247 ----
7 files changed, 1668 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
delete mode 100644 Documentation/hwmon/bt1-pvt.rst
delete mode 100644 drivers/hwmon/bt1-pvt.c
delete mode 100644 drivers/hwmon/bt1-pvt.h
diff --git a/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml b/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
deleted file mode 100644
index 5d3ce641fcde..000000000000
--- a/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
+++ /dev/null
@@ -1,105 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/hwmon/baikal,bt1-pvt.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Baikal-T1 PVT Sensor
-
-maintainers:
- - Serge Semin <fancer.lancer@gmail.com>
-
-description: |
- Baikal-T1 SoC provides an embedded process, voltage and temperature
- sensor to monitor an internal SoC environment (chip temperature, supply
- voltage and process monitor) and on time detect critical situations,
- which may cause the system instability and even damages. The IP-block
- is based on the Analog Bits PVT sensor, but is equipped with a dedicated
- control wrapper, which provides a MMIO registers-based access to the
- sensor core functionality (APB3-bus based) and exposes an additional
- functions like thresholds/data ready interrupts, its status and masks,
- measurements timeout. Its internal structure is depicted on the next
- diagram:
-
- Analog Bits core Bakal-T1 PVT control block
- +--------------------+ +------------------------+
- | Temperature sensor |-+ +------| Sensors control |
- |--------------------| |<---En---| |------------------------|
- | Voltage sensor |-|<--Mode--| +--->| Sampled data |
- |--------------------| |<--Trim--+ | |------------------------|
- | Low-Vt sensor |-| | +--| Thresholds comparator |
- |--------------------| |---Data----| | |------------------------|
- | High-Vt sensor |-| | +->| Interrupts status |
- |--------------------| |--Valid--+-+ | |------------------------|
- | Standard-Vt sensor |-+ +---+--| Interrupts mask |
- +--------------------+ |------------------------|
- ^ | Interrupts timeout |
- | +------------------------+
- | ^ ^
- Rclk-----+----------------------------------------+ |
- APB3-------------------------------------------------+
-
- This bindings describes the external Baikal-T1 PVT control interfaces
- like MMIO registers space, interrupt request number and clocks source.
- These are then used by the corresponding hwmon device driver to
- implement the sysfs files-based access to the sensors functionality.
-
-properties:
- compatible:
- const: baikal,bt1-pvt
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- clocks:
- items:
- - description: PVT reference clock
- - description: APB3 interface clock
-
- clock-names:
- items:
- - const: ref
- - const: pclk
-
- "#thermal-sensor-cells":
- description: Baikal-T1 can be referenced as the CPU thermal-sensor
- const: 0
-
- baikal,pvt-temp-offset-millicelsius:
- description: |
- Temperature sensor trimming factor. It can be used to manually adjust the
- temperature measurements within 7.130 degrees Celsius.
- default: 0
- minimum: 0
- maximum: 7130
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - clocks
- - clock-names
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/mips-gic.h>
-
- pvt@1f200000 {
- compatible = "baikal,bt1-pvt";
- reg = <0x1f200000 0x1000>;
- #thermal-sensor-cells = <0>;
-
- interrupts = <GIC_SHARED 31 IRQ_TYPE_LEVEL_HIGH>;
-
- baikal,pvt-temp-offset-millicelsius = <1000>;
-
- clocks = <&ccu_sys>, <&ccu_sys>;
- clock-names = "ref", "pclk";
- };
-...
diff --git a/Documentation/hwmon/bt1-pvt.rst b/Documentation/hwmon/bt1-pvt.rst
deleted file mode 100644
index cbb0c0613132..000000000000
--- a/Documentation/hwmon/bt1-pvt.rst
+++ /dev/null
@@ -1,117 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0-only
-
-Kernel driver bt1-pvt
-=====================
-
-Supported chips:
-
- * Baikal-T1 PVT sensor (in SoC)
-
- Prefix: 'bt1-pvt'
-
- Addresses scanned: -
-
- Datasheet: Provided by BAIKAL ELECTRONICS upon request and under NDA
-
-Authors:
- Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>
- Serge Semin <Sergey.Semin@baikalelectronics.ru>
-
-Description
------------
-
-This driver implements support for the hardware monitoring capabilities of the
-embedded into Baikal-T1 process, voltage and temperature sensors. PVT IP-core
-consists of one temperature and four voltage sensors, which can be used to
-monitor the chip internal environment like heating, supply voltage and
-transistors performance. The driver can optionally provide the hwmon alarms
-for each sensor the PVT controller supports. The alarms functionality is made
-compile-time configurable due to the hardware interface implementation
-peculiarity, which is connected with an ability to convert data from only one
-sensor at a time. Additional limitation is that the controller performs the
-thresholds checking synchronously with the data conversion procedure. Due to
-these in order to have the hwmon alarms automatically detected the driver code
-must switch from one sensor to another, read converted data and manually check
-the threshold status bits. Depending on the measurements timeout settings
-(update_interval sysfs node value) this design may cause additional burden on
-the system performance. So in case if alarms are unnecessary in your system
-design it's recommended to have them disabled to prevent the PVT IRQs being
-periodically raised to get the data cache/alarms status up to date. By default
-in alarm-less configuration the data conversion is performed by the driver
-on demand when read operation is requested via corresponding _input-file.
-
-Temperature Monitoring
-----------------------
-
-Temperature is measured with 10-bit resolution and reported in millidegree
-Celsius. The driver performs all the scaling by itself therefore reports true
-temperatures that don't need any user-space adjustments. While the data
-translation formulae isn't linear, which gives us non-linear discreteness,
-it's close to one, but giving a bit better accuracy for higher temperatures.
-The temperature input is mapped as follows (the last column indicates the input
-ranges)::
-
- temp1: CPU embedded diode -48.38C - +147.438C
-
-In case if the alarms kernel config is enabled in the driver the temperature input
-has associated min and max limits which trigger an alarm when crossed.
-
-Voltage Monitoring
-------------------
-
-The voltage inputs are also sampled with 10-bit resolution and reported in
-millivolts. But in this case the data translation formulae is linear, which
-provides a constant measurements discreteness. The data scaling is also
-performed by the driver, so returning true millivolts. The voltage inputs are
-mapped as follows (the last column indicates the input ranges)::
-
- in0: VDD (processor core) 0.62V - 1.168V
- in1: Low-Vt (low voltage threshold) 0.62V - 1.168V
- in2: High-Vt (high voltage threshold) 0.62V - 1.168V
- in3: Standard-Vt (standard voltage threshold) 0.62V - 1.168V
-
-In case if the alarms config is enabled in the driver the voltage inputs
-have associated min and max limits which trigger an alarm when crossed.
-
-Sysfs Attributes
-----------------
-
-Following is a list of all sysfs attributes that the driver provides, their
-permissions and a short description:
-
-=============================== ======= =======================================
-Name Perm Description
-=============================== ======= =======================================
-update_interval RW Measurements update interval per
- sensor.
-temp1_type RO Sensor type (always 1 as CPU embedded
- diode).
-temp1_label RO CPU Core Temperature sensor.
-temp1_input RO Measured temperature in millidegree
- Celsius.
-temp1_min RW Low limit for temp input.
-temp1_max RW High limit for temp input.
-temp1_min_alarm RO Temperature input alarm. Returns 1 if
- temperature input went below min limit,
- 0 otherwise.
-temp1_max_alarm RO Temperature input alarm. Returns 1 if
- temperature input went above max limit,
- 0 otherwise.
-temp1_offset RW Temperature offset in millidegree
- Celsius which is added to the
- temperature reading by the chip. It can
- be used to manually adjust the
- temperature measurements within 7.130
- degrees Celsius.
-in[0-3]_label RO CPU Voltage sensor (either core or
- low/high/standard thresholds).
-in[0-3]_input RO Measured voltage in millivolts.
-in[0-3]_min RW Low limit for voltage input.
-in[0-3]_max RW High limit for voltage input.
-in[0-3]_min_alarm RO Voltage input alarm. Returns 1 if
- voltage input went below min limit,
- 0 otherwise.
-in[0-3]_max_alarm RO Voltage input alarm. Returns 1 if
- voltage input went above max limit,
- 0 otherwise.
-=============================== ======= =======================================
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index d91dbb20c7dc..d860de4a0b75 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -52,7 +52,6 @@ Hardware Monitoring Kernel Drivers
bcm54140
bel-pfe
bpa-rs600
- bt1-pvt
cgbc-hwmon
chipcap2
coretemp
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 41c381764c2b..03d393ff5955 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -457,32 +457,6 @@ config SENSORS_ATXP1
This driver can also be built as a module. If so, the module
will be called atxp1.
-config SENSORS_BT1_PVT
- tristate "Baikal-T1 Process, Voltage, Temperature sensor driver"
- depends on MIPS_BAIKAL_T1 || COMPILE_TEST
- select POLYNOMIAL
- help
- If you say yes here you get support for Baikal-T1 PVT sensor
- embedded into the SoC.
-
- This driver can also be built as a module. If so, the module will be
- called bt1-pvt.
-
-config SENSORS_BT1_PVT_ALARMS
- bool "Enable Baikal-T1 PVT sensor alarms"
- depends on SENSORS_BT1_PVT
- help
- Baikal-T1 PVT IP-block provides threshold registers for each
- supported sensor. But the corresponding interrupts might be
- generated by the thresholds comparator only in synchronization with
- a data conversion. Additionally there is only one sensor data can
- be converted at a time. All of these makes the interface impossible
- to be used for the hwmon alarms implementation without periodic
- switch between the PVT sensors. By default the data conversion is
- performed on demand from the user-space. If this config is enabled
- the data conversion will be periodically performed and the data will be
- saved in the internal driver cache.
-
config SENSORS_CGBC
tristate "Congatec Board Controller Sensors"
depends on MFD_CGBC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eade8e3b1bde..9d3659123ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tach.o
obj-$(CONFIG_SENSORS_ASUS_ROG_RYUJIN) += asus_rog_ryujin.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
-obj-$(CONFIG_SENSORS_BT1_PVT) += bt1-pvt.o
obj-$(CONFIG_SENSORS_CGBC) += cgbc-hwmon.o
obj-$(CONFIG_SENSORS_CHIPCAP2) += chipcap2.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
deleted file mode 100644
index b77ebac2e0ce..000000000000
--- a/drivers/hwmon/bt1-pvt.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
- *
- * Authors:
- * Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>
- * Serge Semin <Sergey.Semin@baikalelectronics.ru>
- *
- * Baikal-T1 Process, Voltage, Temperature sensor driver
- */
-
-#include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/hwmon.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/limits.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/polynomial.h>
-#include <linux/seqlock.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#include "bt1-pvt.h"
-
-/*
- * For the sake of the code simplification we created the sensors info table
- * with the sensor names, activation modes, threshold registers base address
- * and the thresholds bit fields.
- */
-static const struct pvt_sensor_info pvt_info[] = {
- PVT_SENSOR_INFO(0, "CPU Core Temperature", hwmon_temp, TEMP, TTHRES),
- PVT_SENSOR_INFO(0, "CPU Core Voltage", hwmon_in, VOLT, VTHRES),
- PVT_SENSOR_INFO(1, "CPU Core Low-Vt", hwmon_in, LVT, LTHRES),
- PVT_SENSOR_INFO(2, "CPU Core High-Vt", hwmon_in, HVT, HTHRES),
- PVT_SENSOR_INFO(3, "CPU Core Standard-Vt", hwmon_in, SVT, STHRES),
-};
-
-/*
- * The original translation formulae of the temperature (in degrees of Celsius)
- * to PVT data and vice-versa are following:
- * N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) +
- * 1.7204e2,
- * T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) +
- * 3.1020e-1*(N^1) - 4.838e1,
- * where T = [-48.380, 147.438]C and N = [0, 1023].
- * They must be accordingly altered to be suitable for the integer arithmetics.
- * The technique is called 'factor redistribution', which just makes sure the
- * multiplications and divisions are made so to have a result of the operations
- * within the integer numbers limit. In addition we need to translate the
- * formulae to accept millidegrees of Celsius. Here what they look like after
- * the alterations:
- * N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T +
- * 17204e2) / 1e4,
- * T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D -
- * 48380,
- * where T = [-48380, 147438] mC and N = [0, 1023].
- */
-static const struct polynomial __maybe_unused poly_temp_to_N = {
- .total_divider = 10000,
- .terms = {
- {4, 18322, 10000, 10000},
- {3, 2343, 10000, 10},
- {2, 87018, 10000, 10},
- {1, 39269, 1000, 1},
- {0, 1720400, 1, 1}
- }
-};
-
-static const struct polynomial poly_N_to_temp = {
- .total_divider = 1,
- .terms = {
- {4, -16743, 1000, 1},
- {3, 81542, 1000, 1},
- {2, -182010, 1000, 1},
- {1, 310200, 1000, 1},
- {0, -48380, 1, 1}
- }
-};
-
-/*
- * Similar alterations are performed for the voltage conversion equations.
- * The original formulae are:
- * N = 1.8658e3*V - 1.1572e3,
- * V = (N + 1.1572e3) / 1.8658e3,
- * where V = [0.620, 1.168] V and N = [0, 1023].
- * After the optimization they looks as follows:
- * N = (18658e-3*V - 11572) / 10,
- * V = N * 10^5 / 18658 + 11572 * 10^4 / 18658.
- */
-static const struct polynomial __maybe_unused poly_volt_to_N = {
- .total_divider = 10,
- .terms = {
- {1, 18658, 1000, 1},
- {0, -11572, 1, 1}
- }
-};
-
-static const struct polynomial poly_N_to_volt = {
- .total_divider = 10,
- .terms = {
- {1, 100000, 18658, 1},
- {0, 115720000, 1, 18658}
- }
-};
-
-static inline u32 pvt_update(void __iomem *reg, u32 mask, u32 data)
-{
- u32 old;
-
- old = readl_relaxed(reg);
- writel((old & ~mask) | (data & mask), reg);
-
- return old & mask;
-}
-
-/*
- * Baikal-T1 PVT mode can be updated only when the controller is disabled.
- * So first we disable it, then set the new mode together with the controller
- * getting back enabled. The same concerns the temperature trim and
- * measurements timeout. If it is necessary the interface mutex is supposed
- * to be locked at the time the operations are performed.
- */
-static inline void pvt_set_mode(struct pvt_hwmon *pvt, u32 mode)
-{
- u32 old;
-
- mode = FIELD_PREP(PVT_CTRL_MODE_MASK, mode);
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_MODE_MASK | PVT_CTRL_EN,
- mode | old);
-}
-
-static inline u32 pvt_calc_trim(long temp)
-{
- temp = clamp_val(temp, 0, PVT_TRIM_TEMP);
-
- return DIV_ROUND_UP(temp, PVT_TRIM_STEP);
-}
-
-static inline void pvt_set_trim(struct pvt_hwmon *pvt, u32 trim)
-{
- u32 old;
-
- trim = FIELD_PREP(PVT_CTRL_TRIM_MASK, trim);
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_TRIM_MASK | PVT_CTRL_EN,
- trim | old);
-}
-
-static inline void pvt_set_tout(struct pvt_hwmon *pvt, u32 tout)
-{
- u32 old;
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- writel(tout, pvt->regs + PVT_TTIMEOUT);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, old);
-}
-
-/*
- * This driver can optionally provide the hwmon alarms for each sensor the PVT
- * controller supports. The alarms functionality is made compile-time
- * configurable due to the hardware interface implementation peculiarity
- * described further in this comment. So in case if alarms are unnecessary in
- * your system design it's recommended to have them disabled to prevent the PVT
- * IRQs being periodically raised to get the data cache/alarms status up to
- * date.
- *
- * Baikal-T1 PVT embedded controller is based on the Analog Bits PVT sensor,
- * but is equipped with a dedicated control wrapper. It exposes the PVT
- * sub-block registers space via the APB3 bus. In addition the wrapper provides
- * a common interrupt vector of the sensors conversion completion events and
- * threshold value alarms. Alas the wrapper interface hasn't been fully thought
- * through. There is only one sensor can be activated at a time, for which the
- * thresholds comparator is enabled right after the data conversion is
- * completed. Due to this if alarms need to be implemented for all available
- * sensors we can't just set the thresholds and enable the interrupts. We need
- * to enable the sensors one after another and let the controller to detect
- * the alarms by itself at each conversion. This also makes pointless to handle
- * the alarms interrupts, since in occasion they happen synchronously with
- * data conversion completion. The best driver design would be to have the
- * completion interrupts enabled only and keep the converted value in the
- * driver data cache. This solution is implemented if hwmon alarms are enabled
- * in this driver. In case if the alarms are disabled, the conversion is
- * performed on demand at the time a sensors input file is read.
- */
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-
-#define pvt_hard_isr NULL
-
-static irqreturn_t pvt_soft_isr(int irq, void *data)
-{
- const struct pvt_sensor_info *info;
- struct pvt_hwmon *pvt = data;
- struct pvt_cache *cache;
- u32 val, thres_sts, old;
-
- /*
- * DVALID bit will be cleared by reading the data. We need to save the
- * status before the next conversion happens. Threshold events will be
- * handled a bit later.
- */
- thres_sts = readl(pvt->regs + PVT_RAW_INTR_STAT);
-
- /*
- * Then lets recharge the PVT interface with the next sampling mode.
- * Lock the interface mutex to serialize trim, timeouts and alarm
- * thresholds settings.
- */
- cache = &pvt->cache[pvt->sensor];
- info = &pvt_info[pvt->sensor];
- pvt->sensor = (pvt->sensor == PVT_SENSOR_LAST) ?
- PVT_SENSOR_FIRST : (pvt->sensor + 1);
-
- /*
- * For some reason we have to mask the interrupt before changing the
- * mode, otherwise sometimes the temperature mode doesn't get
- * activated even though the actual mode in the ctrl register
- * corresponds to one. Then we read the data. By doing so we also
- * recharge the data conversion. After this the mode corresponding
- * to the next sensor in the row is set. Finally we enable the
- * interrupts back.
- */
- mutex_lock(&pvt->iface_mtx);
-
- old = pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- val = readl(pvt->regs + PVT_DATA);
-
- pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
-
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, old);
-
- mutex_unlock(&pvt->iface_mtx);
-
- /*
- * We can now update the data cache with data just retrieved from the
- * sensor. Lock write-seqlock to make sure the reader has a coherent
- * data.
- */
- write_seqlock(&cache->data_seqlock);
-
- cache->data = FIELD_GET(PVT_DATA_DATA_MASK, val);
-
- write_sequnlock(&cache->data_seqlock);
-
- /*
- * While PVT core is doing the next mode data conversion, we'll check
- * whether the alarms were triggered for the current sensor. Note that
- * according to the documentation only one threshold IRQ status can be
- * set at a time, that's why if-else statement is utilized.
- */
- if ((thres_sts & info->thres_sts_lo) ^ cache->thres_sts_lo) {
- WRITE_ONCE(cache->thres_sts_lo, thres_sts & info->thres_sts_lo);
- hwmon_notify_event(pvt->hwmon, info->type, info->attr_min_alarm,
- info->channel);
- } else if ((thres_sts & info->thres_sts_hi) ^ cache->thres_sts_hi) {
- WRITE_ONCE(cache->thres_sts_hi, thres_sts & info->thres_sts_hi);
- hwmon_notify_event(pvt->hwmon, info->type, info->attr_max_alarm,
- info->channel);
- }
-
- return IRQ_HANDLED;
-}
-
-static inline umode_t pvt_limit_is_visible(enum pvt_sensor_type type)
-{
- return 0644;
-}
-
-static inline umode_t pvt_alarm_is_visible(enum pvt_sensor_type type)
-{
- return 0444;
-}
-
-static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- long *val)
-{
- struct pvt_cache *cache = &pvt->cache[type];
- unsigned int seq;
- u32 data;
-
- do {
- seq = read_seqbegin(&cache->data_seqlock);
- data = cache->data;
- } while (read_seqretry(&cache->data_seqlock, seq));
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_read_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- u32 data;
-
- /* No need in serialization, since it is just read from MMIO. */
- data = readl(pvt->regs + pvt_info[type].thres_base);
-
- if (is_low)
- data = FIELD_GET(PVT_THRES_LO_MASK, data);
- else
- data = FIELD_GET(PVT_THRES_HI_MASK, data);
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long val)
-{
- u32 data, limit, mask;
- int ret;
-
- if (type == PVT_TEMP) {
- val = clamp(val, PVT_TEMP_MIN, PVT_TEMP_MAX);
- data = polynomial_calc(&poly_temp_to_N, val);
- } else {
- val = clamp(val, PVT_VOLT_MIN, PVT_VOLT_MAX);
- data = polynomial_calc(&poly_volt_to_N, val);
- }
-
- /* Serialize limit update, since a part of the register is changed. */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- /* Make sure the upper and lower ranges don't intersect. */
- limit = readl(pvt->regs + pvt_info[type].thres_base);
- if (is_low) {
- limit = FIELD_GET(PVT_THRES_HI_MASK, limit);
- data = clamp_val(data, PVT_DATA_MIN, limit);
- data = FIELD_PREP(PVT_THRES_LO_MASK, data);
- mask = PVT_THRES_LO_MASK;
- } else {
- limit = FIELD_GET(PVT_THRES_LO_MASK, limit);
- data = clamp_val(data, limit, PVT_DATA_MAX);
- data = FIELD_PREP(PVT_THRES_HI_MASK, data);
- mask = PVT_THRES_HI_MASK;
- }
-
- pvt_update(pvt->regs + pvt_info[type].thres_base, mask, data);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- if (is_low)
- *val = !!READ_ONCE(pvt->cache[type].thres_sts_lo);
- else
- *val = !!READ_ONCE(pvt->cache[type].thres_sts_hi);
-
- return 0;
-}
-
-static const struct hwmon_channel_info * const pvt_channel_info[] = {
- HWMON_CHANNEL_INFO(chip,
- HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
- HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_TYPE | HWMON_T_LABEL |
- HWMON_T_MIN | HWMON_T_MIN_ALARM |
- HWMON_T_MAX | HWMON_T_MAX_ALARM |
- HWMON_T_OFFSET),
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM),
- NULL
-};
-
-#else /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static irqreturn_t pvt_hard_isr(int irq, void *data)
-{
- struct pvt_hwmon *pvt = data;
- struct pvt_cache *cache;
- u32 val;
-
- /*
- * Mask the DVALID interrupt so after exiting from the handler a
- * repeated conversion wouldn't happen.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- /*
- * Nothing special for alarm-less driver. Just read the data, update
- * the cache and notify a waiter of this event.
- */
- val = readl(pvt->regs + PVT_DATA);
- if (!(val & PVT_DATA_VALID)) {
- dev_err(pvt->dev, "Got IRQ when data isn't valid\n");
- return IRQ_HANDLED;
- }
-
- cache = &pvt->cache[pvt->sensor];
-
- WRITE_ONCE(cache->data, FIELD_GET(PVT_DATA_DATA_MASK, val));
-
- complete(&cache->conversion);
-
- return IRQ_HANDLED;
-}
-
-#define pvt_soft_isr NULL
-
-static inline umode_t pvt_limit_is_visible(enum pvt_sensor_type type)
-{
- return 0;
-}
-
-static inline umode_t pvt_alarm_is_visible(enum pvt_sensor_type type)
-{
- return 0;
-}
-
-static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- long *val)
-{
- struct pvt_cache *cache = &pvt->cache[type];
- unsigned long timeout;
- u32 data;
- int ret;
-
- /*
- * Lock PVT conversion interface until data cache is updated. The
- * data read procedure is following: set the requested PVT sensor
- * mode, enable IRQ and conversion, wait until conversion is finished,
- * then disable conversion and IRQ, and read the cached data.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- pvt->sensor = type;
- pvt_set_mode(pvt, pvt_info[type].mode);
-
- /*
- * Unmask the DVALID interrupt and enable the sensors conversions.
- * Do the reverse procedure when conversion is done.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
-
- /*
- * Wait with timeout since in case if the sensor is suddenly powered
- * down the request won't be completed and the caller will hang up on
- * this procedure until the power is back up again. Multiply the
- * timeout by the factor of two to prevent a false timeout.
- */
- timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout));
- ret = wait_for_completion_timeout(&cache->conversion, timeout);
-
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- data = READ_ONCE(cache->data);
-
- mutex_unlock(&pvt->iface_mtx);
-
- if (!ret)
- return -ETIMEDOUT;
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_read_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- return -EOPNOTSUPP;
-}
-
-static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long val)
-{
- return -EOPNOTSUPP;
-}
-
-static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- return -EOPNOTSUPP;
-}
-
-static const struct hwmon_channel_info * const pvt_channel_info[] = {
- HWMON_CHANNEL_INFO(chip,
- HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
- HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_TYPE | HWMON_T_LABEL |
- HWMON_T_OFFSET),
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL),
- NULL
-};
-
-#endif /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static inline bool pvt_hwmon_channel_is_valid(enum hwmon_sensor_types type,
- int ch)
-{
- switch (type) {
- case hwmon_temp:
- if (ch < 0 || ch >= PVT_TEMP_CHS)
- return false;
- break;
- case hwmon_in:
- if (ch < 0 || ch >= PVT_VOLT_CHS)
- return false;
- break;
- default:
- break;
- }
-
- /* The rest of the types are independent from the channel number. */
- return true;
-}
-
-static umode_t pvt_hwmon_is_visible(const void *data,
- enum hwmon_sensor_types type,
- u32 attr, int ch)
-{
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return 0;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return 0644;
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- case hwmon_temp_type:
- case hwmon_temp_label:
- return 0444;
- case hwmon_temp_min:
- case hwmon_temp_max:
- return pvt_limit_is_visible(ch);
- case hwmon_temp_min_alarm:
- case hwmon_temp_max_alarm:
- return pvt_alarm_is_visible(ch);
- case hwmon_temp_offset:
- return 0644;
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- case hwmon_in_label:
- return 0444;
- case hwmon_in_min:
- case hwmon_in_max:
- return pvt_limit_is_visible(PVT_VOLT + ch);
- case hwmon_in_min_alarm:
- case hwmon_in_max_alarm:
- return pvt_alarm_is_visible(PVT_VOLT + ch);
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int pvt_read_trim(struct pvt_hwmon *pvt, long *val)
-{
- u32 data;
-
- data = readl(pvt->regs + PVT_CTRL);
- *val = FIELD_GET(PVT_CTRL_TRIM_MASK, data) * PVT_TRIM_STEP;
-
- return 0;
-}
-
-static int pvt_write_trim(struct pvt_hwmon *pvt, long val)
-{
- u32 trim;
- int ret;
-
- /*
- * Serialize trim update, since a part of the register is changed and
- * the controller is supposed to be disabled during this operation.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- trim = pvt_calc_trim(val);
- pvt_set_trim(pvt, trim);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val)
-{
- int ret;
-
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- /* Return the result in msec as hwmon sysfs interface requires. */
- *val = ktime_to_ms(pvt->timeout);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_write_timeout(struct pvt_hwmon *pvt, long val)
-{
- unsigned long rate;
- ktime_t kt, cache;
- u32 data;
- int ret;
-
- rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk);
- if (!rate)
- return -ENODEV;
-
- /*
- * If alarms are enabled, the requested timeout must be divided
- * between all available sensors to have the requested delay
- * applicable to each individual sensor.
- */
- cache = kt = ms_to_ktime(val);
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- kt = ktime_divns(kt, PVT_SENSORS_NUM);
-#endif
-
- /*
- * Subtract a constant lag, which always persists due to the limited
- * PVT sampling rate. Make sure the timeout is not negative.
- */
- kt = ktime_sub_ns(kt, PVT_TOUT_MIN);
- if (ktime_to_ns(kt) < 0)
- kt = ktime_set(0, 0);
-
- /*
- * Finally recalculate the timeout in terms of the reference clock
- * period.
- */
- data = ktime_divns(kt * rate, NSEC_PER_SEC);
-
- /*
- * Update the measurements delay, but lock the interface first, since
- * we have to disable PVT in order to have the new delay actually
- * updated.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- pvt_set_tout(pvt, data);
- pvt->timeout = cache;
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int ch, long *val)
-{
- struct pvt_hwmon *pvt = dev_get_drvdata(dev);
-
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return pvt_read_timeout(pvt, val);
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- return pvt_read_data(pvt, ch, val);
- case hwmon_temp_type:
- *val = 1;
- return 0;
- case hwmon_temp_min:
- return pvt_read_limit(pvt, ch, true, val);
- case hwmon_temp_max:
- return pvt_read_limit(pvt, ch, false, val);
- case hwmon_temp_min_alarm:
- return pvt_read_alarm(pvt, ch, true, val);
- case hwmon_temp_max_alarm:
- return pvt_read_alarm(pvt, ch, false, val);
- case hwmon_temp_offset:
- return pvt_read_trim(pvt, val);
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- return pvt_read_data(pvt, PVT_VOLT + ch, val);
- case hwmon_in_min:
- return pvt_read_limit(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max:
- return pvt_read_limit(pvt, PVT_VOLT + ch, false, val);
- case hwmon_in_min_alarm:
- return pvt_read_alarm(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max_alarm:
- return pvt_read_alarm(pvt, PVT_VOLT + ch, false, val);
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int pvt_hwmon_read_string(struct device *dev,
- enum hwmon_sensor_types type,
- u32 attr, int ch, const char **str)
-{
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_label:
- *str = pvt_info[ch].label;
- return 0;
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_label:
- *str = pvt_info[PVT_VOLT + ch].label;
- return 0;
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int pvt_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int ch, long val)
-{
- struct pvt_hwmon *pvt = dev_get_drvdata(dev);
-
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return pvt_write_timeout(pvt, val);
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_min:
- return pvt_write_limit(pvt, ch, true, val);
- case hwmon_temp_max:
- return pvt_write_limit(pvt, ch, false, val);
- case hwmon_temp_offset:
- return pvt_write_trim(pvt, val);
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_min:
- return pvt_write_limit(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max:
- return pvt_write_limit(pvt, PVT_VOLT + ch, false, val);
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static const struct hwmon_ops pvt_hwmon_ops = {
- .is_visible = pvt_hwmon_is_visible,
- .read = pvt_hwmon_read,
- .read_string = pvt_hwmon_read_string,
- .write = pvt_hwmon_write
-};
-
-static const struct hwmon_chip_info pvt_hwmon_info = {
- .ops = &pvt_hwmon_ops,
- .info = pvt_channel_info
-};
-
-static void pvt_clear_data(void *data)
-{
- struct pvt_hwmon *pvt = data;
-#if !defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- int idx;
-
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- complete_all(&pvt->cache[idx].conversion);
-#endif
-
- mutex_destroy(&pvt->iface_mtx);
-}
-
-static struct pvt_hwmon *pvt_create_data(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct pvt_hwmon *pvt;
- int ret, idx;
-
- pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL);
- if (!pvt)
- return ERR_PTR(-ENOMEM);
-
- ret = devm_add_action(dev, pvt_clear_data, pvt);
- if (ret) {
- dev_err(dev, "Can't add PVT data clear action\n");
- return ERR_PTR(ret);
- }
-
- pvt->dev = dev;
- pvt->sensor = PVT_SENSOR_FIRST;
- mutex_init(&pvt->iface_mtx);
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- seqlock_init(&pvt->cache[idx].data_seqlock);
-#else
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- init_completion(&pvt->cache[idx].conversion);
-#endif
-
- return pvt;
-}
-
-static int pvt_request_regs(struct pvt_hwmon *pvt)
-{
- struct platform_device *pdev = to_platform_device(pvt->dev);
-
- pvt->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(pvt->regs))
- return PTR_ERR(pvt->regs);
-
- return 0;
-}
-
-static void pvt_disable_clks(void *data)
-{
- struct pvt_hwmon *pvt = data;
-
- clk_bulk_disable_unprepare(PVT_CLOCK_NUM, pvt->clks);
-}
-
-static int pvt_request_clks(struct pvt_hwmon *pvt)
-{
- int ret;
-
- pvt->clks[PVT_CLOCK_APB].id = "pclk";
- pvt->clks[PVT_CLOCK_REF].id = "ref";
-
- ret = devm_clk_bulk_get(pvt->dev, PVT_CLOCK_NUM, pvt->clks);
- if (ret) {
- dev_err(pvt->dev, "Couldn't get PVT clocks descriptors\n");
- return ret;
- }
-
- ret = clk_bulk_prepare_enable(PVT_CLOCK_NUM, pvt->clks);
- if (ret) {
- dev_err(pvt->dev, "Couldn't enable the PVT clocks\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(pvt->dev, pvt_disable_clks, pvt);
- if (ret) {
- dev_err(pvt->dev, "Can't add PVT clocks disable action\n");
- return ret;
- }
-
- return 0;
-}
-
-static int pvt_check_pwr(struct pvt_hwmon *pvt)
-{
- unsigned long tout;
- int ret = 0;
- u32 data;
-
- /*
- * Test out the sensor conversion functionality. If it is not done on
- * time then the domain must have been unpowered and we won't be able
- * to use the device later in this driver.
- * Note If the power source is lost during the normal driver work the
- * data read procedure will either return -ETIMEDOUT (for the
- * alarm-less driver configuration) or just stop the repeated
- * conversion. In the later case alas we won't be able to detect the
- * problem.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
- pvt_set_tout(pvt, 0);
- readl(pvt->regs + PVT_DATA);
-
- tout = PVT_TOUT_MIN / NSEC_PER_USEC;
- usleep_range(tout, 2 * tout);
-
- data = readl(pvt->regs + PVT_DATA);
- if (!(data & PVT_DATA_VALID)) {
- ret = -ENODEV;
- dev_err(pvt->dev, "Sensor is powered down\n");
- }
-
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
-
- return ret;
-}
-
-static int pvt_init_iface(struct pvt_hwmon *pvt)
-{
- unsigned long rate;
- u32 trim, temp;
-
- rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk);
- if (!rate) {
- dev_err(pvt->dev, "Invalid reference clock rate\n");
- return -ENODEV;
- }
-
- /*
- * Make sure all interrupts and controller are disabled so not to
- * accidentally have ISR executed before the driver data is fully
- * initialized. Clear the IRQ status as well.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- readl(pvt->regs + PVT_CLR_INTR);
- readl(pvt->regs + PVT_DATA);
-
- /* Setup default sensor mode, timeout and temperature trim. */
- pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
- pvt_set_tout(pvt, PVT_TOUT_DEF);
-
- /*
- * Preserve the current ref-clock based delay (Ttotal) between the
- * sensors data samples in the driver data so not to recalculate it
- * each time on the data requests and timeout reads. It consists of the
- * delay introduced by the internal ref-clock timer (N / Fclk) and the
- * constant timeout caused by each conversion latency (Tmin):
- * Ttotal = N / Fclk + Tmin
- * If alarms are enabled the sensors are polled one after another and
- * in order to get the next measurement of a particular sensor the
- * caller will have to wait for at most until all the others are
- * polled. In that case the formulae will look a bit different:
- * Ttotal = 5 * (N / Fclk + Tmin)
- */
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0);
- pvt->timeout = ktime_divns(pvt->timeout, rate);
- pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN);
-#else
- pvt->timeout = ktime_set(PVT_TOUT_DEF, 0);
- pvt->timeout = ktime_divns(pvt->timeout, rate);
- pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN);
-#endif
-
- trim = PVT_TRIM_DEF;
- if (!of_property_read_u32(pvt->dev->of_node,
- "baikal,pvt-temp-offset-millicelsius", &temp))
- trim = pvt_calc_trim(temp);
-
- pvt_set_trim(pvt, trim);
-
- return 0;
-}
-
-static int pvt_request_irq(struct pvt_hwmon *pvt)
-{
- struct platform_device *pdev = to_platform_device(pvt->dev);
- int ret;
-
- pvt->irq = platform_get_irq(pdev, 0);
- if (pvt->irq < 0)
- return pvt->irq;
-
- ret = devm_request_threaded_irq(pvt->dev, pvt->irq,
- pvt_hard_isr, pvt_soft_isr,
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- IRQF_SHARED | IRQF_TRIGGER_HIGH |
- IRQF_ONESHOT,
-#else
- IRQF_SHARED | IRQF_TRIGGER_HIGH,
-#endif
- "pvt", pvt);
- if (ret) {
- dev_err(pvt->dev, "Couldn't request PVT IRQ\n");
- return ret;
- }
-
- return 0;
-}
-
-static int pvt_create_hwmon(struct pvt_hwmon *pvt)
-{
- pvt->hwmon = devm_hwmon_device_register_with_info(pvt->dev, "pvt", pvt,
- &pvt_hwmon_info, NULL);
- if (IS_ERR(pvt->hwmon)) {
- dev_err(pvt->dev, "Couldn't create hwmon device\n");
- return PTR_ERR(pvt->hwmon);
- }
-
- return 0;
-}
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-
-static void pvt_disable_iface(void *data)
-{
- struct pvt_hwmon *pvt = data;
-
- mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
- mutex_unlock(&pvt->iface_mtx);
-}
-
-static int pvt_enable_iface(struct pvt_hwmon *pvt)
-{
- int ret;
-
- ret = devm_add_action(pvt->dev, pvt_disable_iface, pvt);
- if (ret) {
- dev_err(pvt->dev, "Can't add PVT disable interface action\n");
- return ret;
- }
-
- /*
- * Enable sensors data conversion and IRQ. We need to lock the
- * interface mutex since hwmon has just been created and the
- * corresponding sysfs files are accessible from user-space,
- * which theoretically may cause races.
- */
- mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-#else /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static int pvt_enable_iface(struct pvt_hwmon *pvt)
-{
- return 0;
-}
-
-#endif /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static int pvt_probe(struct platform_device *pdev)
-{
- struct pvt_hwmon *pvt;
- int ret;
-
- pvt = pvt_create_data(pdev);
- if (IS_ERR(pvt))
- return PTR_ERR(pvt);
-
- ret = pvt_request_regs(pvt);
- if (ret)
- return ret;
-
- ret = pvt_request_clks(pvt);
- if (ret)
- return ret;
-
- ret = pvt_check_pwr(pvt);
- if (ret)
- return ret;
-
- ret = pvt_init_iface(pvt);
- if (ret)
- return ret;
-
- ret = pvt_request_irq(pvt);
- if (ret)
- return ret;
-
- ret = pvt_create_hwmon(pvt);
- if (ret)
- return ret;
-
- ret = pvt_enable_iface(pvt);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static const struct of_device_id pvt_of_match[] = {
- { .compatible = "baikal,bt1-pvt" },
- { }
-};
-MODULE_DEVICE_TABLE(of, pvt_of_match);
-
-static struct platform_driver pvt_driver = {
- .probe = pvt_probe,
- .driver = {
- .name = "bt1-pvt",
- .of_match_table = pvt_of_match
- }
-};
-module_platform_driver(pvt_driver);
-
-MODULE_AUTHOR("Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>");
-MODULE_DESCRIPTION("Baikal-T1 PVT driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/bt1-pvt.h b/drivers/hwmon/bt1-pvt.h
deleted file mode 100644
index 93b8dd5e7c94..000000000000
--- a/drivers/hwmon/bt1-pvt.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
- *
- * Baikal-T1 Process, Voltage, Temperature sensor driver
- */
-#ifndef __HWMON_BT1_PVT_H__
-#define __HWMON_BT1_PVT_H__
-
-#include <linux/completion.h>
-#include <linux/hwmon.h>
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/seqlock.h>
-
-/* Baikal-T1 PVT registers and their bitfields */
-#define PVT_CTRL 0x00
-#define PVT_CTRL_EN BIT(0)
-#define PVT_CTRL_MODE_FLD 1
-#define PVT_CTRL_MODE_MASK GENMASK(3, PVT_CTRL_MODE_FLD)
-#define PVT_CTRL_MODE_TEMP 0x0
-#define PVT_CTRL_MODE_VOLT 0x1
-#define PVT_CTRL_MODE_LVT 0x2
-#define PVT_CTRL_MODE_HVT 0x4
-#define PVT_CTRL_MODE_SVT 0x6
-#define PVT_CTRL_TRIM_FLD 4
-#define PVT_CTRL_TRIM_MASK GENMASK(8, PVT_CTRL_TRIM_FLD)
-#define PVT_DATA 0x04
-#define PVT_DATA_VALID BIT(10)
-#define PVT_DATA_DATA_FLD 0
-#define PVT_DATA_DATA_MASK GENMASK(9, PVT_DATA_DATA_FLD)
-#define PVT_TTHRES 0x08
-#define PVT_VTHRES 0x0C
-#define PVT_LTHRES 0x10
-#define PVT_HTHRES 0x14
-#define PVT_STHRES 0x18
-#define PVT_THRES_LO_FLD 0
-#define PVT_THRES_LO_MASK GENMASK(9, PVT_THRES_LO_FLD)
-#define PVT_THRES_HI_FLD 10
-#define PVT_THRES_HI_MASK GENMASK(19, PVT_THRES_HI_FLD)
-#define PVT_TTIMEOUT 0x1C
-#define PVT_INTR_STAT 0x20
-#define PVT_INTR_MASK 0x24
-#define PVT_RAW_INTR_STAT 0x28
-#define PVT_INTR_DVALID BIT(0)
-#define PVT_INTR_TTHRES_LO BIT(1)
-#define PVT_INTR_TTHRES_HI BIT(2)
-#define PVT_INTR_VTHRES_LO BIT(3)
-#define PVT_INTR_VTHRES_HI BIT(4)
-#define PVT_INTR_LTHRES_LO BIT(5)
-#define PVT_INTR_LTHRES_HI BIT(6)
-#define PVT_INTR_HTHRES_LO BIT(7)
-#define PVT_INTR_HTHRES_HI BIT(8)
-#define PVT_INTR_STHRES_LO BIT(9)
-#define PVT_INTR_STHRES_HI BIT(10)
-#define PVT_INTR_ALL GENMASK(10, 0)
-#define PVT_CLR_INTR 0x2C
-
-/*
- * PVT sensors-related limits and default values
- * @PVT_TEMP_MIN: Minimal temperature in millidegrees of Celsius.
- * @PVT_TEMP_MAX: Maximal temperature in millidegrees of Celsius.
- * @PVT_TEMP_CHS: Number of temperature hwmon channels.
- * @PVT_VOLT_MIN: Minimal voltage in mV.
- * @PVT_VOLT_MAX: Maximal voltage in mV.
- * @PVT_VOLT_CHS: Number of voltage hwmon channels.
- * @PVT_DATA_MIN: Minimal PVT raw data value.
- * @PVT_DATA_MAX: Maximal PVT raw data value.
- * @PVT_TRIM_MIN: Minimal temperature sensor trim value.
- * @PVT_TRIM_MAX: Maximal temperature sensor trim value.
- * @PVT_TRIM_DEF: Default temperature sensor trim value (set a proper value
- * when one is determined for Baikal-T1 SoC).
- * @PVT_TRIM_TEMP: Maximum temperature encoded by the trim factor.
- * @PVT_TRIM_STEP: Temperature stride corresponding to the trim value.
- * @PVT_TOUT_MIN: Minimal timeout between samples in nanoseconds.
- * @PVT_TOUT_DEF: Default data measurements timeout. In case if alarms are
- * activated the PVT IRQ is enabled to be raised after each
- * conversion in order to have the thresholds checked and the
- * converted value cached. Too frequent conversions may cause
- * the system CPU overload. Lets set the 50ms delay between
- * them by default to prevent this.
- */
-#define PVT_TEMP_MIN -48380L
-#define PVT_TEMP_MAX 147438L
-#define PVT_TEMP_CHS 1
-#define PVT_VOLT_MIN 620L
-#define PVT_VOLT_MAX 1168L
-#define PVT_VOLT_CHS 4
-#define PVT_DATA_MIN 0
-#define PVT_DATA_MAX (PVT_DATA_DATA_MASK >> PVT_DATA_DATA_FLD)
-#define PVT_TRIM_MIN 0
-#define PVT_TRIM_MAX (PVT_CTRL_TRIM_MASK >> PVT_CTRL_TRIM_FLD)
-#define PVT_TRIM_TEMP 7130
-#define PVT_TRIM_STEP (PVT_TRIM_TEMP / PVT_TRIM_MAX)
-#define PVT_TRIM_DEF 0
-#define PVT_TOUT_MIN (NSEC_PER_SEC / 3000)
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-# define PVT_TOUT_DEF 60000
-#else
-# define PVT_TOUT_DEF 0
-#endif
-
-/*
- * enum pvt_sensor_type - Baikal-T1 PVT sensor types (correspond to each PVT
- * sampling mode)
- * @PVT_SENSOR*: helpers to traverse the sensors in loops.
- * @PVT_TEMP: PVT Temperature sensor.
- * @PVT_VOLT: PVT Voltage sensor.
- * @PVT_LVT: PVT Low-Voltage threshold sensor.
- * @PVT_HVT: PVT High-Voltage threshold sensor.
- * @PVT_SVT: PVT Standard-Voltage threshold sensor.
- */
-enum pvt_sensor_type {
- PVT_SENSOR_FIRST,
- PVT_TEMP = PVT_SENSOR_FIRST,
- PVT_VOLT,
- PVT_LVT,
- PVT_HVT,
- PVT_SVT,
- PVT_SENSOR_LAST = PVT_SVT,
- PVT_SENSORS_NUM
-};
-
-/*
- * enum pvt_clock_type - Baikal-T1 PVT clocks.
- * @PVT_CLOCK_APB: APB clock.
- * @PVT_CLOCK_REF: PVT reference clock.
- */
-enum pvt_clock_type {
- PVT_CLOCK_APB,
- PVT_CLOCK_REF,
- PVT_CLOCK_NUM
-};
-
-/*
- * struct pvt_sensor_info - Baikal-T1 PVT sensor informational structure
- * @channel: Sensor channel ID.
- * @label: hwmon sensor label.
- * @mode: PVT mode corresponding to the channel.
- * @thres_base: upper and lower threshold values of the sensor.
- * @thres_sts_lo: low threshold status bitfield.
- * @thres_sts_hi: high threshold status bitfield.
- * @type: Sensor type.
- * @attr_min_alarm: Min alarm attribute ID.
- * @attr_min_alarm: Max alarm attribute ID.
- */
-struct pvt_sensor_info {
- int channel;
- const char *label;
- u32 mode;
- unsigned long thres_base;
- u32 thres_sts_lo;
- u32 thres_sts_hi;
- enum hwmon_sensor_types type;
- u32 attr_min_alarm;
- u32 attr_max_alarm;
-};
-
-#define PVT_SENSOR_INFO(_ch, _label, _type, _mode, _thres) \
- { \
- .channel = _ch, \
- .label = _label, \
- .mode = PVT_CTRL_MODE_ ##_mode, \
- .thres_base = PVT_ ##_thres, \
- .thres_sts_lo = PVT_INTR_ ##_thres## _LO, \
- .thres_sts_hi = PVT_INTR_ ##_thres## _HI, \
- .type = _type, \
- .attr_min_alarm = _type## _min, \
- .attr_max_alarm = _type## _max, \
- }
-
-/*
- * struct pvt_cache - PVT sensors data cache
- * @data: data cache in raw format.
- * @thres_sts_lo: low threshold status saved on the previous data conversion.
- * @thres_sts_hi: high threshold status saved on the previous data conversion.
- * @data_seqlock: cached data seq-lock.
- * @conversion: data conversion completion.
- */
-struct pvt_cache {
- u32 data;
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- seqlock_t data_seqlock;
- u32 thres_sts_lo;
- u32 thres_sts_hi;
-#else
- struct completion conversion;
-#endif
-};
-
-/*
- * struct pvt_hwmon - Baikal-T1 PVT private data
- * @dev: device structure of the PVT platform device.
- * @hwmon: hwmon device structure.
- * @regs: pointer to the Baikal-T1 PVT registers region.
- * @irq: PVT events IRQ number.
- * @clks: Array of the PVT clocks descriptor (APB/ref clocks).
- * @ref_clk: Pointer to the reference clocks descriptor.
- * @iface_mtx: Generic interface mutex (used to lock the alarm registers
- * when the alarms enabled, or the data conversion interface
- * if alarms are disabled).
- * @sensor: current PVT sensor the data conversion is being performed for.
- * @cache: data cache descriptor.
- * @timeout: conversion timeout cache.
- */
-struct pvt_hwmon {
- struct device *dev;
- struct device *hwmon;
-
- void __iomem *regs;
- int irq;
-
- struct clk_bulk_data clks[PVT_CLOCK_NUM];
-
- struct mutex iface_mtx;
- enum pvt_sensor_type sensor;
- struct pvt_cache cache[PVT_SENSORS_NUM];
- ktime_t timeout;
-};
-
-/*
- * struct pvt_poly_term - a term descriptor of the PVT data translation
- * polynomial
- * @deg: degree of the term.
- * @coef: multiplication factor of the term.
- * @divider: distributed divider per each degree.
- * @divider_leftover: divider leftover, which couldn't be redistributed.
- */
-struct pvt_poly_term {
- unsigned int deg;
- long coef;
- long divider;
- long divider_leftover;
-};
-
-/*
- * struct pvt_poly - PVT data translation polynomial descriptor
- * @total_divider: total data divider.
- * @terms: polynomial terms up to a free one.
- */
-struct pvt_poly {
- long total_divider;
- struct pvt_poly_term terms[];
-};
-
-#endif /* __HWMON_BT1_PVT_H__ */
--
2.50.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC
2026-02-20 14:35 [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC Andy Shevchenko
@ 2026-02-20 14:49 ` Guenter Roeck
0 siblings, 0 replies; 5+ messages in thread
From: Guenter Roeck @ 2026-02-20 14:49 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-hwmon, devicetree, linux-kernel, linux-doc, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet, Shuah Khan
On Fri, Feb 20, 2026 at 03:35:00PM +0100, Andy Shevchenko wrote:
> As noticed in the discussion [1] the Baikal SoC and platforms
> are not going to be finalized, hence remove stale code.
>
> Link: https://lore.kernel.org/lkml/22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org/ [1]
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Applied.
Guenter
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC
@ 2026-02-20 14:36 Andy Shevchenko
2026-02-20 14:42 ` Andy Shevchenko
2026-02-23 18:58 ` Rob Herring (Arm)
0 siblings, 2 replies; 5+ messages in thread
From: Andy Shevchenko @ 2026-02-20 14:36 UTC (permalink / raw)
To: linux-hwmon, devicetree, linux-kernel, linux-doc
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Corbet, Shuah Khan, Andy Shevchenko
As noticed in the discussion [1] the Baikal SoC and platforms
are not going to be finalized, hence remove stale code.
Link: https://lore.kernel.org/lkml/22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org/ [1]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
.../bindings/hwmon/baikal,bt1-pvt.yaml | 105 --
Documentation/hwmon/bt1-pvt.rst | 117 --
Documentation/hwmon/index.rst | 1 -
drivers/hwmon/Kconfig | 26 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/bt1-pvt.c | 1171 -----------------
drivers/hwmon/bt1-pvt.h | 247 ----
7 files changed, 1668 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
delete mode 100644 Documentation/hwmon/bt1-pvt.rst
delete mode 100644 drivers/hwmon/bt1-pvt.c
delete mode 100644 drivers/hwmon/bt1-pvt.h
diff --git a/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml b/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
deleted file mode 100644
index 5d3ce641fcde..000000000000
--- a/Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
+++ /dev/null
@@ -1,105 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/hwmon/baikal,bt1-pvt.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Baikal-T1 PVT Sensor
-
-maintainers:
- - Serge Semin <fancer.lancer@gmail.com>
-
-description: |
- Baikal-T1 SoC provides an embedded process, voltage and temperature
- sensor to monitor an internal SoC environment (chip temperature, supply
- voltage and process monitor) and on time detect critical situations,
- which may cause the system instability and even damages. The IP-block
- is based on the Analog Bits PVT sensor, but is equipped with a dedicated
- control wrapper, which provides a MMIO registers-based access to the
- sensor core functionality (APB3-bus based) and exposes an additional
- functions like thresholds/data ready interrupts, its status and masks,
- measurements timeout. Its internal structure is depicted on the next
- diagram:
-
- Analog Bits core Bakal-T1 PVT control block
- +--------------------+ +------------------------+
- | Temperature sensor |-+ +------| Sensors control |
- |--------------------| |<---En---| |------------------------|
- | Voltage sensor |-|<--Mode--| +--->| Sampled data |
- |--------------------| |<--Trim--+ | |------------------------|
- | Low-Vt sensor |-| | +--| Thresholds comparator |
- |--------------------| |---Data----| | |------------------------|
- | High-Vt sensor |-| | +->| Interrupts status |
- |--------------------| |--Valid--+-+ | |------------------------|
- | Standard-Vt sensor |-+ +---+--| Interrupts mask |
- +--------------------+ |------------------------|
- ^ | Interrupts timeout |
- | +------------------------+
- | ^ ^
- Rclk-----+----------------------------------------+ |
- APB3-------------------------------------------------+
-
- This bindings describes the external Baikal-T1 PVT control interfaces
- like MMIO registers space, interrupt request number and clocks source.
- These are then used by the corresponding hwmon device driver to
- implement the sysfs files-based access to the sensors functionality.
-
-properties:
- compatible:
- const: baikal,bt1-pvt
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- clocks:
- items:
- - description: PVT reference clock
- - description: APB3 interface clock
-
- clock-names:
- items:
- - const: ref
- - const: pclk
-
- "#thermal-sensor-cells":
- description: Baikal-T1 can be referenced as the CPU thermal-sensor
- const: 0
-
- baikal,pvt-temp-offset-millicelsius:
- description: |
- Temperature sensor trimming factor. It can be used to manually adjust the
- temperature measurements within 7.130 degrees Celsius.
- default: 0
- minimum: 0
- maximum: 7130
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - clocks
- - clock-names
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/mips-gic.h>
-
- pvt@1f200000 {
- compatible = "baikal,bt1-pvt";
- reg = <0x1f200000 0x1000>;
- #thermal-sensor-cells = <0>;
-
- interrupts = <GIC_SHARED 31 IRQ_TYPE_LEVEL_HIGH>;
-
- baikal,pvt-temp-offset-millicelsius = <1000>;
-
- clocks = <&ccu_sys>, <&ccu_sys>;
- clock-names = "ref", "pclk";
- };
-...
diff --git a/Documentation/hwmon/bt1-pvt.rst b/Documentation/hwmon/bt1-pvt.rst
deleted file mode 100644
index cbb0c0613132..000000000000
--- a/Documentation/hwmon/bt1-pvt.rst
+++ /dev/null
@@ -1,117 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0-only
-
-Kernel driver bt1-pvt
-=====================
-
-Supported chips:
-
- * Baikal-T1 PVT sensor (in SoC)
-
- Prefix: 'bt1-pvt'
-
- Addresses scanned: -
-
- Datasheet: Provided by BAIKAL ELECTRONICS upon request and under NDA
-
-Authors:
- Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>
- Serge Semin <Sergey.Semin@baikalelectronics.ru>
-
-Description
------------
-
-This driver implements support for the hardware monitoring capabilities of the
-embedded into Baikal-T1 process, voltage and temperature sensors. PVT IP-core
-consists of one temperature and four voltage sensors, which can be used to
-monitor the chip internal environment like heating, supply voltage and
-transistors performance. The driver can optionally provide the hwmon alarms
-for each sensor the PVT controller supports. The alarms functionality is made
-compile-time configurable due to the hardware interface implementation
-peculiarity, which is connected with an ability to convert data from only one
-sensor at a time. Additional limitation is that the controller performs the
-thresholds checking synchronously with the data conversion procedure. Due to
-these in order to have the hwmon alarms automatically detected the driver code
-must switch from one sensor to another, read converted data and manually check
-the threshold status bits. Depending on the measurements timeout settings
-(update_interval sysfs node value) this design may cause additional burden on
-the system performance. So in case if alarms are unnecessary in your system
-design it's recommended to have them disabled to prevent the PVT IRQs being
-periodically raised to get the data cache/alarms status up to date. By default
-in alarm-less configuration the data conversion is performed by the driver
-on demand when read operation is requested via corresponding _input-file.
-
-Temperature Monitoring
-----------------------
-
-Temperature is measured with 10-bit resolution and reported in millidegree
-Celsius. The driver performs all the scaling by itself therefore reports true
-temperatures that don't need any user-space adjustments. While the data
-translation formulae isn't linear, which gives us non-linear discreteness,
-it's close to one, but giving a bit better accuracy for higher temperatures.
-The temperature input is mapped as follows (the last column indicates the input
-ranges)::
-
- temp1: CPU embedded diode -48.38C - +147.438C
-
-In case if the alarms kernel config is enabled in the driver the temperature input
-has associated min and max limits which trigger an alarm when crossed.
-
-Voltage Monitoring
-------------------
-
-The voltage inputs are also sampled with 10-bit resolution and reported in
-millivolts. But in this case the data translation formulae is linear, which
-provides a constant measurements discreteness. The data scaling is also
-performed by the driver, so returning true millivolts. The voltage inputs are
-mapped as follows (the last column indicates the input ranges)::
-
- in0: VDD (processor core) 0.62V - 1.168V
- in1: Low-Vt (low voltage threshold) 0.62V - 1.168V
- in2: High-Vt (high voltage threshold) 0.62V - 1.168V
- in3: Standard-Vt (standard voltage threshold) 0.62V - 1.168V
-
-In case if the alarms config is enabled in the driver the voltage inputs
-have associated min and max limits which trigger an alarm when crossed.
-
-Sysfs Attributes
-----------------
-
-Following is a list of all sysfs attributes that the driver provides, their
-permissions and a short description:
-
-=============================== ======= =======================================
-Name Perm Description
-=============================== ======= =======================================
-update_interval RW Measurements update interval per
- sensor.
-temp1_type RO Sensor type (always 1 as CPU embedded
- diode).
-temp1_label RO CPU Core Temperature sensor.
-temp1_input RO Measured temperature in millidegree
- Celsius.
-temp1_min RW Low limit for temp input.
-temp1_max RW High limit for temp input.
-temp1_min_alarm RO Temperature input alarm. Returns 1 if
- temperature input went below min limit,
- 0 otherwise.
-temp1_max_alarm RO Temperature input alarm. Returns 1 if
- temperature input went above max limit,
- 0 otherwise.
-temp1_offset RW Temperature offset in millidegree
- Celsius which is added to the
- temperature reading by the chip. It can
- be used to manually adjust the
- temperature measurements within 7.130
- degrees Celsius.
-in[0-3]_label RO CPU Voltage sensor (either core or
- low/high/standard thresholds).
-in[0-3]_input RO Measured voltage in millivolts.
-in[0-3]_min RW Low limit for voltage input.
-in[0-3]_max RW High limit for voltage input.
-in[0-3]_min_alarm RO Voltage input alarm. Returns 1 if
- voltage input went below min limit,
- 0 otherwise.
-in[0-3]_max_alarm RO Voltage input alarm. Returns 1 if
- voltage input went above max limit,
- 0 otherwise.
-=============================== ======= =======================================
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index d91dbb20c7dc..d860de4a0b75 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -52,7 +52,6 @@ Hardware Monitoring Kernel Drivers
bcm54140
bel-pfe
bpa-rs600
- bt1-pvt
cgbc-hwmon
chipcap2
coretemp
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 41c381764c2b..03d393ff5955 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -457,32 +457,6 @@ config SENSORS_ATXP1
This driver can also be built as a module. If so, the module
will be called atxp1.
-config SENSORS_BT1_PVT
- tristate "Baikal-T1 Process, Voltage, Temperature sensor driver"
- depends on MIPS_BAIKAL_T1 || COMPILE_TEST
- select POLYNOMIAL
- help
- If you say yes here you get support for Baikal-T1 PVT sensor
- embedded into the SoC.
-
- This driver can also be built as a module. If so, the module will be
- called bt1-pvt.
-
-config SENSORS_BT1_PVT_ALARMS
- bool "Enable Baikal-T1 PVT sensor alarms"
- depends on SENSORS_BT1_PVT
- help
- Baikal-T1 PVT IP-block provides threshold registers for each
- supported sensor. But the corresponding interrupts might be
- generated by the thresholds comparator only in synchronization with
- a data conversion. Additionally there is only one sensor data can
- be converted at a time. All of these makes the interface impossible
- to be used for the hwmon alarms implementation without periodic
- switch between the PVT sensors. By default the data conversion is
- performed on demand from the user-space. If this config is enabled
- the data conversion will be periodically performed and the data will be
- saved in the internal driver cache.
-
config SENSORS_CGBC
tristate "Congatec Board Controller Sensors"
depends on MFD_CGBC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eade8e3b1bde..9d3659123ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tach.o
obj-$(CONFIG_SENSORS_ASUS_ROG_RYUJIN) += asus_rog_ryujin.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
-obj-$(CONFIG_SENSORS_BT1_PVT) += bt1-pvt.o
obj-$(CONFIG_SENSORS_CGBC) += cgbc-hwmon.o
obj-$(CONFIG_SENSORS_CHIPCAP2) += chipcap2.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
deleted file mode 100644
index b77ebac2e0ce..000000000000
--- a/drivers/hwmon/bt1-pvt.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
- *
- * Authors:
- * Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>
- * Serge Semin <Sergey.Semin@baikalelectronics.ru>
- *
- * Baikal-T1 Process, Voltage, Temperature sensor driver
- */
-
-#include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/hwmon.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/limits.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/polynomial.h>
-#include <linux/seqlock.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#include "bt1-pvt.h"
-
-/*
- * For the sake of the code simplification we created the sensors info table
- * with the sensor names, activation modes, threshold registers base address
- * and the thresholds bit fields.
- */
-static const struct pvt_sensor_info pvt_info[] = {
- PVT_SENSOR_INFO(0, "CPU Core Temperature", hwmon_temp, TEMP, TTHRES),
- PVT_SENSOR_INFO(0, "CPU Core Voltage", hwmon_in, VOLT, VTHRES),
- PVT_SENSOR_INFO(1, "CPU Core Low-Vt", hwmon_in, LVT, LTHRES),
- PVT_SENSOR_INFO(2, "CPU Core High-Vt", hwmon_in, HVT, HTHRES),
- PVT_SENSOR_INFO(3, "CPU Core Standard-Vt", hwmon_in, SVT, STHRES),
-};
-
-/*
- * The original translation formulae of the temperature (in degrees of Celsius)
- * to PVT data and vice-versa are following:
- * N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) +
- * 1.7204e2,
- * T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) +
- * 3.1020e-1*(N^1) - 4.838e1,
- * where T = [-48.380, 147.438]C and N = [0, 1023].
- * They must be accordingly altered to be suitable for the integer arithmetics.
- * The technique is called 'factor redistribution', which just makes sure the
- * multiplications and divisions are made so to have a result of the operations
- * within the integer numbers limit. In addition we need to translate the
- * formulae to accept millidegrees of Celsius. Here what they look like after
- * the alterations:
- * N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T +
- * 17204e2) / 1e4,
- * T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D -
- * 48380,
- * where T = [-48380, 147438] mC and N = [0, 1023].
- */
-static const struct polynomial __maybe_unused poly_temp_to_N = {
- .total_divider = 10000,
- .terms = {
- {4, 18322, 10000, 10000},
- {3, 2343, 10000, 10},
- {2, 87018, 10000, 10},
- {1, 39269, 1000, 1},
- {0, 1720400, 1, 1}
- }
-};
-
-static const struct polynomial poly_N_to_temp = {
- .total_divider = 1,
- .terms = {
- {4, -16743, 1000, 1},
- {3, 81542, 1000, 1},
- {2, -182010, 1000, 1},
- {1, 310200, 1000, 1},
- {0, -48380, 1, 1}
- }
-};
-
-/*
- * Similar alterations are performed for the voltage conversion equations.
- * The original formulae are:
- * N = 1.8658e3*V - 1.1572e3,
- * V = (N + 1.1572e3) / 1.8658e3,
- * where V = [0.620, 1.168] V and N = [0, 1023].
- * After the optimization they looks as follows:
- * N = (18658e-3*V - 11572) / 10,
- * V = N * 10^5 / 18658 + 11572 * 10^4 / 18658.
- */
-static const struct polynomial __maybe_unused poly_volt_to_N = {
- .total_divider = 10,
- .terms = {
- {1, 18658, 1000, 1},
- {0, -11572, 1, 1}
- }
-};
-
-static const struct polynomial poly_N_to_volt = {
- .total_divider = 10,
- .terms = {
- {1, 100000, 18658, 1},
- {0, 115720000, 1, 18658}
- }
-};
-
-static inline u32 pvt_update(void __iomem *reg, u32 mask, u32 data)
-{
- u32 old;
-
- old = readl_relaxed(reg);
- writel((old & ~mask) | (data & mask), reg);
-
- return old & mask;
-}
-
-/*
- * Baikal-T1 PVT mode can be updated only when the controller is disabled.
- * So first we disable it, then set the new mode together with the controller
- * getting back enabled. The same concerns the temperature trim and
- * measurements timeout. If it is necessary the interface mutex is supposed
- * to be locked at the time the operations are performed.
- */
-static inline void pvt_set_mode(struct pvt_hwmon *pvt, u32 mode)
-{
- u32 old;
-
- mode = FIELD_PREP(PVT_CTRL_MODE_MASK, mode);
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_MODE_MASK | PVT_CTRL_EN,
- mode | old);
-}
-
-static inline u32 pvt_calc_trim(long temp)
-{
- temp = clamp_val(temp, 0, PVT_TRIM_TEMP);
-
- return DIV_ROUND_UP(temp, PVT_TRIM_STEP);
-}
-
-static inline void pvt_set_trim(struct pvt_hwmon *pvt, u32 trim)
-{
- u32 old;
-
- trim = FIELD_PREP(PVT_CTRL_TRIM_MASK, trim);
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_TRIM_MASK | PVT_CTRL_EN,
- trim | old);
-}
-
-static inline void pvt_set_tout(struct pvt_hwmon *pvt, u32 tout)
-{
- u32 old;
-
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- writel(tout, pvt->regs + PVT_TTIMEOUT);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, old);
-}
-
-/*
- * This driver can optionally provide the hwmon alarms for each sensor the PVT
- * controller supports. The alarms functionality is made compile-time
- * configurable due to the hardware interface implementation peculiarity
- * described further in this comment. So in case if alarms are unnecessary in
- * your system design it's recommended to have them disabled to prevent the PVT
- * IRQs being periodically raised to get the data cache/alarms status up to
- * date.
- *
- * Baikal-T1 PVT embedded controller is based on the Analog Bits PVT sensor,
- * but is equipped with a dedicated control wrapper. It exposes the PVT
- * sub-block registers space via the APB3 bus. In addition the wrapper provides
- * a common interrupt vector of the sensors conversion completion events and
- * threshold value alarms. Alas the wrapper interface hasn't been fully thought
- * through. There is only one sensor can be activated at a time, for which the
- * thresholds comparator is enabled right after the data conversion is
- * completed. Due to this if alarms need to be implemented for all available
- * sensors we can't just set the thresholds and enable the interrupts. We need
- * to enable the sensors one after another and let the controller to detect
- * the alarms by itself at each conversion. This also makes pointless to handle
- * the alarms interrupts, since in occasion they happen synchronously with
- * data conversion completion. The best driver design would be to have the
- * completion interrupts enabled only and keep the converted value in the
- * driver data cache. This solution is implemented if hwmon alarms are enabled
- * in this driver. In case if the alarms are disabled, the conversion is
- * performed on demand at the time a sensors input file is read.
- */
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-
-#define pvt_hard_isr NULL
-
-static irqreturn_t pvt_soft_isr(int irq, void *data)
-{
- const struct pvt_sensor_info *info;
- struct pvt_hwmon *pvt = data;
- struct pvt_cache *cache;
- u32 val, thres_sts, old;
-
- /*
- * DVALID bit will be cleared by reading the data. We need to save the
- * status before the next conversion happens. Threshold events will be
- * handled a bit later.
- */
- thres_sts = readl(pvt->regs + PVT_RAW_INTR_STAT);
-
- /*
- * Then lets recharge the PVT interface with the next sampling mode.
- * Lock the interface mutex to serialize trim, timeouts and alarm
- * thresholds settings.
- */
- cache = &pvt->cache[pvt->sensor];
- info = &pvt_info[pvt->sensor];
- pvt->sensor = (pvt->sensor == PVT_SENSOR_LAST) ?
- PVT_SENSOR_FIRST : (pvt->sensor + 1);
-
- /*
- * For some reason we have to mask the interrupt before changing the
- * mode, otherwise sometimes the temperature mode doesn't get
- * activated even though the actual mode in the ctrl register
- * corresponds to one. Then we read the data. By doing so we also
- * recharge the data conversion. After this the mode corresponding
- * to the next sensor in the row is set. Finally we enable the
- * interrupts back.
- */
- mutex_lock(&pvt->iface_mtx);
-
- old = pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- val = readl(pvt->regs + PVT_DATA);
-
- pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
-
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, old);
-
- mutex_unlock(&pvt->iface_mtx);
-
- /*
- * We can now update the data cache with data just retrieved from the
- * sensor. Lock write-seqlock to make sure the reader has a coherent
- * data.
- */
- write_seqlock(&cache->data_seqlock);
-
- cache->data = FIELD_GET(PVT_DATA_DATA_MASK, val);
-
- write_sequnlock(&cache->data_seqlock);
-
- /*
- * While PVT core is doing the next mode data conversion, we'll check
- * whether the alarms were triggered for the current sensor. Note that
- * according to the documentation only one threshold IRQ status can be
- * set at a time, that's why if-else statement is utilized.
- */
- if ((thres_sts & info->thres_sts_lo) ^ cache->thres_sts_lo) {
- WRITE_ONCE(cache->thres_sts_lo, thres_sts & info->thres_sts_lo);
- hwmon_notify_event(pvt->hwmon, info->type, info->attr_min_alarm,
- info->channel);
- } else if ((thres_sts & info->thres_sts_hi) ^ cache->thres_sts_hi) {
- WRITE_ONCE(cache->thres_sts_hi, thres_sts & info->thres_sts_hi);
- hwmon_notify_event(pvt->hwmon, info->type, info->attr_max_alarm,
- info->channel);
- }
-
- return IRQ_HANDLED;
-}
-
-static inline umode_t pvt_limit_is_visible(enum pvt_sensor_type type)
-{
- return 0644;
-}
-
-static inline umode_t pvt_alarm_is_visible(enum pvt_sensor_type type)
-{
- return 0444;
-}
-
-static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- long *val)
-{
- struct pvt_cache *cache = &pvt->cache[type];
- unsigned int seq;
- u32 data;
-
- do {
- seq = read_seqbegin(&cache->data_seqlock);
- data = cache->data;
- } while (read_seqretry(&cache->data_seqlock, seq));
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_read_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- u32 data;
-
- /* No need in serialization, since it is just read from MMIO. */
- data = readl(pvt->regs + pvt_info[type].thres_base);
-
- if (is_low)
- data = FIELD_GET(PVT_THRES_LO_MASK, data);
- else
- data = FIELD_GET(PVT_THRES_HI_MASK, data);
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long val)
-{
- u32 data, limit, mask;
- int ret;
-
- if (type == PVT_TEMP) {
- val = clamp(val, PVT_TEMP_MIN, PVT_TEMP_MAX);
- data = polynomial_calc(&poly_temp_to_N, val);
- } else {
- val = clamp(val, PVT_VOLT_MIN, PVT_VOLT_MAX);
- data = polynomial_calc(&poly_volt_to_N, val);
- }
-
- /* Serialize limit update, since a part of the register is changed. */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- /* Make sure the upper and lower ranges don't intersect. */
- limit = readl(pvt->regs + pvt_info[type].thres_base);
- if (is_low) {
- limit = FIELD_GET(PVT_THRES_HI_MASK, limit);
- data = clamp_val(data, PVT_DATA_MIN, limit);
- data = FIELD_PREP(PVT_THRES_LO_MASK, data);
- mask = PVT_THRES_LO_MASK;
- } else {
- limit = FIELD_GET(PVT_THRES_LO_MASK, limit);
- data = clamp_val(data, limit, PVT_DATA_MAX);
- data = FIELD_PREP(PVT_THRES_HI_MASK, data);
- mask = PVT_THRES_HI_MASK;
- }
-
- pvt_update(pvt->regs + pvt_info[type].thres_base, mask, data);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- if (is_low)
- *val = !!READ_ONCE(pvt->cache[type].thres_sts_lo);
- else
- *val = !!READ_ONCE(pvt->cache[type].thres_sts_hi);
-
- return 0;
-}
-
-static const struct hwmon_channel_info * const pvt_channel_info[] = {
- HWMON_CHANNEL_INFO(chip,
- HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
- HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_TYPE | HWMON_T_LABEL |
- HWMON_T_MIN | HWMON_T_MIN_ALARM |
- HWMON_T_MAX | HWMON_T_MAX_ALARM |
- HWMON_T_OFFSET),
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM,
- HWMON_I_INPUT | HWMON_I_LABEL |
- HWMON_I_MIN | HWMON_I_MIN_ALARM |
- HWMON_I_MAX | HWMON_I_MAX_ALARM),
- NULL
-};
-
-#else /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static irqreturn_t pvt_hard_isr(int irq, void *data)
-{
- struct pvt_hwmon *pvt = data;
- struct pvt_cache *cache;
- u32 val;
-
- /*
- * Mask the DVALID interrupt so after exiting from the handler a
- * repeated conversion wouldn't happen.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- /*
- * Nothing special for alarm-less driver. Just read the data, update
- * the cache and notify a waiter of this event.
- */
- val = readl(pvt->regs + PVT_DATA);
- if (!(val & PVT_DATA_VALID)) {
- dev_err(pvt->dev, "Got IRQ when data isn't valid\n");
- return IRQ_HANDLED;
- }
-
- cache = &pvt->cache[pvt->sensor];
-
- WRITE_ONCE(cache->data, FIELD_GET(PVT_DATA_DATA_MASK, val));
-
- complete(&cache->conversion);
-
- return IRQ_HANDLED;
-}
-
-#define pvt_soft_isr NULL
-
-static inline umode_t pvt_limit_is_visible(enum pvt_sensor_type type)
-{
- return 0;
-}
-
-static inline umode_t pvt_alarm_is_visible(enum pvt_sensor_type type)
-{
- return 0;
-}
-
-static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- long *val)
-{
- struct pvt_cache *cache = &pvt->cache[type];
- unsigned long timeout;
- u32 data;
- int ret;
-
- /*
- * Lock PVT conversion interface until data cache is updated. The
- * data read procedure is following: set the requested PVT sensor
- * mode, enable IRQ and conversion, wait until conversion is finished,
- * then disable conversion and IRQ, and read the cached data.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- pvt->sensor = type;
- pvt_set_mode(pvt, pvt_info[type].mode);
-
- /*
- * Unmask the DVALID interrupt and enable the sensors conversions.
- * Do the reverse procedure when conversion is done.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
-
- /*
- * Wait with timeout since in case if the sensor is suddenly powered
- * down the request won't be completed and the caller will hang up on
- * this procedure until the power is back up again. Multiply the
- * timeout by the factor of two to prevent a false timeout.
- */
- timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout));
- ret = wait_for_completion_timeout(&cache->conversion, timeout);
-
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
-
- data = READ_ONCE(cache->data);
-
- mutex_unlock(&pvt->iface_mtx);
-
- if (!ret)
- return -ETIMEDOUT;
-
- if (type == PVT_TEMP)
- *val = polynomial_calc(&poly_N_to_temp, data);
- else
- *val = polynomial_calc(&poly_N_to_volt, data);
-
- return 0;
-}
-
-static int pvt_read_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- return -EOPNOTSUPP;
-}
-
-static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long val)
-{
- return -EOPNOTSUPP;
-}
-
-static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
- bool is_low, long *val)
-{
- return -EOPNOTSUPP;
-}
-
-static const struct hwmon_channel_info * const pvt_channel_info[] = {
- HWMON_CHANNEL_INFO(chip,
- HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
- HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_TYPE | HWMON_T_LABEL |
- HWMON_T_OFFSET),
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL),
- NULL
-};
-
-#endif /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static inline bool pvt_hwmon_channel_is_valid(enum hwmon_sensor_types type,
- int ch)
-{
- switch (type) {
- case hwmon_temp:
- if (ch < 0 || ch >= PVT_TEMP_CHS)
- return false;
- break;
- case hwmon_in:
- if (ch < 0 || ch >= PVT_VOLT_CHS)
- return false;
- break;
- default:
- break;
- }
-
- /* The rest of the types are independent from the channel number. */
- return true;
-}
-
-static umode_t pvt_hwmon_is_visible(const void *data,
- enum hwmon_sensor_types type,
- u32 attr, int ch)
-{
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return 0;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return 0644;
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- case hwmon_temp_type:
- case hwmon_temp_label:
- return 0444;
- case hwmon_temp_min:
- case hwmon_temp_max:
- return pvt_limit_is_visible(ch);
- case hwmon_temp_min_alarm:
- case hwmon_temp_max_alarm:
- return pvt_alarm_is_visible(ch);
- case hwmon_temp_offset:
- return 0644;
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- case hwmon_in_label:
- return 0444;
- case hwmon_in_min:
- case hwmon_in_max:
- return pvt_limit_is_visible(PVT_VOLT + ch);
- case hwmon_in_min_alarm:
- case hwmon_in_max_alarm:
- return pvt_alarm_is_visible(PVT_VOLT + ch);
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int pvt_read_trim(struct pvt_hwmon *pvt, long *val)
-{
- u32 data;
-
- data = readl(pvt->regs + PVT_CTRL);
- *val = FIELD_GET(PVT_CTRL_TRIM_MASK, data) * PVT_TRIM_STEP;
-
- return 0;
-}
-
-static int pvt_write_trim(struct pvt_hwmon *pvt, long val)
-{
- u32 trim;
- int ret;
-
- /*
- * Serialize trim update, since a part of the register is changed and
- * the controller is supposed to be disabled during this operation.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- trim = pvt_calc_trim(val);
- pvt_set_trim(pvt, trim);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val)
-{
- int ret;
-
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- /* Return the result in msec as hwmon sysfs interface requires. */
- *val = ktime_to_ms(pvt->timeout);
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_write_timeout(struct pvt_hwmon *pvt, long val)
-{
- unsigned long rate;
- ktime_t kt, cache;
- u32 data;
- int ret;
-
- rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk);
- if (!rate)
- return -ENODEV;
-
- /*
- * If alarms are enabled, the requested timeout must be divided
- * between all available sensors to have the requested delay
- * applicable to each individual sensor.
- */
- cache = kt = ms_to_ktime(val);
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- kt = ktime_divns(kt, PVT_SENSORS_NUM);
-#endif
-
- /*
- * Subtract a constant lag, which always persists due to the limited
- * PVT sampling rate. Make sure the timeout is not negative.
- */
- kt = ktime_sub_ns(kt, PVT_TOUT_MIN);
- if (ktime_to_ns(kt) < 0)
- kt = ktime_set(0, 0);
-
- /*
- * Finally recalculate the timeout in terms of the reference clock
- * period.
- */
- data = ktime_divns(kt * rate, NSEC_PER_SEC);
-
- /*
- * Update the measurements delay, but lock the interface first, since
- * we have to disable PVT in order to have the new delay actually
- * updated.
- */
- ret = mutex_lock_interruptible(&pvt->iface_mtx);
- if (ret)
- return ret;
-
- pvt_set_tout(pvt, data);
- pvt->timeout = cache;
-
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-static int pvt_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int ch, long *val)
-{
- struct pvt_hwmon *pvt = dev_get_drvdata(dev);
-
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return pvt_read_timeout(pvt, val);
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- return pvt_read_data(pvt, ch, val);
- case hwmon_temp_type:
- *val = 1;
- return 0;
- case hwmon_temp_min:
- return pvt_read_limit(pvt, ch, true, val);
- case hwmon_temp_max:
- return pvt_read_limit(pvt, ch, false, val);
- case hwmon_temp_min_alarm:
- return pvt_read_alarm(pvt, ch, true, val);
- case hwmon_temp_max_alarm:
- return pvt_read_alarm(pvt, ch, false, val);
- case hwmon_temp_offset:
- return pvt_read_trim(pvt, val);
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- return pvt_read_data(pvt, PVT_VOLT + ch, val);
- case hwmon_in_min:
- return pvt_read_limit(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max:
- return pvt_read_limit(pvt, PVT_VOLT + ch, false, val);
- case hwmon_in_min_alarm:
- return pvt_read_alarm(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max_alarm:
- return pvt_read_alarm(pvt, PVT_VOLT + ch, false, val);
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int pvt_hwmon_read_string(struct device *dev,
- enum hwmon_sensor_types type,
- u32 attr, int ch, const char **str)
-{
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_label:
- *str = pvt_info[ch].label;
- return 0;
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_label:
- *str = pvt_info[PVT_VOLT + ch].label;
- return 0;
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int pvt_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int ch, long val)
-{
- struct pvt_hwmon *pvt = dev_get_drvdata(dev);
-
- if (!pvt_hwmon_channel_is_valid(type, ch))
- return -EINVAL;
-
- switch (type) {
- case hwmon_chip:
- switch (attr) {
- case hwmon_chip_update_interval:
- return pvt_write_timeout(pvt, val);
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_min:
- return pvt_write_limit(pvt, ch, true, val);
- case hwmon_temp_max:
- return pvt_write_limit(pvt, ch, false, val);
- case hwmon_temp_offset:
- return pvt_write_trim(pvt, val);
- }
- break;
- case hwmon_in:
- switch (attr) {
- case hwmon_in_min:
- return pvt_write_limit(pvt, PVT_VOLT + ch, true, val);
- case hwmon_in_max:
- return pvt_write_limit(pvt, PVT_VOLT + ch, false, val);
- }
- break;
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-
-static const struct hwmon_ops pvt_hwmon_ops = {
- .is_visible = pvt_hwmon_is_visible,
- .read = pvt_hwmon_read,
- .read_string = pvt_hwmon_read_string,
- .write = pvt_hwmon_write
-};
-
-static const struct hwmon_chip_info pvt_hwmon_info = {
- .ops = &pvt_hwmon_ops,
- .info = pvt_channel_info
-};
-
-static void pvt_clear_data(void *data)
-{
- struct pvt_hwmon *pvt = data;
-#if !defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- int idx;
-
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- complete_all(&pvt->cache[idx].conversion);
-#endif
-
- mutex_destroy(&pvt->iface_mtx);
-}
-
-static struct pvt_hwmon *pvt_create_data(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct pvt_hwmon *pvt;
- int ret, idx;
-
- pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL);
- if (!pvt)
- return ERR_PTR(-ENOMEM);
-
- ret = devm_add_action(dev, pvt_clear_data, pvt);
- if (ret) {
- dev_err(dev, "Can't add PVT data clear action\n");
- return ERR_PTR(ret);
- }
-
- pvt->dev = dev;
- pvt->sensor = PVT_SENSOR_FIRST;
- mutex_init(&pvt->iface_mtx);
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- seqlock_init(&pvt->cache[idx].data_seqlock);
-#else
- for (idx = 0; idx < PVT_SENSORS_NUM; ++idx)
- init_completion(&pvt->cache[idx].conversion);
-#endif
-
- return pvt;
-}
-
-static int pvt_request_regs(struct pvt_hwmon *pvt)
-{
- struct platform_device *pdev = to_platform_device(pvt->dev);
-
- pvt->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(pvt->regs))
- return PTR_ERR(pvt->regs);
-
- return 0;
-}
-
-static void pvt_disable_clks(void *data)
-{
- struct pvt_hwmon *pvt = data;
-
- clk_bulk_disable_unprepare(PVT_CLOCK_NUM, pvt->clks);
-}
-
-static int pvt_request_clks(struct pvt_hwmon *pvt)
-{
- int ret;
-
- pvt->clks[PVT_CLOCK_APB].id = "pclk";
- pvt->clks[PVT_CLOCK_REF].id = "ref";
-
- ret = devm_clk_bulk_get(pvt->dev, PVT_CLOCK_NUM, pvt->clks);
- if (ret) {
- dev_err(pvt->dev, "Couldn't get PVT clocks descriptors\n");
- return ret;
- }
-
- ret = clk_bulk_prepare_enable(PVT_CLOCK_NUM, pvt->clks);
- if (ret) {
- dev_err(pvt->dev, "Couldn't enable the PVT clocks\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(pvt->dev, pvt_disable_clks, pvt);
- if (ret) {
- dev_err(pvt->dev, "Can't add PVT clocks disable action\n");
- return ret;
- }
-
- return 0;
-}
-
-static int pvt_check_pwr(struct pvt_hwmon *pvt)
-{
- unsigned long tout;
- int ret = 0;
- u32 data;
-
- /*
- * Test out the sensor conversion functionality. If it is not done on
- * time then the domain must have been unpowered and we won't be able
- * to use the device later in this driver.
- * Note If the power source is lost during the normal driver work the
- * data read procedure will either return -ETIMEDOUT (for the
- * alarm-less driver configuration) or just stop the repeated
- * conversion. In the later case alas we won't be able to detect the
- * problem.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
- pvt_set_tout(pvt, 0);
- readl(pvt->regs + PVT_DATA);
-
- tout = PVT_TOUT_MIN / NSEC_PER_USEC;
- usleep_range(tout, 2 * tout);
-
- data = readl(pvt->regs + PVT_DATA);
- if (!(data & PVT_DATA_VALID)) {
- ret = -ENODEV;
- dev_err(pvt->dev, "Sensor is powered down\n");
- }
-
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
-
- return ret;
-}
-
-static int pvt_init_iface(struct pvt_hwmon *pvt)
-{
- unsigned long rate;
- u32 trim, temp;
-
- rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk);
- if (!rate) {
- dev_err(pvt->dev, "Invalid reference clock rate\n");
- return -ENODEV;
- }
-
- /*
- * Make sure all interrupts and controller are disabled so not to
- * accidentally have ISR executed before the driver data is fully
- * initialized. Clear the IRQ status as well.
- */
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- readl(pvt->regs + PVT_CLR_INTR);
- readl(pvt->regs + PVT_DATA);
-
- /* Setup default sensor mode, timeout and temperature trim. */
- pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
- pvt_set_tout(pvt, PVT_TOUT_DEF);
-
- /*
- * Preserve the current ref-clock based delay (Ttotal) between the
- * sensors data samples in the driver data so not to recalculate it
- * each time on the data requests and timeout reads. It consists of the
- * delay introduced by the internal ref-clock timer (N / Fclk) and the
- * constant timeout caused by each conversion latency (Tmin):
- * Ttotal = N / Fclk + Tmin
- * If alarms are enabled the sensors are polled one after another and
- * in order to get the next measurement of a particular sensor the
- * caller will have to wait for at most until all the others are
- * polled. In that case the formulae will look a bit different:
- * Ttotal = 5 * (N / Fclk + Tmin)
- */
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0);
- pvt->timeout = ktime_divns(pvt->timeout, rate);
- pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN);
-#else
- pvt->timeout = ktime_set(PVT_TOUT_DEF, 0);
- pvt->timeout = ktime_divns(pvt->timeout, rate);
- pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN);
-#endif
-
- trim = PVT_TRIM_DEF;
- if (!of_property_read_u32(pvt->dev->of_node,
- "baikal,pvt-temp-offset-millicelsius", &temp))
- trim = pvt_calc_trim(temp);
-
- pvt_set_trim(pvt, trim);
-
- return 0;
-}
-
-static int pvt_request_irq(struct pvt_hwmon *pvt)
-{
- struct platform_device *pdev = to_platform_device(pvt->dev);
- int ret;
-
- pvt->irq = platform_get_irq(pdev, 0);
- if (pvt->irq < 0)
- return pvt->irq;
-
- ret = devm_request_threaded_irq(pvt->dev, pvt->irq,
- pvt_hard_isr, pvt_soft_isr,
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- IRQF_SHARED | IRQF_TRIGGER_HIGH |
- IRQF_ONESHOT,
-#else
- IRQF_SHARED | IRQF_TRIGGER_HIGH,
-#endif
- "pvt", pvt);
- if (ret) {
- dev_err(pvt->dev, "Couldn't request PVT IRQ\n");
- return ret;
- }
-
- return 0;
-}
-
-static int pvt_create_hwmon(struct pvt_hwmon *pvt)
-{
- pvt->hwmon = devm_hwmon_device_register_with_info(pvt->dev, "pvt", pvt,
- &pvt_hwmon_info, NULL);
- if (IS_ERR(pvt->hwmon)) {
- dev_err(pvt->dev, "Couldn't create hwmon device\n");
- return PTR_ERR(pvt->hwmon);
- }
-
- return 0;
-}
-
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-
-static void pvt_disable_iface(void *data)
-{
- struct pvt_hwmon *pvt = data;
-
- mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
- PVT_INTR_DVALID);
- mutex_unlock(&pvt->iface_mtx);
-}
-
-static int pvt_enable_iface(struct pvt_hwmon *pvt)
-{
- int ret;
-
- ret = devm_add_action(pvt->dev, pvt_disable_iface, pvt);
- if (ret) {
- dev_err(pvt->dev, "Can't add PVT disable interface action\n");
- return ret;
- }
-
- /*
- * Enable sensors data conversion and IRQ. We need to lock the
- * interface mutex since hwmon has just been created and the
- * corresponding sysfs files are accessible from user-space,
- * which theoretically may cause races.
- */
- mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
- mutex_unlock(&pvt->iface_mtx);
-
- return 0;
-}
-
-#else /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static int pvt_enable_iface(struct pvt_hwmon *pvt)
-{
- return 0;
-}
-
-#endif /* !CONFIG_SENSORS_BT1_PVT_ALARMS */
-
-static int pvt_probe(struct platform_device *pdev)
-{
- struct pvt_hwmon *pvt;
- int ret;
-
- pvt = pvt_create_data(pdev);
- if (IS_ERR(pvt))
- return PTR_ERR(pvt);
-
- ret = pvt_request_regs(pvt);
- if (ret)
- return ret;
-
- ret = pvt_request_clks(pvt);
- if (ret)
- return ret;
-
- ret = pvt_check_pwr(pvt);
- if (ret)
- return ret;
-
- ret = pvt_init_iface(pvt);
- if (ret)
- return ret;
-
- ret = pvt_request_irq(pvt);
- if (ret)
- return ret;
-
- ret = pvt_create_hwmon(pvt);
- if (ret)
- return ret;
-
- ret = pvt_enable_iface(pvt);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static const struct of_device_id pvt_of_match[] = {
- { .compatible = "baikal,bt1-pvt" },
- { }
-};
-MODULE_DEVICE_TABLE(of, pvt_of_match);
-
-static struct platform_driver pvt_driver = {
- .probe = pvt_probe,
- .driver = {
- .name = "bt1-pvt",
- .of_match_table = pvt_of_match
- }
-};
-module_platform_driver(pvt_driver);
-
-MODULE_AUTHOR("Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru>");
-MODULE_DESCRIPTION("Baikal-T1 PVT driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/bt1-pvt.h b/drivers/hwmon/bt1-pvt.h
deleted file mode 100644
index 93b8dd5e7c94..000000000000
--- a/drivers/hwmon/bt1-pvt.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
- *
- * Baikal-T1 Process, Voltage, Temperature sensor driver
- */
-#ifndef __HWMON_BT1_PVT_H__
-#define __HWMON_BT1_PVT_H__
-
-#include <linux/completion.h>
-#include <linux/hwmon.h>
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/seqlock.h>
-
-/* Baikal-T1 PVT registers and their bitfields */
-#define PVT_CTRL 0x00
-#define PVT_CTRL_EN BIT(0)
-#define PVT_CTRL_MODE_FLD 1
-#define PVT_CTRL_MODE_MASK GENMASK(3, PVT_CTRL_MODE_FLD)
-#define PVT_CTRL_MODE_TEMP 0x0
-#define PVT_CTRL_MODE_VOLT 0x1
-#define PVT_CTRL_MODE_LVT 0x2
-#define PVT_CTRL_MODE_HVT 0x4
-#define PVT_CTRL_MODE_SVT 0x6
-#define PVT_CTRL_TRIM_FLD 4
-#define PVT_CTRL_TRIM_MASK GENMASK(8, PVT_CTRL_TRIM_FLD)
-#define PVT_DATA 0x04
-#define PVT_DATA_VALID BIT(10)
-#define PVT_DATA_DATA_FLD 0
-#define PVT_DATA_DATA_MASK GENMASK(9, PVT_DATA_DATA_FLD)
-#define PVT_TTHRES 0x08
-#define PVT_VTHRES 0x0C
-#define PVT_LTHRES 0x10
-#define PVT_HTHRES 0x14
-#define PVT_STHRES 0x18
-#define PVT_THRES_LO_FLD 0
-#define PVT_THRES_LO_MASK GENMASK(9, PVT_THRES_LO_FLD)
-#define PVT_THRES_HI_FLD 10
-#define PVT_THRES_HI_MASK GENMASK(19, PVT_THRES_HI_FLD)
-#define PVT_TTIMEOUT 0x1C
-#define PVT_INTR_STAT 0x20
-#define PVT_INTR_MASK 0x24
-#define PVT_RAW_INTR_STAT 0x28
-#define PVT_INTR_DVALID BIT(0)
-#define PVT_INTR_TTHRES_LO BIT(1)
-#define PVT_INTR_TTHRES_HI BIT(2)
-#define PVT_INTR_VTHRES_LO BIT(3)
-#define PVT_INTR_VTHRES_HI BIT(4)
-#define PVT_INTR_LTHRES_LO BIT(5)
-#define PVT_INTR_LTHRES_HI BIT(6)
-#define PVT_INTR_HTHRES_LO BIT(7)
-#define PVT_INTR_HTHRES_HI BIT(8)
-#define PVT_INTR_STHRES_LO BIT(9)
-#define PVT_INTR_STHRES_HI BIT(10)
-#define PVT_INTR_ALL GENMASK(10, 0)
-#define PVT_CLR_INTR 0x2C
-
-/*
- * PVT sensors-related limits and default values
- * @PVT_TEMP_MIN: Minimal temperature in millidegrees of Celsius.
- * @PVT_TEMP_MAX: Maximal temperature in millidegrees of Celsius.
- * @PVT_TEMP_CHS: Number of temperature hwmon channels.
- * @PVT_VOLT_MIN: Minimal voltage in mV.
- * @PVT_VOLT_MAX: Maximal voltage in mV.
- * @PVT_VOLT_CHS: Number of voltage hwmon channels.
- * @PVT_DATA_MIN: Minimal PVT raw data value.
- * @PVT_DATA_MAX: Maximal PVT raw data value.
- * @PVT_TRIM_MIN: Minimal temperature sensor trim value.
- * @PVT_TRIM_MAX: Maximal temperature sensor trim value.
- * @PVT_TRIM_DEF: Default temperature sensor trim value (set a proper value
- * when one is determined for Baikal-T1 SoC).
- * @PVT_TRIM_TEMP: Maximum temperature encoded by the trim factor.
- * @PVT_TRIM_STEP: Temperature stride corresponding to the trim value.
- * @PVT_TOUT_MIN: Minimal timeout between samples in nanoseconds.
- * @PVT_TOUT_DEF: Default data measurements timeout. In case if alarms are
- * activated the PVT IRQ is enabled to be raised after each
- * conversion in order to have the thresholds checked and the
- * converted value cached. Too frequent conversions may cause
- * the system CPU overload. Lets set the 50ms delay between
- * them by default to prevent this.
- */
-#define PVT_TEMP_MIN -48380L
-#define PVT_TEMP_MAX 147438L
-#define PVT_TEMP_CHS 1
-#define PVT_VOLT_MIN 620L
-#define PVT_VOLT_MAX 1168L
-#define PVT_VOLT_CHS 4
-#define PVT_DATA_MIN 0
-#define PVT_DATA_MAX (PVT_DATA_DATA_MASK >> PVT_DATA_DATA_FLD)
-#define PVT_TRIM_MIN 0
-#define PVT_TRIM_MAX (PVT_CTRL_TRIM_MASK >> PVT_CTRL_TRIM_FLD)
-#define PVT_TRIM_TEMP 7130
-#define PVT_TRIM_STEP (PVT_TRIM_TEMP / PVT_TRIM_MAX)
-#define PVT_TRIM_DEF 0
-#define PVT_TOUT_MIN (NSEC_PER_SEC / 3000)
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
-# define PVT_TOUT_DEF 60000
-#else
-# define PVT_TOUT_DEF 0
-#endif
-
-/*
- * enum pvt_sensor_type - Baikal-T1 PVT sensor types (correspond to each PVT
- * sampling mode)
- * @PVT_SENSOR*: helpers to traverse the sensors in loops.
- * @PVT_TEMP: PVT Temperature sensor.
- * @PVT_VOLT: PVT Voltage sensor.
- * @PVT_LVT: PVT Low-Voltage threshold sensor.
- * @PVT_HVT: PVT High-Voltage threshold sensor.
- * @PVT_SVT: PVT Standard-Voltage threshold sensor.
- */
-enum pvt_sensor_type {
- PVT_SENSOR_FIRST,
- PVT_TEMP = PVT_SENSOR_FIRST,
- PVT_VOLT,
- PVT_LVT,
- PVT_HVT,
- PVT_SVT,
- PVT_SENSOR_LAST = PVT_SVT,
- PVT_SENSORS_NUM
-};
-
-/*
- * enum pvt_clock_type - Baikal-T1 PVT clocks.
- * @PVT_CLOCK_APB: APB clock.
- * @PVT_CLOCK_REF: PVT reference clock.
- */
-enum pvt_clock_type {
- PVT_CLOCK_APB,
- PVT_CLOCK_REF,
- PVT_CLOCK_NUM
-};
-
-/*
- * struct pvt_sensor_info - Baikal-T1 PVT sensor informational structure
- * @channel: Sensor channel ID.
- * @label: hwmon sensor label.
- * @mode: PVT mode corresponding to the channel.
- * @thres_base: upper and lower threshold values of the sensor.
- * @thres_sts_lo: low threshold status bitfield.
- * @thres_sts_hi: high threshold status bitfield.
- * @type: Sensor type.
- * @attr_min_alarm: Min alarm attribute ID.
- * @attr_min_alarm: Max alarm attribute ID.
- */
-struct pvt_sensor_info {
- int channel;
- const char *label;
- u32 mode;
- unsigned long thres_base;
- u32 thres_sts_lo;
- u32 thres_sts_hi;
- enum hwmon_sensor_types type;
- u32 attr_min_alarm;
- u32 attr_max_alarm;
-};
-
-#define PVT_SENSOR_INFO(_ch, _label, _type, _mode, _thres) \
- { \
- .channel = _ch, \
- .label = _label, \
- .mode = PVT_CTRL_MODE_ ##_mode, \
- .thres_base = PVT_ ##_thres, \
- .thres_sts_lo = PVT_INTR_ ##_thres## _LO, \
- .thres_sts_hi = PVT_INTR_ ##_thres## _HI, \
- .type = _type, \
- .attr_min_alarm = _type## _min, \
- .attr_max_alarm = _type## _max, \
- }
-
-/*
- * struct pvt_cache - PVT sensors data cache
- * @data: data cache in raw format.
- * @thres_sts_lo: low threshold status saved on the previous data conversion.
- * @thres_sts_hi: high threshold status saved on the previous data conversion.
- * @data_seqlock: cached data seq-lock.
- * @conversion: data conversion completion.
- */
-struct pvt_cache {
- u32 data;
-#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
- seqlock_t data_seqlock;
- u32 thres_sts_lo;
- u32 thres_sts_hi;
-#else
- struct completion conversion;
-#endif
-};
-
-/*
- * struct pvt_hwmon - Baikal-T1 PVT private data
- * @dev: device structure of the PVT platform device.
- * @hwmon: hwmon device structure.
- * @regs: pointer to the Baikal-T1 PVT registers region.
- * @irq: PVT events IRQ number.
- * @clks: Array of the PVT clocks descriptor (APB/ref clocks).
- * @ref_clk: Pointer to the reference clocks descriptor.
- * @iface_mtx: Generic interface mutex (used to lock the alarm registers
- * when the alarms enabled, or the data conversion interface
- * if alarms are disabled).
- * @sensor: current PVT sensor the data conversion is being performed for.
- * @cache: data cache descriptor.
- * @timeout: conversion timeout cache.
- */
-struct pvt_hwmon {
- struct device *dev;
- struct device *hwmon;
-
- void __iomem *regs;
- int irq;
-
- struct clk_bulk_data clks[PVT_CLOCK_NUM];
-
- struct mutex iface_mtx;
- enum pvt_sensor_type sensor;
- struct pvt_cache cache[PVT_SENSORS_NUM];
- ktime_t timeout;
-};
-
-/*
- * struct pvt_poly_term - a term descriptor of the PVT data translation
- * polynomial
- * @deg: degree of the term.
- * @coef: multiplication factor of the term.
- * @divider: distributed divider per each degree.
- * @divider_leftover: divider leftover, which couldn't be redistributed.
- */
-struct pvt_poly_term {
- unsigned int deg;
- long coef;
- long divider;
- long divider_leftover;
-};
-
-/*
- * struct pvt_poly - PVT data translation polynomial descriptor
- * @total_divider: total data divider.
- * @terms: polynomial terms up to a free one.
- */
-struct pvt_poly {
- long total_divider;
- struct pvt_poly_term terms[];
-};
-
-#endif /* __HWMON_BT1_PVT_H__ */
--
2.50.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC
2026-02-20 14:36 Andy Shevchenko
@ 2026-02-20 14:42 ` Andy Shevchenko
2026-02-23 18:58 ` Rob Herring (Arm)
1 sibling, 0 replies; 5+ messages in thread
From: Andy Shevchenko @ 2026-02-20 14:42 UTC (permalink / raw)
To: linux-hwmon, devicetree, linux-kernel, linux-doc
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Corbet, Shuah Khan
On Fri, Feb 20, 2026 at 03:36:11PM +0100, Andy Shevchenko wrote:
> As noticed in the discussion [1] the Baikal SoC and platforms
> are not going to be finalized, hence remove stale code.
It seems the same message was sent twice. There are no differences at all
between them.
Please, use the first one
https://lore.kernel.org/r/20260220143500.2401057-1-andriy.shevchenko@linux.intel.com
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC
2026-02-20 14:36 Andy Shevchenko
2026-02-20 14:42 ` Andy Shevchenko
@ 2026-02-23 18:58 ` Rob Herring (Arm)
1 sibling, 0 replies; 5+ messages in thread
From: Rob Herring (Arm) @ 2026-02-23 18:58 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Guenter Roeck, Conor Dooley, linux-doc, Krzysztof Kozlowski,
Shuah Khan, linux-kernel, linux-hwmon, Jonathan Corbet,
devicetree
On Fri, 20 Feb 2026 15:36:11 +0100, Andy Shevchenko wrote:
> As noticed in the discussion [1] the Baikal SoC and platforms
> are not going to be finalized, hence remove stale code.
>
> Link: https://lore.kernel.org/lkml/22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org/ [1]
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> .../bindings/hwmon/baikal,bt1-pvt.yaml | 105 --
> Documentation/hwmon/bt1-pvt.rst | 117 --
> Documentation/hwmon/index.rst | 1 -
> drivers/hwmon/Kconfig | 26 -
> drivers/hwmon/Makefile | 1 -
> drivers/hwmon/bt1-pvt.c | 1171 -----------------
> drivers/hwmon/bt1-pvt.h | 247 ----
> 7 files changed, 1668 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml
> delete mode 100644 Documentation/hwmon/bt1-pvt.rst
> delete mode 100644 drivers/hwmon/bt1-pvt.c
> delete mode 100644 drivers/hwmon/bt1-pvt.h
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-02-23 18:58 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20 14:35 [PATCH v1 1/1] hwmon (bt1-pvt) Remove not-going-to-be-supported code for Baikal SoC Andy Shevchenko
2026-02-20 14:49 ` Guenter Roeck
-- strict thread matches above, loose matches on Subject: below --
2026-02-20 14:36 Andy Shevchenko
2026-02-20 14:42 ` Andy Shevchenko
2026-02-23 18:58 ` Rob Herring (Arm)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox