18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2014-2018 Nuvoton Technology corporation. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/clk.h> 58c2ecf20Sopenharmony_ci#include <linux/device.h> 68c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 78c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of_address.h> 128c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 168c2ecf20Sopenharmony_ci#include <linux/thermal.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* NPCM7XX PWM registers */ 198c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_BASE(base, n) ((base) + ((n) * 0x1000L)) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_PR(base, n) (NPCM7XX_PWM_REG_BASE(base, n) + 0x00) 228c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_CSR(base, n) (NPCM7XX_PWM_REG_BASE(base, n) + 0x04) 238c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_CR(base, n) (NPCM7XX_PWM_REG_BASE(base, n) + 0x08) 248c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_CNRx(base, n, ch) \ 258c2ecf20Sopenharmony_ci (NPCM7XX_PWM_REG_BASE(base, n) + 0x0C + (12 * (ch))) 268c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_CMRx(base, n, ch) \ 278c2ecf20Sopenharmony_ci (NPCM7XX_PWM_REG_BASE(base, n) + 0x10 + (12 * (ch))) 288c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_PDRx(base, n, ch) \ 298c2ecf20Sopenharmony_ci (NPCM7XX_PWM_REG_BASE(base, n) + 0x14 + (12 * (ch))) 308c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_PIER(base, n) (NPCM7XX_PWM_REG_BASE(base, n) + 0x3C) 318c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_REG_PIIR(base, n) (NPCM7XX_PWM_REG_BASE(base, n) + 0x40) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH0_MODE_BIT BIT(3) 348c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH1_MODE_BIT BIT(11) 358c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH2_MODE_BIT BIT(15) 368c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH3_MODE_BIT BIT(19) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH0_INV_BIT BIT(2) 398c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH1_INV_BIT BIT(10) 408c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH2_INV_BIT BIT(14) 418c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH3_INV_BIT BIT(18) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH0_EN_BIT BIT(0) 448c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH1_EN_BIT BIT(8) 458c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH2_EN_BIT BIT(12) 468c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_CH3_EN_BIT BIT(16) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Define the maximum PWM channel number */ 498c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_MAX_CHN_NUM 8 508c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE 4 518c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_MAX_MODULES 2 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Define the Counter Register, value = 100 for match 100% */ 548c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_COUNTER_DEFAULT_NUM 255 558c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CMR_DEFAULT_NUM 255 568c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CMR_MAX 255 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* default all PWM channels PRESCALE2 = 1 */ 598c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE2_DEFAULT_CH0 0x4 608c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE2_DEFAULT_CH1 0x40 618c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE2_DEFAULT_CH2 0x400 628c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE2_DEFAULT_CH3 0x4000 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define PWM_OUTPUT_FREQ_25KHZ 25000 658c2ecf20Sopenharmony_ci#define PWN_CNT_DEFAULT 256 668c2ecf20Sopenharmony_ci#define MIN_PRESCALE1 2 678c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE_SHIFT_CH01 8 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_PRESCALE2_DEFAULT (NPCM7XX_PWM_PRESCALE2_DEFAULT_CH0 | \ 708c2ecf20Sopenharmony_ci NPCM7XX_PWM_PRESCALE2_DEFAULT_CH1 | \ 718c2ecf20Sopenharmony_ci NPCM7XX_PWM_PRESCALE2_DEFAULT_CH2 | \ 728c2ecf20Sopenharmony_ci NPCM7XX_PWM_PRESCALE2_DEFAULT_CH3) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define NPCM7XX_PWM_CTRL_MODE_DEFAULT (NPCM7XX_PWM_CTRL_CH0_MODE_BIT | \ 758c2ecf20Sopenharmony_ci NPCM7XX_PWM_CTRL_CH1_MODE_BIT | \ 768c2ecf20Sopenharmony_ci NPCM7XX_PWM_CTRL_CH2_MODE_BIT | \ 778c2ecf20Sopenharmony_ci NPCM7XX_PWM_CTRL_CH3_MODE_BIT) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* NPCM7XX FAN Tacho registers */ 808c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_BASE(base, n) ((base) + ((n) * 0x1000L)) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCNT1(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x00) 838c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCRA(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x02) 848c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCRB(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x04) 858c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCNT2(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x06) 868c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TPRSC(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x08) 878c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCKC(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x0A) 888c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TMCTRL(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x0C) 898c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TICTRL(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x0E) 908c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TICLR(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x10) 918c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TIEN(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x12) 928c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCPA(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x14) 938c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCPB(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x16) 948c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TCPCFG(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x18) 958c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TINASEL(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x1A) 968c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_REG_TINBSEL(base, n) (NPCM7XX_FAN_REG_BASE(base, n) + 0x1C) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCKC_CLKX_NONE 0 998c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCKC_CLK1_APB BIT(0) 1008c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCKC_CLK2_APB BIT(3) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TMCTRL_TBEN BIT(6) 1038c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TMCTRL_TAEN BIT(5) 1048c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TMCTRL_TBEDG BIT(4) 1058c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TMCTRL_TAEDG BIT(3) 1068c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TMCTRL_MODE_5 BIT(2) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_CLEAR_ALL GENMASK(5, 0) 1098c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TFCLR BIT(5) 1108c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TECLR BIT(4) 1118c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TDCLR BIT(3) 1128c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TCCLR BIT(2) 1138c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TBCLR BIT(1) 1148c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICLR_TACLR BIT(0) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_ENABLE_ALL GENMASK(5, 0) 1178c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TFIEN BIT(5) 1188c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TEIEN BIT(4) 1198c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TDIEN BIT(3) 1208c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TCIEN BIT(2) 1218c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TBIEN BIT(1) 1228c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIEN_TAIEN BIT(0) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TFPND BIT(5) 1258c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TEPND BIT(4) 1268c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TDPND BIT(3) 1278c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TCPND BIT(2) 1288c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TBPND BIT(1) 1298c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TICTRL_TAPND BIT(0) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_HIBEN BIT(7) 1328c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_EQBEN BIT(6) 1338c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_LOBEN BIT(5) 1348c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_CPBSEL BIT(4) 1358c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_HIAEN BIT(3) 1368c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_EQAEN BIT(2) 1378c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_LOAEN BIT(1) 1388c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPCFG_CPASEL BIT(0) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* FAN General Definition */ 1418c2ecf20Sopenharmony_ci/* Define the maximum FAN channel number */ 1428c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_MAX_MODULE 8 1438c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_MAX_CHN_NUM_IN_A_MODULE 2 1448c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_MAX_CHN_NUM 16 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Get Fan Tach Timeout (base on clock 214843.75Hz, 1 cnt = 4.654us) 1488c2ecf20Sopenharmony_ci * Timeout 94ms ~= 0x5000 1498c2ecf20Sopenharmony_ci * (The minimum FAN speed could to support ~640RPM/pulse 1, 1508c2ecf20Sopenharmony_ci * 320RPM/pulse 2, ...-- 10.6Hz) 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TIMEOUT 0x5000 1538c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCNT 0xFFFF 1548c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPA (NPCM7XX_FAN_TCNT - NPCM7XX_FAN_TIMEOUT) 1558c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TCPB (NPCM7XX_FAN_TCNT - NPCM7XX_FAN_TIMEOUT) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_POLL_TIMER_200MS 200 1588c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_DEFAULT_PULSE_PER_REVOLUTION 2 1598c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_TINASEL_FANIN_DEFAULT 0 1608c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_CLK_PRESCALE 255 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_CMPA 0 1638c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_CMPB 1 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Obtain the fan number */ 1668c2ecf20Sopenharmony_ci#define NPCM7XX_FAN_INPUT(fan, cmp) (((fan) << 1) + (cmp)) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* fan sample status */ 1698c2ecf20Sopenharmony_ci#define FAN_DISABLE 0xFF 1708c2ecf20Sopenharmony_ci#define FAN_INIT 0x00 1718c2ecf20Sopenharmony_ci#define FAN_PREPARE_TO_GET_FIRST_CAPTURE 0x01 1728c2ecf20Sopenharmony_ci#define FAN_ENOUGH_SAMPLE 0x02 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistruct npcm7xx_fan_dev { 1758c2ecf20Sopenharmony_ci u8 fan_st_flg; 1768c2ecf20Sopenharmony_ci u8 fan_pls_per_rev; 1778c2ecf20Sopenharmony_ci u16 fan_cnt; 1788c2ecf20Sopenharmony_ci u32 fan_cnt_tmp; 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct npcm7xx_cooling_device { 1828c2ecf20Sopenharmony_ci char name[THERMAL_NAME_LENGTH]; 1838c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data; 1848c2ecf20Sopenharmony_ci struct thermal_cooling_device *tcdev; 1858c2ecf20Sopenharmony_ci int pwm_port; 1868c2ecf20Sopenharmony_ci u8 *cooling_levels; 1878c2ecf20Sopenharmony_ci u8 max_state; 1888c2ecf20Sopenharmony_ci u8 cur_state; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct npcm7xx_pwm_fan_data { 1928c2ecf20Sopenharmony_ci void __iomem *pwm_base; 1938c2ecf20Sopenharmony_ci void __iomem *fan_base; 1948c2ecf20Sopenharmony_ci unsigned long pwm_clk_freq; 1958c2ecf20Sopenharmony_ci unsigned long fan_clk_freq; 1968c2ecf20Sopenharmony_ci struct clk *pwm_clk; 1978c2ecf20Sopenharmony_ci struct clk *fan_clk; 1988c2ecf20Sopenharmony_ci struct mutex pwm_lock[NPCM7XX_PWM_MAX_MODULES]; 1998c2ecf20Sopenharmony_ci spinlock_t fan_lock[NPCM7XX_FAN_MAX_MODULE]; 2008c2ecf20Sopenharmony_ci int fan_irq[NPCM7XX_FAN_MAX_MODULE]; 2018c2ecf20Sopenharmony_ci bool pwm_present[NPCM7XX_PWM_MAX_CHN_NUM]; 2028c2ecf20Sopenharmony_ci bool fan_present[NPCM7XX_FAN_MAX_CHN_NUM]; 2038c2ecf20Sopenharmony_ci u32 input_clk_freq; 2048c2ecf20Sopenharmony_ci struct timer_list fan_timer; 2058c2ecf20Sopenharmony_ci struct npcm7xx_fan_dev fan_dev[NPCM7XX_FAN_MAX_CHN_NUM]; 2068c2ecf20Sopenharmony_ci struct npcm7xx_cooling_device *cdev[NPCM7XX_PWM_MAX_CHN_NUM]; 2078c2ecf20Sopenharmony_ci u8 fan_select; 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data, 2118c2ecf20Sopenharmony_ci int channel, u16 val) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci u32 pwm_ch = (channel % NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE); 2148c2ecf20Sopenharmony_ci u32 module = (channel / NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE); 2158c2ecf20Sopenharmony_ci u32 tmp_buf, ctrl_en_bit, env_bit; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Config PWM Comparator register for setting duty cycle 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci mutex_lock(&data->pwm_lock[module]); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* write new CMR value */ 2238c2ecf20Sopenharmony_ci iowrite32(val, NPCM7XX_PWM_REG_CMRx(data->pwm_base, module, pwm_ch)); 2248c2ecf20Sopenharmony_ci tmp_buf = ioread32(NPCM7XX_PWM_REG_CR(data->pwm_base, module)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci switch (pwm_ch) { 2278c2ecf20Sopenharmony_ci case 0: 2288c2ecf20Sopenharmony_ci ctrl_en_bit = NPCM7XX_PWM_CTRL_CH0_EN_BIT; 2298c2ecf20Sopenharmony_ci env_bit = NPCM7XX_PWM_CTRL_CH0_INV_BIT; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case 1: 2328c2ecf20Sopenharmony_ci ctrl_en_bit = NPCM7XX_PWM_CTRL_CH1_EN_BIT; 2338c2ecf20Sopenharmony_ci env_bit = NPCM7XX_PWM_CTRL_CH1_INV_BIT; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case 2: 2368c2ecf20Sopenharmony_ci ctrl_en_bit = NPCM7XX_PWM_CTRL_CH2_EN_BIT; 2378c2ecf20Sopenharmony_ci env_bit = NPCM7XX_PWM_CTRL_CH2_INV_BIT; 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case 3: 2408c2ecf20Sopenharmony_ci ctrl_en_bit = NPCM7XX_PWM_CTRL_CH3_EN_BIT; 2418c2ecf20Sopenharmony_ci env_bit = NPCM7XX_PWM_CTRL_CH3_INV_BIT; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci mutex_unlock(&data->pwm_lock[module]); 2458c2ecf20Sopenharmony_ci return -ENODEV; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (val == 0) { 2498c2ecf20Sopenharmony_ci /* Disable PWM */ 2508c2ecf20Sopenharmony_ci tmp_buf &= ~ctrl_en_bit; 2518c2ecf20Sopenharmony_ci tmp_buf |= env_bit; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci /* Enable PWM */ 2548c2ecf20Sopenharmony_ci tmp_buf |= ctrl_en_bit; 2558c2ecf20Sopenharmony_ci tmp_buf &= ~env_bit; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci iowrite32(tmp_buf, NPCM7XX_PWM_REG_CR(data->pwm_base, module)); 2598c2ecf20Sopenharmony_ci mutex_unlock(&data->pwm_lock[module]); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic inline void npcm7xx_fan_start_capture(struct npcm7xx_pwm_fan_data *data, 2658c2ecf20Sopenharmony_ci u8 fan, u8 cmp) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u8 fan_id; 2688c2ecf20Sopenharmony_ci u8 reg_mode; 2698c2ecf20Sopenharmony_ci u8 reg_int; 2708c2ecf20Sopenharmony_ci unsigned long flags; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci fan_id = NPCM7XX_FAN_INPUT(fan, cmp); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* to check whether any fan tach is enable */ 2758c2ecf20Sopenharmony_ci if (data->fan_dev[fan_id].fan_st_flg != FAN_DISABLE) { 2768c2ecf20Sopenharmony_ci /* reset status */ 2778c2ecf20Sopenharmony_ci spin_lock_irqsave(&data->fan_lock[fan], flags); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_st_flg = FAN_INIT; 2808c2ecf20Sopenharmony_ci reg_int = ioread8(NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * the interrupt enable bits do not need to be cleared before 2848c2ecf20Sopenharmony_ci * it sets, the interrupt enable bits are cleared only on reset. 2858c2ecf20Sopenharmony_ci * the clock unit control register is behaving in the same 2868c2ecf20Sopenharmony_ci * manner that the interrupt enable register behave. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci if (cmp == NPCM7XX_FAN_CMPA) { 2898c2ecf20Sopenharmony_ci /* enable interrupt */ 2908c2ecf20Sopenharmony_ci iowrite8(reg_int | (NPCM7XX_FAN_TIEN_TAIEN | 2918c2ecf20Sopenharmony_ci NPCM7XX_FAN_TIEN_TEIEN), 2928c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci reg_mode = NPCM7XX_FAN_TCKC_CLK1_APB 2958c2ecf20Sopenharmony_ci | ioread8(NPCM7XX_FAN_REG_TCKC(data->fan_base, 2968c2ecf20Sopenharmony_ci fan)); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* start to Capture */ 2998c2ecf20Sopenharmony_ci iowrite8(reg_mode, NPCM7XX_FAN_REG_TCKC(data->fan_base, 3008c2ecf20Sopenharmony_ci fan)); 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci /* enable interrupt */ 3038c2ecf20Sopenharmony_ci iowrite8(reg_int | (NPCM7XX_FAN_TIEN_TBIEN | 3048c2ecf20Sopenharmony_ci NPCM7XX_FAN_TIEN_TFIEN), 3058c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci reg_mode = 3088c2ecf20Sopenharmony_ci NPCM7XX_FAN_TCKC_CLK2_APB 3098c2ecf20Sopenharmony_ci | ioread8(NPCM7XX_FAN_REG_TCKC(data->fan_base, 3108c2ecf20Sopenharmony_ci fan)); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* start to Capture */ 3138c2ecf20Sopenharmony_ci iowrite8(reg_mode, 3148c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCKC(data->fan_base, fan)); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data->fan_lock[fan], flags); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* 3228c2ecf20Sopenharmony_ci * Enable a background timer to poll fan tach value, (200ms * 4) 3238c2ecf20Sopenharmony_ci * to polling all fan 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cistatic void npcm7xx_fan_polling(struct timer_list *t) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data; 3288c2ecf20Sopenharmony_ci int i; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci data = from_timer(data, t, fan_timer); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * Polling two module per one round, 3348c2ecf20Sopenharmony_ci * FAN01 & FAN89 / FAN23 & FAN1011 / FAN45 & FAN1213 / FAN67 & FAN1415 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci for (i = data->fan_select; i < NPCM7XX_FAN_MAX_MODULE; 3378c2ecf20Sopenharmony_ci i = i + 4) { 3388c2ecf20Sopenharmony_ci /* clear the flag and reset the counter (TCNT) */ 3398c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_TICLR_CLEAR_ALL, 3408c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TICLR(data->fan_base, i)); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (data->fan_present[i * 2]) { 3438c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCNT, 3448c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCNT1(data->fan_base, i)); 3458c2ecf20Sopenharmony_ci npcm7xx_fan_start_capture(data, i, NPCM7XX_FAN_CMPA); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci if (data->fan_present[(i * 2) + 1]) { 3488c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCNT, 3498c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCNT2(data->fan_base, i)); 3508c2ecf20Sopenharmony_ci npcm7xx_fan_start_capture(data, i, NPCM7XX_FAN_CMPB); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci data->fan_select++; 3558c2ecf20Sopenharmony_ci data->fan_select &= 0x3; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* reset the timer interval */ 3588c2ecf20Sopenharmony_ci data->fan_timer.expires = jiffies + 3598c2ecf20Sopenharmony_ci msecs_to_jiffies(NPCM7XX_FAN_POLL_TIMER_200MS); 3608c2ecf20Sopenharmony_ci add_timer(&data->fan_timer); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic inline void npcm7xx_fan_compute(struct npcm7xx_pwm_fan_data *data, 3648c2ecf20Sopenharmony_ci u8 fan, u8 cmp, u8 fan_id, u8 flag_int, 3658c2ecf20Sopenharmony_ci u8 flag_mode, u8 flag_clear) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci u8 reg_int; 3688c2ecf20Sopenharmony_ci u8 reg_mode; 3698c2ecf20Sopenharmony_ci u16 fan_cap; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (cmp == NPCM7XX_FAN_CMPA) 3728c2ecf20Sopenharmony_ci fan_cap = ioread16(NPCM7XX_FAN_REG_TCRA(data->fan_base, fan)); 3738c2ecf20Sopenharmony_ci else 3748c2ecf20Sopenharmony_ci fan_cap = ioread16(NPCM7XX_FAN_REG_TCRB(data->fan_base, fan)); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* clear capature flag, H/W will auto reset the NPCM7XX_FAN_TCNTx */ 3778c2ecf20Sopenharmony_ci iowrite8(flag_clear, NPCM7XX_FAN_REG_TICLR(data->fan_base, fan)); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (data->fan_dev[fan_id].fan_st_flg == FAN_INIT) { 3808c2ecf20Sopenharmony_ci /* First capture, drop it */ 3818c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_st_flg = 3828c2ecf20Sopenharmony_ci FAN_PREPARE_TO_GET_FIRST_CAPTURE; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* reset counter */ 3858c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt_tmp = 0; 3868c2ecf20Sopenharmony_ci } else if (data->fan_dev[fan_id].fan_st_flg < FAN_ENOUGH_SAMPLE) { 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * collect the enough sample, 3898c2ecf20Sopenharmony_ci * (ex: 2 pulse fan need to get 2 sample) 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt_tmp += 3928c2ecf20Sopenharmony_ci (NPCM7XX_FAN_TCNT - fan_cap); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_st_flg++; 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci /* get enough sample or fan disable */ 3978c2ecf20Sopenharmony_ci if (data->fan_dev[fan_id].fan_st_flg == FAN_ENOUGH_SAMPLE) { 3988c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt_tmp += 3998c2ecf20Sopenharmony_ci (NPCM7XX_FAN_TCNT - fan_cap); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* compute finial average cnt per pulse */ 4028c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt = 4038c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt_tmp / 4048c2ecf20Sopenharmony_ci FAN_ENOUGH_SAMPLE; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_st_flg = FAN_INIT; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci reg_int = ioread8(NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* disable interrupt */ 4128c2ecf20Sopenharmony_ci iowrite8((reg_int & ~flag_int), 4138c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 4148c2ecf20Sopenharmony_ci reg_mode = ioread8(NPCM7XX_FAN_REG_TCKC(data->fan_base, fan)); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* stop capturing */ 4178c2ecf20Sopenharmony_ci iowrite8((reg_mode & ~flag_mode), 4188c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCKC(data->fan_base, fan)); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic inline void npcm7xx_check_cmp(struct npcm7xx_pwm_fan_data *data, 4238c2ecf20Sopenharmony_ci u8 fan, u8 cmp, u8 flag) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci u8 reg_int; 4268c2ecf20Sopenharmony_ci u8 reg_mode; 4278c2ecf20Sopenharmony_ci u8 flag_timeout; 4288c2ecf20Sopenharmony_ci u8 flag_cap; 4298c2ecf20Sopenharmony_ci u8 flag_clear; 4308c2ecf20Sopenharmony_ci u8 flag_int; 4318c2ecf20Sopenharmony_ci u8 flag_mode; 4328c2ecf20Sopenharmony_ci u8 fan_id; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci fan_id = NPCM7XX_FAN_INPUT(fan, cmp); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (cmp == NPCM7XX_FAN_CMPA) { 4378c2ecf20Sopenharmony_ci flag_cap = NPCM7XX_FAN_TICTRL_TAPND; 4388c2ecf20Sopenharmony_ci flag_timeout = NPCM7XX_FAN_TICTRL_TEPND; 4398c2ecf20Sopenharmony_ci flag_int = NPCM7XX_FAN_TIEN_TAIEN | NPCM7XX_FAN_TIEN_TEIEN; 4408c2ecf20Sopenharmony_ci flag_mode = NPCM7XX_FAN_TCKC_CLK1_APB; 4418c2ecf20Sopenharmony_ci flag_clear = NPCM7XX_FAN_TICLR_TACLR | NPCM7XX_FAN_TICLR_TECLR; 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci flag_cap = NPCM7XX_FAN_TICTRL_TBPND; 4448c2ecf20Sopenharmony_ci flag_timeout = NPCM7XX_FAN_TICTRL_TFPND; 4458c2ecf20Sopenharmony_ci flag_int = NPCM7XX_FAN_TIEN_TBIEN | NPCM7XX_FAN_TIEN_TFIEN; 4468c2ecf20Sopenharmony_ci flag_mode = NPCM7XX_FAN_TCKC_CLK2_APB; 4478c2ecf20Sopenharmony_ci flag_clear = NPCM7XX_FAN_TICLR_TBCLR | NPCM7XX_FAN_TICLR_TFCLR; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (flag & flag_timeout) { 4518c2ecf20Sopenharmony_ci reg_int = ioread8(NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* disable interrupt */ 4548c2ecf20Sopenharmony_ci iowrite8((reg_int & ~flag_int), 4558c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TIEN(data->fan_base, fan)); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* clear interrupt flag */ 4588c2ecf20Sopenharmony_ci iowrite8(flag_clear, 4598c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TICLR(data->fan_base, fan)); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci reg_mode = ioread8(NPCM7XX_FAN_REG_TCKC(data->fan_base, fan)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* stop capturing */ 4648c2ecf20Sopenharmony_ci iowrite8((reg_mode & ~flag_mode), 4658c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCKC(data->fan_base, fan)); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* 4688c2ecf20Sopenharmony_ci * If timeout occurs (NPCM7XX_FAN_TIMEOUT), the fan doesn't 4698c2ecf20Sopenharmony_ci * connect or speed is lower than 10.6Hz (320RPM/pulse2). 4708c2ecf20Sopenharmony_ci * In these situation, the RPM output should be zero. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci data->fan_dev[fan_id].fan_cnt = 0; 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci /* input capture is occurred */ 4758c2ecf20Sopenharmony_ci if (flag & flag_cap) 4768c2ecf20Sopenharmony_ci npcm7xx_fan_compute(data, fan, cmp, fan_id, flag_int, 4778c2ecf20Sopenharmony_ci flag_mode, flag_clear); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic irqreturn_t npcm7xx_fan_isr(int irq, void *dev_id) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data = dev_id; 4848c2ecf20Sopenharmony_ci unsigned long flags; 4858c2ecf20Sopenharmony_ci int module; 4868c2ecf20Sopenharmony_ci u8 flag; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci module = irq - data->fan_irq[0]; 4898c2ecf20Sopenharmony_ci spin_lock_irqsave(&data->fan_lock[module], flags); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci flag = ioread8(NPCM7XX_FAN_REG_TICTRL(data->fan_base, module)); 4928c2ecf20Sopenharmony_ci if (flag > 0) { 4938c2ecf20Sopenharmony_ci npcm7xx_check_cmp(data, module, NPCM7XX_FAN_CMPA, flag); 4948c2ecf20Sopenharmony_ci npcm7xx_check_cmp(data, module, NPCM7XX_FAN_CMPB, flag); 4958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data->fan_lock[module], flags); 4968c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data->fan_lock[module], flags); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return IRQ_NONE; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int npcm7xx_read_pwm(struct device *dev, u32 attr, int channel, 5058c2ecf20Sopenharmony_ci long *val) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data = dev_get_drvdata(dev); 5088c2ecf20Sopenharmony_ci u32 pmw_ch = (channel % NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE); 5098c2ecf20Sopenharmony_ci u32 module = (channel / NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci switch (attr) { 5128c2ecf20Sopenharmony_ci case hwmon_pwm_input: 5138c2ecf20Sopenharmony_ci *val = ioread32 5148c2ecf20Sopenharmony_ci (NPCM7XX_PWM_REG_CMRx(data->pwm_base, module, pmw_ch)); 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci default: 5178c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int npcm7xx_write_pwm(struct device *dev, u32 attr, int channel, 5228c2ecf20Sopenharmony_ci long val) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data = dev_get_drvdata(dev); 5258c2ecf20Sopenharmony_ci int err; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci switch (attr) { 5288c2ecf20Sopenharmony_ci case hwmon_pwm_input: 5298c2ecf20Sopenharmony_ci if (val < 0 || val > NPCM7XX_PWM_CMR_MAX) 5308c2ecf20Sopenharmony_ci return -EINVAL; 5318c2ecf20Sopenharmony_ci err = npcm7xx_pwm_config_set(data, channel, (u16)val); 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci default: 5348c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return err; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic umode_t npcm7xx_pwm_is_visible(const void *_data, u32 attr, int channel) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci const struct npcm7xx_pwm_fan_data *data = _data; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!data->pwm_present[channel]) 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci switch (attr) { 5498c2ecf20Sopenharmony_ci case hwmon_pwm_input: 5508c2ecf20Sopenharmony_ci return 0644; 5518c2ecf20Sopenharmony_ci default: 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int npcm7xx_read_fan(struct device *dev, u32 attr, int channel, 5578c2ecf20Sopenharmony_ci long *val) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data = dev_get_drvdata(dev); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci switch (attr) { 5628c2ecf20Sopenharmony_ci case hwmon_fan_input: 5638c2ecf20Sopenharmony_ci *val = 0; 5648c2ecf20Sopenharmony_ci if (data->fan_dev[channel].fan_cnt <= 0) 5658c2ecf20Sopenharmony_ci return data->fan_dev[channel].fan_cnt; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Convert the raw reading to RPM */ 5688c2ecf20Sopenharmony_ci if (data->fan_dev[channel].fan_cnt > 0 && 5698c2ecf20Sopenharmony_ci data->fan_dev[channel].fan_pls_per_rev > 0) 5708c2ecf20Sopenharmony_ci *val = ((data->input_clk_freq * 60) / 5718c2ecf20Sopenharmony_ci (data->fan_dev[channel].fan_cnt * 5728c2ecf20Sopenharmony_ci data->fan_dev[channel].fan_pls_per_rev)); 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci default: 5758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic umode_t npcm7xx_fan_is_visible(const void *_data, u32 attr, int channel) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci const struct npcm7xx_pwm_fan_data *data = _data; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (!data->fan_present[channel]) 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci switch (attr) { 5878c2ecf20Sopenharmony_ci case hwmon_fan_input: 5888c2ecf20Sopenharmony_ci return 0444; 5898c2ecf20Sopenharmony_ci default: 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int npcm7xx_read(struct device *dev, enum hwmon_sensor_types type, 5958c2ecf20Sopenharmony_ci u32 attr, int channel, long *val) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci switch (type) { 5988c2ecf20Sopenharmony_ci case hwmon_pwm: 5998c2ecf20Sopenharmony_ci return npcm7xx_read_pwm(dev, attr, channel, val); 6008c2ecf20Sopenharmony_ci case hwmon_fan: 6018c2ecf20Sopenharmony_ci return npcm7xx_read_fan(dev, attr, channel, val); 6028c2ecf20Sopenharmony_ci default: 6038c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int npcm7xx_write(struct device *dev, enum hwmon_sensor_types type, 6088c2ecf20Sopenharmony_ci u32 attr, int channel, long val) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci switch (type) { 6118c2ecf20Sopenharmony_ci case hwmon_pwm: 6128c2ecf20Sopenharmony_ci return npcm7xx_write_pwm(dev, attr, channel, val); 6138c2ecf20Sopenharmony_ci default: 6148c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic umode_t npcm7xx_is_visible(const void *data, 6198c2ecf20Sopenharmony_ci enum hwmon_sensor_types type, 6208c2ecf20Sopenharmony_ci u32 attr, int channel) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci switch (type) { 6238c2ecf20Sopenharmony_ci case hwmon_pwm: 6248c2ecf20Sopenharmony_ci return npcm7xx_pwm_is_visible(data, attr, channel); 6258c2ecf20Sopenharmony_ci case hwmon_fan: 6268c2ecf20Sopenharmony_ci return npcm7xx_fan_is_visible(data, attr, channel); 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *npcm7xx_info[] = { 6338c2ecf20Sopenharmony_ci HWMON_CHANNEL_INFO(pwm, 6348c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6358c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6368c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6378c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6388c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6398c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6408c2ecf20Sopenharmony_ci HWMON_PWM_INPUT, 6418c2ecf20Sopenharmony_ci HWMON_PWM_INPUT), 6428c2ecf20Sopenharmony_ci HWMON_CHANNEL_INFO(fan, 6438c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6448c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6458c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6468c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6478c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6488c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6498c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6508c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6518c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6528c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6538c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6548c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6558c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6568c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6578c2ecf20Sopenharmony_ci HWMON_F_INPUT, 6588c2ecf20Sopenharmony_ci HWMON_F_INPUT), 6598c2ecf20Sopenharmony_ci NULL 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic const struct hwmon_ops npcm7xx_hwmon_ops = { 6638c2ecf20Sopenharmony_ci .is_visible = npcm7xx_is_visible, 6648c2ecf20Sopenharmony_ci .read = npcm7xx_read, 6658c2ecf20Sopenharmony_ci .write = npcm7xx_write, 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info npcm7xx_chip_info = { 6698c2ecf20Sopenharmony_ci .ops = &npcm7xx_hwmon_ops, 6708c2ecf20Sopenharmony_ci .info = npcm7xx_info, 6718c2ecf20Sopenharmony_ci}; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic u32 npcm7xx_pwm_init(struct npcm7xx_pwm_fan_data *data) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci int m, ch; 6768c2ecf20Sopenharmony_ci u32 prescale_val, output_freq; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci data->pwm_clk_freq = clk_get_rate(data->pwm_clk); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* Adjust NPCM7xx PWMs output frequency to ~25Khz */ 6818c2ecf20Sopenharmony_ci output_freq = data->pwm_clk_freq / PWN_CNT_DEFAULT; 6828c2ecf20Sopenharmony_ci prescale_val = DIV_ROUND_CLOSEST(output_freq, PWM_OUTPUT_FREQ_25KHZ); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* If prescale_val = 0, then the prescale output clock is stopped */ 6858c2ecf20Sopenharmony_ci if (prescale_val < MIN_PRESCALE1) 6868c2ecf20Sopenharmony_ci prescale_val = MIN_PRESCALE1; 6878c2ecf20Sopenharmony_ci /* 6888c2ecf20Sopenharmony_ci * prescale_val need to decrement in one because in the PWM Prescale 6898c2ecf20Sopenharmony_ci * register the Prescale value increment by one 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci prescale_val--; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* Setting PWM Prescale Register value register to both modules */ 6948c2ecf20Sopenharmony_ci prescale_val |= (prescale_val << NPCM7XX_PWM_PRESCALE_SHIFT_CH01); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci for (m = 0; m < NPCM7XX_PWM_MAX_MODULES ; m++) { 6978c2ecf20Sopenharmony_ci iowrite32(prescale_val, NPCM7XX_PWM_REG_PR(data->pwm_base, m)); 6988c2ecf20Sopenharmony_ci iowrite32(NPCM7XX_PWM_PRESCALE2_DEFAULT, 6998c2ecf20Sopenharmony_ci NPCM7XX_PWM_REG_CSR(data->pwm_base, m)); 7008c2ecf20Sopenharmony_ci iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFAULT, 7018c2ecf20Sopenharmony_ci NPCM7XX_PWM_REG_CR(data->pwm_base, m)); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci for (ch = 0; ch < NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE; ch++) { 7048c2ecf20Sopenharmony_ci iowrite32(NPCM7XX_PWM_COUNTER_DEFAULT_NUM, 7058c2ecf20Sopenharmony_ci NPCM7XX_PWM_REG_CNRx(data->pwm_base, m, ch)); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return output_freq / ((prescale_val & 0xf) + 1); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void npcm7xx_fan_init(struct npcm7xx_pwm_fan_data *data) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci int md; 7158c2ecf20Sopenharmony_ci int ch; 7168c2ecf20Sopenharmony_ci int i; 7178c2ecf20Sopenharmony_ci u32 apb_clk_freq; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci for (md = 0; md < NPCM7XX_FAN_MAX_MODULE; md++) { 7208c2ecf20Sopenharmony_ci /* stop FAN0~7 clock */ 7218c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_TCKC_CLKX_NONE, 7228c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCKC(data->fan_base, md)); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* disable all interrupt */ 7258c2ecf20Sopenharmony_ci iowrite8(0x00, NPCM7XX_FAN_REG_TIEN(data->fan_base, md)); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* clear all interrupt */ 7288c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_TICLR_CLEAR_ALL, 7298c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TICLR(data->fan_base, md)); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* set FAN0~7 clock prescaler */ 7328c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_CLK_PRESCALE, 7338c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TPRSC(data->fan_base, md)); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* set FAN0~7 mode (high-to-low transition) */ 7368c2ecf20Sopenharmony_ci iowrite8((NPCM7XX_FAN_TMCTRL_MODE_5 | NPCM7XX_FAN_TMCTRL_TBEN | 7378c2ecf20Sopenharmony_ci NPCM7XX_FAN_TMCTRL_TAEN), 7388c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TMCTRL(data->fan_base, md)); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* set FAN0~7 Initial Count/Cap */ 7418c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCNT, 7428c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCNT1(data->fan_base, md)); 7438c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCNT, 7448c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCNT2(data->fan_base, md)); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* set FAN0~7 compare (equal to count) */ 7478c2ecf20Sopenharmony_ci iowrite8((NPCM7XX_FAN_TCPCFG_EQAEN | NPCM7XX_FAN_TCPCFG_EQBEN), 7488c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCPCFG(data->fan_base, md)); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* set FAN0~7 compare value */ 7518c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCPA, 7528c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCPA(data->fan_base, md)); 7538c2ecf20Sopenharmony_ci iowrite16(NPCM7XX_FAN_TCPB, 7548c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TCPB(data->fan_base, md)); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* set FAN0~7 fan input FANIN 0~15 */ 7578c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_TINASEL_FANIN_DEFAULT, 7588c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TINASEL(data->fan_base, md)); 7598c2ecf20Sopenharmony_ci iowrite8(NPCM7XX_FAN_TINASEL_FANIN_DEFAULT, 7608c2ecf20Sopenharmony_ci NPCM7XX_FAN_REG_TINBSEL(data->fan_base, md)); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci for (i = 0; i < NPCM7XX_FAN_MAX_CHN_NUM_IN_A_MODULE; i++) { 7638c2ecf20Sopenharmony_ci ch = md * NPCM7XX_FAN_MAX_CHN_NUM_IN_A_MODULE + i; 7648c2ecf20Sopenharmony_ci data->fan_dev[ch].fan_st_flg = FAN_DISABLE; 7658c2ecf20Sopenharmony_ci data->fan_dev[ch].fan_pls_per_rev = 7668c2ecf20Sopenharmony_ci NPCM7XX_FAN_DEFAULT_PULSE_PER_REVOLUTION; 7678c2ecf20Sopenharmony_ci data->fan_dev[ch].fan_cnt = 0; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci apb_clk_freq = clk_get_rate(data->fan_clk); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Fan tach input clock = APB clock / prescalar, default is 255. */ 7748c2ecf20Sopenharmony_ci data->input_clk_freq = apb_clk_freq / (NPCM7XX_FAN_CLK_PRESCALE + 1); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int 7788c2ecf20Sopenharmony_cinpcm7xx_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev, 7798c2ecf20Sopenharmony_ci unsigned long *state) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct npcm7xx_cooling_device *cdev = tcdev->devdata; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci *state = cdev->max_state; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci return 0; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic int 7898c2ecf20Sopenharmony_cinpcm7xx_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev, 7908c2ecf20Sopenharmony_ci unsigned long *state) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct npcm7xx_cooling_device *cdev = tcdev->devdata; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci *state = cdev->cur_state; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int 8008c2ecf20Sopenharmony_cinpcm7xx_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev, 8018c2ecf20Sopenharmony_ci unsigned long state) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct npcm7xx_cooling_device *cdev = tcdev->devdata; 8048c2ecf20Sopenharmony_ci int ret; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (state > cdev->max_state) 8078c2ecf20Sopenharmony_ci return -EINVAL; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci cdev->cur_state = state; 8108c2ecf20Sopenharmony_ci ret = npcm7xx_pwm_config_set(cdev->data, cdev->pwm_port, 8118c2ecf20Sopenharmony_ci cdev->cooling_levels[cdev->cur_state]); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return ret; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic const struct thermal_cooling_device_ops npcm7xx_pwm_cool_ops = { 8178c2ecf20Sopenharmony_ci .get_max_state = npcm7xx_pwm_cz_get_max_state, 8188c2ecf20Sopenharmony_ci .get_cur_state = npcm7xx_pwm_cz_get_cur_state, 8198c2ecf20Sopenharmony_ci .set_cur_state = npcm7xx_pwm_cz_set_cur_state, 8208c2ecf20Sopenharmony_ci}; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic int npcm7xx_create_pwm_cooling(struct device *dev, 8238c2ecf20Sopenharmony_ci struct device_node *child, 8248c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data, 8258c2ecf20Sopenharmony_ci u32 pwm_port, u8 num_levels) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci struct npcm7xx_cooling_device *cdev; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL); 8318c2ecf20Sopenharmony_ci if (!cdev) 8328c2ecf20Sopenharmony_ci return -ENOMEM; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL); 8358c2ecf20Sopenharmony_ci if (!cdev->cooling_levels) 8368c2ecf20Sopenharmony_ci return -ENOMEM; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci cdev->max_state = num_levels - 1; 8398c2ecf20Sopenharmony_ci ret = of_property_read_u8_array(child, "cooling-levels", 8408c2ecf20Sopenharmony_ci cdev->cooling_levels, 8418c2ecf20Sopenharmony_ci num_levels); 8428c2ecf20Sopenharmony_ci if (ret) { 8438c2ecf20Sopenharmony_ci dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child, 8478c2ecf20Sopenharmony_ci pwm_port); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child, 8508c2ecf20Sopenharmony_ci cdev->name, cdev, &npcm7xx_pwm_cool_ops); 8518c2ecf20Sopenharmony_ci if (IS_ERR(cdev->tcdev)) 8528c2ecf20Sopenharmony_ci return PTR_ERR(cdev->tcdev); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci cdev->data = data; 8558c2ecf20Sopenharmony_ci cdev->pwm_port = pwm_port; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci data->cdev[pwm_port] = cdev; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return 0; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int npcm7xx_en_pwm_fan(struct device *dev, 8638c2ecf20Sopenharmony_ci struct device_node *child, 8648c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci u8 *fan_ch; 8678c2ecf20Sopenharmony_ci u32 pwm_port; 8688c2ecf20Sopenharmony_ci int ret, fan_cnt; 8698c2ecf20Sopenharmony_ci u8 index, ch; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "reg", &pwm_port); 8728c2ecf20Sopenharmony_ci if (ret) 8738c2ecf20Sopenharmony_ci return ret; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci data->pwm_present[pwm_port] = true; 8768c2ecf20Sopenharmony_ci ret = npcm7xx_pwm_config_set(data, pwm_port, 8778c2ecf20Sopenharmony_ci NPCM7XX_PWM_CMR_DEFAULT_NUM); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ret = of_property_count_u8_elems(child, "cooling-levels"); 8808c2ecf20Sopenharmony_ci if (ret > 0) { 8818c2ecf20Sopenharmony_ci ret = npcm7xx_create_pwm_cooling(dev, child, data, pwm_port, 8828c2ecf20Sopenharmony_ci ret); 8838c2ecf20Sopenharmony_ci if (ret) 8848c2ecf20Sopenharmony_ci return ret; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci fan_cnt = of_property_count_u8_elems(child, "fan-tach-ch"); 8888c2ecf20Sopenharmony_ci if (fan_cnt < 1) 8898c2ecf20Sopenharmony_ci return -EINVAL; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci fan_ch = devm_kcalloc(dev, fan_cnt, sizeof(*fan_ch), GFP_KERNEL); 8928c2ecf20Sopenharmony_ci if (!fan_ch) 8938c2ecf20Sopenharmony_ci return -ENOMEM; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci ret = of_property_read_u8_array(child, "fan-tach-ch", fan_ch, fan_cnt); 8968c2ecf20Sopenharmony_ci if (ret) 8978c2ecf20Sopenharmony_ci return ret; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci for (ch = 0; ch < fan_cnt; ch++) { 9008c2ecf20Sopenharmony_ci index = fan_ch[ch]; 9018c2ecf20Sopenharmony_ci data->fan_present[index] = true; 9028c2ecf20Sopenharmony_ci data->fan_dev[index].fan_st_flg = FAN_INIT; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return 0; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int npcm7xx_pwm_fan_probe(struct platform_device *pdev) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9118c2ecf20Sopenharmony_ci struct device_node *np, *child; 9128c2ecf20Sopenharmony_ci struct npcm7xx_pwm_fan_data *data; 9138c2ecf20Sopenharmony_ci struct resource *res; 9148c2ecf20Sopenharmony_ci struct device *hwmon; 9158c2ecf20Sopenharmony_ci char name[20]; 9168c2ecf20Sopenharmony_ci int ret, cnt; 9178c2ecf20Sopenharmony_ci u32 output_freq; 9188c2ecf20Sopenharmony_ci u32 i; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci np = dev->of_node; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 9238c2ecf20Sopenharmony_ci if (!data) 9248c2ecf20Sopenharmony_ci return -ENOMEM; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"); 9278c2ecf20Sopenharmony_ci if (!res) { 9288c2ecf20Sopenharmony_ci dev_err(dev, "pwm resource not found\n"); 9298c2ecf20Sopenharmony_ci return -ENODEV; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci data->pwm_base = devm_ioremap_resource(dev, res); 9338c2ecf20Sopenharmony_ci dev_dbg(dev, "pwm base resource is %pR\n", res); 9348c2ecf20Sopenharmony_ci if (IS_ERR(data->pwm_base)) 9358c2ecf20Sopenharmony_ci return PTR_ERR(data->pwm_base); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci data->pwm_clk = devm_clk_get(dev, "pwm"); 9388c2ecf20Sopenharmony_ci if (IS_ERR(data->pwm_clk)) { 9398c2ecf20Sopenharmony_ci dev_err(dev, "couldn't get pwm clock\n"); 9408c2ecf20Sopenharmony_ci return PTR_ERR(data->pwm_clk); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fan"); 9448c2ecf20Sopenharmony_ci if (!res) { 9458c2ecf20Sopenharmony_ci dev_err(dev, "fan resource not found\n"); 9468c2ecf20Sopenharmony_ci return -ENODEV; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci data->fan_base = devm_ioremap_resource(dev, res); 9508c2ecf20Sopenharmony_ci dev_dbg(dev, "fan base resource is %pR\n", res); 9518c2ecf20Sopenharmony_ci if (IS_ERR(data->fan_base)) 9528c2ecf20Sopenharmony_ci return PTR_ERR(data->fan_base); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci data->fan_clk = devm_clk_get(dev, "fan"); 9558c2ecf20Sopenharmony_ci if (IS_ERR(data->fan_clk)) { 9568c2ecf20Sopenharmony_ci dev_err(dev, "couldn't get fan clock\n"); 9578c2ecf20Sopenharmony_ci return PTR_ERR(data->fan_clk); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci output_freq = npcm7xx_pwm_init(data); 9618c2ecf20Sopenharmony_ci npcm7xx_fan_init(data); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci for (cnt = 0; cnt < NPCM7XX_PWM_MAX_MODULES ; cnt++) 9648c2ecf20Sopenharmony_ci mutex_init(&data->pwm_lock[cnt]); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci for (i = 0; i < NPCM7XX_FAN_MAX_MODULE; i++) { 9678c2ecf20Sopenharmony_ci spin_lock_init(&data->fan_lock[i]); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci data->fan_irq[i] = platform_get_irq(pdev, i); 9708c2ecf20Sopenharmony_ci if (data->fan_irq[i] < 0) 9718c2ecf20Sopenharmony_ci return data->fan_irq[i]; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci sprintf(name, "NPCM7XX-FAN-MD%d", i); 9748c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr, 9758c2ecf20Sopenharmony_ci 0, name, (void *)data); 9768c2ecf20Sopenharmony_ci if (ret) { 9778c2ecf20Sopenharmony_ci dev_err(dev, "register IRQ fan%d failed\n", i); 9788c2ecf20Sopenharmony_ci return ret; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 9838c2ecf20Sopenharmony_ci ret = npcm7xx_en_pwm_fan(dev, child, data); 9848c2ecf20Sopenharmony_ci if (ret) { 9858c2ecf20Sopenharmony_ci dev_err(dev, "enable pwm and fan failed\n"); 9868c2ecf20Sopenharmony_ci of_node_put(child); 9878c2ecf20Sopenharmony_ci return ret; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci hwmon = devm_hwmon_device_register_with_info(dev, "npcm7xx_pwm_fan", 9928c2ecf20Sopenharmony_ci data, &npcm7xx_chip_info, 9938c2ecf20Sopenharmony_ci NULL); 9948c2ecf20Sopenharmony_ci if (IS_ERR(hwmon)) { 9958c2ecf20Sopenharmony_ci dev_err(dev, "unable to register hwmon device\n"); 9968c2ecf20Sopenharmony_ci return PTR_ERR(hwmon); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci for (i = 0; i < NPCM7XX_FAN_MAX_CHN_NUM; i++) { 10008c2ecf20Sopenharmony_ci if (data->fan_present[i]) { 10018c2ecf20Sopenharmony_ci /* fan timer initialization */ 10028c2ecf20Sopenharmony_ci data->fan_timer.expires = jiffies + 10038c2ecf20Sopenharmony_ci msecs_to_jiffies(NPCM7XX_FAN_POLL_TIMER_200MS); 10048c2ecf20Sopenharmony_ci timer_setup(&data->fan_timer, 10058c2ecf20Sopenharmony_ci npcm7xx_fan_polling, 0); 10068c2ecf20Sopenharmony_ci add_timer(&data->fan_timer); 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci pr_info("NPCM7XX PWM-FAN Driver probed, output Freq %dHz[PWM], input Freq %dHz[FAN]\n", 10128c2ecf20Sopenharmony_ci output_freq, data->input_clk_freq); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return 0; 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic const struct of_device_id of_pwm_fan_match_table[] = { 10188c2ecf20Sopenharmony_ci { .compatible = "nuvoton,npcm750-pwm-fan", }, 10198c2ecf20Sopenharmony_ci {}, 10208c2ecf20Sopenharmony_ci}; 10218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_pwm_fan_match_table); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic struct platform_driver npcm7xx_pwm_fan_driver = { 10248c2ecf20Sopenharmony_ci .probe = npcm7xx_pwm_fan_probe, 10258c2ecf20Sopenharmony_ci .driver = { 10268c2ecf20Sopenharmony_ci .name = "npcm7xx_pwm_fan", 10278c2ecf20Sopenharmony_ci .of_match_table = of_pwm_fan_match_table, 10288c2ecf20Sopenharmony_ci }, 10298c2ecf20Sopenharmony_ci}; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cimodule_platform_driver(npcm7xx_pwm_fan_driver); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Nuvoton NPCM7XX PWM and Fan Tacho driver"); 10348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); 10358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1036