AleX Pelosi | 78a4bea | 2020-09-01 19:02:24 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 2 | /* |
AleX Pelosi | 78a4bea | 2020-09-01 19:02:24 -0700 | [diff] [blame] | 3 | * Copyright 2019 Google, LLC |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | */ |
| 15 | |
| 16 | #ifndef MAX_M5_H_ |
| 17 | #define MAX_M5_H_ |
| 18 | |
| 19 | #include "max1720x_battery.h" |
Jenny Ho | c6bc588 | 2021-02-18 09:21:21 +0800 | [diff] [blame] | 20 | #include "max_m5_reg.h" |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 21 | |
| 22 | #define MAX_M5_I2C_ADDR 0x6C |
| 23 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 24 | |
| 25 | /* change to 1 or 0 to load FG model with default parameters on startup */ |
| 26 | #define MAX_M5_LOAD_MODEL_DISABLED -1 |
| 27 | #define MAX_M5_LOAD_MODEL_IDLE 0 |
Jenny Ho | ba58861 | 2023-11-29 17:59:58 +0800 | [diff] [blame] | 28 | #define MAX_M5_LOAD_MODEL_REQUEST 1 |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 29 | |
| 30 | #define MAX_M5_FG_MODEL_START 0x80 |
| 31 | #define MAX_M5_FG_MODEL_SIZE 48 |
| 32 | |
| 33 | #define MAX_M5_UNLOCK_EXTRA_CONFIG 0x60 |
| 34 | #define MAX_M5_UNLOCK_EXTRA_CONFIG_UNLOCK_CODE 0x80 |
| 35 | #define MAX_M5_UNLOCK_EXTRA_CONFIG_LOCK_CODE 0x00 |
| 36 | |
| 37 | #define MAX_M5_UNLOCK_MODEL_ACCESS 0x62 |
| 38 | #define MAX_M5_MODEL_ACCESS_UNLOCK_CODE 0xc459 |
| 39 | #define MAX_M5_MODEL_ACCESS_LOCK_CODE 0x0000 |
| 40 | #define MAX_M5_MODEL_ACCESS_LOCK_OK 0xFFFF |
| 41 | |
| 42 | #define MAX_M5_TCURVE 0xB9 |
Jenny Ho | b5e49d6 | 2024-03-27 22:29:27 +0800 | [diff] [blame] | 43 | #define MAX_M5_VFOCV 0xFB |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 44 | #define MAX_M5_VFSOC 0xFF |
| 45 | |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 46 | #define MAX_M5_COMMAND 0x60 |
| 47 | #define MAX_M5_COMMAND_HARDWARE_RESET 0x000F |
| 48 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 49 | /* model version */ |
| 50 | #define MAX_M5_INVALID_VERSION -1 |
| 51 | |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 52 | #define MAX_M5_RECAL_MAX_ROUNDS 3 |
| 53 | |
Jenny Ho | 2154dcc | 2023-07-27 07:52:04 +0800 | [diff] [blame] | 54 | #define MAX_M5_RETRY_TIMES 3 |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 55 | |
Jenny Ho | 8c1268f | 2023-12-23 03:00:05 +0800 | [diff] [blame] | 56 | #define MAX_M5_COTRIM 0xEB |
| 57 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 58 | /** ------------------------------------------------------------------------ */ |
| 59 | |
| 60 | /* |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 61 | * Custom parameters are updated while the device is runnig. |
| 62 | * NOTE: a subset (model_state_save) is saved to permanent storage every "n" |
| 63 | * cycles and restored when the model is reloaded (usually on POR). |
| 64 | * TODO: handle switching between RC1 and RC2 model types. |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 65 | */ |
| 66 | struct max_m5_custom_parameters { |
| 67 | u16 iavg_empty; /* WV */ |
| 68 | u16 relaxcfg; |
| 69 | u16 learncfg; |
| 70 | u16 config; |
| 71 | u16 config2; |
| 72 | u16 fullsocthr; |
| 73 | u16 fullcaprep; /* WV */ |
| 74 | u16 designcap; |
| 75 | u16 dpacc; /* WV */ |
| 76 | u16 dqacc; /* WV */ |
| 77 | u16 fullcapnom; /* WV */ |
| 78 | u16 v_empty; |
| 79 | u16 qresidual00; /* WV */ |
| 80 | u16 qresidual10; /* WV */ |
| 81 | u16 qresidual20; /* WV */ |
| 82 | u16 qresidual30; /* WV */ |
| 83 | u16 rcomp0; /* WV */ |
| 84 | u16 tempco; /* WV */ |
| 85 | u16 ichgterm; |
| 86 | u16 tgain; |
| 87 | u16 toff; |
| 88 | u16 tcurve; /* write to 0x00B9 */ |
| 89 | u16 misccfg; /* 0x9d0 for internal current sense, 0x8d0 external */ |
| 90 | |
| 91 | u16 atrate; |
| 92 | u16 convgcfg; |
| 93 | u16 filtercfg; /* write to 0x0029 */ |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 94 | u16 taskperiod; |
Jenny Ho | e8b877c | 2022-01-10 03:27:53 +0800 | [diff] [blame] | 95 | u16 cgain; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 96 | } __attribute__((packed)); |
| 97 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 98 | /* this is what is saved and restored to/from GMSR */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 99 | struct model_state_save { |
| 100 | u16 rcomp0; |
| 101 | u16 tempco; |
| 102 | u16 fullcaprep; |
| 103 | u16 cycles; |
| 104 | u16 fullcapnom; |
| 105 | u16 qresidual00; |
| 106 | u16 qresidual10; |
| 107 | u16 qresidual20; |
| 108 | u16 qresidual30; |
Jenny Ho | dc6c8a0 | 2021-10-29 06:14:33 +0800 | [diff] [blame] | 109 | u16 cv_mixcap; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 110 | u16 halftime; |
Jenny Ho | f77200e | 2021-05-31 17:32:55 +0800 | [diff] [blame] | 111 | u8 crc; |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 112 | } __attribute__((packed)); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 113 | |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 114 | struct max_m5_recalibration_data { |
| 115 | int state; |
| 116 | int rounds; |
| 117 | int base_cycle_reg; |
| 118 | u16 target_cap; |
| 119 | struct mutex lock; |
| 120 | }; |
| 121 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 122 | struct max_m5_data { |
| 123 | struct device *dev; |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 124 | struct max17x0x_regmap *regmap; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 125 | int cap_lsb; /* b/177099997 */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 126 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 127 | /* initial parameters are in device tree they are also learned */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 128 | struct max_m5_custom_parameters parameters; |
| 129 | u16 cycles; |
Jenny Ho | dc6c8a0 | 2021-10-29 06:14:33 +0800 | [diff] [blame] | 130 | u16 cv_mixcap; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 131 | u16 halftime; |
| 132 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 133 | int custom_model_size; |
| 134 | u16 *custom_model; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 135 | u32 model_version; |
Jenny Ho | 7c691da | 2021-05-19 06:15:54 +0800 | [diff] [blame] | 136 | bool force_reset_model_data; |
Jenny Ho | 2154dcc | 2023-07-27 07:52:04 +0800 | [diff] [blame] | 137 | int load_retry; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 138 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 139 | /* to/from GMSR */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 140 | struct model_state_save model_save; |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 141 | |
| 142 | /* recalibration */ |
| 143 | struct max_m5_recalibration_data recal; |
| 144 | }; |
| 145 | |
| 146 | enum max_m5_re_cal_state { |
| 147 | RE_CAL_STATE_IDLE = 0, |
| 148 | RE_CAL_STATE_FG_RESET = 1, |
| 149 | RE_CAL_STATE_LEARNING = 2, |
| 150 | }; |
| 151 | |
| 152 | enum max_m5_re_cal_algo { |
| 153 | RE_CAL_ALGO_0 = 0, |
| 154 | RE_CAL_ALGO_1 = 1, |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 155 | }; |
| 156 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 157 | /** ------------------------------------------------------------------------ */ |
| 158 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 159 | int max_m5_model_read_version(const struct max_m5_data *m5_data); |
Spade Lee | 5c3e620 | 2024-03-29 08:22:59 +0000 | [diff] [blame] | 160 | int max_m5_model_write_version(const struct max_m5_data *m5_data, int version); |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 161 | int max_m5_model_get_cap_lsb(const struct max_m5_data *m5_data); |
Jenny Ho | c6bc588 | 2021-02-18 09:21:21 +0800 | [diff] [blame] | 162 | int max_m5_reset_state_data(struct max_m5_data *m5_data); |
| 163 | int max_m5_needs_reset_model_data(const struct max_m5_data *m5_data); |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 164 | int max_m5_recal_state(const struct max_m5_data *m5_data); |
| 165 | int max_m5_recal_cycle(const struct max_m5_data *m5_data); |
| 166 | int max_m5_recalibration(struct max_m5_data *m5_data, int algo, u16 cap); |
| 167 | int max_m5_check_recal_state(struct max_m5_data *m5_data, int algo, u16 eeprom_cycle); |
| 168 | int m5_init_custom_parameters(struct device *dev, struct max_m5_data *m5_data, |
| 169 | struct device_node *node); |
Jenny Ho | 8923027 | 2023-09-01 18:16:58 +0800 | [diff] [blame] | 170 | int max_m5_get_designcap(const struct max_m5_data *m5_data); |
Jenny Ho | a805e0f | 2023-12-20 17:05:59 +0800 | [diff] [blame] | 171 | int max_m5_model_lock(struct regmap *regmap, bool enabled); |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 172 | |
| 173 | /* |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 174 | * max_m5 might use the low 8 bits of devname to keep the model version number |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 175 | * - 0 not M5, !=0 M5 |
| 176 | */ |
| 177 | static inline int max_m5_check_devname(u16 devname) |
| 178 | { |
Jenny Ho | d5def24 | 2021-04-28 10:51:58 +0800 | [diff] [blame] | 179 | const u16 radix = devname >> 8; |
| 180 | |
| 181 | return radix == 0x62 || radix == 0x63; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | /* b/177099997, handle TaskConfig = 351 */ |
| 185 | static inline int max_m5_cap_lsb(const struct max_m5_data *m5_data) |
| 186 | { |
| 187 | return m5_data ? (1 << m5_data->cap_lsb) : 1; |
| 188 | } |
| 189 | |
| 190 | static inline int max_m5_fg_model_version(const struct max_m5_data *m5_data) |
| 191 | { |
| 192 | return m5_data ? m5_data->model_version : MAX_M5_INVALID_VERSION; |
| 193 | } |
| 194 | |
| 195 | /* |
| 196 | * 0 reload, != 0 no reload |
| 197 | * always reload when the model version is not specified |
| 198 | */ |
| 199 | static inline int max_m5_fg_model_check_version(const struct max_m5_data *m5_data) |
| 200 | { |
| 201 | if (!m5_data) |
| 202 | return 1; |
| 203 | if (m5_data->model_version == MAX_M5_INVALID_VERSION) |
| 204 | return 0; |
| 205 | |
| 206 | return max_m5_model_read_version(m5_data) == m5_data->model_version; |
| 207 | } |
| 208 | |
| 209 | /** ------------------------------------------------------------------------ */ |
| 210 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 211 | int max_m5_regmap_init(struct max17x0x_regmap *regmap, |
| 212 | struct i2c_client *primary); |
| 213 | |
| 214 | void *max_m5_init_data(struct device *dev, struct device_node *batt_node, |
| 215 | struct max17x0x_regmap *regmap); |
Jenny Ho | 6a74c7a | 2023-03-16 05:47:15 +0800 | [diff] [blame] | 216 | void max_m5_free_data(struct max_m5_data *m5_data); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 217 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 218 | int max_m5_load_state_data(struct max_m5_data *m5_data); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 219 | int max_m5_save_state_data(struct max_m5_data *m5_data); |
| 220 | |
| 221 | /* read state from the gauge */ |
| 222 | int max_m5_model_read_state(struct max_m5_data *m5_data); |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 223 | int max_m5_model_check_state(struct max_m5_data *m5_data); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 224 | |
| 225 | /* load model to gauge */ |
| 226 | int max_m5_load_gauge_model(struct max_m5_data *m5_data); |
| 227 | |
AleX Pelosi | fed7fb1 | 2020-11-10 01:22:22 -0800 | [diff] [blame] | 228 | int max_m5_fixup_outliers(struct max1720x_drift_data *ddata, |
| 229 | struct max_m5_data *m5_data); |
| 230 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 231 | ssize_t max_m5_model_state_cstr(char *buf, int max, |
| 232 | struct max_m5_data *m5_data); |
| 233 | int max_m5_model_state_sscan(struct max_m5_data *m5_data, const char *buf, |
| 234 | int max); |
| 235 | int max_m5_fg_model_sscan(struct max_m5_data *m5_data, const char *buf, |
| 236 | int max); |
| 237 | int max_m5_fg_model_cstr(char *buf, int max, const struct max_m5_data *m5_data); |
Jenny Ho | 5f92be5 | 2023-11-22 00:13:54 +0800 | [diff] [blame] | 238 | int max_m5_get_rc_switch_param(struct max_m5_data *m5_data, u16 *rc2_tempco, u16 *rc2_learncfg); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 239 | |
Jenny Ho | c6bc588 | 2021-02-18 09:21:21 +0800 | [diff] [blame] | 240 | /* read saved value */ |
| 241 | ssize_t max_m5_gmsr_state_cstr(char *buf, int max); |
| 242 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 243 | /** ------------------------------------------------------------------------ */ |
| 244 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 245 | /* |
| 246 | * |
| 247 | */ |
| 248 | #if IS_ENABLED(CONFIG_MAX_M5) |
| 249 | |
| 250 | extern int max_m5_read_actual_input_current_ua(struct i2c_client *client, |
| 251 | int *iic); |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 252 | extern int max_m5_read_vbypass(struct i2c_client *client, |
| 253 | int *volt); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 254 | |
| 255 | extern int max_m5_reg_read(struct i2c_client *client, unsigned int reg, |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 256 | unsigned int *val); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 257 | extern int max_m5_reg_write(struct i2c_client *client, unsigned int reg, |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 258 | unsigned int val); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 259 | #else |
| 260 | static inline int |
| 261 | max_m5_read_actual_input_current_ua(struct i2c_client *client, int *iic) |
| 262 | { |
| 263 | return -ENODEV; |
| 264 | } |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 265 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 266 | static inline int |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 267 | max_m5_read_vbypass(struct i2c_client *client, int *volt) |
| 268 | { |
| 269 | return -ENODEV; |
| 270 | } |
| 271 | |
| 272 | static inline int |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 273 | max_m5_reg_read(struct i2c_client *client, unsigned int reg, unsigned int *val) |
| 274 | { |
| 275 | return -ENODEV; |
| 276 | } |
| 277 | |
| 278 | static inline int max_m5_reg_write(struct i2c_client *client, unsigned int reg, |
| 279 | unsigned int val) |
| 280 | { |
| 281 | return -ENODEV; |
| 282 | } |
| 283 | |
| 284 | |
| 285 | #endif |
| 286 | |
| 287 | |
| 288 | |
| 289 | /* reach back into max1720x battery */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 290 | void *max1720x_get_model_data(struct i2c_client *client); |
| 291 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 292 | |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 293 | #endif |