162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Google, Inc 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1062306a36Sopenharmony_ci#include <linux/hwmon.h> 1162306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <linux/reset.h> 1962306a36Sopenharmony_ci#include <linux/sysfs.h> 2062306a36Sopenharmony_ci#include <linux/thermal.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* ASPEED PWM & FAN Tach Register Definition */ 2362306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL 0x00 2462306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL 0x04 2562306a36Sopenharmony_ci#define ASPEED_PTCR_DUTY0_CTRL 0x08 2662306a36Sopenharmony_ci#define ASPEED_PTCR_DUTY1_CTRL 0x0c 2762306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEM_CTRL 0x10 2862306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEM_CTRL1 0x14 2962306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEN_CTRL 0x18 3062306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEN_CTRL1 0x1c 3162306a36Sopenharmony_ci#define ASPEED_PTCR_TACH_SOURCE 0x20 3262306a36Sopenharmony_ci#define ASPEED_PTCR_TRIGGER 0x28 3362306a36Sopenharmony_ci#define ASPEED_PTCR_RESULT 0x2c 3462306a36Sopenharmony_ci#define ASPEED_PTCR_INTR_CTRL 0x30 3562306a36Sopenharmony_ci#define ASPEED_PTCR_INTR_STS 0x34 3662306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEM_LIMIT 0x38 3762306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEN_LIMIT 0x3C 3862306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_EXT 0x40 3962306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_EXT 0x44 4062306a36Sopenharmony_ci#define ASPEED_PTCR_DUTY2_CTRL 0x48 4162306a36Sopenharmony_ci#define ASPEED_PTCR_DUTY3_CTRL 0x4c 4262306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEO_CTRL 0x50 4362306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEO_CTRL1 0x54 4462306a36Sopenharmony_ci#define ASPEED_PTCR_TACH_SOURCE_EXT 0x60 4562306a36Sopenharmony_ci#define ASPEED_PTCR_TYPEO_LIMIT 0x78 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */ 4862306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15 4962306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6 5062306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15)) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14 5362306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5 5462306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14)) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13 5762306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4 5862306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13)) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12 6162306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3 6262306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12)) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x)) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMD_EN BIT(11) 6762306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMC_EN BIT(10) 6862306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMB_EN BIT(9) 6962306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMA_EN BIT(8) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_CLK_SRC BIT(1) 7262306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_CLK_EN BIT(0) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */ 7562306a36Sopenharmony_ci/* TYPE N */ 7662306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16) 7762306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24 7862306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20 7962306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16 8062306a36Sopenharmony_ci/* TYPE M */ 8162306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0) 8262306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8 8362306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4 8462306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control 8862306a36Sopenharmony_ci * 0/1/2/3 register 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define DUTY_CTRL_PWM2_FALL_POINT 24 9162306a36Sopenharmony_ci#define DUTY_CTRL_PWM2_RISE_POINT 16 9262306a36Sopenharmony_ci#define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16) 9362306a36Sopenharmony_ci#define DUTY_CTRL_PWM1_FALL_POINT 8 9462306a36Sopenharmony_ci#define DUTY_CTRL_PWM1_RISE_POINT 0 9562306a36Sopenharmony_ci#define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */ 9862306a36Sopenharmony_ci#define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16)) 9962306a36Sopenharmony_ci#define TYPE_CTRL_FAN1_MASK GENMASK(31, 0) 10062306a36Sopenharmony_ci#define TYPE_CTRL_FAN_PERIOD 16 10162306a36Sopenharmony_ci#define TYPE_CTRL_FAN_MODE 4 10262306a36Sopenharmony_ci#define TYPE_CTRL_FAN_DIVISION 1 10362306a36Sopenharmony_ci#define TYPE_CTRL_FAN_TYPE_EN 1 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */ 10662306a36Sopenharmony_ci/* bit [0,1] at 0x20, bit [2] at 0x60 */ 10762306a36Sopenharmony_ci#define TACH_PWM_SOURCE_BIT01(x) ((x) * 2) 10862306a36Sopenharmony_ci#define TACH_PWM_SOURCE_BIT2(x) ((x) * 2) 10962306a36Sopenharmony_ci#define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2)) 11062306a36Sopenharmony_ci#define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* ASPEED_PTCR_RESULT : 0x2c - Result Register */ 11362306a36Sopenharmony_ci#define RESULT_STATUS_MASK BIT(31) 11462306a36Sopenharmony_ci#define RESULT_VALUE_MASK 0xfffff 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */ 11762306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15 11862306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6 11962306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15)) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14 12262306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5 12362306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14)) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13 12662306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4 12762306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13)) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12 13062306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3 13162306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12)) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMH_EN BIT(11) 13462306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMG_EN BIT(10) 13562306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWMF_EN BIT(9) 13662306a36Sopenharmony_ci#define ASPEED_PTCR_CTRL_PWME_EN BIT(8) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */ 13962306a36Sopenharmony_ci/* TYPE O */ 14062306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0) 14162306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8 14262306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4 14362306a36Sopenharmony_ci#define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define PWM_MAX 255 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define BOTH_EDGES 0x02 /* 10b */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define M_PWM_DIV_H 0x00 15062306a36Sopenharmony_ci#define M_PWM_DIV_L 0x05 15162306a36Sopenharmony_ci#define M_PWM_PERIOD 0x5F 15262306a36Sopenharmony_ci#define M_TACH_CLK_DIV 0x00 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * 5:4 Type N fan tach mode selection bit: 15562306a36Sopenharmony_ci * 00: falling 15662306a36Sopenharmony_ci * 01: rising 15762306a36Sopenharmony_ci * 10: both 15862306a36Sopenharmony_ci * 11: reserved. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci#define M_TACH_MODE 0x02 /* 10b */ 16162306a36Sopenharmony_ci#define M_TACH_UNIT 0x0420 16262306a36Sopenharmony_ci#define INIT_FAN_CTRL 0xFF 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* How long we sleep in us while waiting for an RPM result. */ 16562306a36Sopenharmony_ci#define ASPEED_RPM_STATUS_SLEEP_USEC 500 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define MAX_CDEV_NAME_LEN 16 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistruct aspeed_cooling_device { 17062306a36Sopenharmony_ci char name[16]; 17162306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv; 17262306a36Sopenharmony_ci struct thermal_cooling_device *tcdev; 17362306a36Sopenharmony_ci int pwm_port; 17462306a36Sopenharmony_ci u8 *cooling_levels; 17562306a36Sopenharmony_ci u8 max_state; 17662306a36Sopenharmony_ci u8 cur_state; 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct aspeed_pwm_tacho_data { 18062306a36Sopenharmony_ci struct regmap *regmap; 18162306a36Sopenharmony_ci struct reset_control *rst; 18262306a36Sopenharmony_ci unsigned long clk_freq; 18362306a36Sopenharmony_ci bool pwm_present[8]; 18462306a36Sopenharmony_ci bool fan_tach_present[16]; 18562306a36Sopenharmony_ci u8 type_pwm_clock_unit[3]; 18662306a36Sopenharmony_ci u8 type_pwm_clock_division_h[3]; 18762306a36Sopenharmony_ci u8 type_pwm_clock_division_l[3]; 18862306a36Sopenharmony_ci u8 type_fan_tach_clock_division[3]; 18962306a36Sopenharmony_ci u8 type_fan_tach_mode[3]; 19062306a36Sopenharmony_ci u16 type_fan_tach_unit[3]; 19162306a36Sopenharmony_ci u8 pwm_port_type[8]; 19262306a36Sopenharmony_ci u8 pwm_port_fan_ctrl[8]; 19362306a36Sopenharmony_ci u8 fan_tach_ch_source[16]; 19462306a36Sopenharmony_ci struct aspeed_cooling_device *cdev[8]; 19562306a36Sopenharmony_ci const struct attribute_group *groups[3]; 19662306a36Sopenharmony_ci /* protects access to shared ASPEED_PTCR_RESULT */ 19762306a36Sopenharmony_ci struct mutex tach_lock; 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cienum type { TYPEM, TYPEN, TYPEO }; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistruct type_params { 20362306a36Sopenharmony_ci u32 l_value; 20462306a36Sopenharmony_ci u32 h_value; 20562306a36Sopenharmony_ci u32 unit_value; 20662306a36Sopenharmony_ci u32 clk_ctrl_mask; 20762306a36Sopenharmony_ci u32 clk_ctrl_reg; 20862306a36Sopenharmony_ci u32 ctrl_reg; 20962306a36Sopenharmony_ci u32 ctrl_reg1; 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic const struct type_params type_params[] = { 21362306a36Sopenharmony_ci [TYPEM] = { 21462306a36Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L, 21562306a36Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H, 21662306a36Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT, 21762306a36Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK, 21862306a36Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL, 21962306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEM_CTRL, 22062306a36Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci [TYPEN] = { 22362306a36Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L, 22462306a36Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H, 22562306a36Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT, 22662306a36Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK, 22762306a36Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL, 22862306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEN_CTRL, 22962306a36Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1, 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci [TYPEO] = { 23262306a36Sopenharmony_ci .l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L, 23362306a36Sopenharmony_ci .h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H, 23462306a36Sopenharmony_ci .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT, 23562306a36Sopenharmony_ci .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK, 23662306a36Sopenharmony_ci .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT, 23762306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_TYPEO_CTRL, 23862306a36Sopenharmony_ci .ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1, 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cienum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH }; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistruct pwm_port_params { 24562306a36Sopenharmony_ci u32 pwm_en; 24662306a36Sopenharmony_ci u32 ctrl_reg; 24762306a36Sopenharmony_ci u32 type_part1; 24862306a36Sopenharmony_ci u32 type_part2; 24962306a36Sopenharmony_ci u32 type_mask; 25062306a36Sopenharmony_ci u32 duty_ctrl_rise_point; 25162306a36Sopenharmony_ci u32 duty_ctrl_fall_point; 25262306a36Sopenharmony_ci u32 duty_ctrl_reg; 25362306a36Sopenharmony_ci u32 duty_ctrl_rise_fall_mask; 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic const struct pwm_port_params pwm_port_params[] = { 25762306a36Sopenharmony_ci [PWMA] = { 25862306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMA_EN, 25962306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 26062306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1, 26162306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2, 26262306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK, 26362306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 26462306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 26562306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL, 26662306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 26762306a36Sopenharmony_ci }, 26862306a36Sopenharmony_ci [PWMB] = { 26962306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMB_EN, 27062306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 27162306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1, 27262306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2, 27362306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK, 27462306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 27562306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 27662306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL, 27762306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 27862306a36Sopenharmony_ci }, 27962306a36Sopenharmony_ci [PWMC] = { 28062306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMC_EN, 28162306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 28262306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1, 28362306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2, 28462306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK, 28562306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 28662306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 28762306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL, 28862306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 28962306a36Sopenharmony_ci }, 29062306a36Sopenharmony_ci [PWMD] = { 29162306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMD_EN, 29262306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL, 29362306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1, 29462306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2, 29562306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK, 29662306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 29762306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 29862306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL, 29962306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 30062306a36Sopenharmony_ci }, 30162306a36Sopenharmony_ci [PWME] = { 30262306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWME_EN, 30362306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 30462306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1, 30562306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2, 30662306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK, 30762306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 30862306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 30962306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL, 31062306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 31162306a36Sopenharmony_ci }, 31262306a36Sopenharmony_ci [PWMF] = { 31362306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMF_EN, 31462306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 31562306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1, 31662306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2, 31762306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK, 31862306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 31962306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 32062306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL, 32162306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 32262306a36Sopenharmony_ci }, 32362306a36Sopenharmony_ci [PWMG] = { 32462306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMG_EN, 32562306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 32662306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1, 32762306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2, 32862306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK, 32962306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT, 33062306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT, 33162306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL, 33262306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK, 33362306a36Sopenharmony_ci }, 33462306a36Sopenharmony_ci [PWMH] = { 33562306a36Sopenharmony_ci .pwm_en = ASPEED_PTCR_CTRL_PWMH_EN, 33662306a36Sopenharmony_ci .ctrl_reg = ASPEED_PTCR_CTRL_EXT, 33762306a36Sopenharmony_ci .type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1, 33862306a36Sopenharmony_ci .type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2, 33962306a36Sopenharmony_ci .type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK, 34062306a36Sopenharmony_ci .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT, 34162306a36Sopenharmony_ci .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT, 34262306a36Sopenharmony_ci .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL, 34362306a36Sopenharmony_ci .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK, 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg, 34862306a36Sopenharmony_ci unsigned int val) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci void __iomem *regs = (void __iomem *)context; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci writel(val, regs + reg); 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg, 35762306a36Sopenharmony_ci unsigned int *val) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci void __iomem *regs = (void __iomem *)context; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci *val = readl(regs + reg); 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic const struct regmap_config aspeed_pwm_tacho_regmap_config = { 36662306a36Sopenharmony_ci .reg_bits = 32, 36762306a36Sopenharmony_ci .val_bits = 32, 36862306a36Sopenharmony_ci .reg_stride = 4, 36962306a36Sopenharmony_ci .max_register = ASPEED_PTCR_TYPEO_LIMIT, 37062306a36Sopenharmony_ci .reg_write = regmap_aspeed_pwm_tacho_reg_write, 37162306a36Sopenharmony_ci .reg_read = regmap_aspeed_pwm_tacho_reg_read, 37262306a36Sopenharmony_ci .fast_io = true, 37362306a36Sopenharmony_ci}; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void aspeed_set_clock_enable(struct regmap *regmap, bool val) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 37862306a36Sopenharmony_ci ASPEED_PTCR_CTRL_CLK_EN, 37962306a36Sopenharmony_ci val ? ASPEED_PTCR_CTRL_CLK_EN : 0); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void aspeed_set_clock_source(struct regmap *regmap, int val) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 38562306a36Sopenharmony_ci ASPEED_PTCR_CTRL_CLK_SRC, 38662306a36Sopenharmony_ci val ? ASPEED_PTCR_CTRL_CLK_SRC : 0); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type, 39062306a36Sopenharmony_ci u8 div_high, u8 div_low, u8 unit) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci u32 reg_value = ((div_high << type_params[type].h_value) | 39362306a36Sopenharmony_ci (div_low << type_params[type].l_value) | 39462306a36Sopenharmony_ci (unit << type_params[type].unit_value)); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci regmap_update_bits(regmap, type_params[type].clk_ctrl_reg, 39762306a36Sopenharmony_ci type_params[type].clk_ctrl_mask, reg_value); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port, 40162306a36Sopenharmony_ci bool enable) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg, 40462306a36Sopenharmony_ci pwm_port_params[pwm_port].pwm_en, 40562306a36Sopenharmony_ci enable ? pwm_port_params[pwm_port].pwm_en : 0); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void aspeed_set_pwm_port_type(struct regmap *regmap, 40962306a36Sopenharmony_ci u8 pwm_port, u8 type) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg, 41662306a36Sopenharmony_ci pwm_port_params[pwm_port].type_mask, reg_value); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap, 42062306a36Sopenharmony_ci u8 pwm_port, u8 rising, 42162306a36Sopenharmony_ci u8 falling) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci u32 reg_value = (rising << 42462306a36Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_rise_point); 42562306a36Sopenharmony_ci reg_value |= (falling << 42662306a36Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_fall_point); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg, 42962306a36Sopenharmony_ci pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask, 43062306a36Sopenharmony_ci reg_value); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type, 43462306a36Sopenharmony_ci bool enable) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg, 43762306a36Sopenharmony_ci TYPE_CTRL_FAN_TYPE_EN, 43862306a36Sopenharmony_ci enable ? TYPE_CTRL_FAN_TYPE_EN : 0); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type, 44262306a36Sopenharmony_ci u8 mode, u16 unit, u8 division) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) | 44562306a36Sopenharmony_ci (unit << TYPE_CTRL_FAN_PERIOD) | 44662306a36Sopenharmony_ci (division << TYPE_CTRL_FAN_DIVISION)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg, 44962306a36Sopenharmony_ci TYPE_CTRL_FAN_MASK, reg_value); 45062306a36Sopenharmony_ci regmap_update_bits(regmap, type_params[type].ctrl_reg1, 45162306a36Sopenharmony_ci TYPE_CTRL_FAN1_MASK, unit << 16); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch, 45562306a36Sopenharmony_ci bool enable) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_CTRL, 45862306a36Sopenharmony_ci ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch), 45962306a36Sopenharmony_ci enable ? 46062306a36Sopenharmony_ci ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch, 46462306a36Sopenharmony_ci u8 fan_tach_ch_source) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci u32 reg_value1 = ((fan_tach_ch_source & 0x3) << 46762306a36Sopenharmony_ci TACH_PWM_SOURCE_BIT01(fan_tach_ch)); 46862306a36Sopenharmony_ci u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) << 46962306a36Sopenharmony_ci TACH_PWM_SOURCE_BIT2(fan_tach_ch)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE, 47262306a36Sopenharmony_ci TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch), 47362306a36Sopenharmony_ci reg_value1); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 47662306a36Sopenharmony_ci TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch), 47762306a36Sopenharmony_ci reg_value2); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv, 48162306a36Sopenharmony_ci u8 index, u8 fan_ctrl) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci u16 period, dc_time_on; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]]; 48662306a36Sopenharmony_ci period += 1; 48762306a36Sopenharmony_ci dc_time_on = (fan_ctrl * period) / PWM_MAX; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (dc_time_on == 0) { 49062306a36Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, index, false); 49162306a36Sopenharmony_ci } else { 49262306a36Sopenharmony_ci if (dc_time_on == period) 49362306a36Sopenharmony_ci dc_time_on = 0; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0, 49662306a36Sopenharmony_ci dc_time_on); 49762306a36Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, index, true); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data 50262306a36Sopenharmony_ci *priv, u8 type) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci u32 clk; 50562306a36Sopenharmony_ci u16 tacho_unit; 50662306a36Sopenharmony_ci u8 clk_unit, div_h, div_l, tacho_div; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci clk = priv->clk_freq; 50962306a36Sopenharmony_ci clk_unit = priv->type_pwm_clock_unit[type]; 51062306a36Sopenharmony_ci div_h = priv->type_pwm_clock_division_h[type]; 51162306a36Sopenharmony_ci div_h = 0x1 << div_h; 51262306a36Sopenharmony_ci div_l = priv->type_pwm_clock_division_l[type]; 51362306a36Sopenharmony_ci if (div_l == 0) 51462306a36Sopenharmony_ci div_l = 1; 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci div_l = div_l * 2; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci tacho_unit = priv->type_fan_tach_unit[type]; 51962306a36Sopenharmony_ci tacho_div = priv->type_fan_tach_clock_division[type]; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci tacho_div = 0x4 << (tacho_div * 2); 52262306a36Sopenharmony_ci return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv, 52662306a36Sopenharmony_ci u8 fan_tach_ch) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci u32 raw_data, tach_div, clk_source, msec, usec, val; 52962306a36Sopenharmony_ci u8 fan_tach_ch_source, type, mode, both; 53062306a36Sopenharmony_ci int ret; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci mutex_lock(&priv->tach_lock); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0); 53562306a36Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch]; 53862306a36Sopenharmony_ci type = priv->pwm_port_type[fan_tach_ch_source]; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci msec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type)); 54162306a36Sopenharmony_ci usec = msec * 1000; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ret = regmap_read_poll_timeout( 54462306a36Sopenharmony_ci priv->regmap, 54562306a36Sopenharmony_ci ASPEED_PTCR_RESULT, 54662306a36Sopenharmony_ci val, 54762306a36Sopenharmony_ci (val & RESULT_STATUS_MASK), 54862306a36Sopenharmony_ci ASPEED_RPM_STATUS_SLEEP_USEC, 54962306a36Sopenharmony_ci usec); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci mutex_unlock(&priv->tach_lock); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* return -ETIMEDOUT if we didn't get an answer. */ 55462306a36Sopenharmony_ci if (ret) 55562306a36Sopenharmony_ci return ret; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci raw_data = val & RESULT_VALUE_MASK; 55862306a36Sopenharmony_ci tach_div = priv->type_fan_tach_clock_division[type]; 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * We need the mode to determine if the raw_data is double (from 56162306a36Sopenharmony_ci * counting both edges). 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci mode = priv->type_fan_tach_mode[type]; 56462306a36Sopenharmony_ci both = (mode & BOTH_EDGES) ? 1 : 0; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci tach_div = (0x4 << both) << (tach_div * 2); 56762306a36Sopenharmony_ci clk_source = priv->clk_freq; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (raw_data == 0) 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return (clk_source * 60) / (2 * raw_data * tach_div); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic ssize_t pwm_store(struct device *dev, struct device_attribute *attr, 57662306a36Sopenharmony_ci const char *buf, size_t count) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 57962306a36Sopenharmony_ci int index = sensor_attr->index; 58062306a36Sopenharmony_ci int ret; 58162306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 58262306a36Sopenharmony_ci long fan_ctrl; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ret = kstrtol(buf, 10, &fan_ctrl); 58562306a36Sopenharmony_ci if (ret != 0) 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (fan_ctrl < 0 || fan_ctrl > PWM_MAX) 58962306a36Sopenharmony_ci return -EINVAL; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (priv->pwm_port_fan_ctrl[index] == fan_ctrl) 59262306a36Sopenharmony_ci return count; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci priv->pwm_port_fan_ctrl[index] = fan_ctrl; 59562306a36Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return count; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic ssize_t pwm_show(struct device *dev, struct device_attribute *attr, 60162306a36Sopenharmony_ci char *buf) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 60462306a36Sopenharmony_ci int index = sensor_attr->index; 60562306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic ssize_t rpm_show(struct device *dev, struct device_attribute *attr, 61162306a36Sopenharmony_ci char *buf) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 61462306a36Sopenharmony_ci int index = sensor_attr->index; 61562306a36Sopenharmony_ci int rpm; 61662306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci rpm = aspeed_get_fan_tach_ch_rpm(priv, index); 61962306a36Sopenharmony_ci if (rpm < 0) 62062306a36Sopenharmony_ci return rpm; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return sprintf(buf, "%d\n", rpm); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic umode_t pwm_is_visible(struct kobject *kobj, 62662306a36Sopenharmony_ci struct attribute *a, int index) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 62962306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!priv->pwm_present[index]) 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci return a->mode; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic umode_t fan_dev_is_visible(struct kobject *kobj, 63762306a36Sopenharmony_ci struct attribute *a, int index) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 64062306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (!priv->fan_tach_present[index]) 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci return a->mode; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 64862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); 64962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2); 65062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4, pwm, 3); 65162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm5, pwm, 4); 65262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm6, pwm, 5); 65362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm7, pwm, 6); 65462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm8, pwm, 7); 65562306a36Sopenharmony_cistatic struct attribute *pwm_dev_attrs[] = { 65662306a36Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 65762306a36Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 65862306a36Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 65962306a36Sopenharmony_ci &sensor_dev_attr_pwm4.dev_attr.attr, 66062306a36Sopenharmony_ci &sensor_dev_attr_pwm5.dev_attr.attr, 66162306a36Sopenharmony_ci &sensor_dev_attr_pwm6.dev_attr.attr, 66262306a36Sopenharmony_ci &sensor_dev_attr_pwm7.dev_attr.attr, 66362306a36Sopenharmony_ci &sensor_dev_attr_pwm8.dev_attr.attr, 66462306a36Sopenharmony_ci NULL, 66562306a36Sopenharmony_ci}; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic const struct attribute_group pwm_dev_group = { 66862306a36Sopenharmony_ci .attrs = pwm_dev_attrs, 66962306a36Sopenharmony_ci .is_visible = pwm_is_visible, 67062306a36Sopenharmony_ci}; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0); 67362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, rpm, 1); 67462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan3_input, rpm, 2); 67562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan4_input, rpm, 3); 67662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan5_input, rpm, 4); 67762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan6_input, rpm, 5); 67862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan7_input, rpm, 6); 67962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan8_input, rpm, 7); 68062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan9_input, rpm, 8); 68162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan10_input, rpm, 9); 68262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan11_input, rpm, 10); 68362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan12_input, rpm, 11); 68462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan13_input, rpm, 12); 68562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan14_input, rpm, 13); 68662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan15_input, rpm, 14); 68762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan16_input, rpm, 15); 68862306a36Sopenharmony_cistatic struct attribute *fan_dev_attrs[] = { 68962306a36Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 69062306a36Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 69162306a36Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 69262306a36Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, 69362306a36Sopenharmony_ci &sensor_dev_attr_fan5_input.dev_attr.attr, 69462306a36Sopenharmony_ci &sensor_dev_attr_fan6_input.dev_attr.attr, 69562306a36Sopenharmony_ci &sensor_dev_attr_fan7_input.dev_attr.attr, 69662306a36Sopenharmony_ci &sensor_dev_attr_fan8_input.dev_attr.attr, 69762306a36Sopenharmony_ci &sensor_dev_attr_fan9_input.dev_attr.attr, 69862306a36Sopenharmony_ci &sensor_dev_attr_fan10_input.dev_attr.attr, 69962306a36Sopenharmony_ci &sensor_dev_attr_fan11_input.dev_attr.attr, 70062306a36Sopenharmony_ci &sensor_dev_attr_fan12_input.dev_attr.attr, 70162306a36Sopenharmony_ci &sensor_dev_attr_fan13_input.dev_attr.attr, 70262306a36Sopenharmony_ci &sensor_dev_attr_fan14_input.dev_attr.attr, 70362306a36Sopenharmony_ci &sensor_dev_attr_fan15_input.dev_attr.attr, 70462306a36Sopenharmony_ci &sensor_dev_attr_fan16_input.dev_attr.attr, 70562306a36Sopenharmony_ci NULL 70662306a36Sopenharmony_ci}; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic const struct attribute_group fan_dev_group = { 70962306a36Sopenharmony_ci .attrs = fan_dev_attrs, 71062306a36Sopenharmony_ci .is_visible = fan_dev_is_visible, 71162306a36Sopenharmony_ci}; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/* 71462306a36Sopenharmony_ci * The clock type is type M : 71562306a36Sopenharmony_ci * The PWM frequency = 24MHz / (type M clock division L bit * 71662306a36Sopenharmony_ci * type M clock division H bit * (type M PWM period bit + 1)) 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_cistatic void aspeed_create_type(struct aspeed_pwm_tacho_data *priv) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H; 72162306a36Sopenharmony_ci priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L; 72262306a36Sopenharmony_ci priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD; 72362306a36Sopenharmony_ci aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H, 72462306a36Sopenharmony_ci M_PWM_DIV_L, M_PWM_PERIOD); 72562306a36Sopenharmony_ci aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true); 72662306a36Sopenharmony_ci priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV; 72762306a36Sopenharmony_ci priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT; 72862306a36Sopenharmony_ci priv->type_fan_tach_mode[TYPEM] = M_TACH_MODE; 72962306a36Sopenharmony_ci aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE, 73062306a36Sopenharmony_ci M_TACH_UNIT, M_TACH_CLK_DIV); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv, 73462306a36Sopenharmony_ci u8 pwm_port) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true); 73762306a36Sopenharmony_ci priv->pwm_present[pwm_port] = true; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci priv->pwm_port_type[pwm_port] = TYPEM; 74062306a36Sopenharmony_ci aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL; 74362306a36Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv, 74762306a36Sopenharmony_ci u8 *fan_tach_ch, 74862306a36Sopenharmony_ci int count, 74962306a36Sopenharmony_ci u8 pwm_source) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci u8 val, index; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci for (val = 0; val < count; val++) { 75462306a36Sopenharmony_ci index = fan_tach_ch[val]; 75562306a36Sopenharmony_ci aspeed_set_fan_tach_ch_enable(priv->regmap, index, true); 75662306a36Sopenharmony_ci priv->fan_tach_present[index] = true; 75762306a36Sopenharmony_ci priv->fan_tach_ch_source[index] = pwm_source; 75862306a36Sopenharmony_ci aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic int 76362306a36Sopenharmony_ciaspeed_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev, 76462306a36Sopenharmony_ci unsigned long *state) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci *state = cdev->max_state; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int 77462306a36Sopenharmony_ciaspeed_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev, 77562306a36Sopenharmony_ci unsigned long *state) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci *state = cdev->cur_state; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int 78562306a36Sopenharmony_ciaspeed_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev, 78662306a36Sopenharmony_ci unsigned long state) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct aspeed_cooling_device *cdev = tcdev->devdata; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (state > cdev->max_state) 79162306a36Sopenharmony_ci return -EINVAL; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci cdev->cur_state = state; 79462306a36Sopenharmony_ci cdev->priv->pwm_port_fan_ctrl[cdev->pwm_port] = 79562306a36Sopenharmony_ci cdev->cooling_levels[cdev->cur_state]; 79662306a36Sopenharmony_ci aspeed_set_pwm_port_fan_ctrl(cdev->priv, cdev->pwm_port, 79762306a36Sopenharmony_ci cdev->cooling_levels[cdev->cur_state]); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 0; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = { 80362306a36Sopenharmony_ci .get_max_state = aspeed_pwm_cz_get_max_state, 80462306a36Sopenharmony_ci .get_cur_state = aspeed_pwm_cz_get_cur_state, 80562306a36Sopenharmony_ci .set_cur_state = aspeed_pwm_cz_set_cur_state, 80662306a36Sopenharmony_ci}; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic int aspeed_create_pwm_cooling(struct device *dev, 80962306a36Sopenharmony_ci struct device_node *child, 81062306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv, 81162306a36Sopenharmony_ci u32 pwm_port, u8 num_levels) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci int ret; 81462306a36Sopenharmony_ci struct aspeed_cooling_device *cdev; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (!cdev) 81962306a36Sopenharmony_ci return -ENOMEM; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL); 82262306a36Sopenharmony_ci if (!cdev->cooling_levels) 82362306a36Sopenharmony_ci return -ENOMEM; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci cdev->max_state = num_levels - 1; 82662306a36Sopenharmony_ci ret = of_property_read_u8_array(child, "cooling-levels", 82762306a36Sopenharmony_ci cdev->cooling_levels, 82862306a36Sopenharmony_ci num_levels); 82962306a36Sopenharmony_ci if (ret) { 83062306a36Sopenharmony_ci dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); 83162306a36Sopenharmony_ci return ret; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child, 83662306a36Sopenharmony_ci cdev->name, cdev, &aspeed_pwm_cool_ops); 83762306a36Sopenharmony_ci if (IS_ERR(cdev->tcdev)) 83862306a36Sopenharmony_ci return PTR_ERR(cdev->tcdev); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci cdev->priv = priv; 84162306a36Sopenharmony_ci cdev->pwm_port = pwm_port; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci priv->cdev[pwm_port] = cdev; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic int aspeed_create_fan(struct device *dev, 84962306a36Sopenharmony_ci struct device_node *child, 85062306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci u8 *fan_tach_ch; 85362306a36Sopenharmony_ci u32 pwm_port; 85462306a36Sopenharmony_ci int ret, count; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ret = of_property_read_u32(child, "reg", &pwm_port); 85762306a36Sopenharmony_ci if (ret) 85862306a36Sopenharmony_ci return ret; 85962306a36Sopenharmony_ci if (pwm_port >= ARRAY_SIZE(pwm_port_params)) 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci aspeed_create_pwm_port(priv, (u8)pwm_port); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci ret = of_property_count_u8_elems(child, "cooling-levels"); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (ret > 0) { 86662306a36Sopenharmony_ci ret = aspeed_create_pwm_cooling(dev, child, priv, pwm_port, 86762306a36Sopenharmony_ci ret); 86862306a36Sopenharmony_ci if (ret) 86962306a36Sopenharmony_ci return ret; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch"); 87362306a36Sopenharmony_ci if (count < 1) 87462306a36Sopenharmony_ci return -EINVAL; 87562306a36Sopenharmony_ci fan_tach_ch = devm_kcalloc(dev, count, sizeof(*fan_tach_ch), 87662306a36Sopenharmony_ci GFP_KERNEL); 87762306a36Sopenharmony_ci if (!fan_tach_ch) 87862306a36Sopenharmony_ci return -ENOMEM; 87962306a36Sopenharmony_ci ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch", 88062306a36Sopenharmony_ci fan_tach_ch, count); 88162306a36Sopenharmony_ci if (ret) 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void aspeed_pwm_tacho_remove(void *data) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv = data; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci reset_control_assert(priv->rst); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int aspeed_pwm_tacho_probe(struct platform_device *pdev) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 89862306a36Sopenharmony_ci struct device_node *np, *child; 89962306a36Sopenharmony_ci struct aspeed_pwm_tacho_data *priv; 90062306a36Sopenharmony_ci void __iomem *regs; 90162306a36Sopenharmony_ci struct device *hwmon; 90262306a36Sopenharmony_ci struct clk *clk; 90362306a36Sopenharmony_ci int ret; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci np = dev->of_node; 90662306a36Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 90762306a36Sopenharmony_ci if (IS_ERR(regs)) 90862306a36Sopenharmony_ci return PTR_ERR(regs); 90962306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 91062306a36Sopenharmony_ci if (!priv) 91162306a36Sopenharmony_ci return -ENOMEM; 91262306a36Sopenharmony_ci mutex_init(&priv->tach_lock); 91362306a36Sopenharmony_ci priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs, 91462306a36Sopenharmony_ci &aspeed_pwm_tacho_regmap_config); 91562306a36Sopenharmony_ci if (IS_ERR(priv->regmap)) 91662306a36Sopenharmony_ci return PTR_ERR(priv->regmap); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci priv->rst = devm_reset_control_get_exclusive(dev, NULL); 91962306a36Sopenharmony_ci if (IS_ERR(priv->rst)) { 92062306a36Sopenharmony_ci dev_err(dev, 92162306a36Sopenharmony_ci "missing or invalid reset controller device tree entry"); 92262306a36Sopenharmony_ci return PTR_ERR(priv->rst); 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci reset_control_deassert(priv->rst); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv); 92762306a36Sopenharmony_ci if (ret) 92862306a36Sopenharmony_ci return ret; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0); 93162306a36Sopenharmony_ci regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci clk = devm_clk_get(dev, NULL); 93462306a36Sopenharmony_ci if (IS_ERR(clk)) 93562306a36Sopenharmony_ci return -ENODEV; 93662306a36Sopenharmony_ci priv->clk_freq = clk_get_rate(clk); 93762306a36Sopenharmony_ci aspeed_set_clock_enable(priv->regmap, true); 93862306a36Sopenharmony_ci aspeed_set_clock_source(priv->regmap, 0); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci aspeed_create_type(priv); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci for_each_child_of_node(np, child) { 94362306a36Sopenharmony_ci ret = aspeed_create_fan(dev, child, priv); 94462306a36Sopenharmony_ci if (ret) { 94562306a36Sopenharmony_ci of_node_put(child); 94662306a36Sopenharmony_ci return ret; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci priv->groups[0] = &pwm_dev_group; 95162306a36Sopenharmony_ci priv->groups[1] = &fan_dev_group; 95262306a36Sopenharmony_ci priv->groups[2] = NULL; 95362306a36Sopenharmony_ci hwmon = devm_hwmon_device_register_with_groups(dev, 95462306a36Sopenharmony_ci "aspeed_pwm_tacho", 95562306a36Sopenharmony_ci priv, priv->groups); 95662306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic const struct of_device_id of_pwm_tacho_match_table[] = { 96062306a36Sopenharmony_ci { .compatible = "aspeed,ast2400-pwm-tacho", }, 96162306a36Sopenharmony_ci { .compatible = "aspeed,ast2500-pwm-tacho", }, 96262306a36Sopenharmony_ci {}, 96362306a36Sopenharmony_ci}; 96462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic struct platform_driver aspeed_pwm_tacho_driver = { 96762306a36Sopenharmony_ci .probe = aspeed_pwm_tacho_probe, 96862306a36Sopenharmony_ci .driver = { 96962306a36Sopenharmony_ci .name = "aspeed_pwm_tacho", 97062306a36Sopenharmony_ci .of_match_table = of_pwm_tacho_match_table, 97162306a36Sopenharmony_ci }, 97262306a36Sopenharmony_ci}; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cimodule_platform_driver(aspeed_pwm_tacho_driver); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ciMODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>"); 97762306a36Sopenharmony_ciMODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver"); 97862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 979