18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Google, Inc 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 108c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 118c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/reset.h> 208c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 218c2ecf20Sopenharmony_ci#include <linux/thermal.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* ASPEED PWM & FAN Tach Register Definition */ 248c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL 0x00 258c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL 0x04 268c2ecf20Sopenharmony_ci#define ASPEED_PTCR_DUTY0_CTRL 0x08 278c2ecf20Sopenharmony_ci#define ASPEED_PTCR_DUTY1_CTRL 0x0c 288c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEM_CTRL 0x10 298c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEM_CTRL1 0x14 308c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEN_CTRL 0x18 318c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEN_CTRL1 0x1c 328c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TACH_SOURCE 0x20 338c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TRIGGER 0x28 348c2ecf20Sopenharmony_ci#define ASPEED_PTCR_RESULT 0x2c 358c2ecf20Sopenharmony_ci#define ASPEED_PTCR_INTR_CTRL 0x30 368c2ecf20Sopenharmony_ci#define ASPEED_PTCR_INTR_STS 0x34 378c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEM_LIMIT 0x38 388c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEN_LIMIT 0x3C 398c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_EXT 0x40 408c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_EXT 0x44 418c2ecf20Sopenharmony_ci#define ASPEED_PTCR_DUTY2_CTRL 0x48 428c2ecf20Sopenharmony_ci#define ASPEED_PTCR_DUTY3_CTRL 0x4c 438c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEO_CTRL 0x50 448c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEO_CTRL1 0x54 458c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TACH_SOURCE_EXT 0x60 468c2ecf20Sopenharmony_ci#define ASPEED_PTCR_TYPEO_LIMIT 0x78 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */ 498c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15 508c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6 518c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15)) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14 548c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5 558c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14)) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13 588c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4 598c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13)) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12 628c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3 638c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12)) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x)) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMD_EN BIT(11) 688c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMC_EN BIT(10) 698c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMB_EN BIT(9) 708c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMA_EN BIT(8) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_CLK_SRC BIT(1) 738c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_CLK_EN BIT(0) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */ 768c2ecf20Sopenharmony_ci/* TYPE N */ 778c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16) 788c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24 798c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20 808c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16 818c2ecf20Sopenharmony_ci/* TYPE M */ 828c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0) 838c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8 848c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4 858c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control 898c2ecf20Sopenharmony_ci * 0/1/2/3 register 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM2_FALL_POINT 24 928c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM2_RISE_POINT 16 938c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16) 948c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM1_FALL_POINT 8 958c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM1_RISE_POINT 0 968c2ecf20Sopenharmony_ci#define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */ 998c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16)) 1008c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN1_MASK GENMASK(31, 0) 1018c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN_PERIOD 16 1028c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN_MODE 4 1038c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN_DIVISION 1 1048c2ecf20Sopenharmony_ci#define TYPE_CTRL_FAN_TYPE_EN 1 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */ 1078c2ecf20Sopenharmony_ci/* bit [0,1] at 0x20, bit [2] at 0x60 */ 1088c2ecf20Sopenharmony_ci#define TACH_PWM_SOURCE_BIT01(x) ((x) * 2) 1098c2ecf20Sopenharmony_ci#define TACH_PWM_SOURCE_BIT2(x) ((x) * 2) 1108c2ecf20Sopenharmony_ci#define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2)) 1118c2ecf20Sopenharmony_ci#define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* ASPEED_PTCR_RESULT : 0x2c - Result Register */ 1148c2ecf20Sopenharmony_ci#define RESULT_STATUS_MASK BIT(31) 1158c2ecf20Sopenharmony_ci#define RESULT_VALUE_MASK 0xfffff 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */ 1188c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15 1198c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6 1208c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15)) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14 1238c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5 1248c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14)) 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13 1278c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4 1288c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13)) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12 1318c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3 1328c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12)) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMH_EN BIT(11) 1358c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMG_EN BIT(10) 1368c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMF_EN BIT(9) 1378c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWME_EN BIT(8) 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */ 1408c2ecf20Sopenharmony_ci/* TYPE O */ 1418c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0) 1428c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8 1438c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4 1448c2ecf20Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define PWM_MAX 255 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define BOTH_EDGES 0x02 /* 10b */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define M_PWM_DIV_H 0x00 1518c2ecf20Sopenharmony_ci#define M_PWM_DIV_L 0x05 1528c2ecf20Sopenharmony_ci#define M_PWM_PERIOD 0x5F 1538c2ecf20Sopenharmony_ci#define M_TACH_CLK_DIV 0x00 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * 5:4 Type N fan tach mode selection bit: 1568c2ecf20Sopenharmony_ci * 00: falling 1578c2ecf20Sopenharmony_ci * 01: rising 1588c2ecf20Sopenharmony_ci * 10: both 1598c2ecf20Sopenharmony_ci * 11: reserved. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci#define M_TACH_MODE 0x02 /* 10b */ 1628c2ecf20Sopenharmony_ci#define M_TACH_UNIT 0x0210 1638c2ecf20Sopenharmony_ci#define INIT_FAN_CTRL 0xFF 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* How long we sleep in us while waiting for an RPM result. */ 1668c2ecf20Sopenharmony_ci#define ASPEED_RPM_STATUS_SLEEP_USEC 500 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define MAX_CDEV_NAME_LEN 16 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistruct aspeed_cooling_device { 1718c2ecf20Sopenharmony_ci char name[16]; 1728c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv; 1738c2ecf20Sopenharmony_ci struct thermal_cooling_device *tcdev; 1748c2ecf20Sopenharmony_ci int pwm_port; 1758c2ecf20Sopenharmony_ci u8 *cooling_levels; 1768c2ecf20Sopenharmony_ci u8 max_state; 1778c2ecf20Sopenharmony_ci u8 cur_state; 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistruct aspeed_pwm_tacho_data { 1818c2ecf20Sopenharmony_ci struct regmap *regmap; 1828c2ecf20Sopenharmony_ci struct reset_control *rst; 1838c2ecf20Sopenharmony_ci unsigned long clk_freq; 1848c2ecf20Sopenharmony_ci bool pwm_present[8]; 1858c2ecf20Sopenharmony_ci bool fan_tach_present[16]; 1868c2ecf20Sopenharmony_ci u8 type_pwm_clock_unit[3]; 1878c2ecf20Sopenharmony_ci u8 type_pwm_clock_division_h[3]; 1888c2ecf20Sopenharmony_ci u8 type_pwm_clock_division_l[3]; 1898c2ecf20Sopenharmony_ci u8 type_fan_tach_clock_division[3]; 1908c2ecf20Sopenharmony_ci u8 type_fan_tach_mode[3]; 1918c2ecf20Sopenharmony_ci u16 type_fan_tach_unit[3]; 1928c2ecf20Sopenharmony_ci u8 pwm_port_type[8]; 1938c2ecf20Sopenharmony_ci u8 pwm_port_fan_ctrl[8]; 1948c2ecf20Sopenharmony_ci u8 fan_tach_ch_source[16]; 1958c2ecf20Sopenharmony_ci struct aspeed_cooling_device *cdev[8]; 1968c2ecf20Sopenharmony_ci const struct attribute_group *groups[3]; 1978c2ecf20Sopenharmony_ci /* protects access to shared ASPEED_PTCR_RESULT */ 1988c2ecf20Sopenharmony_ci struct mutex tach_lock; 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cienum type { TYPEM, TYPEN, TYPEO }; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistruct type_params { 2048c2ecf20Sopenharmony_ci u32 l_value; 2058c2ecf20Sopenharmony_ci u32 h_value; 2068c2ecf20Sopenharmony_ci u32 unit_value; 2078c2ecf20Sopenharmony_ci u32 clk_ctrl_mask; 2088c2ecf20Sopenharmony_ci u32 clk_ctrl_reg; 2098c2ecf20Sopenharmony_ci u32 ctrl_reg; 2108c2ecf20Sopenharmony_ci u32 ctrl_reg1; 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic const struct type_params type_params[] = { 2148c2ecf20Sopenharmony_ci [TYPEM] = { 2158c2ecf20Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L, 2168c2ecf20Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H, 2178c2ecf20Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT, 2188c2ecf20Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK, 2198c2ecf20Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL, 2208c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEM_CTRL, 2218c2ecf20Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1, 2228c2ecf20Sopenharmony_ci }, 2238c2ecf20Sopenharmony_ci [TYPEN] = { 2248c2ecf20Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L, 2258c2ecf20Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H, 2268c2ecf20Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT, 2278c2ecf20Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK, 2288c2ecf20Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL, 2298c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEN_CTRL, 2308c2ecf20Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci [TYPEO] = { 2338c2ecf20Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L, 2348c2ecf20Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H, 2358c2ecf20Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT, 2368c2ecf20Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK, 2378c2ecf20Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT, 2388c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEO_CTRL, 2398c2ecf20Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1, 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cienum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH }; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistruct pwm_port_params { 2468c2ecf20Sopenharmony_ci u32 pwm_en; 2478c2ecf20Sopenharmony_ci u32 ctrl_reg; 2488c2ecf20Sopenharmony_ci u32 type_part1; 2498c2ecf20Sopenharmony_ci u32 type_part2; 2508c2ecf20Sopenharmony_ci u32 type_mask; 2518c2ecf20Sopenharmony_ci u32 duty_ctrl_rise_point; 2528c2ecf20Sopenharmony_ci u32 duty_ctrl_fall_point; 2538c2ecf20Sopenharmony_ci u32 duty_ctrl_reg; 2548c2ecf20Sopenharmony_ci u32 duty_ctrl_rise_fall_mask; 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic const struct pwm_port_params pwm_port_params[] = { 2588c2ecf20Sopenharmony_ci [PWMA] = { 2598c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMA_EN, 2608c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 2618c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1, 2628c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2, 2638c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK, 2648c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 2658c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 2668c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL, 2678c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci [PWMB] = { 2708c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMB_EN, 2718c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 2728c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1, 2738c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2, 2748c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK, 2758c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 2768c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 2778c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL, 2788c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 2798c2ecf20Sopenharmony_ci }, 2808c2ecf20Sopenharmony_ci [PWMC] = { 2818c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMC_EN, 2828c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 2838c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1, 2848c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2, 2858c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK, 2868c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 2878c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 2888c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL, 2898c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 2908c2ecf20Sopenharmony_ci }, 2918c2ecf20Sopenharmony_ci [PWMD] = { 2928c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMD_EN, 2938c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 2948c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1, 2958c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2, 2968c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK, 2978c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 2988c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 2998c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL, 3008c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 3018c2ecf20Sopenharmony_ci }, 3028c2ecf20Sopenharmony_ci [PWME] = { 3038c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWME_EN, 3048c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 3058c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1, 3068c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2, 3078c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK, 3088c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 3098c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 3108c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL, 3118c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 3128c2ecf20Sopenharmony_ci }, 3138c2ecf20Sopenharmony_ci [PWMF] = { 3148c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMF_EN, 3158c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 3168c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1, 3178c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2, 3188c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK, 3198c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 3208c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 3218c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL, 3228c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci [PWMG] = { 3258c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMG_EN, 3268c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 3278c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1, 3288c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2, 3298c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK, 3308c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 3318c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 3328c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL, 3338c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci [PWMH] = { 3368c2ecf20Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMH_EN, 3378c2ecf20Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 3388c2ecf20Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1, 3398c2ecf20Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2, 3408c2ecf20Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK, 3418c2ecf20Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 3428c2ecf20Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 3438c2ecf20Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL, 3448c2ecf20Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg, 3498c2ecf20Sopenharmony_ci unsigned int val) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci void __iomem *regs = (void __iomem *)context; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci writel(val, regs + reg); 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg, 3588c2ecf20Sopenharmony_ci unsigned int *val) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci void __iomem *regs = (void __iomem *)context; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci *val = readl(regs + reg); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct regmap_config aspeed_pwm_tacho_regmap_config = { 3678c2ecf20Sopenharmony_ci .reg_bits = 32, 3688c2ecf20Sopenharmony_ci .val_bits = 32, 3698c2ecf20Sopenharmony_ci .reg_stride = 4, 3708c2ecf20Sopenharmony_ci .max_register = ASPEED_PTCR_TYPEO_LIMIT, 3718c2ecf20Sopenharmony_ci .reg_write = regmap_aspeed_pwm_tacho_reg_write, 3728c2ecf20Sopenharmony_ci .reg_read = regmap_aspeed_pwm_tacho_reg_read, 3738c2ecf20Sopenharmony_ci .fast_io = true, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void aspeed_set_clock_enable(struct regmap *regmap, bool val) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 3798c2ecf20Sopenharmony_ci ASPEED_PTCR_CTRL_CLK_EN, 3808c2ecf20Sopenharmony_ci val ? ASPEED_PTCR_CTRL_CLK_EN : 0); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void aspeed_set_clock_source(struct regmap *regmap, int val) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 3868c2ecf20Sopenharmony_ci ASPEED_PTCR_CTRL_CLK_SRC, 3878c2ecf20Sopenharmony_ci val ? ASPEED_PTCR_CTRL_CLK_SRC : 0); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type, 3918c2ecf20Sopenharmony_ci u8 div_high, u8 div_low, u8 unit) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci u32 reg_value = ((div_high << type_params[type].h_value) | 3948c2ecf20Sopenharmony_ci (div_low << type_params[type].l_value) | 3958c2ecf20Sopenharmony_ci (unit << type_params[type].unit_value)); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci regmap_update_bits(regmap, type_params[type].clk_ctrl_reg, 3988c2ecf20Sopenharmony_ci type_params[type].clk_ctrl_mask, reg_value); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port, 4028c2ecf20Sopenharmony_ci bool enable) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg, 4058c2ecf20Sopenharmony_ci pwm_port_params[pwm_port].pwm_en, 4068c2ecf20Sopenharmony_ci enable ? pwm_port_params[pwm_port].pwm_en : 0); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void aspeed_set_pwm_port_type(struct regmap *regmap, 4108c2ecf20Sopenharmony_ci u8 pwm_port, u8 type) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg, 4178c2ecf20Sopenharmony_ci pwm_port_params[pwm_port].type_mask, reg_value); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap, 4218c2ecf20Sopenharmony_ci u8 pwm_port, u8 rising, 4228c2ecf20Sopenharmony_ci u8 falling) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci u32 reg_value = (rising << 4258c2ecf20Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_rise_point); 4268c2ecf20Sopenharmony_ci reg_value |= (falling << 4278c2ecf20Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_fall_point); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg, 4308c2ecf20Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask, 4318c2ecf20Sopenharmony_ci reg_value); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type, 4358c2ecf20Sopenharmony_ci bool enable) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg, 4388c2ecf20Sopenharmony_ci TYPE_CTRL_FAN_TYPE_EN, 4398c2ecf20Sopenharmony_ci enable ? TYPE_CTRL_FAN_TYPE_EN : 0); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type, 4438c2ecf20Sopenharmony_ci u8 mode, u16 unit, u8 division) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) | 4468c2ecf20Sopenharmony_ci (unit << TYPE_CTRL_FAN_PERIOD) | 4478c2ecf20Sopenharmony_ci (division << TYPE_CTRL_FAN_DIVISION)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg, 4508c2ecf20Sopenharmony_ci TYPE_CTRL_FAN_MASK, reg_value); 4518c2ecf20Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg1, 4528c2ecf20Sopenharmony_ci TYPE_CTRL_FAN1_MASK, unit << 16); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch, 4568c2ecf20Sopenharmony_ci bool enable) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 4598c2ecf20Sopenharmony_ci ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch), 4608c2ecf20Sopenharmony_ci enable ? 4618c2ecf20Sopenharmony_ci ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch, 4658c2ecf20Sopenharmony_ci u8 fan_tach_ch_source) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci u32 reg_value1 = ((fan_tach_ch_source & 0x3) << 4688c2ecf20Sopenharmony_ci TACH_PWM_SOURCE_BIT01(fan_tach_ch)); 4698c2ecf20Sopenharmony_ci u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) << 4708c2ecf20Sopenharmony_ci TACH_PWM_SOURCE_BIT2(fan_tach_ch)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE, 4738c2ecf20Sopenharmony_ci TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch), 4748c2ecf20Sopenharmony_ci reg_value1); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 4778c2ecf20Sopenharmony_ci TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch), 4788c2ecf20Sopenharmony_ci reg_value2); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv, 4828c2ecf20Sopenharmony_ci u8 index, u8 fan_ctrl) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci u16 period, dc_time_on; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]]; 4878c2ecf20Sopenharmony_ci period += 1; 4888c2ecf20Sopenharmony_ci dc_time_on = (fan_ctrl * period) / PWM_MAX; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (dc_time_on == 0) { 4918c2ecf20Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, index, false); 4928c2ecf20Sopenharmony_ci } else { 4938c2ecf20Sopenharmony_ci if (dc_time_on == period) 4948c2ecf20Sopenharmony_ci dc_time_on = 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0, 4978c2ecf20Sopenharmony_ci dc_time_on); 4988c2ecf20Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, index, true); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data 5038c2ecf20Sopenharmony_ci *priv, u8 type) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci u32 clk; 5068c2ecf20Sopenharmony_ci u16 tacho_unit; 5078c2ecf20Sopenharmony_ci u8 clk_unit, div_h, div_l, tacho_div; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci clk = priv->clk_freq; 5108c2ecf20Sopenharmony_ci clk_unit = priv->type_pwm_clock_unit[type]; 5118c2ecf20Sopenharmony_ci div_h = priv->type_pwm_clock_division_h[type]; 5128c2ecf20Sopenharmony_ci div_h = 0x1 << div_h; 5138c2ecf20Sopenharmony_ci div_l = priv->type_pwm_clock_division_l[type]; 5148c2ecf20Sopenharmony_ci if (div_l == 0) 5158c2ecf20Sopenharmony_ci div_l = 1; 5168c2ecf20Sopenharmony_ci else 5178c2ecf20Sopenharmony_ci div_l = div_l * 2; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci tacho_unit = priv->type_fan_tach_unit[type]; 5208c2ecf20Sopenharmony_ci tacho_div = priv->type_fan_tach_clock_division[type]; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci tacho_div = 0x4 << (tacho_div * 2); 5238c2ecf20Sopenharmony_ci return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv, 5278c2ecf20Sopenharmony_ci u8 fan_tach_ch) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci u32 raw_data, tach_div, clk_source, msec, usec, val; 5308c2ecf20Sopenharmony_ci u8 fan_tach_ch_source, type, mode, both; 5318c2ecf20Sopenharmony_ci int ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci mutex_lock(&priv->tach_lock); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0); 5368c2ecf20Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch]; 5398c2ecf20Sopenharmony_ci type = priv->pwm_port_type[fan_tach_ch_source]; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci msec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type)); 5428c2ecf20Sopenharmony_ci usec = msec * 1000; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout( 5458c2ecf20Sopenharmony_ci priv->regmap, 5468c2ecf20Sopenharmony_ci ASPEED_PTCR_RESULT, 5478c2ecf20Sopenharmony_ci val, 5488c2ecf20Sopenharmony_ci (val & RESULT_STATUS_MASK), 5498c2ecf20Sopenharmony_ci ASPEED_RPM_STATUS_SLEEP_USEC, 5508c2ecf20Sopenharmony_ci usec); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci mutex_unlock(&priv->tach_lock); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* return -ETIMEDOUT if we didn't get an answer. */ 5558c2ecf20Sopenharmony_ci if (ret) 5568c2ecf20Sopenharmony_ci return ret; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci raw_data = val & RESULT_VALUE_MASK; 5598c2ecf20Sopenharmony_ci tach_div = priv->type_fan_tach_clock_division[type]; 5608c2ecf20Sopenharmony_ci /* 5618c2ecf20Sopenharmony_ci * We need the mode to determine if the raw_data is double (from 5628c2ecf20Sopenharmony_ci * counting both edges). 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_ci mode = priv->type_fan_tach_mode[type]; 5658c2ecf20Sopenharmony_ci both = (mode & BOTH_EDGES) ? 1 : 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci tach_div = (0x4 << both) << (tach_div * 2); 5688c2ecf20Sopenharmony_ci clk_source = priv->clk_freq; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (raw_data == 0) 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return (clk_source * 60) / (2 * raw_data * tach_div); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic ssize_t pwm_store(struct device *dev, struct device_attribute *attr, 5778c2ecf20Sopenharmony_ci const char *buf, size_t count) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 5808c2ecf20Sopenharmony_ci int index = sensor_attr->index; 5818c2ecf20Sopenharmony_ci int ret; 5828c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 5838c2ecf20Sopenharmony_ci long fan_ctrl; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ret = kstrtol(buf, 10, &fan_ctrl); 5868c2ecf20Sopenharmony_ci if (ret != 0) 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (fan_ctrl < 0 || fan_ctrl > PWM_MAX) 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (priv->pwm_port_fan_ctrl[index] == fan_ctrl) 5938c2ecf20Sopenharmony_ci return count; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci priv->pwm_port_fan_ctrl[index] = fan_ctrl; 5968c2ecf20Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return count; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic ssize_t pwm_show(struct device *dev, struct device_attribute *attr, 6028c2ecf20Sopenharmony_ci char *buf) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 6058c2ecf20Sopenharmony_ci int index = sensor_attr->index; 6068c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic ssize_t rpm_show(struct device *dev, struct device_attribute *attr, 6128c2ecf20Sopenharmony_ci char *buf) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 6158c2ecf20Sopenharmony_ci int index = sensor_attr->index; 6168c2ecf20Sopenharmony_ci int rpm; 6178c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci rpm = aspeed_get_fan_tach_ch_rpm(priv, index); 6208c2ecf20Sopenharmony_ci if (rpm < 0) 6218c2ecf20Sopenharmony_ci return rpm; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rpm); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic umode_t pwm_is_visible(struct kobject *kobj, 6278c2ecf20Sopenharmony_ci struct attribute *a, int index) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 6308c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (!priv->pwm_present[index]) 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci return a->mode; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic umode_t fan_dev_is_visible(struct kobject *kobj, 6388c2ecf20Sopenharmony_ci struct attribute *a, int index) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 6418c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!priv->fan_tach_present[index]) 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci return a->mode; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 6498c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); 6508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2); 6518c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4, pwm, 3); 6528c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm5, pwm, 4); 6538c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm6, pwm, 5); 6548c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm7, pwm, 6); 6558c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm8, pwm, 7); 6568c2ecf20Sopenharmony_cistatic struct attribute *pwm_dev_attrs[] = { 6578c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 6588c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 6598c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 6608c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4.dev_attr.attr, 6618c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5.dev_attr.attr, 6628c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6.dev_attr.attr, 6638c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm7.dev_attr.attr, 6648c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm8.dev_attr.attr, 6658c2ecf20Sopenharmony_ci NULL, 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic const struct attribute_group pwm_dev_group = { 6698c2ecf20Sopenharmony_ci .attrs = pwm_dev_attrs, 6708c2ecf20Sopenharmony_ci .is_visible = pwm_is_visible, 6718c2ecf20Sopenharmony_ci}; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0); 6748c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, rpm, 1); 6758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan3_input, rpm, 2); 6768c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan4_input, rpm, 3); 6778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan5_input, rpm, 4); 6788c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan6_input, rpm, 5); 6798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan7_input, rpm, 6); 6808c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan8_input, rpm, 7); 6818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan9_input, rpm, 8); 6828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan10_input, rpm, 9); 6838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan11_input, rpm, 10); 6848c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan12_input, rpm, 11); 6858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan13_input, rpm, 12); 6868c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan14_input, rpm, 13); 6878c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan15_input, rpm, 14); 6888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan16_input, rpm, 15); 6898c2ecf20Sopenharmony_cistatic struct attribute *fan_dev_attrs[] = { 6908c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 6918c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 6928c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 6938c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, 6948c2ecf20Sopenharmony_ci &sensor_dev_attr_fan5_input.dev_attr.attr, 6958c2ecf20Sopenharmony_ci &sensor_dev_attr_fan6_input.dev_attr.attr, 6968c2ecf20Sopenharmony_ci &sensor_dev_attr_fan7_input.dev_attr.attr, 6978c2ecf20Sopenharmony_ci &sensor_dev_attr_fan8_input.dev_attr.attr, 6988c2ecf20Sopenharmony_ci &sensor_dev_attr_fan9_input.dev_attr.attr, 6998c2ecf20Sopenharmony_ci &sensor_dev_attr_fan10_input.dev_attr.attr, 7008c2ecf20Sopenharmony_ci &sensor_dev_attr_fan11_input.dev_attr.attr, 7018c2ecf20Sopenharmony_ci &sensor_dev_attr_fan12_input.dev_attr.attr, 7028c2ecf20Sopenharmony_ci &sensor_dev_attr_fan13_input.dev_attr.attr, 7038c2ecf20Sopenharmony_ci &sensor_dev_attr_fan14_input.dev_attr.attr, 7048c2ecf20Sopenharmony_ci &sensor_dev_attr_fan15_input.dev_attr.attr, 7058c2ecf20Sopenharmony_ci &sensor_dev_attr_fan16_input.dev_attr.attr, 7068c2ecf20Sopenharmony_ci NULL 7078c2ecf20Sopenharmony_ci}; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic const struct attribute_group fan_dev_group = { 7108c2ecf20Sopenharmony_ci .attrs = fan_dev_attrs, 7118c2ecf20Sopenharmony_ci .is_visible = fan_dev_is_visible, 7128c2ecf20Sopenharmony_ci}; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* 7158c2ecf20Sopenharmony_ci * The clock type is type M : 7168c2ecf20Sopenharmony_ci * The PWM frequency = 24MHz / (type M clock division L bit * 7178c2ecf20Sopenharmony_ci * type M clock division H bit * (type M PWM period bit + 1)) 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_cistatic void aspeed_create_type(struct aspeed_pwm_tacho_data *priv) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H; 7228c2ecf20Sopenharmony_ci priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L; 7238c2ecf20Sopenharmony_ci priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD; 7248c2ecf20Sopenharmony_ci aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H, 7258c2ecf20Sopenharmony_ci M_PWM_DIV_L, M_PWM_PERIOD); 7268c2ecf20Sopenharmony_ci aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true); 7278c2ecf20Sopenharmony_ci priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV; 7288c2ecf20Sopenharmony_ci priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT; 7298c2ecf20Sopenharmony_ci priv->type_fan_tach_mode[TYPEM] = M_TACH_MODE; 7308c2ecf20Sopenharmony_ci aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE, 7318c2ecf20Sopenharmony_ci M_TACH_UNIT, M_TACH_CLK_DIV); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv, 7358c2ecf20Sopenharmony_ci u8 pwm_port) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true); 7388c2ecf20Sopenharmony_ci priv->pwm_present[pwm_port] = true; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci priv->pwm_port_type[pwm_port] = TYPEM; 7418c2ecf20Sopenharmony_ci aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL; 7448c2ecf20Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv, 7488c2ecf20Sopenharmony_ci u8 *fan_tach_ch, 7498c2ecf20Sopenharmony_ci int count, 7508c2ecf20Sopenharmony_ci u8 pwm_source) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci u8 val, index; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci for (val = 0; val < count; val++) { 7558c2ecf20Sopenharmony_ci index = fan_tach_ch[val]; 7568c2ecf20Sopenharmony_ci aspeed_set_fan_tach_ch_enable(priv->regmap, index, true); 7578c2ecf20Sopenharmony_ci priv->fan_tach_present[index] = true; 7588c2ecf20Sopenharmony_ci priv->fan_tach_ch_source[index] = pwm_source; 7598c2ecf20Sopenharmony_ci aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int 7648c2ecf20Sopenharmony_ciaspeed_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev, 7658c2ecf20Sopenharmony_ci unsigned long *state) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci *state = cdev->max_state; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int 7758c2ecf20Sopenharmony_ciaspeed_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev, 7768c2ecf20Sopenharmony_ci unsigned long *state) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci *state = cdev->cur_state; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int 7868c2ecf20Sopenharmony_ciaspeed_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev, 7878c2ecf20Sopenharmony_ci unsigned long state) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (state > cdev->max_state) 7928c2ecf20Sopenharmony_ci return -EINVAL; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci cdev->cur_state = state; 7958c2ecf20Sopenharmony_ci cdev->priv->pwm_port_fan_ctrl[cdev->pwm_port] = 7968c2ecf20Sopenharmony_ci cdev->cooling_levels[cdev->cur_state]; 7978c2ecf20Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(cdev->priv, cdev->pwm_port, 7988c2ecf20Sopenharmony_ci cdev->cooling_levels[cdev->cur_state]); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return 0; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = { 8048c2ecf20Sopenharmony_ci .get_max_state = aspeed_pwm_cz_get_max_state, 8058c2ecf20Sopenharmony_ci .get_cur_state = aspeed_pwm_cz_get_cur_state, 8068c2ecf20Sopenharmony_ci .set_cur_state = aspeed_pwm_cz_set_cur_state, 8078c2ecf20Sopenharmony_ci}; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int aspeed_create_pwm_cooling(struct device *dev, 8108c2ecf20Sopenharmony_ci struct device_node *child, 8118c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv, 8128c2ecf20Sopenharmony_ci u32 pwm_port, u8 num_levels) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci int ret; 8158c2ecf20Sopenharmony_ci struct aspeed_cooling_device *cdev; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (!cdev) 8208c2ecf20Sopenharmony_ci return -ENOMEM; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL); 8238c2ecf20Sopenharmony_ci if (!cdev->cooling_levels) 8248c2ecf20Sopenharmony_ci return -ENOMEM; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci cdev->max_state = num_levels - 1; 8278c2ecf20Sopenharmony_ci ret = of_property_read_u8_array(child, "cooling-levels", 8288c2ecf20Sopenharmony_ci cdev->cooling_levels, 8298c2ecf20Sopenharmony_ci num_levels); 8308c2ecf20Sopenharmony_ci if (ret) { 8318c2ecf20Sopenharmony_ci dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); 8328c2ecf20Sopenharmony_ci return ret; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child, 8378c2ecf20Sopenharmony_ci cdev->name, cdev, &aspeed_pwm_cool_ops); 8388c2ecf20Sopenharmony_ci if (IS_ERR(cdev->tcdev)) 8398c2ecf20Sopenharmony_ci return PTR_ERR(cdev->tcdev); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci cdev->priv = priv; 8428c2ecf20Sopenharmony_ci cdev->pwm_port = pwm_port; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci priv->cdev[pwm_port] = cdev; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int aspeed_create_fan(struct device *dev, 8508c2ecf20Sopenharmony_ci struct device_node *child, 8518c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci u8 *fan_tach_ch; 8548c2ecf20Sopenharmony_ci u32 pwm_port; 8558c2ecf20Sopenharmony_ci int ret, count; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "reg", &pwm_port); 8588c2ecf20Sopenharmony_ci if (ret) 8598c2ecf20Sopenharmony_ci return ret; 8608c2ecf20Sopenharmony_ci if (pwm_port >= ARRAY_SIZE(pwm_port_params)) 8618c2ecf20Sopenharmony_ci return -EINVAL; 8628c2ecf20Sopenharmony_ci aspeed_create_pwm_port(priv, (u8)pwm_port); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci ret = of_property_count_u8_elems(child, "cooling-levels"); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (ret > 0) { 8678c2ecf20Sopenharmony_ci ret = aspeed_create_pwm_cooling(dev, child, priv, pwm_port, 8688c2ecf20Sopenharmony_ci ret); 8698c2ecf20Sopenharmony_ci if (ret) 8708c2ecf20Sopenharmony_ci return ret; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch"); 8748c2ecf20Sopenharmony_ci if (count < 1) 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci fan_tach_ch = devm_kcalloc(dev, count, sizeof(*fan_tach_ch), 8778c2ecf20Sopenharmony_ci GFP_KERNEL); 8788c2ecf20Sopenharmony_ci if (!fan_tach_ch) 8798c2ecf20Sopenharmony_ci return -ENOMEM; 8808c2ecf20Sopenharmony_ci ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch", 8818c2ecf20Sopenharmony_ci fan_tach_ch, count); 8828c2ecf20Sopenharmony_ci if (ret) 8838c2ecf20Sopenharmony_ci return ret; 8848c2ecf20Sopenharmony_ci aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic void aspeed_pwm_tacho_remove(void *data) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = data; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci reset_control_assert(priv->rst); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic int aspeed_pwm_tacho_probe(struct platform_device *pdev) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 8998c2ecf20Sopenharmony_ci struct device_node *np, *child; 9008c2ecf20Sopenharmony_ci struct aspeed_pwm_tacho_data *priv; 9018c2ecf20Sopenharmony_ci void __iomem *regs; 9028c2ecf20Sopenharmony_ci struct device *hwmon; 9038c2ecf20Sopenharmony_ci struct clk *clk; 9048c2ecf20Sopenharmony_ci int ret; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci np = dev->of_node; 9078c2ecf20Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 9088c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 9098c2ecf20Sopenharmony_ci return PTR_ERR(regs); 9108c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 9118c2ecf20Sopenharmony_ci if (!priv) 9128c2ecf20Sopenharmony_ci return -ENOMEM; 9138c2ecf20Sopenharmony_ci mutex_init(&priv->tach_lock); 9148c2ecf20Sopenharmony_ci priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs, 9158c2ecf20Sopenharmony_ci &aspeed_pwm_tacho_regmap_config); 9168c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) 9178c2ecf20Sopenharmony_ci return PTR_ERR(priv->regmap); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci priv->rst = devm_reset_control_get_exclusive(dev, NULL); 9208c2ecf20Sopenharmony_ci if (IS_ERR(priv->rst)) { 9218c2ecf20Sopenharmony_ci dev_err(dev, 9228c2ecf20Sopenharmony_ci "missing or invalid reset controller device tree entry"); 9238c2ecf20Sopenharmony_ci return PTR_ERR(priv->rst); 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci reset_control_deassert(priv->rst); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv); 9288c2ecf20Sopenharmony_ci if (ret) 9298c2ecf20Sopenharmony_ci return ret; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0); 9328c2ecf20Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, NULL); 9358c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 9368c2ecf20Sopenharmony_ci return -ENODEV; 9378c2ecf20Sopenharmony_ci priv->clk_freq = clk_get_rate(clk); 9388c2ecf20Sopenharmony_ci aspeed_set_clock_enable(priv->regmap, true); 9398c2ecf20Sopenharmony_ci aspeed_set_clock_source(priv->regmap, 0); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci aspeed_create_type(priv); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 9448c2ecf20Sopenharmony_ci ret = aspeed_create_fan(dev, child, priv); 9458c2ecf20Sopenharmony_ci if (ret) { 9468c2ecf20Sopenharmony_ci of_node_put(child); 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci priv->groups[0] = &pwm_dev_group; 9528c2ecf20Sopenharmony_ci priv->groups[1] = &fan_dev_group; 9538c2ecf20Sopenharmony_ci priv->groups[2] = NULL; 9548c2ecf20Sopenharmony_ci hwmon = devm_hwmon_device_register_with_groups(dev, 9558c2ecf20Sopenharmony_ci "aspeed_pwm_tacho", 9568c2ecf20Sopenharmony_ci priv, priv->groups); 9578c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic const struct of_device_id of_pwm_tacho_match_table[] = { 9618c2ecf20Sopenharmony_ci { .compatible = "aspeed,ast2400-pwm-tacho", }, 9628c2ecf20Sopenharmony_ci { .compatible = "aspeed,ast2500-pwm-tacho", }, 9638c2ecf20Sopenharmony_ci {}, 9648c2ecf20Sopenharmony_ci}; 9658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic struct platform_driver aspeed_pwm_tacho_driver = { 9688c2ecf20Sopenharmony_ci .probe = aspeed_pwm_tacho_probe, 9698c2ecf20Sopenharmony_ci .driver = { 9708c2ecf20Sopenharmony_ci .name = "aspeed_pwm_tacho", 9718c2ecf20Sopenharmony_ci .of_match_table = of_pwm_tacho_match_table, 9728c2ecf20Sopenharmony_ci }, 9738c2ecf20Sopenharmony_ci}; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cimodule_platform_driver(aspeed_pwm_tacho_driver); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>"); 9788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver"); 9798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 980