2019-05-19 16:51:33 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-04-05 03:52:41 +03:00
/*
* Copyright ( c ) 2016 Google , Inc
*/
# include <linux/clk.h>
2017-11-02 06:53:47 +03:00
# include <linux/delay.h>
2017-05-30 22:42:01 +03:00
# include <linux/errno.h>
2017-04-05 03:52:41 +03:00
# include <linux/gpio/consumer.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_device.h>
2017-11-02 06:53:47 +03:00
# include <linux/of_platform.h>
2017-04-05 03:52:41 +03:00
# include <linux/platform_device.h>
# include <linux/regmap.h>
2017-12-23 16:05:28 +03:00
# include <linux/reset.h>
2017-11-02 06:53:47 +03:00
# include <linux/sysfs.h>
2017-08-03 11:50:44 +03:00
# include <linux/thermal.h>
2017-04-05 03:52:41 +03:00
/* ASPEED PWM & FAN Tach Register Definition */
# define ASPEED_PTCR_CTRL 0x00
# define ASPEED_PTCR_CLK_CTRL 0x04
# define ASPEED_PTCR_DUTY0_CTRL 0x08
# define ASPEED_PTCR_DUTY1_CTRL 0x0c
# define ASPEED_PTCR_TYPEM_CTRL 0x10
# define ASPEED_PTCR_TYPEM_CTRL1 0x14
# define ASPEED_PTCR_TYPEN_CTRL 0x18
# define ASPEED_PTCR_TYPEN_CTRL1 0x1c
# define ASPEED_PTCR_TACH_SOURCE 0x20
# define ASPEED_PTCR_TRIGGER 0x28
# define ASPEED_PTCR_RESULT 0x2c
# define ASPEED_PTCR_INTR_CTRL 0x30
# define ASPEED_PTCR_INTR_STS 0x34
# define ASPEED_PTCR_TYPEM_LIMIT 0x38
# define ASPEED_PTCR_TYPEN_LIMIT 0x3C
# define ASPEED_PTCR_CTRL_EXT 0x40
# define ASPEED_PTCR_CLK_CTRL_EXT 0x44
# define ASPEED_PTCR_DUTY2_CTRL 0x48
# define ASPEED_PTCR_DUTY3_CTRL 0x4c
# define ASPEED_PTCR_TYPEO_CTRL 0x50
# define ASPEED_PTCR_TYPEO_CTRL1 0x54
# define ASPEED_PTCR_TACH_SOURCE_EXT 0x60
# define ASPEED_PTCR_TYPEO_LIMIT 0x78
/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */
# define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15
# define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6
# define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15))
# define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14
# define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5
# define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14))
# define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13
# define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4
# define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13))
# define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12
# define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3
# define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12))
# define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x))
# define ASPEED_PTCR_CTRL_PWMD_EN BIT(11)
# define ASPEED_PTCR_CTRL_PWMC_EN BIT(10)
# define ASPEED_PTCR_CTRL_PWMB_EN BIT(9)
# define ASPEED_PTCR_CTRL_PWMA_EN BIT(8)
# define ASPEED_PTCR_CTRL_CLK_SRC BIT(1)
# define ASPEED_PTCR_CTRL_CLK_EN BIT(0)
/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */
/* TYPE N */
# define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16)
# define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24
# define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20
# define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16
/* TYPE M */
# define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0)
# define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8
# define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4
# define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0
/*
* ASPEED_PTCR_DUTY_CTRL / 1 / 2 / 3 : 0x08 / 0x0C / 0x48 / 0x4C - PWM - FAN duty control
* 0 / 1 / 2 / 3 register
*/
# define DUTY_CTRL_PWM2_FALL_POINT 24
# define DUTY_CTRL_PWM2_RISE_POINT 16
# define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16)
# define DUTY_CTRL_PWM1_FALL_POINT 8
# define DUTY_CTRL_PWM1_RISE_POINT 0
# define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0)
/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */
# define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16))
# define TYPE_CTRL_FAN1_MASK GENMASK(31, 0)
# define TYPE_CTRL_FAN_PERIOD 16
# define TYPE_CTRL_FAN_MODE 4
# define TYPE_CTRL_FAN_DIVISION 1
# define TYPE_CTRL_FAN_TYPE_EN 1
/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */
/* bit [0,1] at 0x20, bit [2] at 0x60 */
# define TACH_PWM_SOURCE_BIT01(x) ((x) * 2)
# define TACH_PWM_SOURCE_BIT2(x) ((x) * 2)
# define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2))
# define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2)
/* ASPEED_PTCR_RESULT : 0x2c - Result Register */
# define RESULT_STATUS_MASK BIT(31)
# define RESULT_VALUE_MASK 0xfffff
/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */
# define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15
# define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6
# define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15))
# define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14
# define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5
# define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14))
# define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13
# define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4
# define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13))
# define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12
# define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3
# define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12))
# define ASPEED_PTCR_CTRL_PWMH_EN BIT(11)
# define ASPEED_PTCR_CTRL_PWMG_EN BIT(10)
# define ASPEED_PTCR_CTRL_PWMF_EN BIT(9)
# define ASPEED_PTCR_CTRL_PWME_EN BIT(8)
/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */
/* TYPE O */
# define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0)
# define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8
# define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4
# define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0
# define PWM_MAX 255
2017-06-01 17:25:33 +03:00
# define BOTH_EDGES 0x02 /* 10b */
2017-04-05 03:52:41 +03:00
# define M_PWM_DIV_H 0x00
# define M_PWM_DIV_L 0x05
# define M_PWM_PERIOD 0x5F
# define M_TACH_CLK_DIV 0x00
2017-06-01 17:25:33 +03:00
/*
* 5 : 4 Type N fan tach mode selection bit :
* 00 : falling
* 01 : rising
* 10 : both
* 11 : reserved .
*/
# define M_TACH_MODE 0x02 /* 10b */
2022-07-14 17:23:44 +03:00
# define M_TACH_UNIT 0x0420
2017-04-05 03:52:41 +03:00
# define INIT_FAN_CTRL 0xFF
2017-06-24 06:39:56 +03:00
/* How long we sleep in us while waiting for an RPM result. */
# define ASPEED_RPM_STATUS_SLEEP_USEC 500
2017-08-03 11:50:44 +03:00
# define MAX_CDEV_NAME_LEN 16
struct aspeed_cooling_device {
char name [ 16 ] ;
struct aspeed_pwm_tacho_data * priv ;
struct thermal_cooling_device * tcdev ;
int pwm_port ;
u8 * cooling_levels ;
u8 max_state ;
u8 cur_state ;
} ;
2017-04-05 03:52:41 +03:00
struct aspeed_pwm_tacho_data {
struct regmap * regmap ;
2017-12-23 16:05:28 +03:00
struct reset_control * rst ;
2017-04-05 03:52:41 +03:00
unsigned long clk_freq ;
bool pwm_present [ 8 ] ;
bool fan_tach_present [ 16 ] ;
u8 type_pwm_clock_unit [ 3 ] ;
u8 type_pwm_clock_division_h [ 3 ] ;
u8 type_pwm_clock_division_l [ 3 ] ;
u8 type_fan_tach_clock_division [ 3 ] ;
2017-06-01 17:25:33 +03:00
u8 type_fan_tach_mode [ 3 ] ;
2017-04-05 03:52:41 +03:00
u16 type_fan_tach_unit [ 3 ] ;
u8 pwm_port_type [ 8 ] ;
u8 pwm_port_fan_ctrl [ 8 ] ;
u8 fan_tach_ch_source [ 16 ] ;
2017-08-03 11:50:44 +03:00
struct aspeed_cooling_device * cdev [ 8 ] ;
2017-04-05 03:52:41 +03:00
const struct attribute_group * groups [ 3 ] ;
} ;
enum type { TYPEM , TYPEN , TYPEO } ;
struct type_params {
u32 l_value ;
u32 h_value ;
u32 unit_value ;
u32 clk_ctrl_mask ;
u32 clk_ctrl_reg ;
u32 ctrl_reg ;
u32 ctrl_reg1 ;
} ;
static const struct type_params type_params [ ] = {
[ TYPEM ] = {
. l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L ,
. h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H ,
. unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT ,
. clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK ,
. clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL ,
. ctrl_reg = ASPEED_PTCR_TYPEM_CTRL ,
. ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1 ,
} ,
[ TYPEN ] = {
. l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L ,
. h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H ,
. unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT ,
. clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK ,
. clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL ,
. ctrl_reg = ASPEED_PTCR_TYPEN_CTRL ,
. ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1 ,
} ,
[ TYPEO ] = {
. l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L ,
. h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H ,
. unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT ,
. clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK ,
. clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT ,
. ctrl_reg = ASPEED_PTCR_TYPEO_CTRL ,
. ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1 ,
}
} ;
enum pwm_port { PWMA , PWMB , PWMC , PWMD , PWME , PWMF , PWMG , PWMH } ;
struct pwm_port_params {
u32 pwm_en ;
u32 ctrl_reg ;
u32 type_part1 ;
u32 type_part2 ;
u32 type_mask ;
u32 duty_ctrl_rise_point ;
u32 duty_ctrl_fall_point ;
u32 duty_ctrl_reg ;
u32 duty_ctrl_rise_fall_mask ;
} ;
static const struct pwm_port_params pwm_port_params [ ] = {
[ PWMA ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMA_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK ,
} ,
[ PWMB ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMB_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK ,
} ,
[ PWMC ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMC_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK ,
} ,
[ PWMD ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMD_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK ,
} ,
[ PWME ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWME_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL_EXT ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK ,
} ,
[ PWMF ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMF_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL_EXT ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK ,
} ,
[ PWMG ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMG_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL_EXT ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK ,
} ,
[ PWMH ] = {
. pwm_en = ASPEED_PTCR_CTRL_PWMH_EN ,
. ctrl_reg = ASPEED_PTCR_CTRL_EXT ,
. type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 ,
. type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 ,
. type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK ,
. duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT ,
. duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT ,
. duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL ,
. duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK ,
}
} ;
static int regmap_aspeed_pwm_tacho_reg_write ( void * context , unsigned int reg ,
unsigned int val )
{
void __iomem * regs = ( void __iomem * ) context ;
writel ( val , regs + reg ) ;
return 0 ;
}
static int regmap_aspeed_pwm_tacho_reg_read ( void * context , unsigned int reg ,
unsigned int * val )
{
void __iomem * regs = ( void __iomem * ) context ;
* val = readl ( regs + reg ) ;
return 0 ;
}
static const struct regmap_config aspeed_pwm_tacho_regmap_config = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. max_register = ASPEED_PTCR_TYPEO_LIMIT ,
. reg_write = regmap_aspeed_pwm_tacho_reg_write ,
. reg_read = regmap_aspeed_pwm_tacho_reg_read ,
. fast_io = true ,
} ;
static void aspeed_set_clock_enable ( struct regmap * regmap , bool val )
{
regmap_update_bits ( regmap , ASPEED_PTCR_CTRL ,
ASPEED_PTCR_CTRL_CLK_EN ,
val ? ASPEED_PTCR_CTRL_CLK_EN : 0 ) ;
}
static void aspeed_set_clock_source ( struct regmap * regmap , int val )
{
regmap_update_bits ( regmap , ASPEED_PTCR_CTRL ,
ASPEED_PTCR_CTRL_CLK_SRC ,
val ? ASPEED_PTCR_CTRL_CLK_SRC : 0 ) ;
}
static void aspeed_set_pwm_clock_values ( struct regmap * regmap , u8 type ,
u8 div_high , u8 div_low , u8 unit )
{
u32 reg_value = ( ( div_high < < type_params [ type ] . h_value ) |
( div_low < < type_params [ type ] . l_value ) |
( unit < < type_params [ type ] . unit_value ) ) ;
regmap_update_bits ( regmap , type_params [ type ] . clk_ctrl_reg ,
type_params [ type ] . clk_ctrl_mask , reg_value ) ;
}
static void aspeed_set_pwm_port_enable ( struct regmap * regmap , u8 pwm_port ,
bool enable )
{
regmap_update_bits ( regmap , pwm_port_params [ pwm_port ] . ctrl_reg ,
pwm_port_params [ pwm_port ] . pwm_en ,
enable ? pwm_port_params [ pwm_port ] . pwm_en : 0 ) ;
}
static void aspeed_set_pwm_port_type ( struct regmap * regmap ,
u8 pwm_port , u8 type )
{
u32 reg_value = ( type & 0x1 ) < < pwm_port_params [ pwm_port ] . type_part1 ;
reg_value | = ( type & 0x2 ) < < pwm_port_params [ pwm_port ] . type_part2 ;
regmap_update_bits ( regmap , pwm_port_params [ pwm_port ] . ctrl_reg ,
pwm_port_params [ pwm_port ] . type_mask , reg_value ) ;
}
static void aspeed_set_pwm_port_duty_rising_falling ( struct regmap * regmap ,
u8 pwm_port , u8 rising ,
u8 falling )
{
u32 reg_value = ( rising < <
pwm_port_params [ pwm_port ] . duty_ctrl_rise_point ) ;
reg_value | = ( falling < <
pwm_port_params [ pwm_port ] . duty_ctrl_fall_point ) ;
regmap_update_bits ( regmap , pwm_port_params [ pwm_port ] . duty_ctrl_reg ,
pwm_port_params [ pwm_port ] . duty_ctrl_rise_fall_mask ,
reg_value ) ;
}
static void aspeed_set_tacho_type_enable ( struct regmap * regmap , u8 type ,
bool enable )
{
regmap_update_bits ( regmap , type_params [ type ] . ctrl_reg ,
TYPE_CTRL_FAN_TYPE_EN ,
enable ? TYPE_CTRL_FAN_TYPE_EN : 0 ) ;
}
static void aspeed_set_tacho_type_values ( struct regmap * regmap , u8 type ,
u8 mode , u16 unit , u8 division )
{
u32 reg_value = ( ( mode < < TYPE_CTRL_FAN_MODE ) |
( unit < < TYPE_CTRL_FAN_PERIOD ) |
( division < < TYPE_CTRL_FAN_DIVISION ) ) ;
regmap_update_bits ( regmap , type_params [ type ] . ctrl_reg ,
TYPE_CTRL_FAN_MASK , reg_value ) ;
regmap_update_bits ( regmap , type_params [ type ] . ctrl_reg1 ,
TYPE_CTRL_FAN1_MASK , unit < < 16 ) ;
}
static void aspeed_set_fan_tach_ch_enable ( struct regmap * regmap , u8 fan_tach_ch ,
bool enable )
{
regmap_update_bits ( regmap , ASPEED_PTCR_CTRL ,
ASPEED_PTCR_CTRL_FAN_NUM_EN ( fan_tach_ch ) ,
enable ?
ASPEED_PTCR_CTRL_FAN_NUM_EN ( fan_tach_ch ) : 0 ) ;
}
static void aspeed_set_fan_tach_ch_source ( struct regmap * regmap , u8 fan_tach_ch ,
u8 fan_tach_ch_source )
{
u32 reg_value1 = ( ( fan_tach_ch_source & 0x3 ) < <
TACH_PWM_SOURCE_BIT01 ( fan_tach_ch ) ) ;
u32 reg_value2 = ( ( ( fan_tach_ch_source & 0x4 ) > > 2 ) < <
TACH_PWM_SOURCE_BIT2 ( fan_tach_ch ) ) ;
regmap_update_bits ( regmap , ASPEED_PTCR_TACH_SOURCE ,
TACH_PWM_SOURCE_MASK_BIT01 ( fan_tach_ch ) ,
reg_value1 ) ;
regmap_update_bits ( regmap , ASPEED_PTCR_TACH_SOURCE_EXT ,
TACH_PWM_SOURCE_MASK_BIT2 ( fan_tach_ch ) ,
reg_value2 ) ;
}
static void aspeed_set_pwm_port_fan_ctrl ( struct aspeed_pwm_tacho_data * priv ,
u8 index , u8 fan_ctrl )
{
u16 period , dc_time_on ;
period = priv - > type_pwm_clock_unit [ priv - > pwm_port_type [ index ] ] ;
period + = 1 ;
dc_time_on = ( fan_ctrl * period ) / PWM_MAX ;
if ( dc_time_on = = 0 ) {
aspeed_set_pwm_port_enable ( priv - > regmap , index , false ) ;
} else {
if ( dc_time_on = = period )
dc_time_on = 0 ;
aspeed_set_pwm_port_duty_rising_falling ( priv - > regmap , index , 0 ,
dc_time_on ) ;
aspeed_set_pwm_port_enable ( priv - > regmap , index , true ) ;
}
}
static u32 aspeed_get_fan_tach_ch_measure_period ( struct aspeed_pwm_tacho_data
* priv , u8 type )
{
u32 clk ;
u16 tacho_unit ;
u8 clk_unit , div_h , div_l , tacho_div ;
clk = priv - > clk_freq ;
clk_unit = priv - > type_pwm_clock_unit [ type ] ;
div_h = priv - > type_pwm_clock_division_h [ type ] ;
div_h = 0x1 < < div_h ;
div_l = priv - > type_pwm_clock_division_l [ type ] ;
if ( div_l = = 0 )
div_l = 1 ;
else
div_l = div_l * 2 ;
tacho_unit = priv - > type_fan_tach_unit [ type ] ;
tacho_div = priv - > type_fan_tach_clock_division [ type ] ;
tacho_div = 0x4 < < ( tacho_div * 2 ) ;
return clk / ( clk_unit * div_h * div_l * tacho_div * tacho_unit ) ;
}
2017-05-30 22:42:01 +03:00
static int aspeed_get_fan_tach_ch_rpm ( struct aspeed_pwm_tacho_data * priv ,
2017-04-05 03:52:41 +03:00
u8 fan_tach_ch )
{
2017-06-24 06:39:56 +03:00
u32 raw_data , tach_div , clk_source , msec , usec , val ;
2017-06-01 17:25:33 +03:00
u8 fan_tach_ch_source , type , mode , both ;
2017-06-24 06:39:56 +03:00
int ret ;
2017-04-05 03:52:41 +03:00
regmap_write ( priv - > regmap , ASPEED_PTCR_TRIGGER , 0 ) ;
regmap_write ( priv - > regmap , ASPEED_PTCR_TRIGGER , 0x1 < < fan_tach_ch ) ;
fan_tach_ch_source = priv - > fan_tach_ch_source [ fan_tach_ch ] ;
type = priv - > pwm_port_type [ fan_tach_ch_source ] ;
2017-06-24 06:39:56 +03:00
msec = ( 1000 / aspeed_get_fan_tach_ch_measure_period ( priv , type ) ) ;
usec = msec * 1000 ;
ret = regmap_read_poll_timeout (
priv - > regmap ,
ASPEED_PTCR_RESULT ,
val ,
( val & RESULT_STATUS_MASK ) ,
ASPEED_RPM_STATUS_SLEEP_USEC ,
usec ) ;
2017-04-05 03:52:41 +03:00
2017-06-24 06:39:56 +03:00
/* return -ETIMEDOUT if we didn't get an answer. */
if ( ret )
return ret ;
2017-05-30 22:42:01 +03:00
2017-04-05 03:52:41 +03:00
raw_data = val & RESULT_VALUE_MASK ;
tach_div = priv - > type_fan_tach_clock_division [ type ] ;
2017-06-01 17:25:33 +03:00
/*
* We need the mode to determine if the raw_data is double ( from
* counting both edges ) .
*/
mode = priv - > type_fan_tach_mode [ type ] ;
both = ( mode & BOTH_EDGES ) ? 1 : 0 ;
tach_div = ( 0x4 < < both ) < < ( tach_div * 2 ) ;
2017-04-05 03:52:41 +03:00
clk_source = priv - > clk_freq ;
if ( raw_data = = 0 )
return 0 ;
return ( clk_source * 60 ) / ( 2 * raw_data * tach_div ) ;
}
2018-12-11 01:02:03 +03:00
static ssize_t pwm_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2017-04-05 03:52:41 +03:00
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int index = sensor_attr - > index ;
int ret ;
struct aspeed_pwm_tacho_data * priv = dev_get_drvdata ( dev ) ;
long fan_ctrl ;
ret = kstrtol ( buf , 10 , & fan_ctrl ) ;
if ( ret ! = 0 )
return ret ;
if ( fan_ctrl < 0 | | fan_ctrl > PWM_MAX )
return - EINVAL ;
if ( priv - > pwm_port_fan_ctrl [ index ] = = fan_ctrl )
return count ;
priv - > pwm_port_fan_ctrl [ index ] = fan_ctrl ;
aspeed_set_pwm_port_fan_ctrl ( priv , index , fan_ctrl ) ;
return count ;
}
2018-12-11 01:02:03 +03:00
static ssize_t pwm_show ( struct device * dev , struct device_attribute * attr ,
2017-04-05 03:52:41 +03:00
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int index = sensor_attr - > index ;
struct aspeed_pwm_tacho_data * priv = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %u \n " , priv - > pwm_port_fan_ctrl [ index ] ) ;
}
2018-12-11 01:02:03 +03:00
static ssize_t rpm_show ( struct device * dev , struct device_attribute * attr ,
2017-04-05 03:52:41 +03:00
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int index = sensor_attr - > index ;
2017-05-30 22:42:01 +03:00
int rpm ;
2017-04-05 03:52:41 +03:00
struct aspeed_pwm_tacho_data * priv = dev_get_drvdata ( dev ) ;
rpm = aspeed_get_fan_tach_ch_rpm ( priv , index ) ;
2017-05-30 22:42:01 +03:00
if ( rpm < 0 )
return rpm ;
2017-04-05 03:52:41 +03:00
2017-05-30 22:42:01 +03:00
return sprintf ( buf , " %d \n " , rpm ) ;
2017-04-05 03:52:41 +03:00
}
static umode_t pwm_is_visible ( struct kobject * kobj ,
struct attribute * a , int index )
{
2021-01-04 05:05:45 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2017-04-05 03:52:41 +03:00
struct aspeed_pwm_tacho_data * priv = dev_get_drvdata ( dev ) ;
if ( ! priv - > pwm_present [ index ] )
return 0 ;
return a - > mode ;
}
static umode_t fan_dev_is_visible ( struct kobject * kobj ,
struct attribute * a , int index )
{
2021-01-04 05:05:45 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2017-04-05 03:52:41 +03:00
struct aspeed_pwm_tacho_data * priv = dev_get_drvdata ( dev ) ;
if ( ! priv - > fan_tach_present [ index ] )
return 0 ;
return a - > mode ;
}
2018-12-11 01:02:03 +03:00
static SENSOR_DEVICE_ATTR_RW ( pwm1 , pwm , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm2 , pwm , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm3 , pwm , 2 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm4 , pwm , 3 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm5 , pwm , 4 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm6 , pwm , 5 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm7 , pwm , 6 ) ;
static SENSOR_DEVICE_ATTR_RW ( pwm8 , pwm , 7 ) ;
2017-04-05 03:52:41 +03:00
static struct attribute * pwm_dev_attrs [ ] = {
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm2 . dev_attr . attr ,
& sensor_dev_attr_pwm3 . dev_attr . attr ,
& sensor_dev_attr_pwm4 . dev_attr . attr ,
& sensor_dev_attr_pwm5 . dev_attr . attr ,
& sensor_dev_attr_pwm6 . dev_attr . attr ,
& sensor_dev_attr_pwm7 . dev_attr . attr ,
2017-06-02 22:43:28 +03:00
& sensor_dev_attr_pwm8 . dev_attr . attr ,
2017-04-05 03:52:41 +03:00
NULL ,
} ;
static const struct attribute_group pwm_dev_group = {
. attrs = pwm_dev_attrs ,
. is_visible = pwm_is_visible ,
} ;
2018-12-11 01:02:03 +03:00
static SENSOR_DEVICE_ATTR_RO ( fan1_input , rpm , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan2_input , rpm , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan3_input , rpm , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan4_input , rpm , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan5_input , rpm , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan6_input , rpm , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan7_input , rpm , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan8_input , rpm , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan9_input , rpm , 8 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan10_input , rpm , 9 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan11_input , rpm , 10 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan12_input , rpm , 11 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan13_input , rpm , 12 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan14_input , rpm , 13 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan15_input , rpm , 14 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan16_input , rpm , 15 ) ;
2017-04-05 03:52:41 +03:00
static struct attribute * fan_dev_attrs [ ] = {
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan3_input . dev_attr . attr ,
& sensor_dev_attr_fan4_input . dev_attr . attr ,
& sensor_dev_attr_fan5_input . dev_attr . attr ,
& sensor_dev_attr_fan6_input . dev_attr . attr ,
& sensor_dev_attr_fan7_input . dev_attr . attr ,
& sensor_dev_attr_fan8_input . dev_attr . attr ,
& sensor_dev_attr_fan9_input . dev_attr . attr ,
& sensor_dev_attr_fan10_input . dev_attr . attr ,
& sensor_dev_attr_fan11_input . dev_attr . attr ,
& sensor_dev_attr_fan12_input . dev_attr . attr ,
& sensor_dev_attr_fan13_input . dev_attr . attr ,
& sensor_dev_attr_fan14_input . dev_attr . attr ,
& sensor_dev_attr_fan15_input . dev_attr . attr ,
2017-06-02 22:43:28 +03:00
& sensor_dev_attr_fan16_input . dev_attr . attr ,
2017-04-05 03:52:41 +03:00
NULL
} ;
static const struct attribute_group fan_dev_group = {
. attrs = fan_dev_attrs ,
. is_visible = fan_dev_is_visible ,
} ;
/*
* The clock type is type M :
* The PWM frequency = 24 MHz / ( type M clock division L bit *
* type M clock division H bit * ( type M PWM period bit + 1 ) )
*/
static void aspeed_create_type ( struct aspeed_pwm_tacho_data * priv )
{
priv - > type_pwm_clock_division_h [ TYPEM ] = M_PWM_DIV_H ;
priv - > type_pwm_clock_division_l [ TYPEM ] = M_PWM_DIV_L ;
priv - > type_pwm_clock_unit [ TYPEM ] = M_PWM_PERIOD ;
aspeed_set_pwm_clock_values ( priv - > regmap , TYPEM , M_PWM_DIV_H ,
M_PWM_DIV_L , M_PWM_PERIOD ) ;
aspeed_set_tacho_type_enable ( priv - > regmap , TYPEM , true ) ;
priv - > type_fan_tach_clock_division [ TYPEM ] = M_TACH_CLK_DIV ;
priv - > type_fan_tach_unit [ TYPEM ] = M_TACH_UNIT ;
2017-06-01 17:25:33 +03:00
priv - > type_fan_tach_mode [ TYPEM ] = M_TACH_MODE ;
2017-04-05 03:52:41 +03:00
aspeed_set_tacho_type_values ( priv - > regmap , TYPEM , M_TACH_MODE ,
M_TACH_UNIT , M_TACH_CLK_DIV ) ;
}
static void aspeed_create_pwm_port ( struct aspeed_pwm_tacho_data * priv ,
u8 pwm_port )
{
aspeed_set_pwm_port_enable ( priv - > regmap , pwm_port , true ) ;
priv - > pwm_present [ pwm_port ] = true ;
priv - > pwm_port_type [ pwm_port ] = TYPEM ;
aspeed_set_pwm_port_type ( priv - > regmap , pwm_port , TYPEM ) ;
priv - > pwm_port_fan_ctrl [ pwm_port ] = INIT_FAN_CTRL ;
aspeed_set_pwm_port_fan_ctrl ( priv , pwm_port , INIT_FAN_CTRL ) ;
}
static void aspeed_create_fan_tach_channel ( struct aspeed_pwm_tacho_data * priv ,
u8 * fan_tach_ch ,
int count ,
u8 pwm_source )
{
u8 val , index ;
for ( val = 0 ; val < count ; val + + ) {
index = fan_tach_ch [ val ] ;
aspeed_set_fan_tach_ch_enable ( priv - > regmap , index , true ) ;
priv - > fan_tach_present [ index ] = true ;
priv - > fan_tach_ch_source [ index ] = pwm_source ;
aspeed_set_fan_tach_ch_source ( priv - > regmap , index , pwm_source ) ;
}
}
2017-08-03 11:50:44 +03:00
static int
aspeed_pwm_cz_get_max_state ( struct thermal_cooling_device * tcdev ,
unsigned long * state )
{
struct aspeed_cooling_device * cdev = tcdev - > devdata ;
* state = cdev - > max_state ;
return 0 ;
}
static int
aspeed_pwm_cz_get_cur_state ( struct thermal_cooling_device * tcdev ,
unsigned long * state )
{
struct aspeed_cooling_device * cdev = tcdev - > devdata ;
* state = cdev - > cur_state ;
return 0 ;
}
static int
aspeed_pwm_cz_set_cur_state ( struct thermal_cooling_device * tcdev ,
unsigned long state )
{
struct aspeed_cooling_device * cdev = tcdev - > devdata ;
if ( state > cdev - > max_state )
return - EINVAL ;
cdev - > cur_state = state ;
cdev - > priv - > pwm_port_fan_ctrl [ cdev - > pwm_port ] =
cdev - > cooling_levels [ cdev - > cur_state ] ;
aspeed_set_pwm_port_fan_ctrl ( cdev - > priv , cdev - > pwm_port ,
cdev - > cooling_levels [ cdev - > cur_state ] ) ;
return 0 ;
}
static const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = {
. get_max_state = aspeed_pwm_cz_get_max_state ,
. get_cur_state = aspeed_pwm_cz_get_cur_state ,
. set_cur_state = aspeed_pwm_cz_set_cur_state ,
} ;
static int aspeed_create_pwm_cooling ( struct device * dev ,
struct device_node * child ,
struct aspeed_pwm_tacho_data * priv ,
u32 pwm_port , u8 num_levels )
{
int ret ;
struct aspeed_cooling_device * cdev ;
cdev = devm_kzalloc ( dev , sizeof ( * cdev ) , GFP_KERNEL ) ;
if ( ! cdev )
return - ENOMEM ;
cdev - > cooling_levels = devm_kzalloc ( dev , num_levels , GFP_KERNEL ) ;
if ( ! cdev - > cooling_levels )
return - ENOMEM ;
cdev - > max_state = num_levels - 1 ;
ret = of_property_read_u8_array ( child , " cooling-levels " ,
cdev - > cooling_levels ,
num_levels ) ;
if ( ret ) {
dev_err ( dev , " Property 'cooling-levels' cannot be read. \n " ) ;
return ret ;
}
2018-08-28 04:52:21 +03:00
snprintf ( cdev - > name , MAX_CDEV_NAME_LEN , " %pOFn%d " , child , pwm_port ) ;
2017-08-03 11:50:44 +03:00
2019-04-18 22:58:16 +03:00
cdev - > tcdev = devm_thermal_of_cooling_device_register ( dev , child ,
cdev - > name , cdev , & aspeed_pwm_cool_ops ) ;
2017-08-03 11:50:44 +03:00
if ( IS_ERR ( cdev - > tcdev ) )
return PTR_ERR ( cdev - > tcdev ) ;
cdev - > priv = priv ;
cdev - > pwm_port = pwm_port ;
priv - > cdev [ pwm_port ] = cdev ;
return 0 ;
}
2017-04-05 03:52:41 +03:00
static int aspeed_create_fan ( struct device * dev ,
struct device_node * child ,
struct aspeed_pwm_tacho_data * priv )
{
u8 * fan_tach_ch ;
u32 pwm_port ;
int ret , count ;
ret = of_property_read_u32 ( child , " reg " , & pwm_port ) ;
if ( ret )
return ret ;
2020-07-03 14:15:18 +03:00
if ( pwm_port > = ARRAY_SIZE ( pwm_port_params ) )
return - EINVAL ;
2017-04-05 03:52:41 +03:00
aspeed_create_pwm_port ( priv , ( u8 ) pwm_port ) ;
2017-08-03 11:50:44 +03:00
ret = of_property_count_u8_elems ( child , " cooling-levels " ) ;
if ( ret > 0 ) {
ret = aspeed_create_pwm_cooling ( dev , child , priv , pwm_port ,
ret ) ;
if ( ret )
return ret ;
}
2017-04-05 03:52:41 +03:00
count = of_property_count_u8_elems ( child , " aspeed,fan-tach-ch " ) ;
if ( count < 1 )
return - EINVAL ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
fan_tach_ch = devm_kcalloc ( dev , count , sizeof ( * fan_tach_ch ) ,
2017-04-05 03:52:41 +03:00
GFP_KERNEL ) ;
if ( ! fan_tach_ch )
return - ENOMEM ;
ret = of_property_read_u8_array ( child , " aspeed,fan-tach-ch " ,
fan_tach_ch , count ) ;
if ( ret )
return ret ;
aspeed_create_fan_tach_channel ( priv , fan_tach_ch , count , pwm_port ) ;
return 0 ;
}
2017-12-23 16:05:28 +03:00
static void aspeed_pwm_tacho_remove ( void * data )
{
struct aspeed_pwm_tacho_data * priv = data ;
reset_control_assert ( priv - > rst ) ;
}
2017-04-05 03:52:41 +03:00
static int aspeed_pwm_tacho_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct device_node * np , * child ;
struct aspeed_pwm_tacho_data * priv ;
void __iomem * regs ;
struct device * hwmon ;
struct clk * clk ;
int ret ;
np = dev - > of_node ;
2019-09-18 11:12:31 +03:00
regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2017-04-05 03:52:41 +03:00
if ( IS_ERR ( regs ) )
return PTR_ERR ( regs ) ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > regmap = devm_regmap_init ( dev , NULL , ( __force void * ) regs ,
& aspeed_pwm_tacho_regmap_config ) ;
if ( IS_ERR ( priv - > regmap ) )
return PTR_ERR ( priv - > regmap ) ;
2017-12-23 16:05:28 +03:00
priv - > rst = devm_reset_control_get_exclusive ( dev , NULL ) ;
if ( IS_ERR ( priv - > rst ) ) {
dev_err ( dev ,
" missing or invalid reset controller device tree entry " ) ;
return PTR_ERR ( priv - > rst ) ;
}
reset_control_deassert ( priv - > rst ) ;
ret = devm_add_action_or_reset ( dev , aspeed_pwm_tacho_remove , priv ) ;
if ( ret )
return ret ;
2017-04-05 03:52:41 +03:00
regmap_write ( priv - > regmap , ASPEED_PTCR_TACH_SOURCE , 0 ) ;
regmap_write ( priv - > regmap , ASPEED_PTCR_TACH_SOURCE_EXT , 0 ) ;
clk = devm_clk_get ( dev , NULL ) ;
if ( IS_ERR ( clk ) )
return - ENODEV ;
priv - > clk_freq = clk_get_rate ( clk ) ;
aspeed_set_clock_enable ( priv - > regmap , true ) ;
aspeed_set_clock_source ( priv - > regmap , 0 ) ;
aspeed_create_type ( priv ) ;
for_each_child_of_node ( np , child ) {
ret = aspeed_create_fan ( dev , child , priv ) ;
2017-08-03 11:50:44 +03:00
if ( ret ) {
of_node_put ( child ) ;
2017-04-05 03:52:41 +03:00
return ret ;
2017-08-03 11:50:44 +03:00
}
2017-04-05 03:52:41 +03:00
}
priv - > groups [ 0 ] = & pwm_dev_group ;
priv - > groups [ 1 ] = & fan_dev_group ;
priv - > groups [ 2 ] = NULL ;
hwmon = devm_hwmon_device_register_with_groups ( dev ,
" aspeed_pwm_tacho " ,
priv , priv - > groups ) ;
return PTR_ERR_OR_ZERO ( hwmon ) ;
}
static const struct of_device_id of_pwm_tacho_match_table [ ] = {
{ . compatible = " aspeed,ast2400-pwm-tacho " , } ,
{ . compatible = " aspeed,ast2500-pwm-tacho " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , of_pwm_tacho_match_table ) ;
static struct platform_driver aspeed_pwm_tacho_driver = {
. probe = aspeed_pwm_tacho_probe ,
. driver = {
. name = " aspeed_pwm_tacho " ,
. of_match_table = of_pwm_tacho_match_table ,
} ,
} ;
module_platform_driver ( aspeed_pwm_tacho_driver ) ;
MODULE_AUTHOR ( " Jaghathiswari Rankappagounder Natarajan <jaghu@google.com> " ) ;
MODULE_DESCRIPTION ( " ASPEED PWM and Fan Tacho device driver " ) ;
MODULE_LICENSE ( " GPL " ) ;