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 |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 28 | #define MAX_M5_LOAD_MODEL_REQUEST 5 |
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 |
| 43 | #define MAX_M5_VFSOC 0xFF |
| 44 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 45 | /* model version */ |
| 46 | #define MAX_M5_INVALID_VERSION -1 |
| 47 | |
| 48 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 49 | /** ------------------------------------------------------------------------ */ |
| 50 | |
| 51 | /* |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 52 | * Custom parameters are updated while the device is runnig. |
| 53 | * NOTE: a subset (model_state_save) is saved to permanent storage every "n" |
| 54 | * cycles and restored when the model is reloaded (usually on POR). |
| 55 | * TODO: handle switching between RC1 and RC2 model types. |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 56 | */ |
| 57 | struct max_m5_custom_parameters { |
| 58 | u16 iavg_empty; /* WV */ |
| 59 | u16 relaxcfg; |
| 60 | u16 learncfg; |
| 61 | u16 config; |
| 62 | u16 config2; |
| 63 | u16 fullsocthr; |
| 64 | u16 fullcaprep; /* WV */ |
| 65 | u16 designcap; |
| 66 | u16 dpacc; /* WV */ |
| 67 | u16 dqacc; /* WV */ |
| 68 | u16 fullcapnom; /* WV */ |
| 69 | u16 v_empty; |
| 70 | u16 qresidual00; /* WV */ |
| 71 | u16 qresidual10; /* WV */ |
| 72 | u16 qresidual20; /* WV */ |
| 73 | u16 qresidual30; /* WV */ |
| 74 | u16 rcomp0; /* WV */ |
| 75 | u16 tempco; /* WV */ |
| 76 | u16 ichgterm; |
| 77 | u16 tgain; |
| 78 | u16 toff; |
| 79 | u16 tcurve; /* write to 0x00B9 */ |
| 80 | u16 misccfg; /* 0x9d0 for internal current sense, 0x8d0 external */ |
| 81 | |
| 82 | u16 atrate; |
| 83 | u16 convgcfg; |
| 84 | u16 filtercfg; /* write to 0x0029 */ |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 85 | u16 taskperiod; |
Jenny Ho | e8b877c | 2022-01-10 03:27:53 +0800 | [diff] [blame] | 86 | u16 cgain; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 87 | } __attribute__((packed)); |
| 88 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 89 | /* this is what is saved and restored to/from GMSR */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 90 | struct model_state_save { |
| 91 | u16 rcomp0; |
| 92 | u16 tempco; |
| 93 | u16 fullcaprep; |
| 94 | u16 cycles; |
| 95 | u16 fullcapnom; |
| 96 | u16 qresidual00; |
| 97 | u16 qresidual10; |
| 98 | u16 qresidual20; |
| 99 | u16 qresidual30; |
Jenny Ho | dc6c8a0 | 2021-10-29 06:14:33 +0800 | [diff] [blame] | 100 | u16 cv_mixcap; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 101 | u16 halftime; |
Jenny Ho | f77200e | 2021-05-31 17:32:55 +0800 | [diff] [blame] | 102 | u8 crc; |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 103 | } __attribute__((packed)); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 104 | |
| 105 | struct max_m5_data { |
| 106 | struct device *dev; |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 107 | struct max17x0x_regmap *regmap; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 108 | int cap_lsb; /* b/177099997 */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 109 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 110 | /* initial parameters are in device tree they are also learned */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 111 | struct max_m5_custom_parameters parameters; |
| 112 | u16 cycles; |
Jenny Ho | dc6c8a0 | 2021-10-29 06:14:33 +0800 | [diff] [blame] | 113 | u16 cv_mixcap; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 114 | u16 halftime; |
| 115 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 116 | int custom_model_size; |
| 117 | u16 *custom_model; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 118 | u32 model_version; |
Jenny Ho | 7c691da | 2021-05-19 06:15:54 +0800 | [diff] [blame] | 119 | bool force_reset_model_data; |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 120 | |
AleX Pelosi | 76b6350 | 2020-11-03 16:49:44 -0800 | [diff] [blame] | 121 | /* to/from GMSR */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 122 | struct model_state_save model_save; |
| 123 | }; |
| 124 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 125 | /** ------------------------------------------------------------------------ */ |
| 126 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 127 | int max_m5_model_read_version(const struct max_m5_data *m5_data); |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 128 | 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] | 129 | int max_m5_reset_state_data(struct max_m5_data *m5_data); |
| 130 | int max_m5_needs_reset_model_data(const struct max_m5_data *m5_data); |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 131 | |
| 132 | /* |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 133 | * 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] | 134 | * - 0 not M5, !=0 M5 |
| 135 | */ |
| 136 | static inline int max_m5_check_devname(u16 devname) |
| 137 | { |
Jenny Ho | d5def24 | 2021-04-28 10:51:58 +0800 | [diff] [blame] | 138 | const u16 radix = devname >> 8; |
| 139 | |
| 140 | return radix == 0x62 || radix == 0x63; |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | /* b/177099997, handle TaskConfig = 351 */ |
| 144 | static inline int max_m5_cap_lsb(const struct max_m5_data *m5_data) |
| 145 | { |
| 146 | return m5_data ? (1 << m5_data->cap_lsb) : 1; |
| 147 | } |
| 148 | |
| 149 | static inline int max_m5_fg_model_version(const struct max_m5_data *m5_data) |
| 150 | { |
| 151 | return m5_data ? m5_data->model_version : MAX_M5_INVALID_VERSION; |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | * 0 reload, != 0 no reload |
| 156 | * always reload when the model version is not specified |
| 157 | */ |
| 158 | static inline int max_m5_fg_model_check_version(const struct max_m5_data *m5_data) |
| 159 | { |
| 160 | if (!m5_data) |
| 161 | return 1; |
| 162 | if (m5_data->model_version == MAX_M5_INVALID_VERSION) |
| 163 | return 0; |
| 164 | |
| 165 | return max_m5_model_read_version(m5_data) == m5_data->model_version; |
| 166 | } |
| 167 | |
| 168 | /** ------------------------------------------------------------------------ */ |
| 169 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 170 | int max_m5_regmap_init(struct max17x0x_regmap *regmap, |
| 171 | struct i2c_client *primary); |
| 172 | |
| 173 | void *max_m5_init_data(struct device *dev, struct device_node *batt_node, |
| 174 | struct max17x0x_regmap *regmap); |
| 175 | void max_m5_free_data(void *data); |
| 176 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 177 | int max_m5_load_state_data(struct max_m5_data *m5_data); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 178 | int max_m5_save_state_data(struct max_m5_data *m5_data); |
| 179 | |
| 180 | /* read state from the gauge */ |
| 181 | int max_m5_model_read_state(struct max_m5_data *m5_data); |
AleX Pelosi | fc6f66d | 2021-01-12 18:14:48 -0800 | [diff] [blame] | 182 | int max_m5_model_check_state(struct max_m5_data *m5_data); |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 183 | |
| 184 | /* load model to gauge */ |
| 185 | int max_m5_load_gauge_model(struct max_m5_data *m5_data); |
| 186 | |
AleX Pelosi | fed7fb1 | 2020-11-10 01:22:22 -0800 | [diff] [blame] | 187 | int max_m5_fixup_outliers(struct max1720x_drift_data *ddata, |
| 188 | struct max_m5_data *m5_data); |
| 189 | |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 190 | ssize_t max_m5_model_state_cstr(char *buf, int max, |
| 191 | struct max_m5_data *m5_data); |
| 192 | int max_m5_model_state_sscan(struct max_m5_data *m5_data, const char *buf, |
| 193 | int max); |
| 194 | int max_m5_fg_model_sscan(struct max_m5_data *m5_data, const char *buf, |
| 195 | int max); |
| 196 | int max_m5_fg_model_cstr(char *buf, int max, const struct max_m5_data *m5_data); |
| 197 | |
Jenny Ho | c6bc588 | 2021-02-18 09:21:21 +0800 | [diff] [blame] | 198 | /* read saved value */ |
| 199 | ssize_t max_m5_gmsr_state_cstr(char *buf, int max); |
| 200 | |
AleX Pelosi | 962aedf | 2021-01-07 15:39:43 -0800 | [diff] [blame] | 201 | /** ------------------------------------------------------------------------ */ |
| 202 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 203 | /* |
| 204 | * |
| 205 | */ |
| 206 | #if IS_ENABLED(CONFIG_MAX_M5) |
| 207 | |
| 208 | extern int max_m5_read_actual_input_current_ua(struct i2c_client *client, |
| 209 | int *iic); |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 210 | extern int max_m5_read_vbypass(struct i2c_client *client, |
| 211 | int *volt); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 212 | |
| 213 | 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] | 214 | unsigned int *val); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 215 | 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] | 216 | unsigned int val); |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 217 | #else |
| 218 | static inline int |
| 219 | max_m5_read_actual_input_current_ua(struct i2c_client *client, int *iic) |
| 220 | { |
| 221 | return -ENODEV; |
| 222 | } |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 223 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 224 | static inline int |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 225 | max_m5_read_vbypass(struct i2c_client *client, int *volt) |
| 226 | { |
| 227 | return -ENODEV; |
| 228 | } |
| 229 | |
| 230 | static inline int |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 231 | max_m5_reg_read(struct i2c_client *client, unsigned int reg, unsigned int *val) |
| 232 | { |
| 233 | return -ENODEV; |
| 234 | } |
| 235 | |
| 236 | static inline int max_m5_reg_write(struct i2c_client *client, unsigned int reg, |
| 237 | unsigned int val) |
| 238 | { |
| 239 | return -ENODEV; |
| 240 | } |
| 241 | |
| 242 | |
| 243 | #endif |
| 244 | |
| 245 | |
| 246 | |
| 247 | /* reach back into max1720x battery */ |
Ken Tsou | 8acade1 | 2020-07-09 03:17:35 +0800 | [diff] [blame] | 248 | void *max1720x_get_model_data(struct i2c_client *client); |
| 249 | |
AleX Pelosi | 3289228 | 2020-09-11 02:29:20 -0700 | [diff] [blame] | 250 | |
Jack Wu | 83f98e3 | 2021-08-09 18:15:52 +0800 | [diff] [blame] | 251 | #endif |