diff options
| -rw-r--r-- | drivers/thermal/armada_thermal.c | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index ceebabf45c53..f35289b1cea9 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c | |||
| @@ -47,6 +47,11 @@ | |||
| 47 | #define CONTROL0_OFFSET 0x0 | 47 | #define CONTROL0_OFFSET 0x0 |
| 48 | #define CONTROL1_OFFSET 0x4 | 48 | #define CONTROL1_OFFSET 0x4 |
| 49 | 49 | ||
| 50 | /* TSEN refers to the temperature sensors within the AP */ | ||
| 51 | #define CONTROL0_TSEN_START BIT(0) | ||
| 52 | #define CONTROL0_TSEN_RESET BIT(1) | ||
| 53 | #define CONTROL0_TSEN_ENABLE BIT(2) | ||
| 54 | |||
| 50 | struct armada_thermal_data; | 55 | struct armada_thermal_data; |
| 51 | 56 | ||
| 52 | /* Marvell EBU Thermal Sensor Dev Structure */ | 57 | /* Marvell EBU Thermal Sensor Dev Structure */ |
| @@ -66,10 +71,11 @@ struct armada_thermal_data { | |||
| 66 | bool (*is_valid)(struct armada_thermal_priv *); | 71 | bool (*is_valid)(struct armada_thermal_priv *); |
| 67 | 72 | ||
| 68 | /* Formula coeficients: temp = (b - m * reg) / div */ | 73 | /* Formula coeficients: temp = (b - m * reg) / div */ |
| 69 | unsigned long coef_b; | 74 | s64 coef_b; |
| 70 | unsigned long coef_m; | 75 | s64 coef_m; |
| 71 | unsigned long coef_div; | 76 | u32 coef_div; |
| 72 | bool inverted; | 77 | bool inverted; |
| 78 | bool signed_sample; | ||
| 73 | 79 | ||
| 74 | /* Register shift and mask to access the sensor temperature */ | 80 | /* Register shift and mask to access the sensor temperature */ |
| 75 | unsigned int temp_shift; | 81 | unsigned int temp_shift; |
| @@ -155,6 +161,18 @@ static void armada380_init_sensor(struct platform_device *pdev, | |||
| 155 | } | 161 | } |
| 156 | } | 162 | } |
| 157 | 163 | ||
| 164 | static void armada_ap806_init_sensor(struct platform_device *pdev, | ||
| 165 | struct armada_thermal_priv *priv) | ||
| 166 | { | ||
| 167 | u32 reg; | ||
| 168 | |||
| 169 | reg = readl_relaxed(priv->control0); | ||
| 170 | reg &= ~CONTROL0_TSEN_RESET; | ||
| 171 | reg |= CONTROL0_TSEN_START | CONTROL0_TSEN_ENABLE; | ||
| 172 | writel(reg, priv->control0); | ||
| 173 | msleep(10); | ||
| 174 | } | ||
| 175 | |||
| 158 | static bool armada_is_valid(struct armada_thermal_priv *priv) | 176 | static bool armada_is_valid(struct armada_thermal_priv *priv) |
| 159 | { | 177 | { |
| 160 | u32 reg = readl_relaxed(priv->status); | 178 | u32 reg = readl_relaxed(priv->status); |
| @@ -163,11 +181,11 @@ static bool armada_is_valid(struct armada_thermal_priv *priv) | |||
| 163 | } | 181 | } |
| 164 | 182 | ||
| 165 | static int armada_get_temp(struct thermal_zone_device *thermal, | 183 | static int armada_get_temp(struct thermal_zone_device *thermal, |
| 166 | int *temp) | 184 | int *temp) |
| 167 | { | 185 | { |
| 168 | struct armada_thermal_priv *priv = thermal->devdata; | 186 | struct armada_thermal_priv *priv = thermal->devdata; |
| 169 | unsigned long reg; | 187 | u32 reg, div; |
| 170 | unsigned long m, b, div; | 188 | s64 sample, b, m; |
| 171 | 189 | ||
| 172 | /* Valid check */ | 190 | /* Valid check */ |
| 173 | if (priv->data->is_valid && !priv->data->is_valid(priv)) { | 191 | if (priv->data->is_valid && !priv->data->is_valid(priv)) { |
| @@ -178,6 +196,11 @@ static int armada_get_temp(struct thermal_zone_device *thermal, | |||
| 178 | 196 | ||
| 179 | reg = readl_relaxed(priv->status); | 197 | reg = readl_relaxed(priv->status); |
| 180 | reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask; | 198 | reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask; |
| 199 | if (priv->data->signed_sample) | ||
| 200 | /* The most significant bit is the sign bit */ | ||
| 201 | sample = sign_extend32(reg, fls(priv->data->temp_mask) - 1); | ||
| 202 | else | ||
| 203 | sample = reg; | ||
| 181 | 204 | ||
| 182 | /* Get formula coeficients */ | 205 | /* Get formula coeficients */ |
| 183 | b = priv->data->coef_b; | 206 | b = priv->data->coef_b; |
| @@ -185,9 +208,10 @@ static int armada_get_temp(struct thermal_zone_device *thermal, | |||
| 185 | div = priv->data->coef_div; | 208 | div = priv->data->coef_div; |
| 186 | 209 | ||
| 187 | if (priv->data->inverted) | 210 | if (priv->data->inverted) |
| 188 | *temp = ((m * reg) - b) / div; | 211 | *temp = div_s64((m * sample) - b, div); |
| 189 | else | 212 | else |
| 190 | *temp = (b - (m * reg)) / div; | 213 | *temp = div_s64(b - (m * sample), div); |
| 214 | |||
| 191 | return 0; | 215 | return 0; |
| 192 | } | 216 | } |
| 193 | 217 | ||
| @@ -199,8 +223,8 @@ static const struct armada_thermal_data armadaxp_data = { | |||
| 199 | .init_sensor = armadaxp_init_sensor, | 223 | .init_sensor = armadaxp_init_sensor, |
| 200 | .temp_shift = 10, | 224 | .temp_shift = 10, |
| 201 | .temp_mask = 0x1ff, | 225 | .temp_mask = 0x1ff, |
| 202 | .coef_b = 3153000000UL, | 226 | .coef_b = 3153000000ULL, |
| 203 | .coef_m = 10000000UL, | 227 | .coef_m = 10000000ULL, |
| 204 | .coef_div = 13825, | 228 | .coef_div = 13825, |
| 205 | }; | 229 | }; |
| 206 | 230 | ||
| @@ -210,8 +234,8 @@ static const struct armada_thermal_data armada370_data = { | |||
| 210 | .is_valid_bit = BIT(9), | 234 | .is_valid_bit = BIT(9), |
| 211 | .temp_shift = 10, | 235 | .temp_shift = 10, |
| 212 | .temp_mask = 0x1ff, | 236 | .temp_mask = 0x1ff, |
| 213 | .coef_b = 3153000000UL, | 237 | .coef_b = 3153000000ULL, |
| 214 | .coef_m = 10000000UL, | 238 | .coef_m = 10000000ULL, |
| 215 | .coef_div = 13825, | 239 | .coef_div = 13825, |
| 216 | }; | 240 | }; |
| 217 | 241 | ||
| @@ -221,8 +245,8 @@ static const struct armada_thermal_data armada375_data = { | |||
| 221 | .is_valid_bit = BIT(10), | 245 | .is_valid_bit = BIT(10), |
| 222 | .temp_shift = 0, | 246 | .temp_shift = 0, |
| 223 | .temp_mask = 0x1ff, | 247 | .temp_mask = 0x1ff, |
| 224 | .coef_b = 3171900000UL, | 248 | .coef_b = 3171900000ULL, |
| 225 | .coef_m = 10000000UL, | 249 | .coef_m = 10000000ULL, |
| 226 | .coef_div = 13616, | 250 | .coef_div = 13616, |
| 227 | .needs_control0 = true, | 251 | .needs_control0 = true, |
| 228 | }; | 252 | }; |
| @@ -233,12 +257,26 @@ static const struct armada_thermal_data armada380_data = { | |||
| 233 | .is_valid_bit = BIT(10), | 257 | .is_valid_bit = BIT(10), |
| 234 | .temp_shift = 0, | 258 | .temp_shift = 0, |
| 235 | .temp_mask = 0x3ff, | 259 | .temp_mask = 0x3ff, |
| 236 | .coef_b = 1172499100UL, | 260 | .coef_b = 1172499100ULL, |
| 237 | .coef_m = 2000096UL, | 261 | .coef_m = 2000096ULL, |
| 238 | .coef_div = 4201, | 262 | .coef_div = 4201, |
| 239 | .inverted = true, | 263 | .inverted = true, |
| 240 | }; | 264 | }; |
| 241 | 265 | ||
| 266 | static const struct armada_thermal_data armada_ap806_data = { | ||
| 267 | .is_valid = armada_is_valid, | ||
| 268 | .init_sensor = armada_ap806_init_sensor, | ||
| 269 | .is_valid_bit = BIT(16), | ||
| 270 | .temp_shift = 0, | ||
| 271 | .temp_mask = 0x3ff, | ||
| 272 | .coef_b = -150000LL, | ||
| 273 | .coef_m = 423ULL, | ||
| 274 | .coef_div = 1, | ||
| 275 | .inverted = true, | ||
| 276 | .signed_sample = true, | ||
| 277 | .needs_control0 = true, | ||
| 278 | }; | ||
| 279 | |||
| 242 | static const struct of_device_id armada_thermal_id_table[] = { | 280 | static const struct of_device_id armada_thermal_id_table[] = { |
| 243 | { | 281 | { |
| 244 | .compatible = "marvell,armadaxp-thermal", | 282 | .compatible = "marvell,armadaxp-thermal", |
| @@ -257,6 +295,10 @@ static const struct of_device_id armada_thermal_id_table[] = { | |||
| 257 | .data = &armada380_data, | 295 | .data = &armada380_data, |
| 258 | }, | 296 | }, |
| 259 | { | 297 | { |
| 298 | .compatible = "marvell,armada-ap806-thermal", | ||
| 299 | .data = &armada_ap806_data, | ||
| 300 | }, | ||
| 301 | { | ||
| 260 | /* sentinel */ | 302 | /* sentinel */ |
| 261 | }, | 303 | }, |
| 262 | }; | 304 | }; |
