1 /* 2 * (C) Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/gpio.h> 9 #include <dm/device.h> 10 #include <power/fuel_gauge.h> 11 #include <power/pmic.h> 12 #include <linux/usb/phy-rockchip-inno-usb2.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 #define BQ25700_ID 0x25700 17 #define BQ25703_ID 0x25703 18 19 #define COMPAT_BQ25700 "ti,bq25700" 20 #define COMPAT_BQ25703 "ti,bq25703" 21 22 #define BQ25700_I2C_SPEED 100000 23 #define BQ25700_CHARGE_CURRENT_1500MA 0x5C0 24 #define BQ25700_SDP_INPUT_CURRENT_500MA 0xA00 25 #define BQ25700_DCP_INPUT_CURRENT_1500MA 0x1E00 26 #define BQ25700_DCP_INPUT_CURRENT_2000MA 0x2800 27 #define BQ25700_DCP_INPUT_CURRENT_3000MA 0x3C00 28 29 #define WATCHDOG_ENSABLE (0x03 << 13) 30 31 #define BQ25700_CHARGEOPTION0_REG 0x12 32 #define BQ25700_CHARGECURREN_REG 0x14 33 #define BQ25700_CHARGERSTAUS_REG 0x20 34 #define BQ25700_INPUTVOLTAGE_REG 0x3D 35 #define BQ25700_INPUTCURREN_REG 0x3F 36 37 #define BQ25703_CHARGEOPTION0_REG 0x00 38 #define BQ25703_CHARGECURREN_REG 0x02 39 #define BQ25703_CHARGERSTAUS_REG 0x20 40 #define BQ25703_INPUTVOLTAGE_REG 0x0A 41 #define BQ25703_INPUTCURREN_REG 0x0E 42 43 enum bq25700_table_ids { 44 /* range tables */ 45 TBL_ICHG, 46 TBL_CHGMAX, 47 TBL_INPUTVOL, 48 TBL_INPUTCUR, 49 TBL_SYSVMIN, 50 TBL_OTGVOL, 51 TBL_OTGCUR, 52 TBL_EXTCON, 53 }; 54 55 struct bq25700 { 56 struct udevice *dev; 57 struct gpio_desc typec0_enable_gpio; 58 struct gpio_desc typec1_enable_gpio; 59 u32 ichg; 60 u32 chip_id; 61 }; 62 63 struct bq25700_range { 64 u32 min; 65 u32 max; 66 u32 step; 67 }; 68 69 static int bq25700_read(struct bq25700 *charger, uint reg) 70 { 71 u16 val; 72 int ret; 73 74 ret = dm_i2c_read(charger->dev, reg, (u8 *)&val, 2); 75 if (ret) { 76 debug("write error to device: %p register: %#x!", 77 charger->dev, reg); 78 return ret; 79 } 80 81 return val; 82 } 83 84 static int bq25700_write(struct bq25700 *charger, uint reg, u16 val) 85 { 86 int ret; 87 88 ret = dm_i2c_write(charger->dev, reg, (u8 *)&val, 2); 89 if (ret) { 90 debug("write error to device: %p register: %#x!", 91 charger->dev, reg); 92 return ret; 93 } 94 95 return 0; 96 } 97 98 #if defined(CONFIG_POWER_FUSB302) 99 static const union { 100 struct bq25700_range rt; 101 } bq25700_tables[] = { 102 /* range tables */ 103 [TBL_ICHG] = { .rt = {0, 8128000, 64000} }, 104 /* uV */ 105 [TBL_CHGMAX] = { .rt = {0, 19200000, 16000} }, 106 /* uV max charge voltage*/ 107 [TBL_INPUTVOL] = { .rt = {3200000, 19520000, 64000} }, 108 /* uV input charge voltage*/ 109 [TBL_INPUTCUR] = {.rt = {0, 6350000, 50000} }, 110 /*uA input current*/ 111 [TBL_SYSVMIN] = { .rt = {1024000, 16182000, 256000} }, 112 /* uV min system voltage*/ 113 [TBL_OTGVOL] = {.rt = {4480000, 20800000, 64000} }, 114 /*uV OTG volage*/ 115 [TBL_OTGCUR] = {.rt = {0, 6350000, 50000} }, 116 }; 117 118 static u32 bq25700_find_idx(u32 value, enum bq25700_table_ids id) 119 { 120 const struct bq25700_range *rtbl = &bq25700_tables[id].rt; 121 u32 rtbl_size; 122 u32 idx; 123 124 rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; 125 126 for (idx = 1; 127 idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); 128 idx++) 129 ; 130 131 return idx - 1; 132 } 133 #endif 134 135 static bool bq25700_charger_status(struct bq25700 *charger) 136 { 137 #if defined(CONFIG_POWER_FUSB302) 138 static u16 charge_flag; 139 #endif 140 int state_of_charger; 141 u16 value; 142 143 value = bq25700_read(charger, BQ25700_CHARGERSTAUS_REG); 144 state_of_charger = value >> 15; 145 146 #if defined(CONFIG_POWER_FUSB302) 147 if (state_of_charger) { 148 charge_flag = 1; 149 } else if (!state_of_charger && charge_flag == 1) { 150 typec_discharge(); 151 charge_flag = 0; 152 } 153 #endif 154 155 return state_of_charger; 156 } 157 158 static bool bq25703_charger_status(struct bq25700 *charger) 159 { 160 #if defined(CONFIG_POWER_FUSB302) 161 static u16 charge_flag; 162 #endif 163 int state_of_charger; 164 u16 value; 165 166 value = bq25700_read(charger, BQ25703_CHARGERSTAUS_REG); 167 state_of_charger = value >> 15; 168 169 #if defined(CONFIG_POWER_FUSB302) 170 if (state_of_charger) { 171 charge_flag = 1; 172 } else if (!state_of_charger && charge_flag == 1) { 173 typec_discharge(); 174 charge_flag = 0; 175 } 176 #endif 177 178 return state_of_charger; 179 } 180 181 static bool bq257xx_charger_status(struct udevice *dev) 182 { 183 struct bq25700 *charger = dev_get_priv(dev); 184 185 if (charger->chip_id == BQ25700_ID) 186 return bq25700_charger_status(charger); 187 else 188 return bq25703_charger_status(charger); 189 } 190 191 static int bq25700_charger_capability(struct udevice *dev) 192 { 193 return FG_CAP_CHARGER; 194 } 195 196 static int bq25700_get_usb_type(void) 197 { 198 #ifdef CONFIG_PHY_ROCKCHIP_INNO_USB2 199 return rockchip_chg_get_type(); 200 #else 201 return 0; 202 #endif 203 } 204 205 static void bq25700_charger_current_init(struct bq25700 *charger) 206 { 207 u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA; 208 u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA; 209 u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA; 210 u32 pd_inputcurrent = 0; 211 #if defined(CONFIG_POWER_FUSB302) 212 u16 vol_idx, cur_idx, pd_inputvol; 213 #endif 214 u16 temp; 215 216 temp = bq25700_read(charger, BQ25700_CHARGEOPTION0_REG); 217 temp &= (~WATCHDOG_ENSABLE); 218 bq25700_write(charger, BQ25700_CHARGEOPTION0_REG, temp); 219 220 #if defined(CONFIG_POWER_FUSB302) 221 if (!get_pd_output_val(&pd_inputvol, &pd_inputcurrent)) { 222 printf("%s pd charge input vol:%dmv current:%dma\n", 223 __func__, pd_inputvol, pd_inputcurrent); 224 vol_idx = bq25700_find_idx((pd_inputvol - 1280) * 1000, 225 TBL_INPUTVOL); 226 cur_idx = bq25700_find_idx(pd_inputcurrent * 1000, 227 TBL_INPUTCUR); 228 cur_idx = cur_idx << 8; 229 vol_idx = vol_idx << 6; 230 if (pd_inputcurrent != 0) { 231 bq25700_write(charger, BQ25700_INPUTCURREN_REG, 232 cur_idx); 233 bq25700_write(charger, BQ25700_INPUTVOLTAGE_REG, 234 vol_idx); 235 charge_current = bq25700_find_idx(charger.ichg, 236 TBL_ICHG); 237 charge_current = charge_current << 8; 238 } 239 } 240 #endif 241 242 if (pd_inputcurrent == 0) { 243 if (bq25700_get_usb_type() > 1) 244 bq25700_write(charger, BQ25700_INPUTCURREN_REG, 245 dcp_inputcurrent); 246 else 247 bq25700_write(charger, BQ25700_INPUTCURREN_REG, 248 sdp_inputcurrent); 249 } 250 251 if (bq25700_charger_status(charger)) 252 bq25700_write(charger, BQ25700_CHARGECURREN_REG, 253 charge_current); 254 } 255 256 static void bq25703_charger_current_init(struct bq25700 *charger) 257 { 258 u16 charge_current = BQ25700_CHARGE_CURRENT_1500MA; 259 u16 sdp_inputcurrent = BQ25700_SDP_INPUT_CURRENT_500MA; 260 u16 dcp_inputcurrent = BQ25700_DCP_INPUT_CURRENT_1500MA; 261 u32 pd_inputcurrent = 0; 262 #if defined(CONFIG_POWER_FUSB302) 263 u16 vol_idx, cur_idx, pd_inputvol; 264 #endif 265 u16 temp; 266 267 temp = bq25700_read(charger, BQ25703_CHARGEOPTION0_REG); 268 temp &= (~WATCHDOG_ENSABLE); 269 bq25700_write(charger, BQ25703_CHARGEOPTION0_REG, temp); 270 271 #if defined(CONFIG_POWER_FUSB302) 272 if (!get_pd_output_val(&pd_inputvol, &pd_inputcurrent)) { 273 printf("%s pd charge input vol:%dmv current:%dma\n", 274 __func__, pd_inputvol, pd_inputcurrent); 275 vol_idx = bq25700_find_idx((pd_inputvol - 1280) * 1000, 276 TBL_INPUTVOL); 277 cur_idx = bq25700_find_idx(pd_inputcurrent * 1000, 278 TBL_INPUTCUR); 279 cur_idx = cur_idx << 8; 280 vol_idx = vol_idx << 6; 281 if (pd_inputcurrent != 0) { 282 bq25700_write(charger, BQ25703_INPUTCURREN_REG, 283 cur_idx); 284 bq25700_write(charger, BQ25703_INPUTVOLTAGE_REG, 285 vol_idx); 286 charge_current = bq25700_find_idx(charger.ichg, 287 TBL_ICHG); 288 charge_current = charge_current << 8; 289 } 290 } 291 #endif 292 293 if (pd_inputcurrent == 0) { 294 if (bq25700_get_usb_type() > 1) 295 bq25700_write(charger, BQ25703_INPUTCURREN_REG, 296 dcp_inputcurrent); 297 else 298 bq25700_write(charger, BQ25703_INPUTCURREN_REG, 299 sdp_inputcurrent); 300 } 301 302 if (bq25703_charger_status(charger)) 303 bq25700_write(charger, BQ25703_CHARGECURREN_REG, 304 charge_current); 305 } 306 307 static int bq25700_ofdata_to_platdata(struct udevice *dev) 308 { 309 struct bq25700 *charger = dev_get_priv(dev); 310 const void *blob = gd->fdt_blob; 311 int node, node1; 312 #if defined(CONFIG_POWER_FUSB302) 313 int port_num; 314 #endif 315 316 charger->dev = dev; 317 318 node = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25700); 319 node1 = fdt_node_offset_by_compatible(blob, 0, COMPAT_BQ25703); 320 if ((node < 0) && (node1 < 0)) { 321 printf("Can't find dts node for charger bq25700\n"); 322 return -ENODEV; 323 } 324 325 if (node < 0) { 326 node = node1; 327 charger->chip_id = BQ25703_ID; 328 } else { 329 charger->chip_id = BQ25700_ID; 330 } 331 332 charger->ichg = fdtdec_get_int(blob, node, "ti,charge-current", 0); 333 334 #if defined(CONFIG_POWER_FUSB302) 335 gpio_request_by_name(dev, "typec0-enable-gpios", 0, 336 &charger.typec0_enable_gpio); 337 gpio_request_by_name(dev, "typec1-enable-gpios", 0, 338 &charger.typec1_enable_gpio); 339 340 if (dm_gpio_is_valid(charger.typec1_enable_gpio.gpio) && 341 dm_gpio_is_valid(charger.typec0_enable_gpio.gpio)) { 342 port_num = get_pd_port_num(); 343 if (port_num == 0) { 344 printf("fusb0 charge typec0:1 typec1:0\n"); 345 dm_gpio_set_value(&charger.typec0_enable_gpio.gpio, 1); 346 dm_gpio_set_value(&charger.typec1_enable_gpio.gpio, 0); 347 } else if (port_num == 1) { 348 printf("fusb1 charge typec0:0 typec1:1\n"); 349 dm_gpio_set_value(&charger.typec0_enable_gpio.gpio, 0); 350 dm_gpio_set_value(&charger.typec1_enable_gpio.gpio, 1); 351 } 352 udelay(1000 * 200); 353 } 354 #endif 355 356 return 0; 357 } 358 359 static int bq25700_probe(struct udevice *dev) 360 { 361 struct bq25700 *charger = dev_get_priv(dev); 362 363 if (charger->chip_id == BQ25700_ID) 364 bq25700_charger_current_init(charger); 365 else 366 bq25703_charger_current_init(charger); 367 368 return 0; 369 } 370 371 static const struct udevice_id charger_ids[] = { 372 { .compatible = "ti,bq25700" }, 373 { .compatible = "ti,bq25703" }, 374 { }, 375 }; 376 377 static struct dm_fuel_gauge_ops charger_ops = { 378 .get_chrg_online = bq257xx_charger_status, 379 .capability = bq25700_charger_capability, 380 }; 381 382 U_BOOT_DRIVER(bq25700_charger) = { 383 .name = "bq25700_charger", 384 .id = UCLASS_FG, 385 .probe = bq25700_probe, 386 .of_match = charger_ids, 387 .ops = &charger_ops, 388 .ofdata_to_platdata = bq25700_ofdata_to_platdata, 389 .priv_auto_alloc_size = sizeof(struct bq25700), 390 }; 391