18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 MaxLinear, Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This driver is a hardware monitoring driver for PVT controller 68c2ecf20Sopenharmony_ci * (MR75203) which is used to configure & control Moortec embedded 78c2ecf20Sopenharmony_ci * analog IP to enable multiple embedded temperature sensor(TS), 88c2ecf20Sopenharmony_ci * voltage monitor(VM) & process detector(PD) modules. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/bits.h> 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/property.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/reset.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* PVT Common register */ 228c2ecf20Sopenharmony_ci#define PVT_IP_CONFIG 0x04 238c2ecf20Sopenharmony_ci#define TS_NUM_MSK GENMASK(4, 0) 248c2ecf20Sopenharmony_ci#define TS_NUM_SFT 0 258c2ecf20Sopenharmony_ci#define PD_NUM_MSK GENMASK(12, 8) 268c2ecf20Sopenharmony_ci#define PD_NUM_SFT 8 278c2ecf20Sopenharmony_ci#define VM_NUM_MSK GENMASK(20, 16) 288c2ecf20Sopenharmony_ci#define VM_NUM_SFT 16 298c2ecf20Sopenharmony_ci#define CH_NUM_MSK GENMASK(31, 24) 308c2ecf20Sopenharmony_ci#define CH_NUM_SFT 24 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Macro Common Register */ 338c2ecf20Sopenharmony_ci#define CLK_SYNTH 0x00 348c2ecf20Sopenharmony_ci#define CLK_SYNTH_LO_SFT 0 358c2ecf20Sopenharmony_ci#define CLK_SYNTH_HI_SFT 8 368c2ecf20Sopenharmony_ci#define CLK_SYNTH_HOLD_SFT 16 378c2ecf20Sopenharmony_ci#define CLK_SYNTH_EN BIT(24) 388c2ecf20Sopenharmony_ci#define CLK_SYS_CYCLES_MAX 514 398c2ecf20Sopenharmony_ci#define CLK_SYS_CYCLES_MIN 2 408c2ecf20Sopenharmony_ci#define HZ_PER_MHZ 1000000L 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define SDIF_DISABLE 0x04 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define SDIF_STAT 0x08 458c2ecf20Sopenharmony_ci#define SDIF_BUSY BIT(0) 468c2ecf20Sopenharmony_ci#define SDIF_LOCK BIT(1) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SDIF_W 0x0c 498c2ecf20Sopenharmony_ci#define SDIF_PROG BIT(31) 508c2ecf20Sopenharmony_ci#define SDIF_WRN_W BIT(27) 518c2ecf20Sopenharmony_ci#define SDIF_WRN_R 0x00 528c2ecf20Sopenharmony_ci#define SDIF_ADDR_SFT 24 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define SDIF_HALT 0x10 558c2ecf20Sopenharmony_ci#define SDIF_CTRL 0x14 568c2ecf20Sopenharmony_ci#define SDIF_SMPL_CTRL 0x20 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* TS & PD Individual Macro Register */ 598c2ecf20Sopenharmony_ci#define COM_REG_SIZE 0x40 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define SDIF_DONE(n) (COM_REG_SIZE + 0x14 + 0x40 * (n)) 628c2ecf20Sopenharmony_ci#define SDIF_SMPL_DONE BIT(0) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define SDIF_DATA(n) (COM_REG_SIZE + 0x18 + 0x40 * (n)) 658c2ecf20Sopenharmony_ci#define SAMPLE_DATA_MSK GENMASK(15, 0) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define HILO_RESET(n) (COM_REG_SIZE + 0x2c + 0x40 * (n)) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* VM Individual Macro Register */ 708c2ecf20Sopenharmony_ci#define VM_COM_REG_SIZE 0x200 718c2ecf20Sopenharmony_ci#define VM_SDIF_DONE(vm) (VM_COM_REG_SIZE + 0x34 + 0x200 * (vm)) 728c2ecf20Sopenharmony_ci#define VM_SDIF_DATA(vm, ch) \ 738c2ecf20Sopenharmony_ci (VM_COM_REG_SIZE + 0x40 + 0x200 * (vm) + 0x4 * (ch)) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* SDA Slave Register */ 768c2ecf20Sopenharmony_ci#define IP_CTRL 0x00 778c2ecf20Sopenharmony_ci#define IP_RST_REL BIT(1) 788c2ecf20Sopenharmony_ci#define IP_RUN_CONT BIT(3) 798c2ecf20Sopenharmony_ci#define IP_AUTO BIT(8) 808c2ecf20Sopenharmony_ci#define IP_VM_MODE BIT(10) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define IP_CFG 0x01 838c2ecf20Sopenharmony_ci#define CFG0_MODE_2 BIT(0) 848c2ecf20Sopenharmony_ci#define CFG0_PARALLEL_OUT 0 858c2ecf20Sopenharmony_ci#define CFG0_12_BIT 0 868c2ecf20Sopenharmony_ci#define CFG1_VOL_MEAS_MODE 0 878c2ecf20Sopenharmony_ci#define CFG1_PARALLEL_OUT 0 888c2ecf20Sopenharmony_ci#define CFG1_14_BIT 0 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define IP_DATA 0x03 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define IP_POLL 0x04 938c2ecf20Sopenharmony_ci#define VM_CH_INIT BIT(20) 948c2ecf20Sopenharmony_ci#define VM_CH_REQ BIT(21) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define IP_TMR 0x05 978c2ecf20Sopenharmony_ci#define POWER_DELAY_CYCLE_256 0x100 988c2ecf20Sopenharmony_ci#define POWER_DELAY_CYCLE_64 0x40 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define PVT_POLL_DELAY_US 20 1018c2ecf20Sopenharmony_ci#define PVT_POLL_TIMEOUT_US 20000 1028c2ecf20Sopenharmony_ci#define PVT_H_CONST 100000 1038c2ecf20Sopenharmony_ci#define PVT_CAL5_CONST 2047 1048c2ecf20Sopenharmony_ci#define PVT_G_CONST 40000 1058c2ecf20Sopenharmony_ci#define PVT_CONV_BITS 10 1068c2ecf20Sopenharmony_ci#define PVT_N_CONST 90 1078c2ecf20Sopenharmony_ci#define PVT_R_CONST 245805 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistruct pvt_device { 1108c2ecf20Sopenharmony_ci struct regmap *c_map; 1118c2ecf20Sopenharmony_ci struct regmap *t_map; 1128c2ecf20Sopenharmony_ci struct regmap *p_map; 1138c2ecf20Sopenharmony_ci struct regmap *v_map; 1148c2ecf20Sopenharmony_ci struct clk *clk; 1158c2ecf20Sopenharmony_ci struct reset_control *rst; 1168c2ecf20Sopenharmony_ci u32 t_num; 1178c2ecf20Sopenharmony_ci u32 p_num; 1188c2ecf20Sopenharmony_ci u32 v_num; 1198c2ecf20Sopenharmony_ci u32 c_num; 1208c2ecf20Sopenharmony_ci u32 ip_freq; 1218c2ecf20Sopenharmony_ci u8 *vm_idx; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type, 1258c2ecf20Sopenharmony_ci u32 attr, int channel) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci switch (type) { 1288c2ecf20Sopenharmony_ci case hwmon_temp: 1298c2ecf20Sopenharmony_ci if (attr == hwmon_temp_input) 1308c2ecf20Sopenharmony_ci return 0444; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case hwmon_in: 1338c2ecf20Sopenharmony_ci if (attr == hwmon_in_input) 1348c2ecf20Sopenharmony_ci return 0444; 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci default: 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int pvt_read_temp(struct device *dev, u32 attr, int channel, long *val) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct pvt_device *pvt = dev_get_drvdata(dev); 1458c2ecf20Sopenharmony_ci struct regmap *t_map = pvt->t_map; 1468c2ecf20Sopenharmony_ci u32 stat, nbs; 1478c2ecf20Sopenharmony_ci int ret; 1488c2ecf20Sopenharmony_ci u64 tmp; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci switch (attr) { 1518c2ecf20Sopenharmony_ci case hwmon_temp_input: 1528c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(t_map, SDIF_DONE(channel), 1538c2ecf20Sopenharmony_ci stat, stat & SDIF_SMPL_DONE, 1548c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 1558c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 1568c2ecf20Sopenharmony_ci if (ret) 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = regmap_read(t_map, SDIF_DATA(channel), &nbs); 1608c2ecf20Sopenharmony_ci if(ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci nbs &= SAMPLE_DATA_MSK; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * Convert the register value to 1678c2ecf20Sopenharmony_ci * degrees centigrade temperature 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci tmp = nbs * PVT_H_CONST; 1708c2ecf20Sopenharmony_ci do_div(tmp, PVT_CAL5_CONST); 1718c2ecf20Sopenharmony_ci *val = tmp - PVT_G_CONST - pvt->ip_freq; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci default: 1758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct pvt_device *pvt = dev_get_drvdata(dev); 1828c2ecf20Sopenharmony_ci struct regmap *v_map = pvt->v_map; 1838c2ecf20Sopenharmony_ci u8 vm_idx, ch_idx; 1848c2ecf20Sopenharmony_ci u32 n, stat; 1858c2ecf20Sopenharmony_ci int ret; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (channel >= pvt->v_num * pvt->c_num) 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci vm_idx = pvt->vm_idx[channel / pvt->c_num]; 1918c2ecf20Sopenharmony_ci ch_idx = channel % pvt->c_num; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci switch (attr) { 1948c2ecf20Sopenharmony_ci case hwmon_in_input: 1958c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(v_map, VM_SDIF_DONE(vm_idx), 1968c2ecf20Sopenharmony_ci stat, stat & SDIF_SMPL_DONE, 1978c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 1988c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx, ch_idx), &n); 2038c2ecf20Sopenharmony_ci if(ret < 0) 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci n &= SAMPLE_DATA_MSK; 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * Convert the N bitstream count into voltage. 2098c2ecf20Sopenharmony_ci * To support negative voltage calculation for 64bit machines 2108c2ecf20Sopenharmony_ci * n must be cast to long, since n and *val differ both in 2118c2ecf20Sopenharmony_ci * signedness and in size. 2128c2ecf20Sopenharmony_ci * Division is used instead of right shift, because for signed 2138c2ecf20Sopenharmony_ci * numbers, the sign bit is used to fill the vacated bit 2148c2ecf20Sopenharmony_ci * positions, and if the number is negative, 1 is used. 2158c2ecf20Sopenharmony_ci * BIT(x) may not be used instead of (1 << x) because it's 2168c2ecf20Sopenharmony_ci * unsigned. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci *val = (PVT_N_CONST * (long)n - PVT_R_CONST) / (1 << PVT_CONV_BITS); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci default: 2228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int pvt_read(struct device *dev, enum hwmon_sensor_types type, 2278c2ecf20Sopenharmony_ci u32 attr, int channel, long *val) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci switch (type) { 2308c2ecf20Sopenharmony_ci case hwmon_temp: 2318c2ecf20Sopenharmony_ci return pvt_read_temp(dev, attr, channel, val); 2328c2ecf20Sopenharmony_ci case hwmon_in: 2338c2ecf20Sopenharmony_ci return pvt_read_in(dev, attr, channel, val); 2348c2ecf20Sopenharmony_ci default: 2358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic const u32 pvt_chip_config[] = { 2408c2ecf20Sopenharmony_ci HWMON_C_REGISTER_TZ, 2418c2ecf20Sopenharmony_ci 0 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info pvt_chip = { 2458c2ecf20Sopenharmony_ci .type = hwmon_chip, 2468c2ecf20Sopenharmony_ci .config = pvt_chip_config, 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic struct hwmon_channel_info pvt_temp = { 2508c2ecf20Sopenharmony_ci .type = hwmon_temp, 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic struct hwmon_channel_info pvt_in = { 2548c2ecf20Sopenharmony_ci .type = hwmon_in, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic const struct hwmon_ops pvt_hwmon_ops = { 2588c2ecf20Sopenharmony_ci .is_visible = pvt_is_visible, 2598c2ecf20Sopenharmony_ci .read = pvt_read, 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic struct hwmon_chip_info pvt_chip_info = { 2638c2ecf20Sopenharmony_ci .ops = &pvt_hwmon_ops, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int pvt_init(struct pvt_device *pvt) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci u16 sys_freq, key, middle, low = 4, high = 8; 2698c2ecf20Sopenharmony_ci struct regmap *t_map = pvt->t_map; 2708c2ecf20Sopenharmony_ci struct regmap *p_map = pvt->p_map; 2718c2ecf20Sopenharmony_ci struct regmap *v_map = pvt->v_map; 2728c2ecf20Sopenharmony_ci u32 t_num = pvt->t_num; 2738c2ecf20Sopenharmony_ci u32 p_num = pvt->p_num; 2748c2ecf20Sopenharmony_ci u32 v_num = pvt->v_num; 2758c2ecf20Sopenharmony_ci u32 clk_synth, val; 2768c2ecf20Sopenharmony_ci int ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci sys_freq = clk_get_rate(pvt->clk) / HZ_PER_MHZ; 2798c2ecf20Sopenharmony_ci while (high >= low) { 2808c2ecf20Sopenharmony_ci middle = (low + high + 1) / 2; 2818c2ecf20Sopenharmony_ci key = DIV_ROUND_CLOSEST(sys_freq, middle); 2828c2ecf20Sopenharmony_ci if (key > CLK_SYS_CYCLES_MAX) { 2838c2ecf20Sopenharmony_ci low = middle + 1; 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci } else if (key < CLK_SYS_CYCLES_MIN) { 2868c2ecf20Sopenharmony_ci high = middle - 1; 2878c2ecf20Sopenharmony_ci continue; 2888c2ecf20Sopenharmony_ci } else { 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* 2948c2ecf20Sopenharmony_ci * The system supports 'clk_sys' to 'clk_ip' frequency ratios 2958c2ecf20Sopenharmony_ci * from 2:1 to 512:1 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci key = clamp_val(key, CLK_SYS_CYCLES_MIN, CLK_SYS_CYCLES_MAX) - 2; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci clk_synth = ((key + 1) >> 1) << CLK_SYNTH_LO_SFT | 3008c2ecf20Sopenharmony_ci (key >> 1) << CLK_SYNTH_HI_SFT | 3018c2ecf20Sopenharmony_ci (key >> 1) << CLK_SYNTH_HOLD_SFT | CLK_SYNTH_EN; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pvt->ip_freq = sys_freq * 100 / (key + 2); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (t_num) { 3068c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_SMPL_CTRL, 0x0); 3078c2ecf20Sopenharmony_ci if(ret < 0) 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_HALT, 0x0); 3118c2ecf20Sopenharmony_ci if(ret < 0) 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ret = regmap_write(t_map, CLK_SYNTH, clk_synth); 3158c2ecf20Sopenharmony_ci if(ret < 0) 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_DISABLE, 0x0); 3198c2ecf20Sopenharmony_ci if(ret < 0) 3208c2ecf20Sopenharmony_ci return ret; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(t_map, SDIF_STAT, 3238c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 3248c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 3258c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 3268c2ecf20Sopenharmony_ci if (ret) 3278c2ecf20Sopenharmony_ci return ret; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci val = CFG0_MODE_2 | CFG0_PARALLEL_OUT | CFG0_12_BIT | 3308c2ecf20Sopenharmony_ci IP_CFG << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; 3318c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_W, val); 3328c2ecf20Sopenharmony_ci if(ret < 0) 3338c2ecf20Sopenharmony_ci return ret; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(t_map, SDIF_STAT, 3368c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 3378c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 3388c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci val = POWER_DELAY_CYCLE_256 | IP_TMR << SDIF_ADDR_SFT | 3438c2ecf20Sopenharmony_ci SDIF_WRN_W | SDIF_PROG; 3448c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_W, val); 3458c2ecf20Sopenharmony_ci if(ret < 0) 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(t_map, SDIF_STAT, 3498c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 3508c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 3518c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | 3568c2ecf20Sopenharmony_ci IP_CTRL << SDIF_ADDR_SFT | 3578c2ecf20Sopenharmony_ci SDIF_WRN_W | SDIF_PROG; 3588c2ecf20Sopenharmony_ci ret = regmap_write(t_map, SDIF_W, val); 3598c2ecf20Sopenharmony_ci if(ret < 0) 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (p_num) { 3648c2ecf20Sopenharmony_ci ret = regmap_write(p_map, SDIF_HALT, 0x0); 3658c2ecf20Sopenharmony_ci if(ret < 0) 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ret = regmap_write(p_map, SDIF_DISABLE, BIT(p_num) - 1); 3698c2ecf20Sopenharmony_ci if(ret < 0) 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ret = regmap_write(p_map, CLK_SYNTH, clk_synth); 3738c2ecf20Sopenharmony_ci if(ret < 0) 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (v_num) { 3788c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_SMPL_CTRL, 0x0); 3798c2ecf20Sopenharmony_ci if(ret < 0) 3808c2ecf20Sopenharmony_ci return ret; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_HALT, 0x0); 3838c2ecf20Sopenharmony_ci if(ret < 0) 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = regmap_write(v_map, CLK_SYNTH, clk_synth); 3878c2ecf20Sopenharmony_ci if(ret < 0) 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_DISABLE, 0x0); 3918c2ecf20Sopenharmony_ci if(ret < 0) 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(v_map, SDIF_STAT, 3958c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 3968c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 3978c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 3988c2ecf20Sopenharmony_ci if (ret) 3998c2ecf20Sopenharmony_ci return ret; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci val = (BIT(pvt->c_num) - 1) | VM_CH_INIT | 4028c2ecf20Sopenharmony_ci IP_POLL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; 4038c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_W, val); 4048c2ecf20Sopenharmony_ci if (ret < 0) 4058c2ecf20Sopenharmony_ci return ret; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(v_map, SDIF_STAT, 4088c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 4098c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 4108c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 4118c2ecf20Sopenharmony_ci if (ret) 4128c2ecf20Sopenharmony_ci return ret; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci val = CFG1_VOL_MEAS_MODE | CFG1_PARALLEL_OUT | 4158c2ecf20Sopenharmony_ci CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT | 4168c2ecf20Sopenharmony_ci SDIF_WRN_W | SDIF_PROG; 4178c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_W, val); 4188c2ecf20Sopenharmony_ci if(ret < 0) 4198c2ecf20Sopenharmony_ci return ret; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(v_map, SDIF_STAT, 4228c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 4238c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 4248c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 4258c2ecf20Sopenharmony_ci if (ret) 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci val = POWER_DELAY_CYCLE_64 | IP_TMR << SDIF_ADDR_SFT | 4298c2ecf20Sopenharmony_ci SDIF_WRN_W | SDIF_PROG; 4308c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_W, val); 4318c2ecf20Sopenharmony_ci if(ret < 0) 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(v_map, SDIF_STAT, 4358c2ecf20Sopenharmony_ci val, !(val & SDIF_BUSY), 4368c2ecf20Sopenharmony_ci PVT_POLL_DELAY_US, 4378c2ecf20Sopenharmony_ci PVT_POLL_TIMEOUT_US); 4388c2ecf20Sopenharmony_ci if (ret) 4398c2ecf20Sopenharmony_ci return ret; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | IP_VM_MODE | 4428c2ecf20Sopenharmony_ci IP_CTRL << SDIF_ADDR_SFT | 4438c2ecf20Sopenharmony_ci SDIF_WRN_W | SDIF_PROG; 4448c2ecf20Sopenharmony_ci ret = regmap_write(v_map, SDIF_W, val); 4458c2ecf20Sopenharmony_ci if(ret < 0) 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic struct regmap_config pvt_regmap_config = { 4538c2ecf20Sopenharmony_ci .reg_bits = 32, 4548c2ecf20Sopenharmony_ci .reg_stride = 4, 4558c2ecf20Sopenharmony_ci .val_bits = 32, 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int pvt_get_regmap(struct platform_device *pdev, char *reg_name, 4598c2ecf20Sopenharmony_ci struct pvt_device *pvt) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4628c2ecf20Sopenharmony_ci struct regmap **reg_map; 4638c2ecf20Sopenharmony_ci void __iomem *io_base; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!strcmp(reg_name, "common")) 4668c2ecf20Sopenharmony_ci reg_map = &pvt->c_map; 4678c2ecf20Sopenharmony_ci else if (!strcmp(reg_name, "ts")) 4688c2ecf20Sopenharmony_ci reg_map = &pvt->t_map; 4698c2ecf20Sopenharmony_ci else if (!strcmp(reg_name, "pd")) 4708c2ecf20Sopenharmony_ci reg_map = &pvt->p_map; 4718c2ecf20Sopenharmony_ci else if (!strcmp(reg_name, "vm")) 4728c2ecf20Sopenharmony_ci reg_map = &pvt->v_map; 4738c2ecf20Sopenharmony_ci else 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci io_base = devm_platform_ioremap_resource_byname(pdev, reg_name); 4778c2ecf20Sopenharmony_ci if (IS_ERR(io_base)) 4788c2ecf20Sopenharmony_ci return PTR_ERR(io_base); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci pvt_regmap_config.name = reg_name; 4818c2ecf20Sopenharmony_ci *reg_map = devm_regmap_init_mmio(dev, io_base, &pvt_regmap_config); 4828c2ecf20Sopenharmony_ci if (IS_ERR(*reg_map)) { 4838c2ecf20Sopenharmony_ci dev_err(dev, "failed to init register map\n"); 4848c2ecf20Sopenharmony_ci return PTR_ERR(*reg_map); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void pvt_clk_disable(void *data) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct pvt_device *pvt = data; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci clk_disable_unprepare(pvt->clk); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int pvt_clk_enable(struct device *dev, struct pvt_device *pvt) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci int ret; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ret = clk_prepare_enable(pvt->clk); 5028c2ecf20Sopenharmony_ci if (ret) 5038c2ecf20Sopenharmony_ci return ret; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return devm_add_action_or_reset(dev, pvt_clk_disable, pvt); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void pvt_reset_control_assert(void *data) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct pvt_device *pvt = data; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci reset_control_assert(pvt->rst); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ret = reset_control_deassert(pvt->rst); 5208c2ecf20Sopenharmony_ci if (ret) 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return devm_add_action_or_reset(dev, pvt_reset_control_assert, pvt); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int mr75203_probe(struct platform_device *pdev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci u32 ts_num, vm_num, pd_num, ch_num, val, index, i; 5298c2ecf20Sopenharmony_ci const struct hwmon_channel_info **pvt_info; 5308c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5318c2ecf20Sopenharmony_ci u32 *temp_config, *in_config; 5328c2ecf20Sopenharmony_ci struct device *hwmon_dev; 5338c2ecf20Sopenharmony_ci struct pvt_device *pvt; 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL); 5378c2ecf20Sopenharmony_ci if (!pvt) 5388c2ecf20Sopenharmony_ci return -ENOMEM; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci ret = pvt_get_regmap(pdev, "common", pvt); 5418c2ecf20Sopenharmony_ci if (ret) 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci pvt->clk = devm_clk_get(dev, NULL); 5458c2ecf20Sopenharmony_ci if (IS_ERR(pvt->clk)) 5468c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(pvt->clk), "failed to get clock\n"); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci ret = pvt_clk_enable(dev, pvt); 5498c2ecf20Sopenharmony_ci if (ret) { 5508c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable clock\n"); 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci pvt->rst = devm_reset_control_get_exclusive(dev, NULL); 5558c2ecf20Sopenharmony_ci if (IS_ERR(pvt->rst)) 5568c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(pvt->rst), 5578c2ecf20Sopenharmony_ci "failed to get reset control\n"); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ret = pvt_reset_control_deassert(dev, pvt); 5608c2ecf20Sopenharmony_ci if (ret) 5618c2ecf20Sopenharmony_ci return dev_err_probe(dev, ret, "cannot deassert reset control\n"); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = regmap_read(pvt->c_map, PVT_IP_CONFIG, &val); 5648c2ecf20Sopenharmony_ci if(ret < 0) 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT; 5688c2ecf20Sopenharmony_ci pd_num = (val & PD_NUM_MSK) >> PD_NUM_SFT; 5698c2ecf20Sopenharmony_ci vm_num = (val & VM_NUM_MSK) >> VM_NUM_SFT; 5708c2ecf20Sopenharmony_ci ch_num = (val & CH_NUM_MSK) >> CH_NUM_SFT; 5718c2ecf20Sopenharmony_ci pvt->t_num = ts_num; 5728c2ecf20Sopenharmony_ci pvt->p_num = pd_num; 5738c2ecf20Sopenharmony_ci pvt->v_num = vm_num; 5748c2ecf20Sopenharmony_ci pvt->c_num = ch_num; 5758c2ecf20Sopenharmony_ci val = 0; 5768c2ecf20Sopenharmony_ci if (ts_num) 5778c2ecf20Sopenharmony_ci val++; 5788c2ecf20Sopenharmony_ci if (vm_num) 5798c2ecf20Sopenharmony_ci val++; 5808c2ecf20Sopenharmony_ci if (!val) 5818c2ecf20Sopenharmony_ci return -ENODEV; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci pvt_info = devm_kcalloc(dev, val + 2, sizeof(*pvt_info), GFP_KERNEL); 5848c2ecf20Sopenharmony_ci if (!pvt_info) 5858c2ecf20Sopenharmony_ci return -ENOMEM; 5868c2ecf20Sopenharmony_ci pvt_info[0] = &pvt_chip; 5878c2ecf20Sopenharmony_ci index = 1; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (ts_num) { 5908c2ecf20Sopenharmony_ci ret = pvt_get_regmap(pdev, "ts", pvt); 5918c2ecf20Sopenharmony_ci if (ret) 5928c2ecf20Sopenharmony_ci return ret; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci temp_config = devm_kcalloc(dev, ts_num + 1, 5958c2ecf20Sopenharmony_ci sizeof(*temp_config), GFP_KERNEL); 5968c2ecf20Sopenharmony_ci if (!temp_config) 5978c2ecf20Sopenharmony_ci return -ENOMEM; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci memset32(temp_config, HWMON_T_INPUT, ts_num); 6008c2ecf20Sopenharmony_ci pvt_temp.config = temp_config; 6018c2ecf20Sopenharmony_ci pvt_info[index++] = &pvt_temp; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (pd_num) { 6058c2ecf20Sopenharmony_ci ret = pvt_get_regmap(pdev, "pd", pvt); 6068c2ecf20Sopenharmony_ci if (ret) 6078c2ecf20Sopenharmony_ci return ret; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (vm_num) { 6118c2ecf20Sopenharmony_ci u32 total_ch; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ret = pvt_get_regmap(pdev, "vm", pvt); 6148c2ecf20Sopenharmony_ci if (ret) 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci pvt->vm_idx = devm_kcalloc(dev, vm_num, sizeof(*pvt->vm_idx), 6188c2ecf20Sopenharmony_ci GFP_KERNEL); 6198c2ecf20Sopenharmony_ci if (!pvt->vm_idx) 6208c2ecf20Sopenharmony_ci return -ENOMEM; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci ret = device_property_read_u8_array(dev, "intel,vm-map", 6238c2ecf20Sopenharmony_ci pvt->vm_idx, vm_num); 6248c2ecf20Sopenharmony_ci if (ret) { 6258c2ecf20Sopenharmony_ci /* 6268c2ecf20Sopenharmony_ci * Incase intel,vm-map property is not defined, we 6278c2ecf20Sopenharmony_ci * assume incremental channel numbers. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci for (i = 0; i < vm_num; i++) 6308c2ecf20Sopenharmony_ci pvt->vm_idx[i] = i; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci for (i = 0; i < vm_num; i++) 6338c2ecf20Sopenharmony_ci if (pvt->vm_idx[i] >= vm_num || 6348c2ecf20Sopenharmony_ci pvt->vm_idx[i] == 0xff) { 6358c2ecf20Sopenharmony_ci pvt->v_num = i; 6368c2ecf20Sopenharmony_ci vm_num = i; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci total_ch = ch_num * vm_num; 6428c2ecf20Sopenharmony_ci in_config = devm_kcalloc(dev, total_ch + 1, 6438c2ecf20Sopenharmony_ci sizeof(*in_config), GFP_KERNEL); 6448c2ecf20Sopenharmony_ci if (!in_config) 6458c2ecf20Sopenharmony_ci return -ENOMEM; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci memset32(in_config, HWMON_I_INPUT, total_ch); 6488c2ecf20Sopenharmony_ci in_config[total_ch] = 0; 6498c2ecf20Sopenharmony_ci pvt_in.config = in_config; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci pvt_info[index++] = &pvt_in; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci ret = pvt_init(pvt); 6558c2ecf20Sopenharmony_ci if (ret) { 6568c2ecf20Sopenharmony_ci dev_err(dev, "failed to init pvt: %d\n", ret); 6578c2ecf20Sopenharmony_ci return ret; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci pvt_chip_info.info = pvt_info; 6618c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, "pvt", 6628c2ecf20Sopenharmony_ci pvt, 6638c2ecf20Sopenharmony_ci &pvt_chip_info, 6648c2ecf20Sopenharmony_ci NULL); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic const struct of_device_id moortec_pvt_of_match[] = { 6708c2ecf20Sopenharmony_ci { .compatible = "moortec,mr75203" }, 6718c2ecf20Sopenharmony_ci { } 6728c2ecf20Sopenharmony_ci}; 6738c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, moortec_pvt_of_match); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic struct platform_driver moortec_pvt_driver = { 6768c2ecf20Sopenharmony_ci .driver = { 6778c2ecf20Sopenharmony_ci .name = "moortec-pvt", 6788c2ecf20Sopenharmony_ci .of_match_table = moortec_pvt_of_match, 6798c2ecf20Sopenharmony_ci }, 6808c2ecf20Sopenharmony_ci .probe = mr75203_probe, 6818c2ecf20Sopenharmony_ci}; 6828c2ecf20Sopenharmony_cimodule_platform_driver(moortec_pvt_driver); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 685