From 0301f9b2bc948069aaad2899e15e6c94a07ca818 Mon Sep 17 00:00:00 2001 From: Ayushi Smriti Date: Mon, 2 Mar 2020 22:51:46 +0530 Subject: [PATCH] pwm and tach driver changes for ast2600 This commit includes additions/changes in driver code to support 9 PWM outputs and 9 fan tachometer inputs for ast2600 Signed-off-by: Ayushi Smriti --- drivers/hwmon/aspeed-g6-pwm-tacho.c | 328 +++++++++++++++------------- 1 file changed, 171 insertions(+), 157 deletions(-) diff --git a/drivers/hwmon/aspeed-g6-pwm-tacho.c b/drivers/hwmon/aspeed-g6-pwm-tacho.c index 1894f6ad5edb..1ff788bf1133 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tacho.c +++ b/drivers/hwmon/aspeed-g6-pwm-tacho.c @@ -64,6 +64,8 @@ #define PWM_RISING_FALLING_BIT (8) //pwm falling point bit [7:0] #define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0] +#define DEF_PWM_PERIOD 0xff + #define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register #define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08) #define TACHO_IER BIT(31) //enable tacho interrupt @@ -72,8 +74,7 @@ #define TACHO_ENABLE BIT(28) //{enable tacho} #define TACHO_DEBOUNCE_BIT (26) //{tacho de-bounce} #define TACHO_DEBOUNCE_MASK (0x3 << 26) //{tacho de-bounce} -#define TECHIO_EDGE_MASK (0x3 << 24) //tacho edge} -#define TECHIO_EDGE_BIT (24) //tacho edge} +#define TACHIO_EDGE_BIT (24) /*tacho edge}*/ #define TACHO_CLK_DIV_T_MASK (0xf << 20) #define TACHO_CLK_DIV_BIT (20) #define TACHO_THRESHOLD_MASK (0xfffff) //tacho threshold bit @@ -102,211 +103,183 @@ #define MAX_CDEV_NAME_LEN 16 +#define DEFAULT_TARGET_PWM_FREQ 25000 +#define DEFAULT_MIN_RPM 2900 + +#define PWM_FALLING_VALUE 0xff + struct aspeed_pwm_channel_params { + int target_freq; + int pwm_freq; int load_wdt_rising_falling_pt; int load_wdt_selection; //0: rising , 1: falling int load_wdt_enable; int duty_sync_enable; int invert_pin; - u8 divide_h; - u8 divide_l; - u8 period; u8 rising; u8 falling; }; static struct aspeed_pwm_channel_params default_pwm_params[] = { [0] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 1, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [1] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [2] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [3] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [4] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [5] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [6] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [7] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [8] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [9] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [10] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [11] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [12] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [13] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [14] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, [15] = { + .target_freq = 25000, .load_wdt_rising_falling_pt = 0x10, .load_wdt_selection = 0, .load_wdt_enable = 0, .duty_sync_enable = 0, .invert_pin = 0, - .divide_h = 0x5, - .divide_l = 0x6, - .period = 0x13, //5% ~~ .rising = 0x00, - .falling = 0x0a, + .falling = PWM_FALLING_VALUE, }, }; @@ -318,125 +291,146 @@ static struct aspeed_pwm_channel_params default_pwm_params[] = { * 11: reserved. */ +#define F2F_EDGES 0x00 +#define R2R_EDGES 0x01 +#define BOTH_EDGES 0x02 + struct aspeed_tacho_channel_params { + u32 min_rpm; int limited_inverse; u16 threshold; u8 tacho_edge; u8 tacho_debounce; - u8 divide; + u32 divide; }; static struct aspeed_tacho_channel_params default_tacho_params[] = { [0] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [1] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [2] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [3] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [4] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [5] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [6] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [7] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [8] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [9] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [10] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [11] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [12] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [13] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [14] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, [15] = { + .min_rpm = 2900, .limited_inverse = 0, .threshold = 0, - .tacho_edge = 0, + .tacho_edge = F2F_EDGES, .tacho_debounce = 0, .divide = 8, }, @@ -501,29 +495,28 @@ static void aspeed_set_pwm_channel_enable(struct regmap *regmap, u8 pwm_channel, static void aspeed_set_fan_tach_ch_enable(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch, bool enable) { - u32 i = 0, j; + u32 i; u32 divide_val = 0; + u32 target_div; u32 reg_value = 0; if(enable) { - //4 ^ n - //check pwm clk and to change tacho devide 25KZ - for(i = 0; i < 12; i++) { + /*RPM calculation as per ast2600 datasheet*/ + target_div = (priv->clk_freq * 60 / priv->tacho_channel[fan_tach_ch].min_rpm * 2) / (0xfffff + 1); + if (target_div) { + for (i = 0; i < 12; i++) { + divide_val = BIT(i) * BIT(i); + if (divide_val > target_div) + break; + } + } else { divide_val = 1; - for (j = 1; j <= i; j++) - divide_val *= 4; -// printk("i : %d , priv->clk_freq/divide_val %d ",i, priv->clk_freq/divide_val); - if((priv->clk_freq/divide_val) < 250000) - break; } - i--; - divide_val = ((1 << i) * (1 << i)); -// printk("tacho divide_val %d , i %x max tacho clk %d \n", divide_val, i, priv->clk_freq / divide_val); - priv->tacho_channel[fan_tach_ch].divide = i; + priv->tacho_channel[fan_tach_ch].divide = divide_val; reg_value = TACHO_ENABLE | - (priv->tacho_channel[fan_tach_ch].tacho_edge << TECHIO_EDGE_BIT) | - (priv->tacho_channel[fan_tach_ch].divide << TACHO_CLK_DIV_BIT) | + (priv->tacho_channel[fan_tach_ch].tacho_edge << TACHIO_EDGE_BIT) | + (i << TACHO_CLK_DIV_BIT) | (priv->tacho_channel[fan_tach_ch].tacho_debounce << TACHO_DEBOUNCE_BIT); if(priv->tacho_channel[fan_tach_ch].limited_inverse) @@ -541,14 +534,28 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p u8 index, u8 fan_ctrl) { u32 duty_value, ctrl_value; + u32 div_h, div_l, cal_freq; if (fan_ctrl == 0) { aspeed_set_pwm_channel_enable(priv->regmap, index, false); } else { - duty_value = (priv->pwm_channel[index].period << PWM_PERIOD_BIT) | - (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT); + cal_freq = priv->clk_freq / (DEF_PWM_PERIOD + 1); + /*calculate for target frequence*/ + for (div_l = 0; div_l < 0x100; div_l++) { + for (div_h = 0; div_h < 0x10; div_h++) { + if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq) + break; + } + if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq) + break; + } + + priv->pwm_channel[index].pwm_freq = cal_freq / (BIT(div_h) * (div_l + 1)); - ctrl_value = (priv->pwm_channel[index].divide_h << 8) | priv->pwm_channel[index].divide_l; + ctrl_value = (div_h << 8) | div_l; + + duty_value = (DEF_PWM_PERIOD << PWM_PERIOD_BIT) | + (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT); if (priv->pwm_channel[index].load_wdt_enable) { ctrl_value |= PWM_DUTY_LOAD_AS_WDT_EN; @@ -568,13 +575,11 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p } } -#define BOTH_EDGES 0x02 /* 10b */ - static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch) { u32 raw_data, tach_div, clk_source, val; - u8 mode, both; + u8 multiplier = 2; int i, retries = 3; for(i = 0; i < retries; i++) { @@ -587,22 +592,15 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv, if(raw_data == 0xfffff) return 0; - tach_div = priv->tacho_channel[fan_tach_ch].divide; - /* - * We need the mode to determine if the raw_data is double (from - * counting both edges). - */ - mode = priv->tacho_channel[fan_tach_ch].tacho_edge; - both = (mode & BOTH_EDGES) ? 1 : 0; -// printk("clk %ld, raw_data %x , tach_div %x both %x \n", priv->clk_freq, raw_data, tach_div, both); + raw_data += 1; + tach_div = raw_data * (priv->tacho_channel[fan_tach_ch].divide) * (multiplier); - tach_div = (tach_div * 2) * (0x1 << both); clk_source = priv->clk_freq; if (raw_data == 0) return 0; - return (clk_source * 60) / (2 * raw_data * tach_div); + return (clk_source / tach_div * 60); } @@ -614,19 +612,27 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, int ret; struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); long fan_ctrl; + u8 org_falling = priv->pwm_channel[index].falling; ret = kstrtol(buf, 10, &fan_ctrl); if (ret != 0) return ret; - if (fan_ctrl < 0 || fan_ctrl > priv->pwm_channel[index].period) + if (fan_ctrl < 0 || fan_ctrl > DEF_PWM_PERIOD) return -EINVAL; if (priv->pwm_channel[index].falling == fan_ctrl) return count; priv->pwm_channel[index].falling = fan_ctrl; - aspeed_set_pwm_channel_fan_ctrl(priv, index, fan_ctrl); + + if (fan_ctrl == 0) + aspeed_set_pwm_channel_enable(priv->regmap, index, false); + else + regmap_update_bits(priv->regmap, ASPEED_PWM_DUTY_CYCLE_CH(index), GENMASK(15, 8), (fan_ctrl << PWM_RISING_FALLING_BIT)); + + if (org_falling == 0) + aspeed_set_pwm_channel_enable(priv->regmap, index, true); return count; } @@ -678,40 +684,39 @@ static umode_t fan_dev_is_visible(struct kobject *kobj, return a->mode; } -static SENSOR_DEVICE_ATTR(pwm0, 0644, - show_pwm, set_pwm, 0); static SENSOR_DEVICE_ATTR(pwm1, 0644, - show_pwm, set_pwm, 1); + show_pwm, set_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, 0644, - show_pwm, set_pwm, 2); + show_pwm, set_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, 0644, - show_pwm, set_pwm, 3); + show_pwm, set_pwm, 2); static SENSOR_DEVICE_ATTR(pwm4, 0644, - show_pwm, set_pwm, 4); + show_pwm, set_pwm, 3); static SENSOR_DEVICE_ATTR(pwm5, 0644, - show_pwm, set_pwm, 5); + show_pwm, set_pwm, 4); static SENSOR_DEVICE_ATTR(pwm6, 0644, - show_pwm, set_pwm, 6); + show_pwm, set_pwm, 5); static SENSOR_DEVICE_ATTR(pwm7, 0644, - show_pwm, set_pwm, 7); + show_pwm, set_pwm, 6); static SENSOR_DEVICE_ATTR(pwm8, 0644, - show_pwm, set_pwm, 8); + show_pwm, set_pwm, 7); static SENSOR_DEVICE_ATTR(pwm9, 0644, - show_pwm, set_pwm, 9); + show_pwm, set_pwm, 8); static SENSOR_DEVICE_ATTR(pwm10, 0644, - show_pwm, set_pwm, 10); + show_pwm, set_pwm, 9); static SENSOR_DEVICE_ATTR(pwm11, 0644, - show_pwm, set_pwm, 11); + show_pwm, set_pwm, 10); static SENSOR_DEVICE_ATTR(pwm12, 0644, - show_pwm, set_pwm, 12); + show_pwm, set_pwm, 11); static SENSOR_DEVICE_ATTR(pwm13, 0644, - show_pwm, set_pwm, 13); + show_pwm, set_pwm, 12); static SENSOR_DEVICE_ATTR(pwm14, 0644, - show_pwm, set_pwm, 14); + show_pwm, set_pwm, 13); static SENSOR_DEVICE_ATTR(pwm15, 0644, + show_pwm, set_pwm, 14); +static SENSOR_DEVICE_ATTR(pwm16, 0644, show_pwm, set_pwm, 15); static struct attribute *pwm_dev_attrs[] = { - &sensor_dev_attr_pwm0.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, @@ -727,6 +732,7 @@ static struct attribute *pwm_dev_attrs[] = { &sensor_dev_attr_pwm13.dev_attr.attr, &sensor_dev_attr_pwm14.dev_attr.attr, &sensor_dev_attr_pwm15.dev_attr.attr, + &sensor_dev_attr_pwm16.dev_attr.attr, NULL, }; @@ -735,40 +741,39 @@ static const struct attribute_group pwm_dev_group = { .is_visible = pwm_is_visible, }; -static SENSOR_DEVICE_ATTR(fan0_input, 0444, - show_rpm, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_input, 0444, - show_rpm, NULL, 1); + show_rpm, NULL, 0); static SENSOR_DEVICE_ATTR(fan2_input, 0444, - show_rpm, NULL, 2); + show_rpm, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, 0444, - show_rpm, NULL, 3); + show_rpm, NULL, 2); static SENSOR_DEVICE_ATTR(fan4_input, 0444, - show_rpm, NULL, 4); + show_rpm, NULL, 3); static SENSOR_DEVICE_ATTR(fan5_input, 0444, - show_rpm, NULL, 5); + show_rpm, NULL, 4); static SENSOR_DEVICE_ATTR(fan6_input, 0444, - show_rpm, NULL, 6); + show_rpm, NULL, 5); static SENSOR_DEVICE_ATTR(fan7_input, 0444, - show_rpm, NULL, 7); + show_rpm, NULL, 6); static SENSOR_DEVICE_ATTR(fan8_input, 0444, - show_rpm, NULL, 8); + show_rpm, NULL, 7); static SENSOR_DEVICE_ATTR(fan9_input, 0444, - show_rpm, NULL, 9); + show_rpm, NULL, 8); static SENSOR_DEVICE_ATTR(fan10_input, 0444, - show_rpm, NULL, 10); + show_rpm, NULL, 9); static SENSOR_DEVICE_ATTR(fan11_input, 0444, - show_rpm, NULL, 11); + show_rpm, NULL, 10); static SENSOR_DEVICE_ATTR(fan12_input, 0444, - show_rpm, NULL, 12); + show_rpm, NULL, 11); static SENSOR_DEVICE_ATTR(fan13_input, 0444, - show_rpm, NULL, 13); + show_rpm, NULL, 12); static SENSOR_DEVICE_ATTR(fan14_input, 0444, - show_rpm, NULL, 14); + show_rpm, NULL, 13); static SENSOR_DEVICE_ATTR(fan15_input, 0444, + show_rpm, NULL, 14); +static SENSOR_DEVICE_ATTR(fan16_input, 0444, show_rpm, NULL, 15); static struct attribute *fan_dev_attrs[] = { - &sensor_dev_attr_fan0_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, @@ -784,6 +789,7 @@ static struct attribute *fan_dev_attrs[] = { &sensor_dev_attr_fan13_input.dev_attr.attr, &sensor_dev_attr_fan14_input.dev_attr.attr, &sensor_dev_attr_fan15_input.dev_attr.attr, + &sensor_dev_attr_fan16_input.dev_attr.attr, NULL }; @@ -802,14 +808,14 @@ static void aspeed_create_pwm_channel(struct aspeed_pwm_tachometer_data *priv, } static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tachometer_data *priv, - u8 *fan_tach_ch, - int count) + u8 *fan_tach_ch, int count, u32 min_rpm) { u8 val, index; for (val = 0; val < count; val++) { index = fan_tach_ch[val]; priv->fan_tach_present[index] = true; + priv->tacho_channel[index].min_rpm = min_rpm; aspeed_set_fan_tach_ch_enable(priv, index, true); } } @@ -906,13 +912,19 @@ static int aspeed_pwm_create_fan(struct device *dev, struct aspeed_pwm_tachometer_data *priv) { u8 *fan_tach_ch; + u32 fan_min_rpm; u32 pwm_channel; + u32 target_pwm_freq; int ret, count; ret = of_property_read_u32(child, "reg", &pwm_channel); if (ret) return ret; + ret = of_property_read_u32(child, "aspeed,target_pwm", &target_pwm_freq); + if (ret) + target_pwm_freq = DEFAULT_TARGET_PWM_FREQ; + aspeed_create_pwm_channel(priv, (u8)pwm_channel); ret = of_property_count_u8_elems(child, "cooling-levels"); @@ -935,9 +947,11 @@ static int aspeed_pwm_create_fan(struct device *dev, fan_tach_ch, count); if (ret) return ret; + ret = of_property_read_u32(child, "aspeed,min_rpm", &fan_min_rpm); + if (ret) + fan_min_rpm = DEFAULT_MIN_RPM; - aspeed_create_fan_tach_channel(priv, fan_tach_ch, count); - + aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, fan_min_rpm); return 0; } -- 2.17.1