blob: 9bcffcfca4087cc78bf2243563e9f77c7c92a73d [file] [log] [blame]
AleX Pelosi78a4bea2020-09-01 19:02:24 -07001/* SPDX-License-Identifier: GPL-2.0 */
Ken Tsou8acade12020-07-09 03:17:35 +08002/*
Ken Tsouf956a7f2022-04-12 09:50:46 +08003 * Copyright 2020-2022 Google LLC
Ken Tsou8acade12020-07-09 03:17:35 +08004 *
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18#ifdef CONFIG_PM_SLEEP
19#define SUPPORT_PM_SLEEP 1
20#endif
21
22#include <linux/kernel.h>
23#include <linux/printk.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/of_gpio.h>
27#include <linux/gpio.h>
28#include <linux/pm_runtime.h>
29#include <linux/platform_device.h>
Ken Tsou8acade12020-07-09 03:17:35 +080030#include <linux/thermal.h>
31#include <linux/slab.h>
AleX Pelosid71f5852020-08-26 18:40:28 -070032#include <misc/gvotable.h>
33#include "gbms_power_supply.h"
Ken Tsou8acade12020-07-09 03:17:35 +080034#include "google_bms.h"
35#include "google_dc_pps.h"
36#include "google_psy.h"
Ken Tsou8acade12020-07-09 03:17:35 +080037
38#include <linux/debugfs.h>
39
AleX Pelosif20ccc82021-02-12 22:57:34 -080040/* Non DC Charger is the default */
41#define GCPM_DEFAULT_CHARGER 0
AleX Pelosia0f55512021-03-17 00:30:20 -070042/* TODO: handle capabilities based on index number */
AleX Pelosic6a1bb22021-07-15 23:15:32 -070043#define GCPM_INDEX_DC_DISABLE -1
AleX Pelosif20ccc82021-02-12 22:57:34 -080044#define GCPM_INDEX_DC_ENABLE 1
AleX Pelosic1ba48c2021-01-16 13:49:59 -080045#define GCPM_MAX_CHARGERS 4
AleX Pelosif20ccc82021-02-12 22:57:34 -080046
AleX Pelosi49ac41c2021-02-18 18:13:42 -080047/* tier based, disabled now */
AleX Pelosic1ba48c2021-01-16 13:49:59 -080048#define GCPM_DEFAULT_DC_LIMIT_DEMAND 0
AleX Pelosibc7f0a22021-04-03 15:17:41 -070049/* thermal will change this */
AleX Pelosi58ddf5c2021-06-16 11:48:58 -070050#define GCPM_DEFAULT_DC_LIMIT_CC_MIN 1000000
51#define GCPM_DEFAULT_DC_LIMIT_CC_MIN_WLC 2000000
AleX Pelosi49ac41c2021-02-18 18:13:42 -080052
53/* voltage based */
54#define GCPM_DEFAULT_DC_LIMIT_VBATT_MIN 3600000
55#define GCPM_DEFAULT_DC_LIMIT_DELTA_LOW 200000
56
AleX Pelosibc7f0a22021-04-03 15:17:41 -070057/* demand based limits */
AleX Pelosi7b049872021-06-07 11:53:35 -070058#define GCPM_DEFAULT_DC_LIMIT_VBATT_MAX 4450000
AleX Pelosi17146d62021-07-17 20:36:35 -070059#define GCPM_DEFAULT_DC_LIMIT_DELTA_HIGH 200000
Ken Tsou8acade12020-07-09 03:17:35 +080060
AleX Pelosi87e78af2022-02-08 15:08:43 -080061/* SOC debounce */
62#define GCPM_DEFAULT_DC_LIMIT_SOC_HIGH 100
63
AleX Pelosie7b31a42021-04-07 19:24:51 -070064/* behavior in taper */
AleX Pelosi568ddbf2021-03-23 23:56:50 -070065#define GCPM_TAPER_STEP_FV_MARGIN 0
AleX Pelosia1eb56b2021-07-07 18:24:58 -070066#define GCPM_TAPER_STEP_CC_STEP 0
67#define GCPM_TAPER_STEP_COUNT 0
68#define GCPM_TAPER_STEP_GRACE 1
AleX Pelosi568ddbf2021-03-23 23:56:50 -070069#define GCPM_TAPER_STEP_VOLTAGE 0
AleX Pelosi87f4b472021-05-20 02:30:14 -070070#define GCPM_TAPER_STEP_CURRENT 0
71/* enough time for the charger to settle to a new limit */
72#define GCPM_TAPER_STEP_INTERVAL_S 120
AleX Pelosi568ddbf2021-03-23 23:56:50 -070073
Ken Tsou8acade12020-07-09 03:17:35 +080074/* TODO: move to configuration */
75#define DC_TA_VMAX_MV 9800000
76/* TODO: move to configuration */
77#define DC_TA_VMIN_MV 8000000
78/* TODO: move to configuration */
79#define DC_VBATT_HEADROOM_MV 500000
80
81enum gcpm_dc_state_t {
AleX Pelosif3776622021-01-18 13:32:08 -080082 DC_DISABLED = -1,
83 DC_IDLE = 0,
Ken Tsou8acade12020-07-09 03:17:35 +080084 DC_ENABLE,
85 DC_RUNNING,
86 DC_ENABLE_PASSTHROUGH,
87 DC_PASSTHROUGH,
88};
89
AleX Pelosi58ddf5c2021-06-16 11:48:58 -070090/* DC_ERROR_RETRY_MS <= DC_RUN_DELAY_MS */
91#define DC_ENABLE_DELAY_MS 500
92#define DC_RUN_DELAY_MS 9000
93#define DC_ERROR_RETRY_MS PPS_ERROR_RETRY_MS
94
95#define PPS_PROG_TIMEOUT_S 10
96#define PPS_PROG_RETRY_MS 2000
97#define PPS_ACTIVE_RETRY_MS 1500
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -070098#define PPS_ACTIVE_USB_TIMEOUT_S 25
99#define PPS_ACTIVE_WLC_TIMEOUT_S 500
100#define PPS_READY_DELTA_TIMEOUT_S 10
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700101
102#define PPS_ERROR_RETRY_MS 1000
103
104enum {
105 PPS_INDEX_NOT_SUPP = -1,
106 PPS_INDEX_TCPM = 1,
107 PPS_INDEX_WLC = 2,
108 PPS_INDEX_MAX = 2,
109};
110
AleX Pelosib961e472022-02-09 19:33:47 -0800111#define MDIS_OF_CDEV_NAME "google,mdis_charger"
112#define MDIS_CDEV_NAME "chg_mdis"
113#define MDIS_IN_MAX 4
AleX Pelosie1b18722022-04-18 23:32:31 -0700114#define MDIS_OUT_MAX GCPM_MAX_CHARGERS
AleX Pelosib961e472022-02-09 19:33:47 -0800115
116struct mdis_thermal_device
117{
118 struct gcpm_drv *gcpm;
119 struct mutex tdev_lock;
120
121 struct thermal_cooling_device *tcd;
122 u32 *thermal_mitigation;
123 int thermal_levels;
124 int current_level;
Jenny Hoa6dfac42022-09-14 14:41:43 +0800125 int therm_fan_alarm_level;
AleX Pelosib961e472022-02-09 19:33:47 -0800126};
127
Ken Tsou8acade12020-07-09 03:17:35 +0800128struct gcpm_drv {
129 struct device *device;
130 struct power_supply *psy;
131 struct delayed_work init_work;
132
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700133 /* charge limit for wireless DC (legacy) */
AleX Pelosief75a072021-06-12 17:38:36 -0700134 struct gvotable_election *dc_fcc_votable;
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700135
136 bool cp_fcc_hold; /* debounces CP */
137 int cp_fcc_hold_limit; /* limit to re-enter CP */
AleX Pelosib961e472022-02-09 19:33:47 -0800138
139 /* MDIS: wired and wireless via main charger */
140 struct gvotable_election *fcc_votable;
141 struct gvotable_election *dc_icl_votable;
AleX Pelosi430da992022-06-05 23:52:25 +0000142 struct gvotable_election *tx_icl_votable;
AleX Pelosib961e472022-02-09 19:33:47 -0800143 /* MDIS: wired and wireless via DC charger */
144 struct gvotable_election *cp_votable;
145 /* MDIS: configuration */
146 struct power_supply *mdis_in[MDIS_IN_MAX];
AleX Pelosie1b18722022-04-18 23:32:31 -0700147 int mdis_in_count;
AleX Pelosib961e472022-02-09 19:33:47 -0800148 struct power_supply *mdis_out[MDIS_OUT_MAX];
AleX Pelosie1b18722022-04-18 23:32:31 -0700149 int mdis_out_count;
AleX Pelosib961e472022-02-09 19:33:47 -0800150 u32 *mdis_out_limits[MDIS_OUT_MAX];
151 u32 mdis_out_sel[MDIS_OUT_MAX];
152 /* MDIS: device and current budget */
153 struct mdis_thermal_device thermal_device;
154 struct gvotable_election *mdis_votable;
Jenny Hoa6dfac42022-09-14 14:41:43 +0800155 struct gvotable_election *fan_level_votable;
AleX Pelosief75a072021-06-12 17:38:36 -0700156
AleX Pelosibf11ec02022-04-22 11:25:06 -0700157 /* CSI */
158 struct gvotable_election *csi_status_votable;
159
AleX Pelosif3776622021-01-18 13:32:08 -0800160 /* combine PPS, route to the active PPS source */
161 struct power_supply *pps_psy;
162
AleX Pelosie1b18722022-04-18 23:32:31 -0700163 /* basically the same as mdis_out */
Ken Tsou8acade12020-07-09 03:17:35 +0800164 int chg_psy_retries;
165 struct power_supply *chg_psy_avail[GCPM_MAX_CHARGERS];
166 const char *chg_psy_names[GCPM_MAX_CHARGERS];
Prasanna Prapancham19203302022-09-09 20:58:11 +0000167 struct gvotable_election *dc_chg_avail_votable;
Ken Tsou8acade12020-07-09 03:17:35 +0800168 struct mutex chg_psy_lock;
169 int chg_psy_active;
170 int chg_psy_count;
AleX Pelosif3776622021-01-18 13:32:08 -0800171
Wasb Liucf32f212022-10-05 16:50:30 +0800172 /* wakelock */
173 struct wakeup_source *gcpm_ws;
174
Ken Tsou8acade12020-07-09 03:17:35 +0800175 /* force a charger, this might have side effects */
176 int force_active;
177
AleX Pelosid301b6d2021-04-27 20:18:32 -0700178 struct logbuffer *log;
179
AleX Pelosif3776622021-01-18 13:32:08 -0800180 /* TCPM state for wired PPS charging */
Ken Tsou8acade12020-07-09 03:17:35 +0800181 const char *tcpm_psy_name;
AleX Pelosif3776622021-01-18 13:32:08 -0800182 struct power_supply *tcpm_psy;
183 struct pd_pps_data tcpm_pps_data;
Ken Tsou8acade12020-07-09 03:17:35 +0800184 int log_psy_ratelimit;
185 u32 tcpm_phandle;
186
AleX Pelosif3776622021-01-18 13:32:08 -0800187 /* TCPM state for wireless PPS charging */
188 const char *wlc_dc_name;
189 struct power_supply *wlc_dc_psy;
190 struct pd_pps_data wlc_pps_data;
191 u32 wlc_phandle;
192
AleX Pelosi49ac41c2021-02-18 18:13:42 -0800193 struct delayed_work select_work;
194
AleX Pelosi87e78af2022-02-08 15:08:43 -0800195 /* set to force PPS negotiation */
Ken Tsou8acade12020-07-09 03:17:35 +0800196 bool force_pps;
197 /* pps state and detect */
Ken Tsou8acade12020-07-09 03:17:35 +0800198 struct delayed_work pps_work;
199 /* request of output ua, */
200 int out_ua;
201 int out_uv;
202
203 int dcen_gpio;
204 u32 dcen_gpio_default;
205
AleX Pelosif3776622021-01-18 13:32:08 -0800206 /* >0 when enabled, pps charger to use */
207 int pps_index;
208 /* >0 when enabled, dc_charger */
Ken Tsou8acade12020-07-09 03:17:35 +0800209 int dc_index;
210 /* dc_charging state */
211 int dc_state;
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800212
AleX Pelosi7dcf87a2021-01-22 22:57:37 -0800213 ktime_t dc_start_time;
214
Ted Lind35c7422021-05-17 11:32:58 +0800215 /* Disable DC control */
216 int dc_ctl;
217
AleX Pelosif3776622021-01-18 13:32:08 -0800218 /* force check of the DC limit again (debug) */
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800219 bool new_dc_limit;
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700220
221 /* taper off of current at tier, voltage */
222 u32 taper_step_interval; /* countdown interval in seconds */
223 u32 taper_step_voltage; /* voltage before countdown */
AleX Pelosi87f4b472021-05-20 02:30:14 -0700224 u32 taper_step_current; /* current before countdown */
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700225 u32 taper_step_grace; /* steps from voltage before countdown */
226 u32 taper_step_count; /* countdown steps before dc_done */
Jack Wu1c6320c2021-06-17 19:47:20 +0800227 u32 taper_step_fv_margin; /* countdown steps before dc_done */
228 u32 taper_step_cc_step; /* countdown steps before dc_done */
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700229 int taper_step; /* actual countdown */
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800230
AleX Pelosi87e78af2022-02-08 15:08:43 -0800231 /* policy: soc% based limits for DC charging */
232 u32 dc_limit_soc_high; /* DC will not start over high */
Ken Tsou8acade12020-07-09 03:17:35 +0800233 /* policy: power demand limit for DC charging */
AleX Pelosi49ac41c2021-02-18 18:13:42 -0800234 u32 dc_limit_vbatt_low; /* DC will not stop until low */
235 u32 dc_limit_vbatt_min; /* DC will start at min */
236 u32 dc_limit_vbatt_high; /* DC will not start over high */
237 u32 dc_limit_vbatt_max; /* DC stop at max */
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800238 u32 dc_limit_demand;
Ken Tsou8acade12020-07-09 03:17:35 +0800239
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700240 /* TODO: keep TCPM/DC state in a structure add there */
241 u32 dc_limit_cc_min; /* PPS_DC stop if CC_MAX is under this */
242 u32 dc_limit_cc_min_wlc; /* WLC_DC stop if CC_MAX is under this */
243
244 /* cc_max and fv_uv are the demand from google_charger */
Ken Tsou8acade12020-07-09 03:17:35 +0800245 int cc_max;
246 int fv_uv;
247
AleX Pelosi9efbf842021-02-03 21:01:28 -0800248 bool dc_init_complete;
Ken Tsou8acade12020-07-09 03:17:35 +0800249 bool init_complete;
250 bool resume_complete;
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800251 struct notifier_block chg_nb;
Ken Tsou8acade12020-07-09 03:17:35 +0800252
253 /* tie up to charger mode */
254 struct gvotable_election *gbms_mode;
255
256 /* debug fs */
257 struct dentry *debug_entry;
258};
259
AleX Pelosia0f55512021-03-17 00:30:20 -0700260#define gcpm_psy_name(psy) \
261 ((psy) && (psy)->desc && (psy)->desc->name ? (psy)->desc->name : "???")
262
AleX Pelosi8c7d20d2022-03-28 14:29:55 -0700263/* TODO: rename to "can_dc" and handle capabilities based on index number */
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700264#define gcpm_is_dc(gcpm, index) \
AleX Pelosia0f55512021-03-17 00:30:20 -0700265 ((index) >= GCPM_INDEX_DC_ENABLE)
266
AleX Pelosifc92c9e2021-07-08 11:16:51 -0700267/* Logging ----------------------------------------------------------------- */
268
269int debug_printk_prlog = LOGLEVEL_INFO;
270
AleX Pelosifc92c9e2021-07-08 11:16:51 -0700271/* ------------------------------------------------------------------------- */
272
AleX Pelosib961e472022-02-09 19:33:47 -0800273static struct gvotable_election *gcpm_get_cp_votable(struct gcpm_drv *gcpm)
274{
275 if (!gcpm->cp_votable) {
276 struct gvotable_election *v;
277
278 v = gvotable_election_get_handle("GCPM_FCC");
279 if (!IS_ERR_OR_NULL(v))
280 gcpm->cp_votable = v;
281 }
282
283 return gcpm->cp_votable;
284}
285
286static struct gvotable_election *gcpm_get_dc_icl_votable(struct gcpm_drv *gcpm)
287{
288 if (!gcpm->dc_icl_votable) {
289 struct gvotable_election *v;
290
291 v = gvotable_election_get_handle("DC_ICL");
292 if (!IS_ERR_OR_NULL(v))
293 gcpm->dc_icl_votable = v;
294 }
295
296 return gcpm->dc_icl_votable;
297}
298
299static struct gvotable_election *gcpm_get_fcc_votable(struct gcpm_drv *gcpm)
300{
301 if (!gcpm->fcc_votable) {
302 struct gvotable_election *v;
303
304 v = gvotable_election_get_handle("MSC_FCC");
305 if (!IS_ERR_OR_NULL(v))
306 gcpm->fcc_votable = v;
307 }
308
309 return gcpm->fcc_votable;
310}
311
AleX Pelosib961e472022-02-09 19:33:47 -0800312/* will kick gcpm_fcc_callback(), needs mutex_unlock(&gcpm->chg_psy_lock); */
313static int gcpm_update_gcpm_fcc(struct gcpm_drv *gcpm, const char *reason,
314 int limit, bool enable)
315{
316 struct gvotable_election *el;
317 int ret = -ENODEV;
318
319 el = gcpm_get_cp_votable(gcpm);
320 if (el)
321 ret = gvotable_cast_int_vote(el, reason, limit, enable);
322
323 return ret;
324}
325
326/* current limit for DC charging */
327static int gcpm_get_gcpm_fcc(struct gcpm_drv *gcpm)
328{
329 struct gvotable_election *el;
330 int dc_iin = -1;
331
332 el = gcpm_get_cp_votable(gcpm);
333 if (el)
334 dc_iin = gvotable_get_current_int_vote(el);
335 if (dc_iin < 0)
336 dc_iin = gcpm->cc_max;
337
338 return dc_iin;
339}
340
341/* ------------------------------------------------------------------------- */
AleX Pelosief75a072021-06-12 17:38:36 -0700342
AleX Pelosia0f55512021-03-17 00:30:20 -0700343static struct power_supply *gcpm_chg_get_charger(const struct gcpm_drv *gcpm, int index)
344{
345 return (index < 0 || index >= gcpm->chg_psy_count) ? NULL : gcpm->chg_psy_avail[index];
346}
347
AleX Pelosi49ac41c2021-02-18 18:13:42 -0800348static struct power_supply *gcpm_chg_get_default(const struct gcpm_drv *gcpm)
349{
AleX Pelosia0f55512021-03-17 00:30:20 -0700350 return gcpm_chg_get_charger(gcpm, GCPM_DEFAULT_CHARGER);
AleX Pelosi49ac41c2021-02-18 18:13:42 -0800351}
352
Ken Tsou8acade12020-07-09 03:17:35 +0800353/* TODO: place a lock around the operation? */
AleX Pelosic1ba48c2021-01-16 13:49:59 -0800354static struct power_supply *gcpm_chg_get_active(const struct gcpm_drv *gcpm)
Ken Tsou8acade12020-07-09 03:17:35 +0800355{
AleX Pelosia0f55512021-03-17 00:30:20 -0700356 return gcpm_chg_get_charger(gcpm, gcpm->chg_psy_active);
Ken Tsou8acade12020-07-09 03:17:35 +0800357}
358
AleX Pelosi8c7d20d2022-03-28 14:29:55 -0700359static bool gcpm_chg_is_cp_active(const struct gcpm_drv *gcpm)
360{
361 return gcpm_is_dc(gcpm, gcpm->chg_psy_active);
362}
363
AleX Pelosib961e472022-02-09 19:33:47 -0800364/* !=NULL if the adapter is not CP */
365static struct power_supply *gcpm_chg_get_active_cp(const struct gcpm_drv *gcpm)
366{
367 struct power_supply *psy = NULL;
368
AleX Pelosi8c7d20d2022-03-28 14:29:55 -0700369 if (gcpm_chg_is_cp_active(gcpm))
AleX Pelosib961e472022-02-09 19:33:47 -0800370 psy = gcpm_chg_get_charger(gcpm, gcpm->chg_psy_active);
371
372 return psy;
373}
374
375
Ken Tsou8acade12020-07-09 03:17:35 +0800376static int gcpm_chg_ping(struct gcpm_drv *gcpm, int index, bool online)
377{
378 struct power_supply *chg_psy;
379 int ret;
380
381 chg_psy = gcpm->chg_psy_avail[index];
382 if (!chg_psy)
383 return 0;
384
385 ret = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_ONLINE, 0);
386 if (ret < 0)
387 pr_debug("adapter %d cannot ping (%d)", index, ret);
388
389 return 0;
390}
391
AleX Pelosia0f55512021-03-17 00:30:20 -0700392/* use the charger one when avalaible or fallback to the generated one */
Ken Tsou8acade12020-07-09 03:17:35 +0800393static uint64_t gcpm_get_charger_state(const struct gcpm_drv *gcpm,
394 struct power_supply *chg_psy)
395{
396 union gbms_charger_state chg_state;
397 int rc;
398
399 rc = gbms_read_charger_state(&chg_state, chg_psy);
400 if (rc < 0)
401 return 0;
402
403 return chg_state.v;
404}
405
AleX Pelosia0f55512021-03-17 00:30:20 -0700406/*
407 * chg_psy_active==-1 if index was active
408 * NOTE: GBMS_PROP_CHARGING_ENABLED will be pinged later on
409 */
410static int gcpm_chg_offline(struct gcpm_drv *gcpm, int index)
411{
412 const int active_index = gcpm->chg_psy_active;
413 struct power_supply *chg_psy;
414 int ret;
415
Wasb Liu42b15322022-11-24 14:40:51 +0800416 ret = gcpm_update_gcpm_fcc(gcpm, "CC_MAX", gcpm->cc_max, false);
417 if (ret < 0)
418 pr_debug("PPS_DC: offline cannot update cp_fcc (%d)\n", ret);
419
420
AleX Pelosia0f55512021-03-17 00:30:20 -0700421 chg_psy = gcpm_chg_get_charger(gcpm, index);
422 if (!chg_psy)
423 return 0;
424
425 /* OFFLINE should stop charging */
426 ret = GPSY_SET_PROP(chg_psy, GBMS_PROP_CHARGING_ENABLED, 0);
427 if (ret == 0)
428 ret = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_ONLINE, 0);
429 if (ret == 0 && gcpm->chg_psy_active == index)
430 gcpm->chg_psy_active = -1;
431
AleX Pelosiac304992021-06-15 19:45:59 -0700432 pr_info("%s: %s active=%d->%d offline_ok=%d\n", __func__,
433 pps_name(chg_psy), active_index, gcpm->chg_psy_active, ret == 0);
AleX Pelosia0f55512021-03-17 00:30:20 -0700434
435 return ret;
436}
437
438/* preset charging parameters */
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700439static int gcpm_chg_preset(struct power_supply *chg_psy, int fv_uv, int cc_max)
AleX Pelosia0f55512021-03-17 00:30:20 -0700440{
441 const char *name = gcpm_psy_name(chg_psy);
442 int ret;
443
AleX Pelosief75a072021-06-12 17:38:36 -0700444 pr_debug("%s: %s fv_uv=%d cc_max=%d\n", __func__, name, fv_uv, cc_max);
AleX Pelosiac304992021-06-15 19:45:59 -0700445
AleX Pelosia0f55512021-03-17 00:30:20 -0700446 ret = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700447 fv_uv);
AleX Pelosia0f55512021-03-17 00:30:20 -0700448 if (ret < 0) {
449 pr_err("%s: %s no fv_uv (%d)\n", __func__, name, ret);
450 return ret;
451 }
452
453 ret = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700454 cc_max);
AleX Pelosia0f55512021-03-17 00:30:20 -0700455 if (ret < 0)
456 pr_err("%s: %s no cc_max (%d)\n", __func__, name, ret);
457
458 return ret;
459}
460
461/* setting online might start charging (if ENABLE is set) */
AleX Pelosib961e472022-02-09 19:33:47 -0800462static int gcpm_chg_online(struct power_supply *chg_psy, int fv_uv, int cc_max)
AleX Pelosia0f55512021-03-17 00:30:20 -0700463{
464 const char *name = gcpm_psy_name(chg_psy);
465 bool preset_ok = true;
466 int ret;
467
AleX Pelosib961e472022-02-09 19:33:47 -0800468 if (!chg_psy) {
AleX Pelosi56311c32021-06-10 15:06:10 -0700469 pr_err("%s: invalid charger\n", __func__);
470 return -EINVAL;
471 }
472
AleX Pelosia0f55512021-03-17 00:30:20 -0700473 /* preset the new charger */
AleX Pelosib961e472022-02-09 19:33:47 -0800474 ret = gcpm_chg_preset(chg_psy, fv_uv, cc_max);
AleX Pelosia0f55512021-03-17 00:30:20 -0700475 if (ret < 0)
476 preset_ok = false;
477
478 /* online (but so we can enable it) */
479 ret = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_ONLINE, 1);
480 if (ret < 0) {
481 pr_debug("%s: %s online failed (%d)\n", __func__, name, ret);
482 return ret;
483 }
484
485 /* retry preset if failed */
486 if (!preset_ok)
AleX Pelosib961e472022-02-09 19:33:47 -0800487 ret = gcpm_chg_preset(chg_psy, fv_uv, cc_max);
AleX Pelosia0f55512021-03-17 00:30:20 -0700488 if (ret < 0) {
489 int rc;
490
491 pr_err("%s: %s preset failed (%d)\n", __func__, name, ret);
492
493 rc = GPSY_SET_PROP(chg_psy, POWER_SUPPLY_PROP_ONLINE, 0);
494 if (rc < 0)
495 pr_err("%s: %s offline failed (%d)\n", __func__, name, rc);
496 }
497
498 return ret;
499}
500
501/*
502 * gcpm->chg_psy_active == gcpm->dc_index on success.
503 * NOTE: call with a lock around gcpm->chg_psy_lock
504 */
AleX Pelosib961e472022-02-09 19:33:47 -0800505static int gcpm_chg_start(struct gcpm_drv *gcpm, int index, int fv_uv, int cc_max)
AleX Pelosia0f55512021-03-17 00:30:20 -0700506{
507 const int active_index = gcpm->chg_psy_active;
508 struct power_supply *chg_psy;
509 int ret = -EINVAL;
510
511 if (index == active_index)
512 return 0;
513
514 if (active_index != -1)
515 pr_err("%s: %d->%d not idle\n", __func__, active_index, index);
516
517 /* validate the index before switch */
518 chg_psy = gcpm_chg_get_charger(gcpm, index);
519 if (chg_psy)
AleX Pelosib961e472022-02-09 19:33:47 -0800520 ret = gcpm_chg_online(chg_psy, fv_uv, cc_max);
AleX Pelosia0f55512021-03-17 00:30:20 -0700521 if (ret < 0) {
522 /* TODO: force active_index if != -1 */
523 pr_debug("%s: index=%d not online (%d)\n",
524 __func__, index, ret);
525 return ret;
526 }
527
528 pr_debug("%s: active=%d->%d\n", __func__, active_index, index);
529
530 gcpm->chg_psy_active = index;
531 return ret;
532}
533
534/*
535 * Enable DirectCharge mode, PPS and DC charger must be already initialized
536 * NOTE: disable might restart the default charger with stale settings
537 */
Ken Tsou8acade12020-07-09 03:17:35 +0800538static int gcpm_dc_enable(struct gcpm_drv *gcpm, bool enabled)
539{
AleX Pelosia0f55512021-03-17 00:30:20 -0700540 if (gcpm->dcen_gpio >= 0 && !gcpm->dcen_gpio_default)
541 gpio_set_value(gcpm->dcen_gpio, enabled);
542
Ken Tsou8acade12020-07-09 03:17:35 +0800543 if (!gcpm->gbms_mode) {
544 struct gvotable_election *v;
545
546 v = gvotable_election_get_handle(GBMS_MODE_VOTABLE);
547 if (IS_ERR_OR_NULL(v))
548 return -ENODEV;
549 gcpm->gbms_mode = v;
550 }
551
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800552 return gvotable_cast_long_vote(gcpm->gbms_mode, "GCPM",
553 GBMS_CHGR_MODE_CHGR_DC, enabled);
Ken Tsou8acade12020-07-09 03:17:35 +0800554}
555
AleX Pelosif3776622021-01-18 13:32:08 -0800556/*
557 * disable DC and switch back to the default charger. Final DC statate is
558 * DC_IDLE (i.e. this can be used to reset dc_state from DC_DISABLED).
559 * NOTE: call with a lock around gcpm->chg_psy_lock
AleX Pelosia0f55512021-03-17 00:30:20 -0700560 * NOTE: I could pass in and return dc_state instead of changing gcpm
AleX Pelosief75a072021-06-12 17:38:36 -0700561 * must hold a lock on mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosif3776622021-01-18 13:32:08 -0800562 */
AleX Pelosia0f55512021-03-17 00:30:20 -0700563static int gcpm_dc_stop(struct gcpm_drv *gcpm, int index)
Ken Tsou8acade12020-07-09 03:17:35 +0800564{
AleX Pelosi29b5cab2021-09-27 11:39:25 -0700565 int dc_state = gcpm->dc_state;
AleX Pelosia0f55512021-03-17 00:30:20 -0700566 int ret = 0;
Ken Tsou8acade12020-07-09 03:17:35 +0800567
AleX Pelosi568ddbf2021-03-23 23:56:50 -0700568 if (!gcpm_is_dc(gcpm, index))
AleX Pelosi29b5cab2021-09-27 11:39:25 -0700569 dc_state = DC_ENABLE_PASSTHROUGH;
Ken Tsou8acade12020-07-09 03:17:35 +0800570
AleX Pelosi29b5cab2021-09-27 11:39:25 -0700571 switch (dc_state) {
Ken Tsou8acade12020-07-09 03:17:35 +0800572 case DC_RUNNING:
573 case DC_PASSTHROUGH:
AleX Pelosia0f55512021-03-17 00:30:20 -0700574 ret = gcpm_chg_offline(gcpm, index);
575 if (ret < 0)
576 pr_warn("DC_PPS: Cannot offline DC index=%d (%d)",
577 index, ret);
578 else
579 gcpm->dc_state = DC_ENABLE;
580 /* Fall Through */
581 case DC_ENABLE:
582 case DC_ENABLE_PASSTHROUGH:
Ken Tsou8acade12020-07-09 03:17:35 +0800583 ret = gcpm_dc_enable(gcpm, false);
584 if (ret < 0) {
585 pr_err("DC_PPS: Cannot disable DC (%d)", ret);
586 break;
587 }
Ken Tsou8acade12020-07-09 03:17:35 +0800588 /* Fall Through */
589 default:
AleX Pelosia0f55512021-03-17 00:30:20 -0700590 gcpm->dc_state = DC_DISABLED;
Ken Tsou8acade12020-07-09 03:17:35 +0800591 break;
592 }
593
594 return ret;
595}
596
AleX Pelosib961e472022-02-09 19:33:47 -0800597/*
598 * route the dc_limit to MSC_FCC for wireless charing.
599 * @return <0 on error, 0 on limit not applied, 1 on limit applied (and positive)
600 * call holding a lock on mutex_lock(&gcpm->chg_psy_lock);
601 */
602static int gcpm_dc_fcc_update(struct gcpm_drv *gcpm, int value)
603{
604 struct gvotable_election *msc_fcc;
605 int limit = value;
606 int ret = -ENODEV;
607
608 msc_fcc = gcpm_get_fcc_votable(gcpm);
609 if (!msc_fcc)
610 goto error_exit;
611
612 /* apply/enable DC_FCC only when a WLC_DC source is selected */
Wasb Liu8e2ddbd2022-07-28 17:55:03 +0800613 if ((gcpm->pps_index != PPS_INDEX_WLC) ||
614 (gcpm->dc_index <= GCPM_DEFAULT_CHARGER) || limit < 0)
AleX Pelosib961e472022-02-09 19:33:47 -0800615 limit = -1;
616
617 /*
618 * The thermal voter for FCC wired must be disabled to allow higher
619 * charger rates for DC_FCC than for the wired case.
620 */
621 ret = gvotable_cast_int_vote(msc_fcc, "DC_FCC", limit, limit >= 0);
622 if (ret < 0)
623 pr_err("%s: vote %d on MSC_FCC failed (%d)\n", __func__,
624 limit, ret);
625 else
626 ret = limit >= 0;
627
628error_exit:
AleX Pelosi430da992022-06-05 23:52:25 +0000629 dev_dbg(gcpm->device, "%s: DC_FCC->MSC_FCC pps_index=%d value=%d limit=%d applied=%d\n",
630 __func__, gcpm->pps_index, value, limit, ret);
AleX Pelosib961e472022-02-09 19:33:47 -0800631
632 return ret;
633}
634
AleX Pelosi833497e2022-04-07 13:37:01 -0700635/*
AleX Pelosiafb445a2022-05-17 20:15:01 +0000636 * route the dc_limit to MSC_FCC for wireless charging and adjust the MDIS
AleX Pelosicba61dd2022-05-19 03:40:37 +0000637 * limits when switching between CP and non CP charging.
AleX Pelosiafb445a2022-05-17 20:15:01 +0000638 * NOTE: when in MDIS is at level = 0 the cooling zone disable the MDIS votes
639 * on MSC_FCC, DC_ICL and GCPM_FCC.
AleX Pelosicba61dd2022-05-19 03:40:37 +0000640 * NOTE: called with negative cp_limit when switching from WLC_CP to WLC and
641 * with the HOLD limit when re-starting PPS_DC and WLC_DC.
AleX Pelosifed6c8c2022-05-02 16:32:05 -0700642 * @return <0 on error, 0 on limit not applied, 1 on limit applied and positive
AleX Pelosi833497e2022-04-07 13:37:01 -0700643 * call holding a lock on mutex_lock(&gcpm->chg_psy_lock);
644 */
645static int gcpm_update_votes(struct gcpm_drv *gcpm, int cp_limit)
646{
AleX Pelosiafb445a2022-05-17 20:15:01 +0000647 const bool enable = gcpm->thermal_device.current_level > 0;
AleX Pelosi833497e2022-04-07 13:37:01 -0700648 struct gvotable_election *el;
649 int ret;
650
AleX Pelosi5229a772022-06-14 07:08:02 +0000651 pr_debug("%s: cp_limit=%d\n", __func__, cp_limit);
652
AleX Pelosi02431162022-06-03 21:06:40 +0000653 /* update DC_FCC limit before disabling the others */
AleX Pelosi833497e2022-04-07 13:37:01 -0700654 if (cp_limit > 0)
AleX Pelosicba61dd2022-05-19 03:40:37 +0000655 ret = gcpm_dc_fcc_update(gcpm, enable ? cp_limit : -1);
AleX Pelosi833497e2022-04-07 13:37:01 -0700656
AleX Pelosi02431162022-06-03 21:06:40 +0000657 /* vote on DC_ICL */
AleX Pelosi833497e2022-04-07 13:37:01 -0700658 el = gcpm_get_dc_icl_votable(gcpm);
AleX Pelosifed6c8c2022-05-02 16:32:05 -0700659 if (el)
AleX Pelosi5229a772022-06-14 07:08:02 +0000660 gvotable_recast_ballot(el, "MDIS", enable && cp_limit == 0);
AleX Pelosi833497e2022-04-07 13:37:01 -0700661
AleX Pelosi02431162022-06-03 21:06:40 +0000662 /* vote on MSC_FCC: applied only when CP is not enabled */
AleX Pelosi833497e2022-04-07 13:37:01 -0700663 el = gcpm_get_fcc_votable(gcpm);
AleX Pelosifed6c8c2022-05-02 16:32:05 -0700664 if (el)
AleX Pelosi5229a772022-06-14 07:08:02 +0000665 gvotable_recast_ballot(el, "MDIS", enable && cp_limit == 0);
AleX Pelosiafb445a2022-05-17 20:15:01 +0000666
AleX Pelosi02431162022-06-03 21:06:40 +0000667 /* vote on GCPM_FCC: valid only on cp */
AleX Pelosiafb445a2022-05-17 20:15:01 +0000668 el = gcpm_get_cp_votable(gcpm);
669 if (el)
AleX Pelosi02431162022-06-03 21:06:40 +0000670 gvotable_recast_ballot(el, "MDIS", enable && cp_limit);
AleX Pelosi833497e2022-04-07 13:37:01 -0700671
AleX Pelosi02431162022-06-03 21:06:40 +0000672 /* update DC_FCC limit after enabling the others */
AleX Pelosi833497e2022-04-07 13:37:01 -0700673 if (cp_limit <= 0)
AleX Pelosicba61dd2022-05-19 03:40:37 +0000674 ret = gcpm_dc_fcc_update(gcpm, enable ? cp_limit : -1);
AleX Pelosi833497e2022-04-07 13:37:01 -0700675
676 return ret;
677}
678
679
Ken Tsou8acade12020-07-09 03:17:35 +0800680/* NOTE: call with a lock around gcpm->chg_psy_lock */
681static int gcpm_dc_start(struct gcpm_drv *gcpm, int index)
682{
AleX Pelosib961e472022-02-09 19:33:47 -0800683 const int dc_iin = gcpm_get_gcpm_fcc(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +0800684 struct power_supply *dc_psy;
685 int ret;
686
AleX Pelosicba61dd2022-05-19 03:40:37 +0000687 pr_info("PPS_DC: index=%d dc_iin=%d hold=%d\n",
688 index, dc_iin, gcpm->cp_fcc_hold_limit);
AleX Pelosib961e472022-02-09 19:33:47 -0800689
AleX Pelosicae94c32021-05-25 21:54:54 -0700690 /* ENABLE will be called by the dc_pps workloop */
AleX Pelosib961e472022-02-09 19:33:47 -0800691 ret = gcpm_chg_start(gcpm, index, gcpm->fv_uv, dc_iin);
Ken Tsou8acade12020-07-09 03:17:35 +0800692 if (ret < 0) {
AleX Pelosia0f55512021-03-17 00:30:20 -0700693 pr_err("PPS_DC: index=%d not started (%d)\n", index, ret);
Ken Tsou8acade12020-07-09 03:17:35 +0800694 return ret;
695 }
696
AleX Pelosief75a072021-06-12 17:38:36 -0700697 /*
698 * Restoring the DC_FCC limit might change charging current and cause
699 * demand to fall under dc_limit_demand. The possible resulting loop
700 * (enable/disable) is solved in gcpm_chg_select_work().
AleX Pelosicba61dd2022-05-19 03:40:37 +0000701 * NOTE: ->cp_fcc_hold_limit cannot be 0
AleX Pelosief75a072021-06-12 17:38:36 -0700702 */
AleX Pelosi833497e2022-04-07 13:37:01 -0700703 ret = gcpm_update_votes(gcpm, gcpm->cp_fcc_hold_limit);
AleX Pelosief75a072021-06-12 17:38:36 -0700704 if (ret < 0)
AleX Pelosi02431162022-06-03 21:06:40 +0000705 pr_debug("PPS_DC: start cannot update votes (%d)\n", ret);
AleX Pelosief75a072021-06-12 17:38:36 -0700706
Wasb Liu42b15322022-11-24 14:40:51 +0800707 ret = gcpm_update_gcpm_fcc(gcpm, "CC_MAX", gcpm->cc_max, true);
708 if (ret < 0)
709 pr_debug("PPS_DC: start cannot update cp_fcc (%d)\n", ret);
710
AleX Pelosib961e472022-02-09 19:33:47 -0800711 /* this is the CP */
712 dc_psy = gcpm_chg_get_active_cp(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +0800713 if (!dc_psy) {
714 pr_err("PPS_DC: gcpm->dc_state == DC_READY, no adapter\n");
715 return -ENODEV;
716 }
717
AleX Pelosief75a072021-06-12 17:38:36 -0700718 /* set IIN_CFG (might not need) */
Ken Tsou8acade12020-07-09 03:17:35 +0800719 ret = GPSY_SET_PROP(dc_psy, POWER_SUPPLY_PROP_CURRENT_MAX,
720 gcpm->out_ua);
721 if (ret < 0) {
722 pr_err("PPS_DC: no IIN (%d)\n", ret);
723 return ret;
724 }
725
AleX Pelosif3776622021-01-18 13:32:08 -0800726 /* vote on MODE */
Ken Tsou8acade12020-07-09 03:17:35 +0800727 ret = gcpm_dc_enable(gcpm, true);
728 if (ret < 0) {
AleX Pelosi9cba1082021-02-05 10:45:11 -0800729 pr_err("PPS_DC: dc_ready failed=%d\n", ret);
Ken Tsou8acade12020-07-09 03:17:35 +0800730 return ret;
731 }
732
AleX Pelosi9cba1082021-02-05 10:45:11 -0800733 pr_debug("PPS_DC: dc_ready ok state=%d fv_uv=%d cc_max=%d, out_ua=%d\n",
Ken Tsou8acade12020-07-09 03:17:35 +0800734 gcpm->dc_state, gcpm->fv_uv, gcpm->cc_max, gcpm->out_ua);
735
736 return 0;
737}
738
AleX Pelosif3776622021-01-18 13:32:08 -0800739/*
AleX Pelosic6a1bb22021-07-15 23:15:32 -0700740 * Select the DC charger using the thermal policy.
741 * DC charging is enabled when demand is over dc_limit (default 0) and
742 * vbatt > vbatt_min (default or device tree). DC is not disabled when
743 * vbatt is over vbat low.
744 * DC is stopped when vbatt is over vbatt_max (default or DT) and not started
745 * when vbatt is over vbatt_high (some default 200mV under vbatt_max).
AleX Pelosif3776622021-01-18 13:32:08 -0800746 * NOTE: program target before enabling chaging.
747 */
Ted Lind35c7422021-05-17 11:32:58 +0800748enum gcpm_dc_ctl_t {
749 GCPM_DC_CTL_DEFAULT = 0,
750 GCPM_DC_CTL_DISABLE_WIRED,
751 GCPM_DC_CTL_DISABLE_WIRELESS,
752 GCPM_DC_CTL_DISABLE_BOTH,
753};
754
AleX Pelosib961e472022-02-09 19:33:47 -0800755/*
756 * the current source as index in mdis_in[].
757 * < 0 error, the index in mdis_in[] if the source is in PPS mode
758 */
759static int gcpm_mdis_match_cp_source(struct gcpm_drv *gcpm, int *online)
760{
761 union power_supply_propval pval;
762 int i, ret;
763
764 for (i = 0; i < MDIS_IN_MAX; i++) {
765 if (!gcpm->mdis_in[i])
766 continue;
767
768 ret = power_supply_get_property(gcpm->mdis_in[i],
769 POWER_SUPPLY_PROP_ONLINE,
770 &pval);
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700771 if (ret || !pval.intval)
AleX Pelosib961e472022-02-09 19:33:47 -0800772 continue;
773
774 *online = pval.intval;
775 return i;
776 }
777
778 return -EINVAL;
779}
780
AleX Pelosi430da992022-06-05 23:52:25 +0000781static int gcpm_mdis_in_is_wireless(struct gcpm_drv *gcpm, int index)
782{
783 return index == 1; /* TODO: query at startup using type==WIRELESS */
784}
785
AleX Pelosicba61dd2022-05-19 03:40:37 +0000786/* return the PPS_CP or the WLC_CP limit */
AleX Pelosiba7f4ec2022-05-18 03:00:39 +0000787static int gcpm_chg_select_check_cp_limit(struct gcpm_drv *gcpm)
Ken Tsou8acade12020-07-09 03:17:35 +0800788{
AleX Pelosi430da992022-06-05 23:52:25 +0000789 int online, cp_min = -1, in_idx;
Ted Lind35c7422021-05-17 11:32:58 +0800790
AleX Pelosi430da992022-06-05 23:52:25 +0000791 in_idx = gcpm_mdis_match_cp_source(gcpm, &online);
792 if (in_idx < 0 || gcpm_mdis_in_is_wireless(gcpm, in_idx)) {
793 if (gcpm->dc_limit_cc_min_wlc >= 0)
794 cp_min = gcpm->dc_limit_cc_min_wlc;
795 } else if (gcpm->dc_limit_cc_min >= 0) {
AleX Pelosicba61dd2022-05-19 03:40:37 +0000796 cp_min = gcpm->dc_limit_cc_min;
AleX Pelosi430da992022-06-05 23:52:25 +0000797 }
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700798
AleX Pelosi430da992022-06-05 23:52:25 +0000799 /* wlc might use a different (higher) CP limit than wired */
800 dev_dbg(gcpm->device, "%s: in_idx=%d cp_min=%d\n", __func__, in_idx, cp_min);
AleX Pelosiba7f4ec2022-05-18 03:00:39 +0000801 return cp_min;
802}
803
804/* call holding mutex_lock(&gcpm->chg_psy_lock) */
805static int gcpm_chg_select_by_demand(struct gcpm_drv *gcpm)
806{
AleX Pelosiba7f4ec2022-05-18 03:00:39 +0000807 int cc_max = gcpm->cc_max; /* from google_charger */
808 int index = GCPM_DEFAULT_CHARGER;
809 int batt_demand = -1;
AleX Pelosi430da992022-06-05 23:52:25 +0000810 int cp_min;
AleX Pelosiba7f4ec2022-05-18 03:00:39 +0000811
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700812 /*
AleX Pelosi02431162022-06-03 21:06:40 +0000813 * ->cc_max is lowered from the main-charger thermal limit and might
814 * prevent this code from selecting the CP charger again when thermals
815 * caused this code to switch from CP to the main charger.
AleX Pelosib961e472022-02-09 19:33:47 -0800816 *
817 * NOTE: Need to check the value directly because source selection is
818 * done holding a lock on &gcpm->chg_psy_lock (cc_max will become the
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700819 * same as gcpm->cp_fcc_hold_limit on exit).
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700820 */
Wasb Liu97123872022-11-11 17:37:30 +0800821 if (gcpm->cp_fcc_hold && gcpm->cp_fcc_hold_limit >= 0 && cc_max != 0) {
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700822 /*
AleX Pelosi02431162022-06-03 21:06:40 +0000823 * ->cp_fcc_hold is set when a thermal limit caused the switch
824 * from CP to main-charger. In this case ->cp_fcc_hold_limit
825 * keeps the current (alternate) CP limit that should be used
826 * to determine whether to go back to the Charge Pump.
827 * NOTE: ->cp_fcc_hold_limit is changed when the DC_FCC changes
828 * (wireless CP) AND when MDIS changes but is not changed when
829 * the MSC_FCC limit changes. This means that without MDIS
830 * CP will restart on PD wired only when the actual charging
831 * current exceeds the cp_min limit.
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700832 */
AleX Pelosi430da992022-06-05 23:52:25 +0000833 dev_dbg(gcpm->device, "%s: change due to hold cc_max=%d->%d\n",
834 __func__, cc_max, gcpm->cp_fcc_hold_limit);
AleX Pelosi02431162022-06-03 21:06:40 +0000835 cc_max = gcpm->cp_fcc_hold_limit;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700836 }
837
AleX Pelosic6a1bb22021-07-15 23:15:32 -0700838 /* keeps on default charger until we have valid charging parameters */
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700839 if (cc_max <= 0 || gcpm->fv_uv <= 0)
AleX Pelosi87e78af2022-02-08 15:08:43 -0800840 goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
AleX Pelosif3776622021-01-18 13:32:08 -0800841
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700842 /*
AleX Pelosi87e78af2022-02-08 15:08:43 -0800843 * power demand comes from charging tier or thermal limit: leave
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700844 * dc_limit_demand to 0 to switch only on cp_min.
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700845 * TODO: handle capabilities based on index number
846 */
847 batt_demand = (cc_max / 1000) * (gcpm->fv_uv / 1000);
AleX Pelosidc530cf2021-05-12 05:36:53 -0700848 if (batt_demand > gcpm->dc_limit_demand)
AleX Pelosif20ccc82021-02-12 22:57:34 -0800849 index = GCPM_INDEX_DC_ENABLE;
AleX Pelosif3776622021-01-18 13:32:08 -0800850
AleX Pelosi430da992022-06-05 23:52:25 +0000851 dev_dbg(gcpm->device, "%s: index=%d cc_max=%d gcpm->fv_uv=%d demand=%d, dc_limit=%d\n",
852 __func__, index, cc_max / 1000, gcpm->fv_uv / 1000,
853 batt_demand, gcpm->dc_limit_demand);
AleX Pelosif3776622021-01-18 13:32:08 -0800854
AleX Pelosi430da992022-06-05 23:52:25 +0000855 /*
856 * the limit for DC depends on the source that is active with the
857 * complication that using the DC_ICL disables the THERMAL limit
858 * on MSC_FCC and will cause an immediate reselection of CP.
859 * The code settig ->hold and ->cp_fcc_hold_limit needs to make sure
860 * that the limit is appropriate.
861 */
862 cp_min = gcpm_chg_select_check_cp_limit(gcpm);
863 if (cp_min == -1 || cc_max <= cp_min) {
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700864 const bool cp_active = gcpm_chg_is_cp_active(gcpm);
865
AleX Pelosi430da992022-06-05 23:52:25 +0000866 /* current demand less than min demand for CP */
867 dev_dbg(gcpm->device,
868 "%s: cc_max=%d under cp_min=%d, ->hold=%d->%d index:%d->%d\n",
869 __func__, cc_max, cp_min, gcpm->cp_fcc_hold,
870 gcpm->cp_fcc_hold ? gcpm->cp_fcc_hold : cp_active,
871 index, GCPM_DEFAULT_CHARGER);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -0700872
AleX Pelosib961e472022-02-09 19:33:47 -0800873 /*
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700874 * Switch to the default charger and hold it.
875 * NOTE: ->cp_fcc_hold is reset in gcpm_dc_fcc_callback()
AleX Pelosi430da992022-06-05 23:52:25 +0000876 * and when the MDIS thermal limit changes. This piece is
877 * only for legacy dc_fcc since the mdis code handle this.
AleX Pelosib961e472022-02-09 19:33:47 -0800878 */
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700879 if (!gcpm->cp_fcc_hold)
880 gcpm->cp_fcc_hold = cp_active;
AleX Pelosi430da992022-06-05 23:52:25 +0000881
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700882 index = GCPM_DEFAULT_CHARGER;
AleX Pelosibc7f0a22021-04-03 15:17:41 -0700883 }
884
AleX Pelosi87e78af2022-02-08 15:08:43 -0800885exit_done:
AleX Pelosi430da992022-06-05 23:52:25 +0000886 dev_dbg(gcpm->device,
887 "by_d: index:%d->%d demand=%d,limit=%d cc_max=%d,cp_min=%d, hold=%d",
888 gcpm->dc_index, index, batt_demand, gcpm->dc_limit_demand,
889 cc_max, cp_min, gcpm->cp_fcc_hold);
AleX Pelosi87e78af2022-02-08 15:08:43 -0800890 return index;
891}
892
893/*
894 * called only before enabling DC to debounce HIGH SOC.
AleX Pelosib961e472022-02-09 19:33:47 -0800895 * call holding mutex_lock(&gcpm->chg_psy_lock)
AleX Pelosi87e78af2022-02-08 15:08:43 -0800896 */
897static int gcpm_chg_select_by_soc(struct power_supply *psy,
898 const struct gcpm_drv *gcpm)
899{
900 union power_supply_propval pval = { };
901 int index = gcpm->dc_index; /* debounce it */
902 int ret;
903
904 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CAPACITY, &pval);
905 if (ret < 0 || pval.intval < gcpm->dc_limit_soc_high)
906 index = GCPM_INDEX_DC_ENABLE;
907
908 pr_debug("%s: index=%d->%d ret=%d soc=%d limit=%d\n", __func__,
909 gcpm->dc_index, index, ret, pval.intval,
910 gcpm->dc_limit_soc_high);
911
AleX Pelosi87e78af2022-02-08 15:08:43 -0800912 return index;
913}
914
AleX Pelosib961e472022-02-09 19:33:47 -0800915/* call holding mutex_lock(&gcpm->chg_psy_lock) */
AleX Pelosi87e78af2022-02-08 15:08:43 -0800916static int gcpm_chg_select_by_voltage(struct power_supply *psy,
917 const struct gcpm_drv *gcpm)
918{
919 const int vbatt_min = gcpm->dc_limit_vbatt_min;
920 const int vbatt_max = gcpm->dc_limit_vbatt_max;
921 const int vbatt_high = gcpm->dc_limit_vbatt_high;
922 const int vbatt_low = gcpm->dc_limit_vbatt_low;
923 int index = GCPM_DEFAULT_CHARGER;
924 int vbatt = -1;
925
926 if (!vbatt_min && !vbatt_max)
927 return GCPM_INDEX_DC_ENABLE;
928
929 vbatt = GPSY_GET_PROP(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
930 if (vbatt < 0) {
931 pr_err("CHG_CHK cannot read vbatt %d\n", vbatt);
932 goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
933 }
934
935 /* vbatt_max is the hard limit */
936 if (vbatt_max && vbatt > vbatt_max)
937 goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
938
939 /*
940 * Need to keep checking the voltage when vbatt is under low
941 * to make sure that DC starts at vbatt_min. Also keeps the
942 * same ->dc_index to avoid instability but keep checking
943 * demand.
944 */
945 if (vbatt_low && vbatt < vbatt_low) {
946 index = gcpm->dc_index == GCPM_DEFAULT_CHARGER ?
947 -EAGAIN : gcpm->dc_index; /* debounce */
948 } else if (vbatt_min && vbatt < vbatt_min) {
949 index = gcpm->dc_index == GCPM_DEFAULT_CHARGER ?
950 -EAGAIN : gcpm->dc_index; /* debounce */
951 } else if (vbatt_high && vbatt > vbatt_high) {
952 index = gcpm->dc_index; /* debounce */
953 } else {
954 /* vbatt_min <= vbatt <= vbatt_high */
955 index = GCPM_INDEX_DC_ENABLE;
956 }
957
958exit_done:
959
960 pr_debug("%s: index=%d->%d vbatt=%d: low=%d min=%d high=%d max=%d\n",
961 __func__, gcpm->dc_index, index, vbatt, vbatt_low, vbatt_min,
962 vbatt_high, vbatt_max);
AleX Pelosif3776622021-01-18 13:32:08 -0800963
AleX Pelosi87e78af2022-02-08 15:08:43 -0800964 return index;
965}
966
967/* call holding mutex_lock(&gcpm->chg_psy_lock) */
968static int gcpm_chg_select(struct gcpm_drv *gcpm)
969{
970 int index = GCPM_DEFAULT_CHARGER;
Prasanna Prapanchamb13d9b52022-11-04 17:29:49 +0000971 int ret;
AleX Pelosi87e78af2022-02-08 15:08:43 -0800972
973 if (!gcpm->dc_init_complete)
974 goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
975
AleX Pelosi0937c4c2022-03-28 22:22:10 -0700976 /* overrides cp_fcc_hold, might trigger taper_control */
AleX Pelosi87e78af2022-02-08 15:08:43 -0800977 if (gcpm->force_active >= 0)
978 return gcpm->force_active;
979
980 /* kill switch */
981 if (gcpm->dc_ctl == GCPM_DC_CTL_DISABLE_BOTH)
982 goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
983
Prasanna Prapanchamb13d9b52022-11-04 17:29:49 +0000984 ret = gvotable_get_current_int_vote(gcpm->dc_chg_avail_votable);
985 dev_dbg(gcpm->device, "%s: dc_chg_avail vote: %d\n", __func__, ret);
986 if (ret <= 0)
987 goto exit_done;
988
AleX Pelosi87e78af2022-02-08 15:08:43 -0800989 /*
990 * check demand first to react to thermal engine, then voltage to
991 * make sure that we are over min and that we don't start over high
992 * and we stop at max, finally use SOC to not restart if over a
993 * SOC%
994 */
995 index = gcpm_chg_select_by_demand(gcpm);
996 if (index == GCPM_INDEX_DC_ENABLE) {
997 struct power_supply *chg_psy;
998
999 /* checking the current charger, should check battery? */
1000 chg_psy = gcpm_chg_get_default(gcpm);
1001 if (chg_psy) {
1002 index = gcpm_chg_select_by_voltage(chg_psy, gcpm);
1003 if (index == GCPM_INDEX_DC_ENABLE)
1004 index = gcpm_chg_select_by_soc(chg_psy, gcpm);
1005 }
1006 }
1007
1008exit_done:
1009
1010 /* consistency check */
1011 if (index >= gcpm->chg_psy_count) {
1012 pr_err("CHG_CHK index=%d out of bounds %d\n", index,
1013 gcpm->chg_psy_count);
1014 index = GCPM_DEFAULT_CHARGER;
1015 }
AleX Pelosifc92c9e2021-07-08 11:16:51 -07001016
AleX Pelosif3776622021-01-18 13:32:08 -08001017 return index;
Ken Tsou8acade12020-07-09 03:17:35 +08001018}
1019
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001020static bool gcpm_chg_dc_check_source(const struct gcpm_drv *gcpm, int index)
Ken Tsou8acade12020-07-09 03:17:35 +08001021{
AleX Pelosif3776622021-01-18 13:32:08 -08001022 /* Will run detection only the first time */
1023 if (gcpm->tcpm_pps_data.stage == PPS_NOTSUPP &&
1024 gcpm->wlc_pps_data.stage == PPS_NOTSUPP )
1025 return false;
1026
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001027 return gcpm_is_dc(gcpm, index);
Ken Tsou8acade12020-07-09 03:17:35 +08001028}
1029
AleX Pelosia0f55512021-03-17 00:30:20 -07001030/* reset gcpm pps state */
AleX Pelosif3776622021-01-18 13:32:08 -08001031static void gcpm_pps_online(struct gcpm_drv *gcpm)
1032{
1033 /* reset setpoint */
1034 gcpm->out_ua = -1;
1035 gcpm->out_uv = -1;
1036
1037 /* reset detection */
Ted Lind35c7422021-05-17 11:32:58 +08001038 if (gcpm->tcpm_pps_data.pps_psy) {
AleX Pelosif3776622021-01-18 13:32:08 -08001039 pps_init_state(&gcpm->tcpm_pps_data);
Ted Lind35c7422021-05-17 11:32:58 +08001040 if (gcpm->dc_ctl & GCPM_DC_CTL_DISABLE_WIRED)
1041 gcpm->tcpm_pps_data.stage = PPS_NOTSUPP;
1042 }
1043 if (gcpm->wlc_pps_data.pps_psy) {
AleX Pelosif3776622021-01-18 13:32:08 -08001044 pps_init_state(&gcpm->wlc_pps_data);
Ted Lind35c7422021-05-17 11:32:58 +08001045 if (gcpm->dc_ctl & GCPM_DC_CTL_DISABLE_WIRELESS)
1046 gcpm->wlc_pps_data.stage = PPS_NOTSUPP;
1047 }
AleX Pelosif3776622021-01-18 13:32:08 -08001048 gcpm->pps_index = 0;
1049}
1050
AleX Pelosif3776622021-01-18 13:32:08 -08001051static struct pd_pps_data *gcpm_pps_data(struct gcpm_drv *gcpm)
1052{
1053 struct pd_pps_data *pps_data = NULL;
1054
1055 if (gcpm->pps_index == PPS_INDEX_TCPM)
1056 pps_data = &gcpm->tcpm_pps_data;
1057 else if (gcpm->pps_index == PPS_INDEX_WLC)
1058 pps_data = &gcpm->wlc_pps_data;
1059
1060 return pps_data;
1061}
1062
AleX Pelosi30afcb82021-07-13 10:50:57 -07001063/* Wait for a source to become ready for the handoff */
AleX Pelosi0303a572021-07-01 21:15:06 -07001064static int gcpm_pps_wait_for_ready(struct gcpm_drv *gcpm)
1065{
1066 struct pd_pps_data *pps_data = gcpm_pps_data(gcpm);
1067 int pps_ui, vout = -1, iout = -1;
1068 bool pwr_ok = false;
1069
1070 if (!pps_data)
1071 return -ENODEV;
1072
1073 /* determine the limit/levels if needed */
1074 if (gcpm->pps_index == PPS_INDEX_WLC) {
1075 struct power_supply *chg_psy = gcpm_chg_get_active(gcpm);
1076 int vbatt = -1;
1077
1078 if (chg_psy)
1079 vbatt = GPSY_GET_PROP(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
1080 if (vbatt > 0)
1081 vout = vbatt * 4;
1082 } else {
1083 pwr_ok = true;
1084 }
1085
1086 /* always need to ping */
1087 pps_ui = pps_update_adapter(pps_data, vout, iout, pps_data->pps_psy);
1088 if (pps_ui < 0) {
1089 pr_err("PPS_Work: pps update, dc_state=%d (%d)\n",
1090 gcpm->dc_state, pps_ui);
1091 return pps_ui;
1092 }
1093
1094 /* wait until adapter is at or over request */
1095 pwr_ok |= (vout <=0 || pps_data->out_uv >= vout) &&
1096 (iout <=0 || pps_data->op_ua >= iout );
1097
1098 pr_info("PPS_Work: pwr_ok=%d pps_ui=%d vout=%d out_uv=%d iout=%d op_ua=%d\n",
1099 pwr_ok, pps_ui, vout, pps_data->out_uv, iout, pps_data->op_ua);
1100
1101 return pwr_ok ? pps_ui : -EAGAIN;
1102}
1103
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001104/* return true when pd_online=PROG_ONLINE and stage=ACTIVE */
1105static int gcpm_pps_check_active(struct pd_pps_data *pps_data)
AleX Pelosi0f914572021-09-21 12:18:30 -07001106{
1107 int pps_ui;
1108
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001109 /* not supported for this stage */
AleX Pelosi0f914572021-09-21 12:18:30 -07001110 if (pps_data->stage == PPS_NOTSUPP)
1111 return 0;
1112
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001113 /* <0 for error, 0 for done, or the next polling interval */
AleX Pelosi0f914572021-09-21 12:18:30 -07001114 pps_ui = pps_work(pps_data, pps_data->pps_psy);
1115 if (pps_data->pd_online < PPS_PSY_PROG_ONLINE)
1116 pr_debug("PPS_Work: TCPM Wait %s pps_ui=%d online=%d, stage=%d\n",
1117 pps_name(pps_data->pps_psy), pps_ui, pps_data->pd_online,
1118 pps_data->stage);
1119
1120 return pps_ui >= 0 && pps_data->stage == PPS_ACTIVE;
1121}
1122
AleX Pelosi0303a572021-07-01 21:15:06 -07001123/*
AleX Pelosi0f914572021-09-21 12:18:30 -07001124 * Debounce online, enable PROG on each of the sources (ping) source that
1125 * transition to PPS_ACTIVE and set the pps_index.
AleX Pelosif3776622021-01-18 13:32:08 -08001126 *
AleX Pelosi9cba1082021-02-05 10:45:11 -08001127 * ->stage ==
1128 * DISABLED => NONE -> AVAILABLE -> ACTIVE -> DISABLED
1129 * -> DISABLED
1130 * -> NOTSUPP
AleX Pelosif3776622021-01-18 13:32:08 -08001131 *
AleX Pelosi0f914572021-09-21 12:18:30 -07001132 * return -EAGAIN if none of the sources is online, -ENODEV none of the sources
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001133 * supports PPS, 0 if one of the sources is ONLINE an
AleX Pelosif3776622021-01-18 13:32:08 -08001134 */
1135static int gcpm_pps_work(struct gcpm_drv *gcpm)
1136{
AleX Pelosi0f914572021-09-21 12:18:30 -07001137 int rc, ret = 0, online = 0, pps_index = 0;
AleX Pelosif3776622021-01-18 13:32:08 -08001138
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001139 /*
1140 * rc>0 when source has .pd_online==PROG_ONLINE and .stage==ACTIVE
1141 * ,stage is active when the source has provided the source caps.
1142 */
1143 rc = gcpm_pps_check_active(&gcpm->tcpm_pps_data);
AleX Pelosi0f914572021-09-21 12:18:30 -07001144 if (rc <= 0) {
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001145 rc = gcpm_pps_check_active(&gcpm->wlc_pps_data);
AleX Pelosi0f914572021-09-21 12:18:30 -07001146 if (rc > 0)
AleX Pelosif3776622021-01-18 13:32:08 -08001147 pps_index = PPS_INDEX_WLC;
AleX Pelosi0f914572021-09-21 12:18:30 -07001148 else
1149 online |= gcpm->wlc_pps_data.pd_online != 0;
AleX Pelosif3776622021-01-18 13:32:08 -08001150
AleX Pelosi0f914572021-09-21 12:18:30 -07001151 online |= gcpm->tcpm_pps_data.pd_online != 0;
AleX Pelosif3776622021-01-18 13:32:08 -08001152 } else {
AleX Pelosi0f914572021-09-21 12:18:30 -07001153 pps_index = PPS_INDEX_TCPM;
AleX Pelosif3776622021-01-18 13:32:08 -08001154 }
1155
AleX Pelosif3776622021-01-18 13:32:08 -08001156 if (gcpm->pps_index != pps_index)
AleX Pelosi0f914572021-09-21 12:18:30 -07001157 logbuffer_log(gcpm->log, "PPS_Work: pps_index %d->%d\n",
1158 gcpm->pps_index, pps_index);
AleX Pelosief75a072021-06-12 17:38:36 -07001159
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001160 /* handles PPS source offline or NOT active anymore */
AleX Pelosi0f914572021-09-21 12:18:30 -07001161 if (pps_index == 0 && gcpm->pps_index)
AleX Pelosif3776622021-01-18 13:32:08 -08001162 ret = -ENODEV;
AleX Pelosi0f914572021-09-21 12:18:30 -07001163 else if (pps_index == 0 && !online)
1164 ret = -EAGAIN;
1165
1166 pr_debug("PPS_Work: tcpm[online=%d, stage=%d] wlc[online=%d, stage=%d] ol=%d ret=%d pps_index=%d->%d\n",
1167 gcpm->tcpm_pps_data.pd_online, gcpm->tcpm_pps_data.stage,
1168 gcpm->wlc_pps_data.pd_online, gcpm->wlc_pps_data.stage,
1169 online, ret, gcpm->pps_index, pps_index);
AleX Pelosif3776622021-01-18 13:32:08 -08001170
1171 gcpm->pps_index = pps_index;
1172 return ret;
1173}
1174
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -07001175static int gcpm_pps_timeout(struct gcpm_drv *gcpm)
1176{
1177 struct pd_pps_data *wlc_pps_data = &gcpm->wlc_pps_data;
1178
1179 return (wlc_pps_data->stage != PPS_NOTSUPP && wlc_pps_data->pd_online)
1180 ? PPS_ACTIVE_WLC_TIMEOUT_S : PPS_ACTIVE_USB_TIMEOUT_S;
1181}
1182
Wasb Liuab7c32f2023-02-04 09:24:28 +00001183static int gcpm_update_mdis_charge_cntl_limit(struct mdis_thermal_device *tdev,
1184 unsigned long lvl);
1185
1186
AleX Pelosif3776622021-01-18 13:32:08 -08001187static int gcpm_pps_offline(struct gcpm_drv *gcpm)
1188{
1189 int ret;
Wasb Liuab7c32f2023-02-04 09:24:28 +00001190 struct mdis_thermal_device *tdev = &gcpm->thermal_device;
AleX Pelosif3776622021-01-18 13:32:08 -08001191
AleX Pelosia0f55512021-03-17 00:30:20 -07001192 /* TODO: migh be a no-op when pps_index == 0 */
1193
AleX Pelosif3776622021-01-18 13:32:08 -08001194 if (gcpm->tcpm_pps_data.pps_psy) {
1195 ret = pps_prog_offline(&gcpm->tcpm_pps_data,
1196 gcpm->tcpm_pps_data.pps_psy);
1197 if (ret < 0)
1198 pr_err("PPS_DC: fail tcpm offline (%d)\n", ret);
1199 }
1200
1201 if (gcpm->wlc_pps_data.pps_psy) {
1202 ret = pps_prog_offline(&gcpm->wlc_pps_data,
1203 gcpm->wlc_pps_data.pps_psy);
1204 if (ret < 0)
1205 pr_err("PPS_DC: fail wlc offline (%d)\n", ret);
1206 }
1207
Wasb Liuab7c32f2023-02-04 09:24:28 +00001208 if (tdev)
1209 gcpm_update_mdis_charge_cntl_limit(tdev, tdev->current_level);
1210
AleX Pelosif3776622021-01-18 13:32:08 -08001211 gcpm->pps_index = 0;
1212 return 0;
1213}
1214
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001215/* <=0 to disable, > 0 to enable "n" counts */
1216static bool gcpm_taper_ctl(struct gcpm_drv *gcpm, int count)
1217{
1218 bool changed = false;
1219
1220 if (count <= 0) {
1221 changed = gcpm->taper_step != 0;
1222 gcpm->taper_step = 0;
1223 } else if (gcpm->taper_step == 0) {
1224 gcpm->taper_step = count;
1225 changed = true;
1226 }
1227
1228 return changed;
1229}
1230
AleX Pelosib961e472022-02-09 19:33:47 -08001231/*
1232 * taper off charging current to ease the transition out of CP charging.
1233 * NOTE: this writes directly to the charging current.
1234 */
1235static bool gcpm_taper_step(const struct gcpm_drv *gcpm,
1236 int dc_iin, int taper_step)
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001237{
1238 const int delta = gcpm->taper_step_count - taper_step;
AleX Pelosib961e472022-02-09 19:33:47 -08001239 int fv_uv = gcpm->fv_uv, cc_max = dc_iin;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001240 struct power_supply *dc_psy;
1241
1242 if (taper_step <= 0)
1243 return true;
1244 /*
1245 * TODO: on a race between TAPER and select, active might not
1246 * be a DC source. Force done to prevent voltage spikes.
1247 */
AleX Pelosib961e472022-02-09 19:33:47 -08001248 dc_psy = gcpm_chg_get_active_cp(gcpm);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001249 if (!dc_psy)
1250 return true;
1251
AleX Pelosi87f4b472021-05-20 02:30:14 -07001252 /* Optional dc voltage limit */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001253 if (gcpm->taper_step_voltage) {
1254 int vbatt;
1255
1256 vbatt = GPSY_GET_PROP(dc_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
1257 if (vbatt < 0)
1258 pr_err("%s: cannot read voltage (%d)", __func__, vbatt);
1259 else if (vbatt < gcpm->taper_step_voltage)
1260 return false;
1261 }
1262
AleX Pelosi87f4b472021-05-20 02:30:14 -07001263 /* Optional dc current limit */
1264 if (gcpm->taper_step_current) {
1265 int ret, ibatt;
1266
1267 /* TODO: use current average if available */
1268 ret = GPSY_GET_INT_PROP(dc_psy, POWER_SUPPLY_PROP_CURRENT_NOW,
1269 &ibatt);
1270 if (ret < 0)
AleX Pelosiad922a52021-07-05 16:59:30 -07001271 pr_err("%s: cannot read current (%d)", __func__, ret);
AleX Pelosi87f4b472021-05-20 02:30:14 -07001272 else if (ibatt > gcpm->taper_step_current)
1273 return false;
1274 }
1275
AleX Pelosiad922a52021-07-05 16:59:30 -07001276 /* delta < 0 during the grace period, which will increase cc_max */
Jack Wu1c6320c2021-06-17 19:47:20 +08001277 fv_uv -= gcpm->taper_step_fv_margin;
AleX Pelosiad922a52021-07-05 16:59:30 -07001278 if (gcpm->taper_step_cc_step) {
1279 cc_max -= delta * gcpm->taper_step_cc_step;
AleX Pelosib961e472022-02-09 19:33:47 -08001280 if (cc_max < dc_iin / 2)
1281 cc_max = dc_iin / 2;
AleX Pelosiad922a52021-07-05 16:59:30 -07001282 }
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001283
AleX Pelosiad922a52021-07-05 16:59:30 -07001284 /* increase of cc_max due to delta < 0 are ignored */
AleX Pelosib961e472022-02-09 19:33:47 -08001285 if (cc_max < dc_iin) {
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001286 int ret;
1287
1288 /* failure to preset stop taper and revert to main */
1289 ret = gcpm_chg_preset(dc_psy, fv_uv, cc_max);
AleX Pelosib961e472022-02-09 19:33:47 -08001290 pr_info("CHG_CHK: taper_step=%d fv_uv=%d->%d, dc_iin=%d->%d\n",
1291 taper_step, gcpm->fv_uv, fv_uv, dc_iin, cc_max);
AleX Pelosi87f4b472021-05-20 02:30:14 -07001292 if (ret < 0) {
1293 pr_err("CHG_CHK: taper_step=%d failed, revert (%d)\n",
1294 taper_step, ret);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001295 return true;
AleX Pelosi87f4b472021-05-20 02:30:14 -07001296 }
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001297
AleX Pelosi87f4b472021-05-20 02:30:14 -07001298 } else {
AleX Pelosib961e472022-02-09 19:33:47 -08001299 pr_debug("CHG_CHK: grace taper_step=%d fv_uv=%d, dc_iin=%d\n",
1300 taper_step, gcpm->fv_uv, dc_iin);
AleX Pelosi87f4b472021-05-20 02:30:14 -07001301 }
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001302
AleX Pelosib961e472022-02-09 19:33:47 -08001303 logbuffer_log(gcpm->log, "taper_step=%d delta=%d fv_uv=%d->%d, dc_iin=%d->%d",
1304 taper_step, delta, gcpm->fv_uv, fv_uv, dc_iin, cc_max);
AleX Pelosifc92c9e2021-07-08 11:16:51 -07001305
1306
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001307 /* not done */
1308 return false;
1309}
1310
AleX Pelosi02431162022-06-03 21:06:40 +00001311/* needs mutex_lock(&gcpm->chg_psy_lock); */
AleX Pelosi87e78af2022-02-08 15:08:43 -08001312static int gcpm_chg_select_logic(struct gcpm_drv *gcpm)
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001313{
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001314 int index, schedule_pps_interval = -1;
1315 bool dc_done = false, dc_ena;
1316
AleX Pelosi430da992022-06-05 23:52:25 +00001317 dev_dbg(gcpm->device, "%s: init_ok=%d dc_state=%d dc_index=%d\n", __func__,
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001318 gcpm->dc_init_complete, gcpm->dc_state, gcpm->dc_index);
1319
AleX Pelosi87e78af2022-02-08 15:08:43 -08001320 if (!gcpm->dc_init_complete)
1321 return -EAGAIN;
AleX Pelosi6e8473e2021-07-09 11:59:36 -07001322
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001323 index = gcpm_chg_select(gcpm);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001324 if (index < 0) {
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001325 pr_debug("%s: index=%d dc_state=%d dc_index=%d\n",
1326 __func__, index, gcpm->dc_state, gcpm->dc_index);
AleX Pelosi87e78af2022-02-08 15:08:43 -08001327 return -EAGAIN;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001328 }
1329
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001330 /* will not try to enable if the source cannot do PPS */
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001331 dc_ena = gcpm_chg_dc_check_source(gcpm, index);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001332
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001333 /*
1334 * taper control reduces cc_max every gcpm->taper_step_interval seconds
1335 * by a fixed amount for gcpm->taper_step_count seconds. fv_uv might
1336 * also be lowered by a fixed amount.
1337 */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001338 if (dc_ena && gcpm->taper_step > 0) {
1339 const int interval = msecs_to_jiffies(gcpm->taper_step_interval * 1000);
AleX Pelosib961e472022-02-09 19:33:47 -08001340 int dc_iin = gcpm->cc_max;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001341
AleX Pelosib961e472022-02-09 19:33:47 -08001342 dc_done = gcpm_taper_step(gcpm, dc_iin, gcpm->taper_step - 1);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001343 if (!dc_done) {
AleX Pelosi6e8473e2021-07-09 11:59:36 -07001344 mod_delayed_work(system_wq, &gcpm->select_work, interval);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001345 gcpm->taper_step -= 1;
1346 }
1347
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001348 pr_debug("%s: taper_step=%d done=%d\n", __func__,
1349 gcpm->taper_step, dc_done);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001350 } else if (gcpm->taper_step != 0) {
AleX Pelosi87e78af2022-02-08 15:08:43 -08001351 const int vbatt_high = gcpm->dc_limit_vbatt_high;
1352
AleX Pelosicba61dd2022-05-19 03:40:37 +00001353 /* reset dc_state after taper step */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001354 gcpm_taper_ctl(gcpm, 0);
AleX Pelosi87e78af2022-02-08 15:08:43 -08001355 if (gcpm->fv_uv < vbatt_high && gcpm->dc_state == DC_DISABLED)
1356 gcpm->dc_state = DC_IDLE;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001357 }
1358
AleX Pelosicba61dd2022-05-19 03:40:37 +00001359 pr_debug("%s: DC dc_ena=%d dc_state=%d dc_index=%d->%d taper_step=%d\n",
1360 __func__, dc_ena, gcpm->dc_state, gcpm->dc_index, index,
1361 gcpm->taper_step);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001362
1363 /*
1364 * NOTE: disabling DC might need to transition to charger mode 0
1365 * same might apply when switching between WLC-DC and PPS-DC.
1366 * Figure out a way to do this if needed.
1367 */
1368 if (!dc_ena || dc_done) {
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001369
1370 if (gcpm->dc_state > DC_IDLE && gcpm->dc_index > 0) {
AleX Pelosief75a072021-06-12 17:38:36 -07001371 pr_info("CHG_CHK: dc_ena=%d dc_done=%d stop PPS_Work for dc_index=%d\n",
1372 dc_ena, dc_done, gcpm->dc_index);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001373
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001374 /*
1375 * dc_done will prevent DC to restart until disconnect
1376 * or voltage goes over _high.
1377 */
1378 gcpm->dc_index = dc_done ? GCPM_INDEX_DC_DISABLE :
1379 GCPM_DEFAULT_CHARGER;
AleX Pelosiad922a52021-07-05 16:59:30 -07001380 gcpm_taper_ctl(gcpm, 0);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001381 schedule_pps_interval = 0;
1382 }
1383 } else if (gcpm->dc_state == DC_DISABLED) {
AleX Pelosicba61dd2022-05-19 03:40:37 +00001384 /*
1385 * dc is disabled when we are done OR when the source doesn't
1386 * support PPS or failed the authentication.
1387 */
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001388 pr_debug("%s: PPS_Work disabled for the session\n", __func__);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001389 } else if (gcpm->dc_state == DC_IDLE) {
AleX Pelosi02431162022-06-03 21:06:40 +00001390 const ktime_t dc_start_time = get_boot_sec();
1391
1392 pr_info("CHG_CHK: start PPS_Work for dc_index=%d at %lld\n",
1393 index, dc_start_time);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001394
1395 /* reset pps state to re-enable detection */
1396 gcpm_pps_online(gcpm);
1397
1398 /* TODO: DC_ENABLE or DC_PASSTHROUGH depending on index */
1399 gcpm->dc_state = DC_ENABLE_PASSTHROUGH;
1400 gcpm->dc_index = index;
1401
AleX Pelosi497a9fd2021-05-13 20:17:36 -07001402 /* grace period of 500ms, PPS Work not called during grace */
AleX Pelosi02431162022-06-03 21:06:40 +00001403 gcpm->dc_start_time = dc_start_time;
AleX Pelosi497a9fd2021-05-13 20:17:36 -07001404 schedule_pps_interval = DC_ENABLE_DELAY_MS;
Wasb Liucf32f212022-10-05 16:50:30 +08001405
1406 __pm_stay_awake(gcpm->gcpm_ws);
1407 pr_debug("%s: pm gcpm stay awake\n", __func__);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001408 }
1409
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001410 if (schedule_pps_interval >= 0) {
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001411 pr_debug("%s: DC schedule pps_work in %ds\n", __func__,
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001412 schedule_pps_interval / 1000);
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001413
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001414 mod_delayed_work(system_wq, &gcpm->pps_work,
1415 msecs_to_jiffies(schedule_pps_interval));
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001416 }
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001417
AleX Pelosi87e78af2022-02-08 15:08:43 -08001418 return 0;
1419}
1420
1421/*
1422 * triggered on every FV_UV and in DC_PASSTHROUGH
1423 * will keep polling if in -EAGAIN
1424 */
1425static void gcpm_chg_select_work(struct work_struct *work)
1426{
1427 struct gcpm_drv *gcpm =
1428 container_of(work, struct gcpm_drv, select_work.work);
1429 int ret;
1430
1431 mutex_lock(&gcpm->chg_psy_lock);
1432
1433 pr_debug("%s: on=%d dc_state=%d dc_index=%d\n", __func__,
1434 gcpm->dc_init_complete, gcpm->dc_state, gcpm->dc_index);
1435
1436 ret = gcpm_chg_select_logic(gcpm);
1437 if (ret == -EAGAIN) {
1438 const int interval = 5; /* 5 seconds */
1439
1440 mod_delayed_work(system_wq, &gcpm->select_work,
1441 msecs_to_jiffies(interval * 1000));
1442 }
1443
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001444 mutex_unlock(&gcpm->chg_psy_lock);
1445}
1446
AleX Pelosi56311c32021-06-10 15:06:10 -07001447static int gcpm_enable_default(struct gcpm_drv *gcpm)
AleX Pelosicae94c32021-05-25 21:54:54 -07001448{
1449 struct power_supply *chg_psy = gcpm_chg_get_default(gcpm);
1450 int ret;
1451
1452 /* gcpm_chg_offline set GBMS_PROP_CHARGING_ENABLED = 0 */
1453 ret = GPSY_SET_PROP(chg_psy, GBMS_PROP_CHARGING_ENABLED, 1);
1454 if (ret < 0) {
AleX Pelosief75a072021-06-12 17:38:36 -07001455 pr_debug("%s: failed 2 enable charging (%d)\n", __func__, ret);
AleX Pelosicae94c32021-05-25 21:54:54 -07001456 return ret;
1457 }
1458
1459 /* (re) online and start the default charger */
AleX Pelosib961e472022-02-09 19:33:47 -08001460 ret = gcpm_chg_start(gcpm, GCPM_DEFAULT_CHARGER, gcpm->fv_uv, gcpm->cc_max);
AleX Pelosicae94c32021-05-25 21:54:54 -07001461 if (ret < 0) {
AleX Pelosief75a072021-06-12 17:38:36 -07001462 pr_debug("%s: failed 2 start (%d)\n", __func__, ret);
AleX Pelosicae94c32021-05-25 21:54:54 -07001463 return ret;
1464 }
1465
1466 return 0;
1467}
1468
AleX Pelosi56311c32021-06-10 15:06:10 -07001469/* online the default charger (do not change active, nor enable) */
1470static int gcpm_online_default(struct gcpm_drv *gcpm)
1471{
AleX Pelosib961e472022-02-09 19:33:47 -08001472 return gcpm_chg_online(gcpm_chg_get_default(gcpm), gcpm->fv_uv, gcpm->cc_max);
AleX Pelosi56311c32021-06-10 15:06:10 -07001473}
1474
AleX Pelosief75a072021-06-12 17:38:36 -07001475/*
1476 * restart the default charger after DC or while trying to start it.
1477 * Can come here during DC_ENABLE_PASSTHROUGH, with PPS enabled and
1478 * after a failure to start DC or on a failure to disable the default
1479 * charger.
AleX Pelosiad922a52021-07-05 16:59:30 -07001480 *
1481 * NOTE: the caller needs to reset gcpm->dc_index
AleX Pelosief75a072021-06-12 17:38:36 -07001482 */
AleX Pelosia0f55512021-03-17 00:30:20 -07001483static int gcpm_pps_wlc_dc_restart_default(struct gcpm_drv *gcpm)
1484{
AleX Pelosia0f55512021-03-17 00:30:20 -07001485 const int active_index = gcpm->chg_psy_active; /* will change */
1486 const int dc_state = gcpm->dc_state; /* will change */
1487 int pps_done, ret;
1488
AleX Pelosief75a072021-06-12 17:38:36 -07001489 /* DC_FCC limit might be enabled as soon as we enter WLC_DC */
AleX Pelosi5229a772022-06-14 07:08:02 +00001490 ret = gcpm_update_votes(gcpm, 0);
AleX Pelosief75a072021-06-12 17:38:36 -07001491 if (ret < 0)
AleX Pelosi02431162022-06-03 21:06:40 +00001492 pr_err("PPS_DC: wlc_dc_rd cannot update votes (%d)\n", ret);
AleX Pelosief75a072021-06-12 17:38:36 -07001493
AleX Pelosiad922a52021-07-05 16:59:30 -07001494 /* Clear taper count if not complete */
1495 gcpm_taper_ctl(gcpm, 0);
1496
AleX Pelosief75a072021-06-12 17:38:36 -07001497 /*
1498 * in dc_state=DC_ENABLE_PASSTHROUGH it might be able to take
1499 * the current charger offline BUT might fail to start DC.
1500 */
1501 if (dc_state <= DC_IDLE)
AleX Pelosia0f55512021-03-17 00:30:20 -07001502 return 0;
1503
AleX Pelosief75a072021-06-12 17:38:36 -07001504 /* online the default charger (do not change active, nor enable)
1505 * TODO: possibly do nothing if the current charger is not DC.
1506 */
AleX Pelosi56311c32021-06-10 15:06:10 -07001507 ret = gcpm_online_default(gcpm);
AleX Pelosia0f55512021-03-17 00:30:20 -07001508 if (ret < 0)
1509 pr_warn("%s: Cannot online default (%d)", __func__, ret);
1510
AleX Pelosief75a072021-06-12 17:38:36 -07001511 /*
1512 * dc_state=DC_DISABLED, chg_psy_active==-1 a DC charger was active.
1513 * in DC_ENABLE_PASSTHROUGH, gcpm_dc_stop() will vote on charger mode.
1514 */
AleX Pelosia0f55512021-03-17 00:30:20 -07001515 ret = gcpm_dc_stop(gcpm, active_index);
1516 if (ret < 0) {
1517 pr_debug("%s: retry disable, dc_state=%d->%d (%d)\n",
1518 __func__, dc_state, gcpm->dc_state, ret);
1519 return -EAGAIN;
1520 }
1521
AleX Pelosief75a072021-06-12 17:38:36 -07001522 /*
AleX Pelosiad922a52021-07-05 16:59:30 -07001523 * Calling pps_offline is not really needed becasuse the adapter will
1524 * revert to fixed once ping stops (pps state is re-initialized on
1525 * DC start). I clear it to keep things neat and tidy.
1526 *
AleX Pelosief75a072021-06-12 17:38:36 -07001527 * NOTE: Make sure that pps_prog_offline only changes from PROG to
1528 * FIXED and not from OFFLINE to FIXED. Setting WLC from OFFLINE
1529 * to FIXED (online) at the wrong time might interfere with
AleX Pelosiad922a52021-07-05 16:59:30 -07001530 * the usecases that need to disable charging explicitly.
AleX Pelosief75a072021-06-12 17:38:36 -07001531 */
AleX Pelosia0f55512021-03-17 00:30:20 -07001532 pps_done = gcpm_pps_offline(gcpm);
1533 if (pps_done < 0)
1534 pr_debug("%s: fail 2 offline pps, dc_state=%d (%d)\n",
1535 __func__, gcpm->dc_state, pps_done);
1536
AleX Pelosi56311c32021-06-10 15:06:10 -07001537 ret = gcpm_enable_default(gcpm);
AleX Pelosia0f55512021-03-17 00:30:20 -07001538 if (ret < 0) {
AleX Pelosicae94c32021-05-25 21:54:54 -07001539 pr_err("%s: fail 2 restart default, dc_state=%d pps_done=%d (%d)\n",
1540 __func__, gcpm->dc_state, pps_done >= 0 ? : pps_done, ret);
AleX Pelosia0f55512021-03-17 00:30:20 -07001541 return -EAGAIN;
1542 }
1543
1544 return 0;
1545}
1546
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001547/*
Ken Tsou8acade12020-07-09 03:17:35 +08001548 * pps_data->stage:
1549 * PPS_NONE -> PPS_AVAILABLE -> PPS_ACTIVE
1550 * -> PPS_DISABLED -> PPS_DISABLED
AleX Pelosi02431162022-06-03 21:06:40 +00001551 * acquires mutex_lock(&gcpm->chg_psy_lock);
Ken Tsou8acade12020-07-09 03:17:35 +08001552 */
AleX Pelosif3776622021-01-18 13:32:08 -08001553static void gcpm_pps_wlc_dc_work(struct work_struct *work)
Ken Tsou8acade12020-07-09 03:17:35 +08001554{
1555 struct gcpm_drv *gcpm =
1556 container_of(work, struct gcpm_drv, pps_work.work);
AleX Pelosif3776622021-01-18 13:32:08 -08001557 struct pd_pps_data *pps_data;
Ken Tsou8acade12020-07-09 03:17:35 +08001558 int ret, pps_ui = -ENODEV;
AleX Pelosi02431162022-06-03 21:06:40 +00001559 ktime_t elap;
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001560
AleX Pelosif3776622021-01-18 13:32:08 -08001561 /* spurious during init */
Ken Tsou8acade12020-07-09 03:17:35 +08001562 mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosi02431162022-06-03 21:06:40 +00001563
1564 elap = gcpm->dc_start_time <= 0 ? 0 : get_boot_sec() - gcpm->dc_start_time;
1565
1566 pr_debug("%s: ok=%d dc_index=%d dc_state=%d dc_start_time=%lld\n",
1567 __func__, gcpm->resume_complete && gcpm->init_complete,
1568 gcpm->dc_index, gcpm->dc_state, gcpm->dc_start_time);
1569
AleX Pelosif3776622021-01-18 13:32:08 -08001570 if (!gcpm->resume_complete || !gcpm->init_complete) {
Wasb Liucf32f212022-10-05 16:50:30 +08001571 pps_ui = DC_ERROR_RETRY_MS;
1572 goto pps_dc_reschedule;
Ken Tsou8acade12020-07-09 03:17:35 +08001573 }
1574
AleX Pelosif3776622021-01-18 13:32:08 -08001575 /* disconnect, gcpm_chg_check() and most errors reset ->dc_index */
1576 if (gcpm->dc_index <= 0) {
AleX Pelosia0f55512021-03-17 00:30:20 -07001577 const int active_index = gcpm->chg_psy_active; /* will change */
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001578 const bool dc_disable = gcpm->dc_index == GCPM_INDEX_DC_DISABLE;
Ken Tsou8acade12020-07-09 03:17:35 +08001579
AleX Pelosi02431162022-06-03 21:06:40 +00001580 pr_debug("%s: stop for gcpm->dc_index=%d\n", __func__, gcpm->dc_index);
1581
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001582 /* will leave gcpm->dc_state in DC_DISABLED */
AleX Pelosia0f55512021-03-17 00:30:20 -07001583 ret = gcpm_pps_wlc_dc_restart_default(gcpm);
AleX Pelosi9cba1082021-02-05 10:45:11 -08001584 if (ret < 0) {
AleX Pelosia0f55512021-03-17 00:30:20 -07001585 pr_warn("PPS_Work: retry restart elap=%lld dc_state=%d %d->%d (%d)\n",
1586 elap, gcpm->dc_state, active_index,
1587 gcpm->chg_psy_active, ret);
1588
AleX Pelosi9cba1082021-02-05 10:45:11 -08001589 pps_ui = DC_ERROR_RETRY_MS;
1590 goto pps_dc_reschedule;
1591 }
1592
AleX Pelosiad922a52021-07-05 16:59:30 -07001593 /* Re-enable DC if just switching to the default charger */
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001594 if (!dc_disable)
AleX Pelosi9cba1082021-02-05 10:45:11 -08001595 gcpm->dc_state = DC_IDLE;
1596
AleX Pelosi412bea42022-06-05 18:18:26 +00001597 gcpm->dc_start_time = 0;
1598
Jenny Ho08b8a842022-01-19 16:30:54 +08001599 gbms_logbuffer_prlog(gcpm->log, LOGLEVEL_INFO, 0, debug_printk_prlog,
AleX Pelosi02431162022-06-03 21:06:40 +00001600 "PPS_Work: done%selap=%lld dc_state=%d %d->%d\n",
1601 dc_disable ? "for the session " : " ",
Jenny Ho08b8a842022-01-19 16:30:54 +08001602 elap, gcpm->dc_state, active_index,
1603 gcpm->chg_psy_active);
AleX Pelosie0b98122021-02-08 16:43:50 -08001604
Wasb Liucf32f212022-10-05 16:50:30 +08001605 pr_debug("%s: pm gcpm relax\n", __func__);
1606 __pm_relax(gcpm->gcpm_ws);
1607
AleX Pelosia0f55512021-03-17 00:30:20 -07001608 /* TODO: send a ps event? */
AleX Pelosi9cba1082021-02-05 10:45:11 -08001609 goto pps_dc_done;
1610 }
1611
AleX Pelosie0b98122021-02-08 16:43:50 -08001612 /* PPS was handed over to the DC driver, just monitor it... */
1613 if (gcpm->dc_state == DC_PASSTHROUGH) {
1614 struct power_supply *dc_psy;
1615 bool prog_online = false;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001616 int index;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001617
AleX Pelosie0b98122021-02-08 16:43:50 -08001618 /* the dc driver needs to keep the source online */
1619 pps_data = gcpm_pps_data(gcpm);
1620 if (pps_data)
AleX Pelosi43ed8592021-06-17 17:54:13 -07001621 prog_online = pps_check_prog_online(pps_data);
AleX Pelosie0b98122021-02-08 16:43:50 -08001622 if (!prog_online) {
1623 pr_err("PPS_Work: PPS offline, elap=%lld dc_index:%d->0\n",
1624 elap, gcpm->dc_index);
1625
AleX Pelosia0f55512021-03-17 00:30:20 -07001626 gcpm->dc_index = GCPM_DEFAULT_CHARGER;
AleX Pelosie0b98122021-02-08 16:43:50 -08001627 pps_ui = DC_ERROR_RETRY_MS;
AleX Pelosie0b98122021-02-08 16:43:50 -08001628 goto pps_dc_reschedule;
1629 }
1630
1631 /* likely changed from debug, bail */
1632 dc_psy = gcpm_chg_get_active(gcpm);
1633 if (!dc_psy) {
1634 pr_err("PPS_Work: No adapter, elap=%lld in PASSTHROUGH\n",
1635 elap);
1636
1637 pps_ui = DC_ERROR_RETRY_MS;
1638 goto pps_dc_reschedule;
1639 }
1640
AleX Pelosia0f55512021-03-17 00:30:20 -07001641 /* something is changed: kick the revert to default */
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001642 index = gcpm_chg_select(gcpm);
1643 if (index != gcpm->dc_index)
1644 mod_delayed_work(system_wq, &gcpm->select_work, 0);
1645
1646 /* ->pps_index valid: set/ping source to DC, ping watchdog */
AleX Pelosie0b98122021-02-08 16:43:50 -08001647 ret = GPSY_SET_PROP(dc_psy, GBMS_PROP_CHARGING_ENABLED,
1648 gcpm->pps_index);
1649 if (ret == 0) {
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001650 ret = gcpm_chg_ping(gcpm, GCPM_DEFAULT_CHARGER, 0);
AleX Pelosie0b98122021-02-08 16:43:50 -08001651 if (ret < 0)
1652 pr_err("PPS_Work: ping failed, elap=%lld with %d\n",
1653 elap, ret);
1654
1655 /* keep running to ping the adapters */
1656 pps_ui = DC_RUN_DELAY_MS;
1657 } else if (ret == -EBUSY || ret == -EAGAIN) {
1658 pps_ui = DC_ERROR_RETRY_MS;
1659 } else {
AleX Pelosia0f55512021-03-17 00:30:20 -07001660 pr_err("PPS_Work: ping DC failed, elap=%lld (%d)\n", elap, ret);
AleX Pelosia0f55512021-03-17 00:30:20 -07001661 ret = gcpm_chg_offline(gcpm, gcpm->dc_index);
1662 if (ret == 0)
AleX Pelosi56311c32021-06-10 15:06:10 -07001663 ret = gcpm_enable_default(gcpm);
AleX Pelosie0b98122021-02-08 16:43:50 -08001664 if (ret < 0) {
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001665 pr_err("PPS_Work: cannot online default %d\n", ret);
AleX Pelosie0b98122021-02-08 16:43:50 -08001666 pps_ui = DC_ERROR_RETRY_MS;
1667 } else {
1668 pr_err("PPS_Work: dc offline\n");
1669 pps_ui = 0;
Wasb Liucf32f212022-10-05 16:50:30 +08001670
1671 pr_debug("%s: pm gcpm relax\n", __func__);
1672 __pm_relax(gcpm->gcpm_ws);
AleX Pelosie0b98122021-02-08 16:43:50 -08001673 }
1674 }
1675
1676 goto pps_dc_reschedule;
1677 }
AleX Pelosi9cba1082021-02-05 10:45:11 -08001678
1679 /*
AleX Pelosi0f914572021-09-21 12:18:30 -07001680 * Wait until one of the sources becomes online AND switch to prog
1681 * mode. gcpm_pps_work will return <0 when PPS is not supported from
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001682 * ANY source. Deadline to PPS_PROG_TIMEOUT_S.
AleX Pelosi9cba1082021-02-05 10:45:11 -08001683 */
1684 ret = gcpm_pps_work(gcpm);
1685 if (ret < 0) {
AleX Pelosie0b98122021-02-08 16:43:50 -08001686 if (elap < PPS_PROG_TIMEOUT_S) {
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001687 pr_debug("PPS_Work: PROG elap=%lld ret=%d retry\n", elap, ret);
AleX Pelosi0f914572021-09-21 12:18:30 -07001688
AleX Pelosi9cba1082021-02-05 10:45:11 -08001689 /* retry for the session */
1690 pps_ui = PPS_PROG_RETRY_MS;
1691 gcpm_pps_online(gcpm);
1692 } else {
AleX Pelosie0b98122021-02-08 16:43:50 -08001693 pr_err("PPS_Work: PROG timeout, elap=%lld dc_state=%d (%d)\n",
1694 elap, gcpm->dc_state, ret);
AleX Pelosia0f55512021-03-17 00:30:20 -07001695
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001696 /* abort for the session */
1697 gcpm->dc_index = GCPM_INDEX_DC_DISABLE;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001698 pps_ui = PPS_ERROR_RETRY_MS;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001699 }
1700
AleX Pelosif3776622021-01-18 13:32:08 -08001701 goto pps_dc_reschedule;
1702 }
1703
AleX Pelosi7dcf87a2021-01-22 22:57:37 -08001704 /*
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001705 * DC runs only when PPS is active (ie. online=PROG_ONLINE and
1706 * ->stage=PPS_ACTIVE). Abort for the session if a source
1707 * went PROG_ONLINE but is not active.
AleX Pelosi7dcf87a2021-01-22 22:57:37 -08001708 */
AleX Pelosi9cba1082021-02-05 10:45:11 -08001709 pps_data = gcpm_pps_data(gcpm);
1710 if (!pps_data) {
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -07001711 int timeout_s = gcpm_pps_timeout(gcpm);
1712
1713 if (elap < timeout_s) {
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001714 pr_debug("PPS_Work: ACTIVE elap=%lld ret=%d retry\n", elap, ret);
1715
1716 /* WLC + Auth might require a very long time */
AleX Pelosi9cba1082021-02-05 10:45:11 -08001717 pps_ui = PPS_ACTIVE_RETRY_MS;
1718 } else {
AleX Pelosi02431162022-06-03 21:06:40 +00001719 pr_err("PPS_Work: ACTIVE timeout=%d, start=%lld elap=%lld dc_state=%d (%d)\n",
1720 timeout_s, elap, gcpm->dc_start_time, gcpm->dc_state, ret);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001721
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001722 /* abort for the session (until disconnect) */
1723 gcpm->dc_index = GCPM_INDEX_DC_DISABLE;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001724 pps_ui = PPS_ERROR_RETRY_MS;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001725 }
1726
AleX Pelosif3776622021-01-18 13:32:08 -08001727 goto pps_dc_reschedule;
1728 }
1729
AleX Pelosi9cba1082021-02-05 10:45:11 -08001730 if (gcpm->dc_state == DC_ENABLE_PASSTHROUGH) {
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -07001731 int timeout_s = gcpm_pps_timeout(gcpm) + PPS_READY_DELTA_TIMEOUT_S;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001732 int index;
Wasb Liuab7c32f2023-02-04 09:24:28 +00001733 struct mdis_thermal_device *tdev = &gcpm->thermal_device;
Ken Tsou8acade12020-07-09 03:17:35 +08001734
AleX Pelosi30afcb82021-07-13 10:50:57 -07001735 /* Also ping the source */
AleX Pelosi0303a572021-07-01 21:15:06 -07001736 pps_ui = gcpm_pps_wait_for_ready(gcpm);
AleX Pelosi9cba1082021-02-05 10:45:11 -08001737 if (pps_ui < 0) {
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -07001738 pr_info("PPS_Work: wait for source timeout=%d elap=%lld, dc_state=%d (%d)\n",
1739 timeout_s, elap, gcpm->dc_state, pps_ui);
AleX Pelosi0303a572021-07-01 21:15:06 -07001740 if (pps_ui != -EAGAIN)
1741 gcpm->dc_index = GCPM_DEFAULT_CHARGER;
AleX Pelosi9f4fd0d2021-08-21 12:26:41 -07001742 if (elap > timeout_s)
AleX Pelosi0303a572021-07-01 21:15:06 -07001743 gcpm->dc_index = GCPM_DEFAULT_CHARGER;
1744
1745 /* error retry */
AleX Pelosi9cba1082021-02-05 10:45:11 -08001746 pps_ui = PPS_ERROR_RETRY_MS;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001747 goto pps_dc_reschedule;
1748 }
1749
1750 /*
1751 * source selection might have changed demand and disabled DC
1752 * (WLC_DC has a different mincurrent). Revert the input
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001753 * selection, retry when ->cp_fcc_hold_limit changes.
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001754 */
1755 index = gcpm_chg_select(gcpm);
1756 if (!gcpm_is_dc(gcpm, index)) {
1757 pr_info("PPS_Work: selection changed index=%d\n", index);
AleX Pelosi0303a572021-07-01 21:15:06 -07001758
1759 gcpm->dc_index = GCPM_DEFAULT_CHARGER;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001760 pps_ui = PPS_ERROR_RETRY_MS;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001761 goto pps_dc_reschedule;
AleX Pelosi9cba1082021-02-05 10:45:11 -08001762 }
Ken Tsou8acade12020-07-09 03:17:35 +08001763
Wasb Liuab7c32f2023-02-04 09:24:28 +00001764 if (tdev)
1765 gcpm_update_mdis_charge_cntl_limit(tdev, tdev->current_level);
1766
AleX Pelosi9cba1082021-02-05 10:45:11 -08001767 /*
1768 * offine current adapter and start new. Charging is enabled
1769 * in DC_PASSTHROUGH setting GBMS_PROP_CHARGING_ENABLED to
1770 * the PPS source.
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001771 * TODO: preset the DC charger before handoff
AleX Pelosi9cba1082021-02-05 10:45:11 -08001772 * NOTE: There are a bunch of interesting recovery scenarios.
1773 */
AleX Pelosia0f55512021-03-17 00:30:20 -07001774 ret = gcpm_chg_offline(gcpm, gcpm->chg_psy_active);
Ken Tsou8acade12020-07-09 03:17:35 +08001775 if (ret == 0)
1776 ret = gcpm_dc_start(gcpm, gcpm->dc_index);
1777 if (ret == 0) {
1778 gcpm->dc_state = DC_PASSTHROUGH;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08001779 pps_ui = DC_ENABLE_DELAY_MS;
Ken Tsou8acade12020-07-09 03:17:35 +08001780 } else if (pps_ui > DC_ERROR_RETRY_MS) {
1781 pps_ui = DC_ERROR_RETRY_MS;
1782 }
Wasb Liucf32f212022-10-05 16:50:30 +08001783
1784 pr_debug("%s: pm gcpm relax\n", __func__);
1785 __pm_relax(gcpm->gcpm_ws);
AleX Pelosi9efbf842021-02-03 21:01:28 -08001786 } else {
AleX Pelosif3776622021-01-18 13:32:08 -08001787 struct power_supply *pps_psy = pps_data->pps_psy;
1788
AleX Pelosi9cba1082021-02-05 10:45:11 -08001789 /* steady on PPS, if DC state is DC_ENABLE or DC_RUNNING */
AleX Pelosif3776622021-01-18 13:32:08 -08001790 pps_ui = pps_update_adapter(pps_data, -1, -1, pps_psy);
Ken Tsou8acade12020-07-09 03:17:35 +08001791
1792 pr_info("PPS_Work: STEADY pd_online=%d pps_ui=%d dc_ena=%d dc_state=%d\n",
1793 pps_data->pd_online, pps_ui, gcpm->dc_index,
1794 gcpm->dc_state);
1795 if (pps_ui < 0)
1796 pps_ui = PPS_ERROR_RETRY_MS;
1797 }
1798
1799pps_dc_reschedule:
1800 if (pps_ui <= 0) {
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001801 pr_debug("PPS_Work: pps_ui=%d dc_index=%d dc_state=%d",
1802 pps_ui, gcpm->dc_index, gcpm->dc_state);
Ken Tsou8acade12020-07-09 03:17:35 +08001803 } else {
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001804 pr_debug("PPS_Work: reschedule in %d dc_index=%d dc_state=%d (%d:%d)",
1805 pps_ui, gcpm->dc_index, gcpm->dc_state, gcpm->out_uv, gcpm->out_ua);
AleX Pelosif3776622021-01-18 13:32:08 -08001806
AleX Pelosia0f55512021-03-17 00:30:20 -07001807 schedule_delayed_work(&gcpm->pps_work, msecs_to_jiffies(pps_ui));
Ken Tsou8acade12020-07-09 03:17:35 +08001808 }
1809
AleX Pelosi9cba1082021-02-05 10:45:11 -08001810pps_dc_done:
Ken Tsou8acade12020-07-09 03:17:35 +08001811 mutex_unlock(&gcpm->chg_psy_lock);
1812}
1813
AleX Pelosib961e472022-02-09 19:33:47 -08001814/*
1815 * coming in though the old dc_fcc votable.
1816 *
1817 * TODO: reimplement in terms of MDIS level remapping the limit
1818 */
Ken Tsouf956a7f2022-04-12 09:50:46 +08001819static int gcpm_dc_fcc_callback(struct gvotable_election *el,
1820 const char *reason,
1821 void *value)
AleX Pelosief75a072021-06-12 17:38:36 -07001822{
1823 struct gcpm_drv *gcpm = gvotable_get_data(el);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001824 const int limit = (long)value;
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001825 int changed = gcpm->cp_fcc_hold_limit != limit;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001826 int applied;
AleX Pelosief75a072021-06-12 17:38:36 -07001827
1828 mutex_lock(&gcpm->chg_psy_lock);
1829
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001830 /*
AleX Pelosia6a8a592022-06-05 23:56:02 +00001831 * ->cp_fcc_hold_limit is updated from MDIS and from the DC_FCC code.
1832 *
1833 * applied=1 here when the dc_limit has been applied to MSC_FCC and we
1834 * need to re-run the selection. Here the limit is applied ONLY when
1835 * using WLC_CP.
1836 *
1837 * NOTE: the thermal engine needs to vote on mdis_chg OR on dc_fcc,
1838 * dc_icl and msc_fcc.
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001839 */
1840 applied = gcpm_dc_fcc_update(gcpm, limit);
1841 if (applied < 0)
1842 pr_err("%s: cannot enforce DC_FCC limit applied=%d\n",
1843 __func__, applied);
AleX Pelosia6a8a592022-06-05 23:56:02 +00001844 else if (applied)
1845 gcpm->cp_fcc_hold_limit = limit;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001846
1847 /*
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001848 * ->cp_fcc_hold will be set in gcpm_chg_select_by_demand() for WLC_DC
AleX Pelosib961e472022-02-09 19:33:47 -08001849 * sessions when cc_max has fallen under the limit for WLC_DC charging
1850 * (->dc_limit_cc_min_wlc). The hold keeps the device charging with
1851 * the default charger (ie. non CP ie WLC) until released.
1852 *
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001853 * Clearing the ->cp_fcc_hold when the thermal limit changes and is
AleX Pelosib961e472022-02-09 19:33:47 -08001854 * NON zero allows gcpm_chg_select_by_demand() to re-evaluate
1855 * returning to CP charging.
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001856 */
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001857 if (limit != 0 && gcpm->cp_fcc_hold) {
1858 gcpm->cp_fcc_hold = false;
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001859 changed += 1;
1860 }
1861
1862 pr_debug("%s: CPM_THERM_DC_FCC limit=%d hold=%d applied=%d changed=%d\n",
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001863 __func__, limit, gcpm->cp_fcc_hold, applied, changed);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001864
AleX Pelosib961e472022-02-09 19:33:47 -08001865 /*
AleX Pelosi0937c4c2022-03-28 22:22:10 -07001866 * ->cp_fcc_hold force the selection of GCPM_DEFAULT_CHARGER in
AleX Pelosib961e472022-02-09 19:33:47 -08001867 * gcpm_chg_select_by_demand().
1868 */
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07001869 if (applied || changed)
1870 mod_delayed_work(system_wq, &gcpm->select_work,
1871 msecs_to_jiffies(DC_ENABLE_DELAY_MS));
AleX Pelosief75a072021-06-12 17:38:36 -07001872
1873 mutex_unlock(&gcpm->chg_psy_lock);
Ken Tsouf956a7f2022-04-12 09:50:46 +08001874 return 0;
AleX Pelosief75a072021-06-12 17:38:36 -07001875}
1876
Wasb Liu4f9b0232022-07-28 17:43:09 +08001877static int gcpm_dc_chg_avail_callback(struct gvotable_election *el,
1878 const char *reason, void *value)
1879{
1880 struct gcpm_drv *gcpm = gvotable_get_data(el);
1881 const int dc_chg_avail = GVOTABLE_PTR_TO_INT(value);
1882
1883 if (!gcpm->init_complete)
1884 return 0;
1885
1886 mod_delayed_work(system_wq, &gcpm->select_work, 0);
1887 pr_debug("DC_CHG_AVAIL: dc_avail=%d, reason=%s\n", dc_chg_avail, reason);
1888
1889 return 0;
1890}
1891
AleX Pelosief75a072021-06-12 17:38:36 -07001892/* --------------------------------------------------------------------- */
1893
AleX Pelosib961e472022-02-09 19:33:47 -08001894
Ken Tsou8acade12020-07-09 03:17:35 +08001895static int gcpm_psy_set_property(struct power_supply *psy,
1896 enum power_supply_property psp,
1897 const union power_supply_propval *pval)
1898{
1899 struct gcpm_drv *gcpm = power_supply_get_drvdata(psy);
Ken Tsou8acade12020-07-09 03:17:35 +08001900 struct power_supply *chg_psy = NULL;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001901 bool ta_check = false;
Ken Tsou8acade12020-07-09 03:17:35 +08001902 bool route = true;
1903 int ret = 0;
1904
1905 pm_runtime_get_sync(gcpm->device);
1906 if (!gcpm->init_complete || !gcpm->resume_complete) {
1907 pm_runtime_put_sync(gcpm->device);
1908 return -EAGAIN;
1909 }
1910 pm_runtime_put_sync(gcpm->device);
1911
1912 mutex_lock(&gcpm->chg_psy_lock);
1913 switch (psp) {
AleX Pelosif3776622021-01-18 13:32:08 -08001914 /* do not route to the active charger */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001915 case GBMS_PROP_TAPER_CONTROL: {
1916 int count = 0;
1917
1918 if (pval->intval != GBMS_TAPER_CONTROL_OFF)
1919 count = gcpm->taper_step_count + gcpm->taper_step_grace;
1920
1921 /* ta_check is set when taper control changes value */
1922 ta_check = gcpm_taper_ctl(gcpm, count);
AleX Pelosif3776622021-01-18 13:32:08 -08001923 route = false;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001924 } break;
AleX Pelosi9efbf842021-02-03 21:01:28 -08001925
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07001926 /* route to the active charger in most cases */
AleX Pelosif3776622021-01-18 13:32:08 -08001927 case GBMS_PROP_CHARGE_DISABLE:
AleX Pelosief75a072021-06-12 17:38:36 -07001928
1929 /* google_charger send this on disconnect and input_suspend. */
1930 pr_info("%s: ChargeDisable value=%d dc_index=%d dc_state=%d\n",
1931 __func__, pval->intval, gcpm->dc_index, gcpm->dc_state);
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001932
AleX Pelosi56311c32021-06-10 15:06:10 -07001933 if (pval->intval) {
AleX Pelosiad922a52021-07-05 16:59:30 -07001934 /*
1935 * more or less the same as gcpm_pps_wlc_dc_work() when
1936 * dc_index <= 0. But the default charger must not be
1937 * restarted in this case though.
1938 * TODO: factor the code with gcpm_pps_wlc_dc_work().
1939 */
1940
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001941 /*
AleX Pelosi0f914572021-09-21 12:18:30 -07001942 * No op if the current source is not DC (uncluding
1943 * stop while in DC_ENABLE_), ->dc_state
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001944 * will be DC_DISABLED if this was actually disabled.
AleX Pelosiad922a52021-07-05 16:59:30 -07001945 */
AleX Pelosi56311c32021-06-10 15:06:10 -07001946 ret = gcpm_dc_stop(gcpm, gcpm->chg_psy_active);
AleX Pelosi670c25e2021-06-15 01:27:15 -07001947 if (ret == -EAGAIN) {
AleX Pelosi0f914572021-09-21 12:18:30 -07001948 pr_debug("%s: cannot disable, try again\n", __func__);
AleX Pelosi670c25e2021-06-15 01:27:15 -07001949 mutex_unlock(&gcpm->chg_psy_lock);
AleX Pelosi56311c32021-06-10 15:06:10 -07001950 return -EAGAIN;
AleX Pelosi670c25e2021-06-15 01:27:15 -07001951 }
AleX Pelosiad922a52021-07-05 16:59:30 -07001952
AleX Pelosi56311c32021-06-10 15:06:10 -07001953 ret = gcpm_pps_offline(gcpm);
1954 if (ret < 0)
1955 pr_debug("%s: fail 2 offline pps, dc_state=%d (%d)\n",
1956 __func__, gcpm->dc_state, ret);
AleX Pelosiad922a52021-07-05 16:59:30 -07001957
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001958 /* reset to the default charger, and clear taper */
AleX Pelosiad922a52021-07-05 16:59:30 -07001959 gcpm->dc_index = GCPM_DEFAULT_CHARGER;
1960 gcpm_taper_ctl(gcpm, 0);
1961
1962 /*
1963 * no-op if dc was NOT running, set online the charger
1964 * but do not start it otherwise.
1965 */
AleX Pelosib961e472022-02-09 19:33:47 -08001966 ret = gcpm_chg_start(gcpm, GCPM_DEFAULT_CHARGER,
1967 gcpm->fv_uv, gcpm->cc_max);
AleX Pelosi56311c32021-06-10 15:06:10 -07001968 if (ret < 0)
1969 pr_err("%s: cannot start default (%d)\n",
1970 __func__, ret);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07001971
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001972 pr_info("%s: ChargeDisable value=%d dc_index=%d dc_state=%d\n",
1973 __func__, pval->intval, gcpm->dc_index, gcpm->dc_state);
1974
AleX Pelosief75a072021-06-12 17:38:36 -07001975 /*
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001976 * route = true so active will get the property.
1977 * No need to re-check the TA selection on disable.
AleX Pelosief75a072021-06-12 17:38:36 -07001978 */
1979 ta_check = false;
AleX Pelosi741c0712021-07-01 21:13:43 -07001980 } else if (gcpm->dc_state <= DC_IDLE) {
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001981 /*
1982 * ->dc_state will be DC_DISABLED if DC was disabled
1983 * via GBMS_PROP_CHARGE_DISABLE(1) of from other
1984 * conditions such as taper control.
1985 */
1986 if (gcpm->dc_state == DC_DISABLED)
1987 gcpm->dc_state = DC_IDLE;
1988
1989 pr_info("%s: ChargeDisable value=%d dc_index=%d dc_state=%d\n",
1990 __func__, pval->intval, gcpm->dc_index, gcpm->dc_state);
1991
AleX Pelosi56311c32021-06-10 15:06:10 -07001992 gcpm_pps_online(gcpm);
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001993 ta_check = true;
AleX Pelosi56311c32021-06-10 15:06:10 -07001994 }
1995
AleX Pelosif3776622021-01-18 13:32:08 -08001996 break;
1997 case POWER_SUPPLY_PROP_ONLINE:
AleX Pelosic6a1bb22021-07-15 23:15:32 -07001998 pr_info("%s: ONLINE value=%d dc_index=%d dc_state=%d\n",
1999 __func__, pval->intval, gcpm->dc_index,
2000 gcpm->dc_state);
AleX Pelosif3776622021-01-18 13:32:08 -08002001 ta_check = true;
2002 break;
AleX Pelosic6a1bb22021-07-15 23:15:32 -07002003
AleX Pelosif3776622021-01-18 13:32:08 -08002004 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2005 psp = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX;
2006 /* compat, fall through */
2007 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
2008 ta_check = gcpm->fv_uv != pval->intval;
2009 gcpm->fv_uv = pval->intval;
2010 break;
Ken Tsou8acade12020-07-09 03:17:35 +08002011
AleX Pelosib961e472022-02-09 19:33:47 -08002012 /*
2013 * from google_charger (usually) with demand adjusted by classic
2014 * thermal engine and/or special charging profiles.
AleX Pelosiafb445a2022-05-17 20:15:01 +00002015 * The MDIS vote on MSC_FCC is disabled by the thermal
2016 *
2017 * Used by the select logic to determine the best charging strategy and
2018 * either routed to the main-charger directly or voted on GCPM_FCC.
AleX Pelosib961e472022-02-09 19:33:47 -08002019 */
AleX Pelosif3776622021-01-18 13:32:08 -08002020 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07002021 route = !gcpm_chg_is_cp_active(gcpm);
AleX Pelosif3776622021-01-18 13:32:08 -08002022 ta_check = gcpm->cc_max != pval->intval;
AleX Pelosicba61dd2022-05-19 03:40:37 +00002023 pr_debug("%s: route=%d ta_check=%d cc_max=%d->%d dc_index=%d\n",
AleX Pelosib961e472022-02-09 19:33:47 -08002024 __func__, route, ta_check, gcpm->cc_max, pval->intval,
2025 gcpm->dc_index);
AleX Pelosif3776622021-01-18 13:32:08 -08002026 gcpm->cc_max = pval->intval;
2027 break;
Ken Tsou8acade12020-07-09 03:17:35 +08002028
AleX Pelosif3776622021-01-18 13:32:08 -08002029 /* just route to the active charger */
2030 default:
2031 break;
Ken Tsou8acade12020-07-09 03:17:35 +08002032 }
2033
AleX Pelosic1ba48c2021-01-16 13:49:59 -08002034 /* used only for debug */
2035 if (gcpm->new_dc_limit) {
2036 gcpm->new_dc_limit = false;
2037 ta_check = true;
2038 }
2039
AleX Pelosib961e472022-02-09 19:33:47 -08002040 /*
2041 * ta_check is set when the charging parameters change (cc_max, fv_uv)
2042 * when changing the online state, in taper control and when charging
2043 * is disabled. this code triggers the logic that selects DC charging
2044 * or that causes charging to switch back the main charger.
2045 */
AleX Pelosi87e78af2022-02-08 15:08:43 -08002046 if (gcpm->dc_init_complete && ta_check) {
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07002047 const bool was_dc = gcpm_is_dc(gcpm, gcpm->dc_index);
Wasb Liu79dfd0d2022-05-11 17:15:25 +08002048 int rc;
AleX Pelosi87e78af2022-02-08 15:08:43 -08002049
AleX Pelosib961e472022-02-09 19:33:47 -08002050 /*
AleX Pelosi30f890f2022-04-18 15:20:38 -07002051 * Synchronous! might kick off gcpm_pps_wlc_dc_work to negotiate
2052 * DC charging. -EAGAIN will cause this code to be called again.
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07002053 * NOTE: gcpm_chg_select_logic() might change gcpm->dc_index
AleX Pelosib961e472022-02-09 19:33:47 -08002054 */
Wasb Liu79dfd0d2022-05-11 17:15:25 +08002055 rc = gcpm_chg_select_logic(gcpm);
2056 if (rc == -EAGAIN) {
AleX Pelosiafb445a2022-05-17 20:15:01 +00002057 const int interval = 5; /* seconds */
AleX Pelosi87e78af2022-02-08 15:08:43 -08002058
AleX Pelosib961e472022-02-09 19:33:47 -08002059 /* let the setting go through but */
AleX Pelosi87e78af2022-02-08 15:08:43 -08002060 mod_delayed_work(system_wq, &gcpm->select_work,
2061 msecs_to_jiffies(interval * 1000));
2062 }
2063
AleX Pelosib961e472022-02-09 19:33:47 -08002064 /*
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07002065 * Do not route while switching from DC to non DC because
2066 * the DC charger might get the wrong limits.
AleX Pelosiafb445a2022-05-17 20:15:01 +00002067 * NOTE: gcpm_pps_wlc_dc_work() will configure the new charger
2068 * on start (or on stop/timeout)
AleX Pelosib961e472022-02-09 19:33:47 -08002069 */
AleX Pelosi8c7d20d2022-03-28 14:29:55 -07002070 if (was_dc && !gcpm_is_dc(gcpm, gcpm->dc_index))
AleX Pelosi87e78af2022-02-08 15:08:43 -08002071 route = false;
2072 }
AleX Pelosi49ac41c2021-02-18 18:13:42 -08002073
AleX Pelosiafb445a2022-05-17 20:15:01 +00002074 /* route to active charger only when needed */
AleX Pelosi9efbf842021-02-03 21:01:28 -08002075 if (!route)
2076 goto done;
2077
2078 chg_psy = gcpm_chg_get_active(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +08002079 if (chg_psy) {
AleX Pelosib961e472022-02-09 19:33:47 -08002080 /* replace the pval with dc_iin limit when DC is selected */
Ken Tsou8acade12020-07-09 03:17:35 +08002081 ret = power_supply_set_property(chg_psy, psp, pval);
AleX Pelosid1e6d7f2021-07-21 00:51:18 -07002082 if (ret < 0 && ret != -EAGAIN) {
AleX Pelosia0f55512021-03-17 00:30:20 -07002083 pr_err("cannot route prop=%d to %d:%s (%d)\n", psp,
2084 gcpm->chg_psy_active, gcpm_psy_name(chg_psy),
2085 ret);
Ken Tsou8acade12020-07-09 03:17:35 +08002086 }
2087 } else {
AleX Pelosif3776622021-01-18 13:32:08 -08002088 pr_err("invalid active charger = %d for prop=%d\n",
Ken Tsou8acade12020-07-09 03:17:35 +08002089 gcpm->chg_psy_active, psp);
2090 }
2091
AleX Pelosi9efbf842021-02-03 21:01:28 -08002092done:
AleX Pelosi30f890f2022-04-18 15:20:38 -07002093 /*
2094 * route==false when using CP and when transitioning OUT of it.
AleX Pelosiafb445a2022-05-17 20:15:01 +00002095 * Will disable CC_MAX vote on GCPM_FCC when/if the limit is routed
2096 * to the main-charger.
AleX Pelosi30f890f2022-04-18 15:20:38 -07002097 */
AleX Pelosib961e472022-02-09 19:33:47 -08002098 if (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX)
AleX Pelosi30f890f2022-04-18 15:20:38 -07002099 gcpm_update_gcpm_fcc(gcpm, "CC_MAX", gcpm->cc_max, !route);
AleX Pelosib961e472022-02-09 19:33:47 -08002100
Ken Tsou8acade12020-07-09 03:17:35 +08002101 mutex_unlock(&gcpm->chg_psy_lock);
AleX Pelosib961e472022-02-09 19:33:47 -08002102
2103 /* the charger should not call into gcpm: this can change though */
Ken Tsou8acade12020-07-09 03:17:35 +08002104 return ret;
2105}
2106
2107static int gcpm_psy_get_property(struct power_supply *psy,
2108 enum power_supply_property psp,
2109 union power_supply_propval *pval)
2110{
2111 struct gcpm_drv *gcpm = power_supply_get_drvdata(psy);
AleX Pelosif20ccc82021-02-12 22:57:34 -08002112 union gbms_charger_state chg_state;
Ken Tsou8acade12020-07-09 03:17:35 +08002113 struct power_supply *chg_psy;
AleX Pelosif20ccc82021-02-12 22:57:34 -08002114 bool route = false;
2115 int ret = 0;
Ken Tsou8acade12020-07-09 03:17:35 +08002116
2117 pm_runtime_get_sync(gcpm->device);
2118 if (!gcpm->init_complete || !gcpm->resume_complete) {
2119 pm_runtime_put_sync(gcpm->device);
2120 return -EAGAIN;
2121 }
2122 pm_runtime_put_sync(gcpm->device);
2123
2124 mutex_lock(&gcpm->chg_psy_lock);
2125 chg_psy = gcpm_chg_get_active(gcpm);
AleX Pelosif20ccc82021-02-12 22:57:34 -08002126 if (!chg_psy) {
AleX Pelosia0f55512021-03-17 00:30:20 -07002127 pr_err("invalid active charger = %d for prop=%d\n",
2128 gcpm->chg_psy_active, psp);
AleX Pelosif20ccc82021-02-12 22:57:34 -08002129 mutex_unlock(&gcpm->chg_psy_lock);
Ken Tsou8acade12020-07-09 03:17:35 +08002130 return -ENODEV;
AleX Pelosif20ccc82021-02-12 22:57:34 -08002131 }
Ken Tsou8acade12020-07-09 03:17:35 +08002132
2133 switch (psp) {
AleX Pelosif3776622021-01-18 13:32:08 -08002134 /* handle locally for now */
2135 case GBMS_PROP_CHARGE_CHARGER_STATE:
AleX Pelosif20ccc82021-02-12 22:57:34 -08002136 chg_state.v = gcpm_get_charger_state(gcpm, chg_psy);
2137 gbms_propval_int64val(pval) = chg_state.v;
AleX Pelosif20ccc82021-02-12 22:57:34 -08002138 break;
Ken Tsou8acade12020-07-09 03:17:35 +08002139
Ken Yangae3657e2023-03-24 00:57:43 +00002140 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
2141 pval->intval = gcpm->cc_max;
2142 break;
2143
2144 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
2145 pval->intval = gcpm->fv_uv;
2146 break;
2147
AleX Pelosif3776622021-01-18 13:32:08 -08002148 /* route to the active charger */
2149 default:
AleX Pelosif20ccc82021-02-12 22:57:34 -08002150 route = true;
AleX Pelosif3776622021-01-18 13:32:08 -08002151 break;
Ken Tsou8acade12020-07-09 03:17:35 +08002152 }
2153
AleX Pelosif20ccc82021-02-12 22:57:34 -08002154 if (route)
2155 ret = power_supply_get_property(chg_psy, psp, pval);
2156
2157 mutex_unlock(&gcpm->chg_psy_lock);
2158 return ret;
Ken Tsou8acade12020-07-09 03:17:35 +08002159}
2160
2161static int gcpm_psy_is_writeable(struct power_supply *psy,
2162 enum power_supply_property psp)
2163{
2164 switch (psp) {
2165 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
2166 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2167 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
2168 case POWER_SUPPLY_PROP_CURRENT_MAX:
AleX Pelosid2ca4072020-09-03 22:07:27 -07002169 case GBMS_PROP_CHARGE_DISABLE:
2170 case GBMS_PROP_TAPER_CONTROL:
Ken Tsou8acade12020-07-09 03:17:35 +08002171 return 1;
2172 default:
2173 break;
2174 }
2175
2176 return 0;
2177}
2178
2179/*
2180 * TODO: POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_TEMP
2181 */
2182static enum power_supply_property gcpm_psy_properties[] = {
2183 POWER_SUPPLY_PROP_ONLINE,
2184 POWER_SUPPLY_PROP_PRESENT,
AleX Pelosi6a128912021-03-12 22:50:45 -08002185 POWER_SUPPLY_PROP_CURRENT_NOW,
Ken Tsou8acade12020-07-09 03:17:35 +08002186 /* pixel battery management subsystem */
2187 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, /* cc_max */
2188 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, /* fv_uv */
2189 POWER_SUPPLY_PROP_CHARGE_TYPE,
Ken Tsou8acade12020-07-09 03:17:35 +08002190 POWER_SUPPLY_PROP_CURRENT_MAX, /* input current limit */
2191 POWER_SUPPLY_PROP_VOLTAGE_MAX, /* set float voltage, compat */
Ken Tsou8acade12020-07-09 03:17:35 +08002192 POWER_SUPPLY_PROP_STATUS,
2193};
2194
2195static struct power_supply_desc gcpm_psy_desc = {
2196 .name = "gcpm",
2197 .type = POWER_SUPPLY_TYPE_UNKNOWN,
2198 .get_property = gcpm_psy_get_property,
2199 .set_property = gcpm_psy_set_property,
2200 .property_is_writeable = gcpm_psy_is_writeable,
2201 .properties = gcpm_psy_properties,
2202 .num_properties = ARRAY_SIZE(gcpm_psy_properties),
2203};
2204
AleX Pelosi127128b2021-02-08 16:32:32 -08002205#define gcpm_psy_changed_tickle_pps(gcpm) \
2206 ((gcpm)->dc_state == DC_PASSTHROUGH || (gcpm)->dc_state == DC_RUNNING)
2207
Ken Tsou8acade12020-07-09 03:17:35 +08002208static int gcpm_psy_changed(struct notifier_block *nb, unsigned long action,
2209 void *data)
2210{
2211 struct gcpm_drv *gcpm = container_of(nb, struct gcpm_drv, chg_nb);
2212 const int index = gcpm->chg_psy_active;
2213 struct power_supply *psy = data;
AleX Pelosi127128b2021-02-08 16:32:32 -08002214 bool tickle_pps_work = false;
Ken Tsou8acade12020-07-09 03:17:35 +08002215
2216 if (index == -1)
2217 return NOTIFY_OK;
2218
2219 if ((action != PSY_EVENT_PROP_CHANGED) ||
2220 (psy == NULL) || (psy->desc == NULL) || (psy->desc->name == NULL))
2221 return NOTIFY_OK;
2222
2223 if (strcmp(psy->desc->name, gcpm->chg_psy_names[index]) == 0) {
2224 /* route upstream when the charger active and found */
2225 if (gcpm->chg_psy_avail[index])
2226 power_supply_changed(gcpm->psy);
AleX Pelosifb2f5982021-02-05 10:45:11 -08002227
AleX Pelosi127128b2021-02-08 16:32:32 -08002228 tickle_pps_work = gcpm_psy_changed_tickle_pps(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +08002229 } else if (strcmp(psy->desc->name, gcpm->chg_psy_names[0]) == 0) {
AleX Pelosi127128b2021-02-08 16:32:32 -08002230 /* possibly JEITA or other violation, check PPS */
2231 tickle_pps_work = gcpm_psy_changed_tickle_pps(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +08002232 } else if (gcpm->tcpm_psy_name &&
AleX Pelosi127128b2021-02-08 16:32:32 -08002233 !strcmp(psy->desc->name, gcpm->tcpm_psy_name)) {
2234
2235 /* from tcpm source (even if not selected) */
2236 tickle_pps_work = gcpm_psy_changed_tickle_pps(gcpm);
2237 } else if (gcpm->wlc_dc_name &&
2238 !strcmp(psy->desc->name, gcpm->wlc_dc_name)) {
2239
2240 /* from wc source (even if not selected) */
2241 tickle_pps_work = gcpm_psy_changed_tickle_pps(gcpm);
Ken Tsou8acade12020-07-09 03:17:35 +08002242 }
2243
AleX Pelosi127128b2021-02-08 16:32:32 -08002244 /* should tickle the PPS loop only when is running */
2245 if (tickle_pps_work)
2246 mod_delayed_work(system_wq, &gcpm->pps_work, 0);
2247
Ken Tsou8acade12020-07-09 03:17:35 +08002248 return NOTIFY_OK;
2249}
2250
Ted Line29ae8a2021-05-20 13:05:02 +08002251static ssize_t dc_limit_demand_show(struct device *dev,
2252 struct device_attribute *attr,
2253 char *buf)
2254{
2255 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2256
2257 return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->dc_limit_demand);
2258}
2259static ssize_t dc_limit_demand_store(struct device *dev,
2260 struct device_attribute *attr,
2261 const char *buf, size_t count)
2262{
2263 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2264 int ret = 0;
2265 u32 val;
2266
2267 ret = kstrtou32(buf, 0, &val);
2268 if (ret < 0)
2269 return ret;
2270
2271 mutex_lock(&gcpm->chg_psy_lock);
2272 if (gcpm->dc_limit_demand != val) {
2273 gcpm->dc_limit_demand = val;
2274 gcpm->new_dc_limit = true;
2275 }
2276
2277 mutex_unlock(&gcpm->chg_psy_lock);
2278
2279 return count;
2280}
2281static DEVICE_ATTR_RW(dc_limit_demand);
2282
2283static ssize_t dc_limit_vbatt_max_show(struct device *dev,
2284 struct device_attribute *attr,
2285 char *buf)
2286{
2287 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2288
2289 return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->dc_limit_vbatt_max);
2290}
2291static ssize_t dc_limit_vbatt_max_store(struct device *dev,
2292 struct device_attribute *attr,
2293 const char *buf, size_t count)
2294{
2295 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2296 int ret = 0;
2297 u32 val;
2298
2299 ret = kstrtou32(buf, 0, &val);
2300 if (ret < 0)
2301 return ret;
2302
2303 gcpm->dc_limit_vbatt_max = val;
2304
2305 return count;
2306}
2307static DEVICE_ATTR_RW(dc_limit_vbatt_max);
2308
2309static ssize_t dc_limit_vbatt_min_show(struct device *dev,
2310 struct device_attribute *attr,
2311 char *buf)
2312{
2313 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2314
2315 return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->dc_limit_vbatt_min);
2316}
2317static ssize_t dc_limit_vbatt_min_store(struct device *dev,
2318 struct device_attribute *attr,
2319 const char *buf, size_t count)
2320{
2321 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2322 int ret = 0;
2323 u32 val;
2324
2325 ret = kstrtou32(buf, 0, &val);
2326 if (ret < 0)
2327 return ret;
2328
2329 gcpm->dc_limit_vbatt_min = val;
2330
2331 return count;
2332}
2333static DEVICE_ATTR_RW(dc_limit_vbatt_min);
2334
Ted Lind35c7422021-05-17 11:32:58 +08002335static ssize_t dc_ctl_show(struct device *dev,
2336 struct device_attribute *attr,
2337 char *buf)
2338{
2339 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2340
2341 return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->dc_ctl);
2342}
2343
2344static ssize_t dc_ctl_store(struct device *dev,
2345 struct device_attribute *attr,
2346 const char *buf, size_t count)
2347{
2348 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2349 int ret = 0, val;
2350
2351 ret = kstrtoint(buf, 0, &val);
2352 if (ret < 0)
2353 return ret;
2354
2355 /*
2356 * 0: enable both (Default)
2357 * 1: disable wired-DC
2358 * 2: disable wireless-DC
2359 * 3: disable both
2360 */
2361 switch (val) {
2362 case GCPM_DC_CTL_DEFAULT:
2363 case GCPM_DC_CTL_DISABLE_WIRED:
2364 case GCPM_DC_CTL_DISABLE_WIRELESS:
2365 case GCPM_DC_CTL_DISABLE_BOTH:
2366 gcpm->dc_ctl = val;
2367 break;
2368 default:
2369 return -EINVAL;
2370 };
2371
2372 return count;
2373}
2374static DEVICE_ATTR_RW(dc_ctl);
2375
Jenny Hoa6dfac42022-09-14 14:41:43 +08002376static ssize_t thermal_mdis_fan_alarm_show(struct device *dev,
2377 struct device_attribute *attr,
2378 char *buf)
2379{
2380 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2381
2382 return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->thermal_device.therm_fan_alarm_level);
2383}
2384
2385static ssize_t thermal_mdis_fan_alarm_store(struct device *dev,
2386 struct device_attribute *attr,
2387 const char *buf, size_t count)
2388{
2389 struct gcpm_drv *gcpm = dev_get_drvdata(dev);
2390 int ret = 0;
2391 u32 value;
2392
2393 ret = kstrtou32(buf, 0, &value);
2394 if (ret < 0)
2395 return ret;
2396
2397 if (value <= gcpm->thermal_device.thermal_levels)
2398 gcpm->thermal_device.therm_fan_alarm_level = value;
2399
2400 return count;
2401}
2402static DEVICE_ATTR_RW(thermal_mdis_fan_alarm);
2403
AleX Pelosib961e472022-02-09 19:33:47 -08002404/* ------------------------------------------------------------------------ */
2405
2406static int gcpm_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
2407 unsigned long *lvl)
2408{
2409 struct mdis_thermal_device *tdev = tcd->devdata;
2410
2411 *lvl = tdev->thermal_levels;
2412 return 0;
2413}
2414
2415static int gcpm_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
2416 unsigned long *lvl)
2417{
2418 struct mdis_thermal_device *tdev = tcd->devdata;
2419
2420 *lvl = tdev->current_level;
2421 return 0;
2422}
2423
Jenny Hoa6dfac42022-09-14 14:41:43 +08002424#define FAN_MDIS_ALARM_DEFAULT 3
2425static int fan_get_level(struct mdis_thermal_device *tdev)
2426{
2427 int fan_level = FAN_LVL_UNKNOWN;
2428
2429 if (tdev->current_level <= 0)
2430 fan_level = FAN_LVL_NOT_CARE;
2431 else if (tdev->current_level >= tdev->therm_fan_alarm_level)
2432 fan_level = FAN_LVL_ALARM;
2433 else
2434 fan_level = FAN_LVL_MED;
2435
2436 return fan_level;
2437}
2438
2439static int gcpm_mdis_update_fan(struct gcpm_drv *gcpm)
2440{
2441 int ret = 0;
2442
2443 if (!gcpm->fan_level_votable)
2444 gcpm->fan_level_votable = gvotable_election_get_handle(VOTABLE_FAN_LEVEL);
2445
2446 if (gcpm->fan_level_votable) {
2447 const int level = fan_get_level(&gcpm->thermal_device);
2448
2449 ret = gvotable_cast_int_vote(gcpm->fan_level_votable, "THERMAL_MDIS",
2450 level, true);
2451 if (ret < 0)
2452 pr_err("%s: cannot update fan level (%d)", __func__, ret);
2453 }
2454
2455 return ret;
2456}
2457
AleX Pelosifed6c8c2022-05-02 16:32:05 -07002458static inline int mdis_cast_vote(struct gvotable_election *el, int vote, bool enabled)
2459{
2460 int ret = 0;
2461
2462 if (enabled)
2463 ret = gvotable_cast_int_vote(el, "MDIS", vote, true);
AleX Pelosiafb445a2022-05-17 20:15:01 +00002464 else if (vote >= 0)
2465 ret = gvotable_cast_int_vote(el, "MDIS", vote, false);
AleX Pelosifed6c8c2022-05-02 16:32:05 -07002466 else
2467 gvotable_recast_ballot(el, "MDIS", false);
2468
2469 return ret;
2470}
2471
AleX Pelosi430da992022-06-05 23:52:25 +00002472static int mdis_set_wlc_online(struct gcpm_drv *gcpm)
2473{
2474 struct power_supply *wlc_psy = gcpm->wlc_pps_data.pps_psy;
2475 union power_supply_propval pval;
2476 int ret;
2477
2478 if (!wlc_psy)
2479 return PPS_PSY_OFFLINE;
2480
2481 ret = power_supply_get_property(wlc_psy, POWER_SUPPLY_PROP_ONLINE, &pval);
2482 if (ret < 0 || pval.intval == PPS_PSY_OFFLINE) {
2483
2484 pval.intval = PPS_PSY_FIXED_ONLINE;
2485 ret = power_supply_set_property(wlc_psy, POWER_SUPPLY_PROP_ONLINE,
2486 &pval);
2487 if (ret < 0)
2488 return ret;
2489 }
2490
2491 return pval.intval;
2492}
2493
2494/*
2495 * A negative msc_fcc, dc_icl or cp_fcc disables the MDIS vote on the
2496 * corresponding source.
2497 * cp_fcc=0 re-enable the MDIS votes on MSC_FCC and DC_ICL and forces the
2498 * transition to MW charging when/if using the charge pump (in this case
2499 * charging will stop if MSC_FCC/DC_ICL are zero).
2500 *
2501 * needs mutex_unlock(&gcpm->chg_psy_lock);
2502 */
AleX Pelosib961e472022-02-09 19:33:47 -08002503static int gcpm_mdis_update_limits(struct gcpm_drv *gcpm, int msc_fcc,
2504 int dc_icl, int cp_fcc)
2505{
AleX Pelosi430da992022-06-05 23:52:25 +00002506 struct gvotable_election *dc_icl_votable;
2507 struct gvotable_election *fcc_votable;
2508 struct gvotable_election *cp_votable;
AleX Pelosib961e472022-02-09 19:33:47 -08002509 int ret;
2510
AleX Pelosi430da992022-06-05 23:52:25 +00002511 pr_info("MSC_MDIS msc_fcc=%d dc_icl=%d cp_fcc=%d\n",
2512 msc_fcc, dc_icl, cp_fcc);
2513
2514 cp_votable = gcpm_get_cp_votable(gcpm);
2515 dc_icl_votable = gcpm_get_dc_icl_votable(gcpm);
2516
2517 /*
2518 * set (or reset) the MDIS limit for CP.
2519 * The callback for GCPM_FCC needs to be locked.
2520 */
2521 if (cp_fcc != 0 && cp_votable) {
2522 ret = mdis_cast_vote(cp_votable, cp_fcc, cp_fcc > 0);
AleX Pelosib961e472022-02-09 19:33:47 -08002523 if (ret < 0)
AleX Pelosi430da992022-06-05 23:52:25 +00002524 dev_err(gcpm->device, "MDIS: vote %d on CP failed (%d)\n",
2525 cp_fcc, ret);
2526 }
2527
2528 /*
2529 * set (or reset) the MDIS limit for MSC_FCC.
2530 * Turns off the main-charger from the charging loop in google_charger
2531 * but will not be able to restart charging if/when the charging loop
2532 * is not running (MSC_FCC might not have a callback that cause a
2533 * respin of the usecase state machine)
2534 * NOTE: this limit is enabled only when CP is not enabled
2535 */
2536 fcc_votable = gcpm_get_fcc_votable(gcpm);
2537 if (fcc_votable) {
2538 ret = mdis_cast_vote(fcc_votable, msc_fcc, msc_fcc >= 0 && cp_fcc == 0);
2539 if (ret < 0)
2540 dev_err(gcpm->device, "MDIS: vote %d on MSC_FCC failed (%d)\n",
AleX Pelosib961e472022-02-09 19:33:47 -08002541 msc_fcc, ret);
2542 }
2543
AleX Pelosi430da992022-06-05 23:52:25 +00002544 /*
2545 * set (or reset) the MDIS limit for DC_ICL.
2546 * NOTE: Can vote on DC_ICL even when using CP.
2547 */
2548 if (dc_icl != 0 && dc_icl_votable) {
2549 int wlc_state;
2550
Jenny Hoa6dfac42022-09-14 14:41:43 +08002551 /* need to set online WLC if not online */
AleX Pelosi430da992022-06-05 23:52:25 +00002552 wlc_state = mdis_set_wlc_online(gcpm);
2553 if (wlc_state == PPS_PSY_OFFLINE)
2554 dev_err(gcpm->device, "MDIS: WLC offine\n");
2555
2556 /* turning ON after critical level for WLC is complicated */
2557 ret = mdis_cast_vote(dc_icl_votable, dc_icl, dc_icl > 0);
2558 if (ret < 0)
2559 dev_err(gcpm->device, "MDIS: vote %d on DC_ICL failed (%d)\n",
2560 dc_icl, ret);
2561 }
2562
2563 /* adjust limit for RTX */
2564 if (!gcpm->tx_icl_votable)
2565 gcpm->tx_icl_votable = gvotable_election_get_handle("TX_ICL");
2566 if (gcpm->tx_icl_votable)
2567 gvotable_cast_int_vote(gcpm->tx_icl_votable, "MDIS", 0, dc_icl == 0);
2568
2569 /*
2570 * turns off the CP and will revert to main.
2571 * NOTE: The limit for main charger MSC_FCC is updated above.
2572 */
2573 if (cp_fcc == 0 && cp_votable) {
2574 ret = mdis_cast_vote(cp_votable, 0, true);
2575 if (ret < 0)
2576 dev_err(gcpm->device, "MDIS: vote %d on CP failed (%d)\n",
2577 cp_fcc, ret);
2578 }
2579
2580 /* turning off wireless charging equires disabling the wireless IC */
2581 if (dc_icl == 0 && dc_icl_votable) {
2582 ret = mdis_cast_vote(dc_icl_votable, 0, true);
AleX Pelosib961e472022-02-09 19:33:47 -08002583 if (ret < 0)
2584 dev_err(gcpm->device, "vote %d on DC_ICL failed (%d)\n",
2585 dc_icl, ret);
2586 }
2587
AleX Pelosib961e472022-02-09 19:33:47 -08002588 /* one or more might fail, consider retries */
2589 return 0;
2590}
2591
AleX Pelosib961e472022-02-09 19:33:47 -08002592 /* max dissipation themal level: apply the limit */
2593static int gcpm_set_mdis_charge_cntl_limit(struct thermal_cooling_device *tcd,
2594 unsigned long lvl)
2595{
2596 struct mdis_thermal_device *tdev = tcd->devdata;
2597 struct gcpm_drv *gcpm = tdev->gcpm;
Wasb Liuab7c32f2023-02-04 09:24:28 +00002598 int ret;
2599
2600 if (tdev->thermal_levels <= 0 || lvl < 0 || lvl > tdev->thermal_levels)
2601 return -EINVAL;
2602
2603 mutex_lock(&gcpm->chg_psy_lock);
2604 ret = gcpm_update_mdis_charge_cntl_limit(tdev, lvl);
2605 mutex_unlock(&gcpm->chg_psy_lock);
2606
2607 return ret;
2608}
2609
2610static int gcpm_update_mdis_charge_cntl_limit(struct mdis_thermal_device *tdev,
2611 unsigned long lvl)
2612{
2613 struct gcpm_drv *gcpm = tdev->gcpm;
Stephane Leefa678232022-10-12 16:55:04 -07002614 int online = 0, in_idx = -1;
AleX Pelosib961e472022-02-09 19:33:47 -08002615 int msc_fcc, dc_icl, cp_fcc, ret;
Prasanna Prapanchamacc08fe2022-11-18 20:08:36 +00002616 bool mdis_crit_lvl;
AleX Pelosib961e472022-02-09 19:33:47 -08002617
AleX Pelosiafb445a2022-05-17 20:15:01 +00002618 if (tdev->thermal_levels <= 0 || lvl < 0 || lvl > tdev->thermal_levels)
AleX Pelosib961e472022-02-09 19:33:47 -08002619 return -EINVAL;
2620
AleX Pelosi430da992022-06-05 23:52:25 +00002621 dev_dbg(gcpm->device, "MSC_THERM_MDIS lvl=%d->%d\n", tdev->current_level, (int)lvl);
2622
AleX Pelosib961e472022-02-09 19:33:47 -08002623 tdev->current_level = lvl;
Prasanna Prapanchamacc08fe2022-11-18 20:08:36 +00002624 mdis_crit_lvl = lvl == tdev->thermal_levels || tdev->thermal_mitigation[lvl] == 0;
2625 if (mdis_crit_lvl) {
Stephane Leefa678232022-10-12 16:55:04 -07002626 msc_fcc = dc_icl = cp_fcc = 0;
AleX Pelosi430da992022-06-05 23:52:25 +00002627 gcpm->cp_fcc_hold_limit = gcpm_chg_select_check_cp_limit(gcpm);
2628 gcpm->cp_fcc_hold = true;
AleX Pelosib961e472022-02-09 19:33:47 -08002629 } else if (tdev->current_level == 0) {
AleX Pelosib961e472022-02-09 19:33:47 -08002630 msc_fcc = dc_icl = cp_fcc = -1;
AleX Pelosi430da992022-06-05 23:52:25 +00002631 /* mdis callback will clear hold and re-evaluate PPS */
2632 gcpm->cp_fcc_hold_limit = -1;
AleX Pelosib961e472022-02-09 19:33:47 -08002633 } else {
AleX Pelosi430da992022-06-05 23:52:25 +00002634 int cp_min = -1;
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00002635
AleX Pelosib961e472022-02-09 19:33:47 -08002636 /* 0 always is the main-charger */
2637 dc_icl = gcpm->mdis_out_limits[0][lvl + tdev->thermal_levels];
2638 msc_fcc = gcpm->mdis_out_limits[0][lvl];
2639
2640 /*
2641 * cp_fcc limit is routed to DC when DC is selected or ignored.
AleX Pelosi430da992022-06-05 23:52:25 +00002642 * the code in gcpm_psy_set_property() uses cp_fcc and cc_max
2643 * to determine when to swich source.
AleX Pelosib961e472022-02-09 19:33:47 -08002644 */
2645 in_idx = gcpm_mdis_match_cp_source(gcpm, &online);
AleX Pelosica862392022-06-21 20:15:58 +00002646 if (in_idx < 0 || online != PPS_PSY_PROG_ONLINE) {
AleX Pelosicba61dd2022-05-19 03:40:37 +00002647 /*
AleX Pelosica862392022-06-21 20:15:58 +00002648 * this happens when none of the sources are online
2649 * or when not using the CP. It CAN happen when we
2650 * resume after the thermal engine has shut this down.
2651 * Forces cp_fcc to 0 to apply dc_icl and msc_fcc.
AleX Pelosicba61dd2022-05-19 03:40:37 +00002652 */
AleX Pelosi430da992022-06-05 23:52:25 +00002653 cp_fcc = 0;
AleX Pelosica862392022-06-21 20:15:58 +00002654
2655 /* forces wlc-overrides-fcc when wireless charging */
2656 if (online && gcpm_mdis_in_is_wireless(gcpm, in_idx))
2657 msc_fcc = -1;
AleX Pelosi430da992022-06-05 23:52:25 +00002658 } else if (gcpm_mdis_in_is_wireless(gcpm, in_idx)) {
2659 /* WLC_CP use the charge pump with wireless charging */
2660 cp_fcc = gcpm->mdis_out_limits[1][lvl + tdev->thermal_levels];
AleX Pelosica862392022-06-21 20:15:58 +00002661
AleX Pelosi430da992022-06-05 23:52:25 +00002662 if (gcpm->dc_limit_cc_min_wlc >= 0)
2663 cp_min = gcpm->dc_limit_cc_min_wlc;
2664 else if (gcpm->dc_limit_cc_min >= 0)
2665 cp_min = gcpm->dc_limit_cc_min;
2666
2667 /*
AleX Pelosica862392022-06-21 20:15:58 +00002668 * forces wlc-overrides-fcc when wireless charging
2669 * Reset only in PROG_ONLINE to allow transitioning
2670 * OUT of WLC_DC when the charging current falls
2671 * under the DC limit.
2672 */
AleX Pelosi430da992022-06-05 23:52:25 +00002673 msc_fcc = -1;
AleX Pelosib961e472022-02-09 19:33:47 -08002674 } else {
AleX Pelosi430da992022-06-05 23:52:25 +00002675 /* PPS_CP use the charge pump with TCPM */
AleX Pelosib961e472022-02-09 19:33:47 -08002676 cp_fcc = gcpm->mdis_out_limits[1][lvl];
AleX Pelosi430da992022-06-05 23:52:25 +00002677 if (gcpm->dc_limit_cc_min >= 0)
2678 cp_min = gcpm->dc_limit_cc_min;
AleX Pelosib961e472022-02-09 19:33:47 -08002679 }
2680
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00002681 /*
AleX Pelosi430da992022-06-05 23:52:25 +00002682 * validate the cp limit against cp_min and disable CP
2683 * with hold if the new limit is under it.
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00002684 * NOTE: there might be a corner case when the MSC_FCC or the
2685 * DC_ICL limit doesn't change after re-enabling the vote.
2686 */
AleX Pelosi430da992022-06-05 23:52:25 +00002687 if (cp_min == -1) {
2688 pr_debug("MSC_MDIS cp_fcc_hold_limit:%d->-1 cp_fcc=%d cp_min=%d\n",
2689 gcpm->cp_fcc_hold_limit, cp_fcc, cp_min);
2690 } else if (cp_fcc > cp_min) {
2691 /* mdis callback will clear hold and re-evaluate PPS */
2692 gcpm->cp_fcc_hold_limit = -1;
2693 pr_debug("MSC_MDIS cp_fcc_hold_limit:%d->-1 cp_fcc=%d cp_min=%d\n",
2694 gcpm->cp_fcc_hold_limit, cp_fcc, cp_min);
2695 } else if (cp_fcc <= cp_min) {
2696 /*
2697 * setting ->cp_fcc_hold_limit to 0 select the
2698 main-charger in gcpm_chg_select_by_demand().
2699 */
2700 gcpm->cp_fcc_hold_limit = gcpm_mdis_in_is_wireless(gcpm, in_idx) ?
2701 0 : cp_min;
2702 gcpm->cp_fcc_hold = true;
2703
2704 pr_debug("MSC_MDIS cp_fcc:%d->0 hold_limit=%d cp_min=%d\n",
2705 cp_fcc, gcpm->cp_fcc_hold_limit, cp_min);
AleX Pelosicba61dd2022-05-19 03:40:37 +00002706 cp_fcc = 0;
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00002707 }
AleX Pelosib961e472022-02-09 19:33:47 -08002708 }
2709
AleX Pelosi430da992022-06-05 23:52:25 +00002710 dev_info(gcpm->device,
2711 "MSC_THERM_MDIS lvl=%lu in_idx=%d online=%d cp_fcc=%d hold=%d, hold_limit=%d\n",
2712 lvl, in_idx, online, cp_fcc, gcpm->cp_fcc_hold,
2713 gcpm->cp_fcc_hold_limit);
AleX Pelosiafb445a2022-05-17 20:15:01 +00002714
Prasanna Prapanchamacc08fe2022-11-18 20:08:36 +00002715 ret = gvotable_cast_int_vote(gcpm->dc_chg_avail_votable, REASON_MDIS,
2716 !mdis_crit_lvl, 1);
2717 if (ret < 0)
2718 dev_err(gcpm->device, "Unable to cast vote for DC Chg avail (%d)\n", ret);
AleX Pelosib961e472022-02-09 19:33:47 -08002719 /*
AleX Pelosi430da992022-06-05 23:52:25 +00002720 * this might be in the callback for mdis_votable
2721 * . cp_fcc == 0 will apply msc_fcc, dc_icl and must cause the
2722 * transition from CP to MW
2723 * . cp_fcc < 0 it only removes the MDIS limit on CP charging
AleX Pelosib961e472022-02-09 19:33:47 -08002724 * . msc_fcc = -1 when charging from dc_icl (wlc-overrides-fcc)
2725 */
AleX Pelosi430da992022-06-05 23:52:25 +00002726 ret = gcpm_mdis_update_limits(gcpm, msc_fcc, dc_icl, cp_fcc);
2727 if (ret < 0)
2728 pr_err("%s: cannot update limits (%d)", __func__, ret);
AleX Pelosib961e472022-02-09 19:33:47 -08002729
AleX Pelosi0937c4c2022-03-28 22:22:10 -07002730 /* fix the disable, run another charging loop */
AleX Pelosi430da992022-06-05 23:52:25 +00002731 if (gcpm->mdis_votable) {
AleX Pelosibf11ec02022-04-22 11:25:06 -07002732 ret = gvotable_cast_int_vote(gcpm->mdis_votable, "MDIS",
Stephane Leefa678232022-10-12 16:55:04 -07002733 lvl, lvl >= 0);
AleX Pelosi430da992022-06-05 23:52:25 +00002734 if (ret < 0)
Stephane Leefa678232022-10-12 16:55:04 -07002735 pr_err("%s: cannot update MDIS level (%d)", __func__, ret);
AleX Pelosi430da992022-06-05 23:52:25 +00002736
2737 }
2738
AleX Pelosib961e472022-02-09 19:33:47 -08002739 return 0;
2740}
2741
AleX Pelosie1b18722022-04-18 23:32:31 -07002742static ssize_t
2743state2power_table_show(struct device *dev, struct device_attribute *attr, char *buf)
2744{
2745 struct thermal_cooling_device *tdev = to_cooling_device(dev);
2746 struct mdis_thermal_device *mdev = tdev->devdata;
2747 ssize_t count = 0;
2748 int i;
2749
2750 for (i = 0; i < mdev->thermal_levels; i++) {
2751 const int budgetMw = mdev->thermal_mitigation[i] / 1000;
2752
2753 count += sysfs_emit_at(buf, count, "%u ", budgetMw);
2754 }
AleX Pelosicd503252022-05-05 18:01:40 +00002755
2756 /* b/231599097 add the implicit 0 at the end of the table */
2757 count += sysfs_emit_at(buf, count, "0\n");
AleX Pelosie1b18722022-04-18 23:32:31 -07002758
2759 return count;
2760}
2761
2762static DEVICE_ATTR_RO(state2power_table);
2763
2764static ssize_t
2765mdis_out_table_show(struct device *dev, struct device_attribute *attr, char *buf)
2766{
2767 struct thermal_cooling_device *tdev = to_cooling_device(dev);
2768 struct mdis_thermal_device *mdev = tdev->devdata;
2769 struct gcpm_drv *gcpm = mdev->gcpm;
Jack Wu877687a2022-07-27 22:17:11 +08002770 const int entries = mdev->thermal_levels * gcpm->mdis_in_count;
AleX Pelosie1b18722022-04-18 23:32:31 -07002771 ssize_t count = 0;
2772 int i, j;
2773
2774 for (i = 0; i < gcpm->mdis_out_count; i++) {
2775
2776 count += sysfs_emit_at(buf, count, "%d:", i);
2777
2778 for (j = 0; j < entries; j++) {
2779 const int limit = gcpm->mdis_out_limits[i][j];
2780
2781 count += sysfs_emit_at(buf, count, "%u ", limit);
2782 }
2783
2784 count += sysfs_emit_at(buf, count, "\n");
2785 }
2786
2787 return count;
2788}
2789
2790static DEVICE_ATTR_RO(mdis_out_table);
2791
AleX Pelosib961e472022-02-09 19:33:47 -08002792static const struct thermal_cooling_device_ops chg_mdis_tcd_ops = {
2793 .get_max_state = gcpm_get_max_charge_cntl_limit,
2794 .get_cur_state = gcpm_get_cur_charge_cntl_limit,
2795 .set_cur_state = gcpm_set_mdis_charge_cntl_limit,
2796};
2797
AleX Pelosie1b18722022-04-18 23:32:31 -07002798#ifdef CONFIG_DEBUG_FS
2799
AleX Pelosie1b18722022-04-18 23:32:31 -07002800static ssize_t mdis_tm_store(struct file *filp, const char __user *user_buf,
2801 size_t count, loff_t *ppos)
2802{
2803 struct gcpm_drv *gcpm = filp->private_data;
2804 const int thermal_levels = gcpm->thermal_device.thermal_levels;
2805 const int mem_size = count + 1;
2806 char *str, *tmp, *saved_ptr;
2807 unsigned long long value;
2808 int ret, i;
2809
2810 tmp = kzalloc(mem_size, GFP_KERNEL);
2811 if (!tmp)
2812 return -ENOMEM;
2813
2814 ret = simple_write_to_buffer(tmp, mem_size, ppos, user_buf, count);
2815 if (!ret)
2816 goto error_done;
2817
2818 for (saved_ptr = tmp, i = 0; i < thermal_levels; i++) {
2819 str = strsep(&saved_ptr, " ");
2820 if (!str)
2821 goto error_done;
2822
2823 ret = kstrtoull(str, 10, &value);
2824 if (ret < 0)
2825 goto error_done;
2826
2827 gcpm->thermal_device.thermal_mitigation[i] = value * 1000;
2828 }
2829
2830error_done:
2831 kfree(tmp);
2832 return count;
2833}
2834
2835DEBUG_ATTRIBUTE_WO(mdis_tm);
2836
2837static ssize_t mdis_out_store(struct file *filp, const char __user *user_buf,
2838 size_t count, loff_t *ppos)
2839{
2840 struct gcpm_drv *gcpm = filp->private_data;
2841 const int levels = gcpm->thermal_device.thermal_levels;
2842 const int mem_size = count + 1;
2843 unsigned long long value, index;
2844 char *str, *tmp, *saved_ptr;
2845 int ret, i;
2846
2847 tmp = kzalloc(mem_size, GFP_KERNEL);
2848 if (!tmp)
2849 return -ENOMEM;
2850
2851 ret = simple_write_to_buffer(tmp, mem_size, ppos, user_buf, count);
2852 if (!ret)
2853 goto error_done;
2854
2855 for (saved_ptr = tmp; true; ) {
2856
2857 str = strsep(&saved_ptr, ":");
2858 if (!str)
2859 goto error_done;
2860
2861 ret = kstrtoull(str, 10, &index);
2862 if (ret < 0)
2863 goto error_done;
2864
2865 if (index < 0 || index >= levels)
2866 break;
2867
Jack Wu877687a2022-07-27 22:17:11 +08002868 for (i = 0; i < levels * gcpm->mdis_in_count; i++) {
AleX Pelosie1b18722022-04-18 23:32:31 -07002869 str = strsep(&saved_ptr, " ");
2870 if (!str)
2871 goto error_done;
2872
2873 ret = kstrtoull(str, 10, &value);
2874 if (ret < 0)
2875 goto error_done;
2876
2877 gcpm->mdis_out_limits[index][i] = value;
2878 }
2879 }
2880
2881error_done:
2882 kfree(tmp);
2883 return count;
2884}
2885
2886DEBUG_ATTRIBUTE_WO(mdis_out);
2887
Alice Shengba6a6d42023-04-24 12:38:58 -07002888static void chg_mdis_tdev_free(struct mdis_thermal_device *tdev,
2889 struct gcpm_drv *gcpm)
2890{
2891 devm_kfree(gcpm->device, tdev->thermal_mitigation);
2892 tdev->thermal_mitigation = NULL;
2893}
2894
2895static int mdis_tdev_register(const char *of_name, const char *tcd_name,
2896 struct mdis_thermal_device *ctdev,
2897 const struct thermal_cooling_device_ops *ops)
2898{
2899 struct device_node *cooling_node = NULL;
2900 int ret;
2901
2902 cooling_node = of_find_node_by_name(NULL, of_name);
2903 if (!cooling_node) {
2904 pr_err("No %s OF node for cooling device\n", of_name);
2905 return -EINVAL;
2906 }
2907
2908 ctdev->tcd = thermal_of_cooling_device_register(cooling_node,
2909 tcd_name,
2910 ctdev,
2911 ops);
2912 if (IS_ERR_OR_NULL(ctdev->tcd)) {
2913 const long err = PTR_ERR(ctdev->tcd);
2914
2915 pr_err("error registering %s cooling device (%ld)\n", tcd_name, err);
2916 return err;
2917 }
2918
2919 ret = device_create_file(&ctdev->tcd->device, &dev_attr_state2power_table);
2920 if (ret)
2921 dev_err(ctdev->gcpm->device, "cound not create state table *(%d)\n", ret);
2922
2923 ret = device_create_file(&ctdev->tcd->device, &dev_attr_mdis_out_table);
2924 if (ret)
2925 dev_err(ctdev->gcpm->device, "cound not create out table *(%d)\n", ret);
2926
2927 return 0;
2928}
2929
Alice Shengbfafbf12023-02-21 14:11:57 -08002930static int mdis_size_show(void *data, u64 *val)
2931{
2932 struct gcpm_drv *gcpm = data;
2933
2934 *val = gcpm->thermal_device.thermal_levels;
2935 return 0;
2936}
2937
2938static int mdis_size_store(void *data, u64 val)
2939{
2940 struct gcpm_drv *gcpm = data;
2941 struct mdis_thermal_device *tdev = &gcpm->thermal_device;
2942 const int newsize = val;
2943 const int newsize_bytes = newsize * sizeof(u32);
2944 u32 *limits;
2945 int bytes, index, i;
2946 int ret;
2947
2948 mutex_lock(&gcpm->chg_psy_lock);
2949
Alice Shengbfafbf12023-02-21 14:11:57 -08002950 bytes = (newsize <= tdev->thermal_levels ? newsize : tdev->thermal_levels) * sizeof(u32);
Alice Shengbfafbf12023-02-21 14:11:57 -08002951
2952 for (index = 0; index < gcpm->mdis_out_count; index++) {
2953 limits = devm_kzalloc(gcpm->device, newsize_bytes * gcpm->mdis_in_count, GFP_KERNEL);
2954 if (!limits) {
2955 ret = -ENOMEM;
2956 tdev->thermal_levels = 0;
2957 goto exit;
2958 }
2959 for (i = 0; i < gcpm->mdis_in_count; i++)
2960 memcpy(limits + (i * newsize), gcpm->mdis_out_limits[index] + (i * tdev->thermal_levels), bytes);
2961 devm_kfree(gcpm->device, gcpm->mdis_out_limits[index]);
2962 gcpm->mdis_out_limits[index] = limits;
2963 }
Alice Shengba6a6d42023-04-24 12:38:58 -07002964
2965 limits = devm_kzalloc(gcpm->device, newsize_bytes, GFP_KERNEL);
2966 if (!limits) {
2967 ret = -ENOMEM;
2968 goto exit;
2969 }
2970 memcpy(limits, tdev->thermal_mitigation, bytes);
2971
Alice Shengbfafbf12023-02-21 14:11:57 -08002972 devm_kfree(gcpm->device, tdev->thermal_mitigation);
2973 tdev->thermal_mitigation = limits;
2974 tdev->thermal_levels = newsize;
2975 ret = 0;
Alice Shengba6a6d42023-04-24 12:38:58 -07002976
2977 /* Need to re-register cooling device because size is stored in the thermal framework */
2978 thermal_cooling_device_unregister(tdev->tcd);
2979
2980 ret = mdis_tdev_register(MDIS_OF_CDEV_NAME, MDIS_CDEV_NAME,
2981 tdev, &chg_mdis_tcd_ops);
2982 if (ret) {
2983 dev_err(gcpm->device,
2984 "Couldn't register %s rc=%d\n", MDIS_OF_CDEV_NAME, ret);
2985
2986 /* Free the limits too! */
2987 chg_mdis_tdev_free(tdev, gcpm);
2988 ret = -EINVAL;
2989 goto exit;
2990 }
2991
Alice Shengbfafbf12023-02-21 14:11:57 -08002992exit:
2993 mutex_unlock(&gcpm->chg_psy_lock);
2994 return ret;
2995}
2996
2997DEFINE_SIMPLE_ATTRIBUTE(mdis_size_fops, mdis_size_show,
2998 mdis_size_store, "%lld\n");
2999
3000static int wlc_cc_lim_show(void *data, u64 *val)
3001{
3002 struct gcpm_drv *gcpm = data;
3003
3004 *val = gcpm->dc_limit_cc_min_wlc;
3005 return 0;
3006}
3007
3008static int wlc_cc_lim_store(void *data, u64 val)
3009{
3010 struct gcpm_drv *gcpm = data;
3011
3012 gcpm->dc_limit_cc_min_wlc = val;
3013 return 0;
3014
3015}
3016
3017DEFINE_SIMPLE_ATTRIBUTE(wlc_cc_lim_fops, wlc_cc_lim_show,
3018 wlc_cc_lim_store, "%lld\n");
3019
3020static int dc_cc_lim_show(void *data, u64 *val)
3021{
3022 struct gcpm_drv *gcpm = data;
3023
3024 *val = gcpm->dc_limit_cc_min;
3025 return 0;
3026}
3027
3028static int dc_cc_lim_store(void *data, u64 val)
3029{
3030 struct gcpm_drv *gcpm = data;
3031
3032 gcpm->dc_limit_cc_min = val;
3033 return 0;
3034
3035}
3036
3037DEFINE_SIMPLE_ATTRIBUTE(dc_cc_lim_fops, dc_cc_lim_show,
3038 dc_cc_lim_store, "%lld\n");
3039
3040
AleX Pelosie1b18722022-04-18 23:32:31 -07003041#endif // CONFIG_DEBUG_FS
3042
AleX Pelosib961e472022-02-09 19:33:47 -08003043/* ------------------------------------------------------------------------- */
3044
3045static int mdis_out_init_sel_online(u32 *out_sel, int len, const struct gcpm_drv *gcpm)
3046{
3047 static const char *name = "google,mdis-out-sel-online";
3048 struct device_node *node = gcpm->device->of_node;
3049 int ret, count, byte_len;
3050
3051 if (!of_find_property(node, name, &byte_len))
3052 return -ENOENT;
3053
3054 count = byte_len / sizeof(u32);
3055 if (count != len)
3056 return -ERANGE;
3057
3058 ret = of_property_read_u32_array(node, name, out_sel, count);
3059 if (ret < 0)
3060 return -EINVAL;
3061
3062 return count;
3063}
3064
3065/* return the array and the len. Pass len = 0 to avoid check on length */
3066static u32* gcpm_init_limits(const char *name, int *len, struct device *dev)
3067{
3068 struct device_node *node = dev->of_node;
3069 int ret, byte_len;
3070 u32 *limits;
3071
3072 if (!of_find_property(node, name, &byte_len))
3073 return ERR_PTR(-ENOENT);
3074
3075 if (*len && (byte_len / sizeof(u32)) > *len)
3076 return ERR_PTR(-EINVAL);
3077
3078 limits = devm_kzalloc(dev, byte_len, GFP_KERNEL);
3079 if (!limits)
3080 return ERR_PTR(-ENOMEM);
3081
3082 ret = of_property_read_u32_array(node, name, limits, byte_len / sizeof(u32));
3083 if (ret < 0) {
3084 devm_kfree(dev, limits);
3085 return ERR_PTR(-ERANGE);
3086 }
3087
3088 *len = byte_len / sizeof(u32);
3089 return limits;
3090}
3091
3092/* ls /dev/thermal/cdev-by-name/ */
3093static int gcpm_tdev_init(struct mdis_thermal_device *tdev, const char *name,
3094 struct gcpm_drv *gcpm)
3095{
3096 int levels = 0;
3097 u32 *limits;
3098
3099 mutex_init(&tdev->tdev_lock);
3100
3101 limits = gcpm_init_limits(name, &levels, gcpm->device);
3102 if (IS_ERR_OR_NULL(limits)) {
3103 dev_err(gcpm->device, "Cannot create thermal device %s (%d)\n",
3104 name, (int)PTR_ERR(limits));
3105 return PTR_ERR(limits);
3106 }
3107
3108 tdev->thermal_levels = levels;
3109 tdev->thermal_mitigation = limits;
3110 tdev->gcpm = gcpm;
3111 return 0;
3112}
3113
AleX Pelosi02431162022-06-03 21:06:40 +00003114/*
3115 * pick the adapter with the highest current under the budget
3116 * needs mutex_lock(&gcpm->chg_psy_lock);
3117 */
Ken Tsouf956a7f2022-04-12 09:50:46 +08003118static int gcpm_mdis_callback(struct gvotable_election *el, const char *reason,
3119 void *value)
AleX Pelosib961e472022-02-09 19:33:47 -08003120{
3121 struct gcpm_drv *gcpm = gvotable_get_data(el);
3122 struct mdis_thermal_device *tdev = &gcpm->thermal_device;
3123 const int budget = (long)value;
AleX Pelosi430da992022-06-05 23:52:25 +00003124 bool trigger_select = budget != 0 && gcpm->cp_fcc_hold;
AleX Pelosib961e472022-02-09 19:33:47 -08003125
AleX Pelosi430da992022-06-05 23:52:25 +00003126 pr_debug("MSC_MDIS callback lvl=%d budget=%d hold=%d cp_fcc_hold_limit=%d\n",
3127 tdev->current_level, budget, gcpm->cp_fcc_hold,
3128 gcpm->cp_fcc_hold_limit);
3129
3130 /*
3131 * the limit is cleared when charging current is greater that the limit.
3132 * NOTE: Clearing the hold allows re-enabling PPS again.
3133 */
3134 if (gcpm->cp_fcc_hold_limit == -1)
3135 gcpm->cp_fcc_hold = false;
AleX Pelosicba61dd2022-05-19 03:40:37 +00003136
3137 /*
3138 * gcpm->cp_fcc_hold is set when charging switched to main from DC
AleX Pelosi430da992022-06-05 23:52:25 +00003139 * due to the charging current falling under cc_mi n limit: clear the
3140 * hold and give PPS a change if the limit is cleared.
3141 * NOTE: need to
AleX Pelosicba61dd2022-05-19 03:40:37 +00003142 */
AleX Pelosi430da992022-06-05 23:52:25 +00003143 if (trigger_select) {
AleX Pelosicba61dd2022-05-19 03:40:37 +00003144 int ret;
3145
AleX Pelosicba61dd2022-05-19 03:40:37 +00003146 ret = gcpm_chg_select_logic(gcpm);
3147 if (ret == -EAGAIN) {
3148 const int interval = 5; /* seconds */
3149
3150 /* let the setting go through but */
3151 mod_delayed_work(system_wq, &gcpm->select_work,
AleX Pelosi430da992022-06-05 23:52:25 +00003152 msecs_to_jiffies(interval * 1000));
AleX Pelosicba61dd2022-05-19 03:40:37 +00003153 }
3154 }
AleX Pelosibf11ec02022-04-22 11:25:06 -07003155
Jenny Hoa6dfac42022-09-14 14:41:43 +08003156 gcpm_mdis_update_fan(gcpm);
3157
AleX Pelosibf11ec02022-04-22 11:25:06 -07003158 if (!gcpm->csi_status_votable) {
3159 gcpm->csi_status_votable = gvotable_election_get_handle(VOTABLE_CSI_STATUS);
3160 if (!gcpm->csi_status_votable)
Ken Tsouf956a7f2022-04-12 09:50:46 +08003161 return 0;
AleX Pelosibf11ec02022-04-22 11:25:06 -07003162 }
3163
3164 /* this is a problem only when speed is affected */
3165 gvotable_cast_long_vote(gcpm->csi_status_votable, "CSI_STATUS_THERM_MDIS",
3166 CSI_STATUS_System_Thermals,
3167 tdev->current_level != 0);
Ken Tsouf956a7f2022-04-12 09:50:46 +08003168
AleX Pelosicba61dd2022-05-19 03:40:37 +00003169 /* will trigger a power supply change now */
3170 power_supply_changed(gcpm->psy);
Ken Tsouf956a7f2022-04-12 09:50:46 +08003171 return 0;
AleX Pelosib961e472022-02-09 19:33:47 -08003172}
3173
3174/*
AleX Pelosiafb445a2022-05-17 20:15:01 +00003175 * Callback for GCPM_FCC votable which routes the CP limit to the DC charger.
3176 * The votable combines the CC_MAX limit from google_charger and the MDIS
3177 * limit from the dissipation based cooling zone.
3178 * NOTE: it might not benecessary if/when we route the MDIS vote to MSC_FCC
3179 * directly.
AleX Pelosib961e472022-02-09 19:33:47 -08003180 * caller needs to hold mutex_lock(&gcpm->chg_psy_lock);
3181 */
Ken Tsouf956a7f2022-04-12 09:50:46 +08003182static int gcpm_fcc_callback(struct gvotable_election *el, const char *reason,
3183 void *value)
AleX Pelosib961e472022-02-09 19:33:47 -08003184{
3185 struct gcpm_drv *gcpm = gvotable_get_data(el);
AleX Pelosiafb445a2022-05-17 20:15:01 +00003186 const int limit = GVOTABLE_PTR_TO_INT(value);
AleX Pelosib961e472022-02-09 19:33:47 -08003187 struct power_supply *cp_psy;
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00003188 int cp_min, ret;
AleX Pelosib961e472022-02-09 19:33:47 -08003189
AleX Pelosi430da992022-06-05 23:52:25 +00003190 /*
3191 * the current limit is changed, validate it against the min
3192 * NOTE: this is also used to trigger select_work when restarting
3193 * charging when coming off thermal mitigation.
3194 */
3195 cp_min = gcpm_chg_select_check_cp_limit(gcpm);
3196 if (cp_min != -1 && limit <= cp_min) {
3197 pr_debug("MSC_GCPM_FCC: limit=%d reason=%s cpmin=%d trigger select\n",
3198 limit, reason, cp_min);
3199 mod_delayed_work(system_wq, &gcpm->select_work, 0);
Ken Tsouf956a7f2022-04-12 09:50:46 +08003200 return 0;
AleX Pelosiafb445a2022-05-17 20:15:01 +00003201 }
AleX Pelosib961e472022-02-09 19:33:47 -08003202
AleX Pelosi430da992022-06-05 23:52:25 +00003203 /* route the vote to the CP when active */
3204 cp_psy = gcpm_chg_get_active_cp(gcpm);
3205 if (!cp_psy) {
3206 pr_debug("MSC_GCPM_FCC: not active limit=%d\n", limit);
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00003207 return 0;
3208 }
3209
AleX Pelosib961e472022-02-09 19:33:47 -08003210 ret = GPSY_SET_PROP(cp_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
3211 limit);
3212 if (ret < 0)
AleX Pelosi02431162022-06-03 21:06:40 +00003213 pr_err("MSC_GCPM_FCC: cannot apply cp_limit to cc_max=%d (%d)\n",
AleX Pelosib961e472022-02-09 19:33:47 -08003214 limit, ret);
Ken Tsouf956a7f2022-04-12 09:50:46 +08003215
AleX Pelosi02431162022-06-03 21:06:40 +00003216 pr_debug("MSC_GCPM_FCC: applied new cp_limit=%d cp_min=%d ret=%d\n",
AleX Pelosiba7f4ec2022-05-18 03:00:39 +00003217 limit, cp_min, ret);
3218
Ken Tsouf956a7f2022-04-12 09:50:46 +08003219 return 0;
AleX Pelosib961e472022-02-09 19:33:47 -08003220}
3221
Ken Tsou8acade12020-07-09 03:17:35 +08003222#define INIT_DELAY_MS 100
3223#define INIT_RETRY_DELAY_MS 1000
Ken Tsou8acade12020-07-09 03:17:35 +08003224#define GCPM_TCPM_PSY_MAX 2
3225
AleX Pelosib961e472022-02-09 19:33:47 -08003226/* Dissipation Based Thermal Management */
3227static int gcpm_init_mdis(struct gcpm_drv *gcpm)
3228{
3229 struct mdis_thermal_device *tdev = &gcpm->thermal_device;
3230 int i, count, ret;
3231
3232 ret = gcpm_tdev_init(tdev, "google,mdis-thermal-mitigation", gcpm);
3233 if (ret < 0 || !tdev->thermal_levels) {
3234 dev_err(gcpm->device, "No device (%d)\n", ret);
3235 return -ENODEV;
3236 }
3237
3238 /*
AleX Pelosie1b18722022-04-18 23:32:31 -07003239 * TODO: remove ->chg_psy_avail[] and ->chg_psy_count and rewrite to
3240 * use ->mdis_out[].
AleX Pelosib961e472022-02-09 19:33:47 -08003241 * NOTE: gcpm_init_work() needs to read into ->mdis_out[].
3242 */
3243 gcpm->mdis_out[0] = gcpm->chg_psy_avail[0];
3244 gcpm->mdis_out[1] = gcpm->chg_psy_avail[1];
AleX Pelosie1b18722022-04-18 23:32:31 -07003245 gcpm->mdis_out_count = gcpm->chg_psy_count;
AleX Pelosib961e472022-02-09 19:33:47 -08003246
3247 /* one for each out, call with #mdis out */
3248 count = mdis_out_init_sel_online(gcpm->mdis_out_sel, gcpm->chg_psy_count, gcpm);
3249 if (count < 0) {
3250 dev_err(gcpm->device, "mdis sel online (%d)\n", ret);
3251 return -ERANGE;
3252 }
3253
3254 /* TODO: rewrite to parse handles in the device tree */
3255 gcpm->mdis_in[0] = gcpm->tcpm_psy;
3256 gcpm->mdis_in[1] = gcpm->wlc_dc_psy;
AleX Pelosie1b18722022-04-18 23:32:31 -07003257 gcpm->mdis_in_count = 2;
AleX Pelosib961e472022-02-09 19:33:47 -08003258
3259 /*
3260 * max charging current for the each thermal level charger and
3261 * mdis_out_sel mode.
3262 */
AleX Pelosie1b18722022-04-18 23:32:31 -07003263 for (i = 0; i < gcpm->mdis_out_count; i++) {
Jack Wu877687a2022-07-27 22:17:11 +08003264 int len = tdev->thermal_levels * gcpm->mdis_in_count;
AleX Pelosib961e472022-02-09 19:33:47 -08003265 char of_name[36];
3266 u32 *limits;
AleX Pelosib961e472022-02-09 19:33:47 -08003267
3268 scnprintf(of_name, sizeof(of_name), "google,mdis-out%d-limits", i);
AleX Pelosib961e472022-02-09 19:33:47 -08003269
3270 limits = gcpm_init_limits(of_name, &len, gcpm->device);
3271 if (IS_ERR_OR_NULL(limits))
3272 return PTR_ERR(limits);
3273
3274 gcpm->mdis_out_limits[i] = limits;
3275 }
3276
Jenny Hoa6dfac42022-09-14 14:41:43 +08003277 ret = of_property_read_u32(gcpm->device->of_node, "google,mdis-fan-alarm-level",
3278 &tdev->therm_fan_alarm_level);
3279 if (ret < 0)
3280 tdev->therm_fan_alarm_level = FAN_MDIS_ALARM_DEFAULT;
3281
AleX Pelosib961e472022-02-09 19:33:47 -08003282 /* mdis thermal engine uses this callback */
3283 gcpm->mdis_votable =
3284 gvotable_create_int_election(NULL, gvotable_comparator_int_min,
3285 gcpm_mdis_callback, gcpm);
3286 if (IS_ERR_OR_NULL(gcpm->mdis_votable)) {
3287 ret = PTR_ERR(gcpm->mdis_votable);
3288 dev_err(gcpm->device, "no mdis votable (%d)\n", ret);
3289 return ret;
3290 }
3291
3292 gvotable_set_default(gcpm->mdis_votable, (void *)-1);
3293 gvotable_set_vote2str(gcpm->mdis_votable, gvotable_v2s_int);
Stephane Leefa678232022-10-12 16:55:04 -07003294 gvotable_election_set_name(gcpm->mdis_votable, VOTABLE_MDIS);
AleX Pelosib961e472022-02-09 19:33:47 -08003295
3296 /* race with above */
3297 ret = mdis_tdev_register(MDIS_OF_CDEV_NAME, MDIS_CDEV_NAME,
3298 tdev, &chg_mdis_tcd_ops);
3299 if (ret) {
3300 dev_err(gcpm->device,
3301 "Couldn't register %s rc=%d\n", MDIS_OF_CDEV_NAME, ret);
3302
3303 // Free the limits too!
3304 chg_mdis_tdev_free(tdev, gcpm);
3305 return -EINVAL;
3306 }
3307
AleX Pelosie1b18722022-04-18 23:32:31 -07003308 if (!gcpm->debug_entry)
3309 return 0;
3310
3311 debugfs_create_file("state2power_table", 0644, gcpm->debug_entry,
3312 gcpm, &mdis_tm_fops);
3313 debugfs_create_file("mdis_out_table", 0644, gcpm->debug_entry,
3314 gcpm, &mdis_out_fops);
Alice Shengbfafbf12023-02-21 14:11:57 -08003315 debugfs_create_file("mdis_size", 0644, gcpm->debug_entry, gcpm, &mdis_size_fops);
3316 debugfs_create_file("wlc_cc_lim", 0644, gcpm->debug_entry, gcpm, &wlc_cc_lim_fops);
3317 debugfs_create_file("dc_cc_lim", 0644, gcpm->debug_entry, gcpm, &dc_cc_lim_fops);
AleX Pelosie1b18722022-04-18 23:32:31 -07003318
AleX Pelosib961e472022-02-09 19:33:47 -08003319 return 0;
3320}
3321
3322/* this can run */
Ken Tsou8acade12020-07-09 03:17:35 +08003323static void gcpm_init_work(struct work_struct *work)
3324{
3325 struct gcpm_drv *gcpm = container_of(work, struct gcpm_drv,
3326 init_work.work);
3327 int i, found = 0, ret = 0;
AleX Pelosif3776622021-01-18 13:32:08 -08003328 bool dc_not_done;
3329
3330 /* might run along set_property() */
3331 mutex_lock(&gcpm->chg_psy_lock);
Ken Tsou8acade12020-07-09 03:17:35 +08003332
3333 /*
3334 * could call pps_init() in probe() and use lazy init for ->tcpm_psy
3335 * when the device an APDO in the sink capabilities.
3336 */
3337 if (gcpm->tcpm_phandle && !gcpm->tcpm_psy) {
3338 struct power_supply *tcpm_psy;
3339
3340 tcpm_psy = pps_get_tcpm_psy(gcpm->device->of_node,
3341 GCPM_TCPM_PSY_MAX);
3342 if (!IS_ERR_OR_NULL(tcpm_psy)) {
AleX Pelosif3776622021-01-18 13:32:08 -08003343 const char *name = tcpm_psy->desc->name;
3344
3345 gcpm->tcpm_psy_name = name;
Ken Tsou8acade12020-07-09 03:17:35 +08003346 gcpm->tcpm_psy = tcpm_psy;
3347
3348 /* PPS charging: needs an APDO */
AleX Pelosif3776622021-01-18 13:32:08 -08003349 ret = pps_init(&gcpm->tcpm_pps_data, gcpm->device,
Wasb Liu61720712022-11-16 19:19:53 +08003350 gcpm->tcpm_psy, "wired-pps");
Ken Tsou8acade12020-07-09 03:17:35 +08003351 if (ret == 0 && gcpm->debug_entry)
AleX Pelosif3776622021-01-18 13:32:08 -08003352 pps_init_fs(&gcpm->tcpm_pps_data, gcpm->debug_entry);
Ken Tsou8acade12020-07-09 03:17:35 +08003353 if (ret < 0) {
3354 pr_err("PPS init failure for %s (%d)\n",
AleX Pelosif3776622021-01-18 13:32:08 -08003355 name, ret);
Ken Tsou8acade12020-07-09 03:17:35 +08003356 } else {
AleX Pelosif3776622021-01-18 13:32:08 -08003357 gcpm->tcpm_pps_data.port_data =
3358 power_supply_get_drvdata(tcpm_psy);
AleX Pelosif3776622021-01-18 13:32:08 -08003359 pps_init_state(&gcpm->tcpm_pps_data);
AleX Pelosid301b6d2021-04-27 20:18:32 -07003360 pps_set_logbuffer(&gcpm->tcpm_pps_data, gcpm->log);
3361 pps_log(&gcpm->tcpm_pps_data, "TCPM_PPS for %s", gcpm->tcpm_psy_name);
Ken Tsou8acade12020-07-09 03:17:35 +08003362 }
3363
3364 } else if (!tcpm_psy || !gcpm->log_psy_ratelimit) {
AleX Pelosif3776622021-01-18 13:32:08 -08003365 /* abort on an error */
3366 pr_warn("PPS not available for tcpm\n");
Ken Tsou8acade12020-07-09 03:17:35 +08003367 gcpm->tcpm_phandle = 0;
3368 } else {
3369 pr_warn("tcpm power supply not found, retrying... ret:%d\n",
3370 ret);
3371 gcpm->log_psy_ratelimit--;
3372 }
3373
3374 }
3375
AleX Pelosif3776622021-01-18 13:32:08 -08003376 /* TODO: lookup by phandle as the dude above */
3377 if (gcpm->wlc_dc_name && !gcpm->wlc_dc_psy) {
3378 struct power_supply *wlc_dc_psy;
3379
3380 wlc_dc_psy = power_supply_get_by_name(gcpm->wlc_dc_name);
3381 if (wlc_dc_psy) {
3382 const char *name = gcpm->wlc_dc_name;
3383
3384 gcpm->wlc_dc_psy = wlc_dc_psy;
3385
3386 /* PPS charging: needs an APDO */
3387 ret = pps_init(&gcpm->wlc_pps_data, gcpm->device,
Wasb Liu61720712022-11-16 19:19:53 +08003388 gcpm->wlc_dc_psy, "wireless-pps");
AleX Pelosif3776622021-01-18 13:32:08 -08003389 if (ret == 0 && gcpm->debug_entry)
3390 pps_init_fs(&gcpm->wlc_pps_data, gcpm->debug_entry);
3391 if (ret < 0) {
3392 pr_err("PPS init failure for %s (%d)\n",
3393 name, ret);
3394 } else {
AleX Pelosif3776622021-01-18 13:32:08 -08003395 gcpm->wlc_pps_data.port_data = NULL;
3396 pps_init_state(&gcpm->wlc_pps_data);
AleX Pelosid301b6d2021-04-27 20:18:32 -07003397 pps_set_logbuffer(&gcpm->wlc_pps_data, gcpm->log);
3398 pps_log(&gcpm->wlc_pps_data, "WLC_PPS for %s", gcpm->wlc_dc_name);
AleX Pelosif3776622021-01-18 13:32:08 -08003399 }
3400
3401 } else if (!gcpm->log_psy_ratelimit) {
3402 /* give up if wlc_dc_psy return an error */
3403 pr_warn("PPS not available for %s\n", gcpm->wlc_dc_name);
3404 gcpm->wlc_dc_name = NULL;
3405 } else {
3406 pr_warn("%s power supply not found, retrying... ret:%d\n",
3407 gcpm->wlc_dc_name, ret);
3408 gcpm->log_psy_ratelimit--;
3409 }
3410 }
3411
Ken Tsou8acade12020-07-09 03:17:35 +08003412 /* default is index 0 */
3413 for (i = 0; i < gcpm->chg_psy_count; i++) {
3414 if (!gcpm->chg_psy_avail[i]) {
3415 const char *name = gcpm->chg_psy_names[i];
3416
3417 gcpm->chg_psy_avail[i] = power_supply_get_by_name(name);
3418 if (gcpm->chg_psy_avail[i])
3419 pr_info("init_work found %d:%s\n", i, name);
3420 }
3421
3422 found += !!gcpm->chg_psy_avail[i];
3423 }
3424
AleX Pelosia0f55512021-03-17 00:30:20 -07003425 /* sort of done when we have the primary, make it online */
3426 if (gcpm->chg_psy_avail[0] && !gcpm->init_complete) {
3427 struct power_supply *def_psy = gcpm->chg_psy_avail[0];
Ken Tsou8acade12020-07-09 03:17:35 +08003428
AleX Pelosia0f55512021-03-17 00:30:20 -07003429 gcpm->chg_nb.notifier_call = gcpm_psy_changed;
3430 ret = power_supply_reg_notifier(&gcpm->chg_nb);
3431 if (ret < 0)
3432 pr_err("%s: no ps notifier, ret=%d\n", __func__, ret);
3433
AleX Pelosi56311c32021-06-10 15:06:10 -07003434 ret = gcpm_enable_default(gcpm);
AleX Pelosia0f55512021-03-17 00:30:20 -07003435 if (ret < 0)
3436 pr_err("%s: default %s not online, ret=%d\n", __func__,
3437 gcpm_psy_name(def_psy), ret);
Ken Tsou8acade12020-07-09 03:17:35 +08003438
AleX Pelosif3776622021-01-18 13:32:08 -08003439 /* this is the reason why we need a lock here */
Ken Tsou8acade12020-07-09 03:17:35 +08003440 gcpm->resume_complete = true;
3441 gcpm->init_complete = true;
3442 }
3443
AleX Pelosif3776622021-01-18 13:32:08 -08003444 /* keep looking for late arrivals, TCPM and WLC if set */
3445 if (found == gcpm->chg_psy_count)
3446 gcpm->chg_psy_retries = 0;
3447 else if (gcpm->chg_psy_retries)
Ken Tsou8acade12020-07-09 03:17:35 +08003448 gcpm->chg_psy_retries--;
3449
AleX Pelosif3776622021-01-18 13:32:08 -08003450 dc_not_done = (gcpm->tcpm_phandle && !gcpm->tcpm_psy) ||
3451 (gcpm->wlc_dc_name && !gcpm->wlc_dc_psy);
3452
AleX Pelosia0f55512021-03-17 00:30:20 -07003453 pr_warn("%s retries=%d dc_not_done=%d tcpm_ok=%d wlc_ok=%d\n",
3454 __func__, gcpm->chg_psy_retries, dc_not_done,
AleX Pelosif3776622021-01-18 13:32:08 -08003455 (!gcpm->tcpm_phandle || gcpm->tcpm_psy),
3456 (!gcpm->wlc_dc_name || gcpm->wlc_dc_psy));
3457
3458 if (gcpm->chg_psy_retries || dc_not_done) {
Ken Tsou8acade12020-07-09 03:17:35 +08003459 const unsigned long jif = msecs_to_jiffies(INIT_RETRY_DELAY_MS);
3460
3461 schedule_delayed_work(&gcpm->init_work, jif);
AleX Pelosib961e472022-02-09 19:33:47 -08003462 mutex_unlock(&gcpm->chg_psy_lock);
3463 return;
Ken Tsou8acade12020-07-09 03:17:35 +08003464 }
AleX Pelosif3776622021-01-18 13:32:08 -08003465
AleX Pelosib961e472022-02-09 19:33:47 -08003466 pr_info("google_cpm init_work done %d/%d pps=%d wlc_dc=%d\n",
3467 found, gcpm->chg_psy_count,
3468 !!gcpm->tcpm_psy, !!gcpm->wlc_dc_psy);
3469
3470 ret = gcpm_init_mdis(gcpm);
3471 if (ret < 0)
3472 pr_info("google_cpm: no mdis engine (%d)\n", ret);
3473
3474 gcpm->dc_init_complete = true;
AleX Pelosif3776622021-01-18 13:32:08 -08003475 mutex_unlock(&gcpm->chg_psy_lock);
Ken Tsouc9c7d8c2021-05-19 15:42:17 +08003476
AleX Pelosib961e472022-02-09 19:33:47 -08003477 /* might run along set_property() */
3478 mod_delayed_work(system_wq, &gcpm->select_work, 0);
Ken Tsou8acade12020-07-09 03:17:35 +08003479}
3480
AleX Pelosif3776622021-01-18 13:32:08 -08003481/* ------------------------------------------------------------------------ */
3482
Ken Tsou8acade12020-07-09 03:17:35 +08003483static int gcpm_debug_get_active(void *data, u64 *val)
3484{
3485 struct gcpm_drv *gcpm = data;
3486
3487 mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08003488 *val = gcpm->dc_index;
Ken Tsou8acade12020-07-09 03:17:35 +08003489 mutex_unlock(&gcpm->chg_psy_lock);
3490 return 0;
3491}
3492
3493static int gcpm_debug_set_active(void *data, u64 val)
3494{
3495 struct gcpm_drv *gcpm = data;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003496 int intval = (int)val;
3497
3498 if (gcpm->force_active != -1 && val == gcpm->force_active)
3499 intval = -1;
3500
3501 pr_info("%s: val=%llu val=%lld intval=%d\n", __func__, val, val, intval);
Ken Tsou8acade12020-07-09 03:17:35 +08003502
3503 if (intval != -1 && (intval < 0 || intval >= gcpm->chg_psy_count))
3504 return -ERANGE;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003505 if (intval != -1 && !gcpm_chg_get_charger(gcpm, intval))
Ken Tsou8acade12020-07-09 03:17:35 +08003506 return -EINVAL;
3507
3508 mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003509 gcpm->force_active = intval;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08003510 mod_delayed_work(system_wq, &gcpm->select_work, 0);
Ken Tsou8acade12020-07-09 03:17:35 +08003511 mutex_unlock(&gcpm->chg_psy_lock);
3512
AleX Pelosi49ac41c2021-02-18 18:13:42 -08003513 return 0;
Ken Tsou8acade12020-07-09 03:17:35 +08003514}
3515
3516DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_active_fops, gcpm_debug_get_active,
Wasb Liuf62620f2021-03-11 18:09:35 +08003517 gcpm_debug_set_active, "%lld\n");
Ken Tsou8acade12020-07-09 03:17:35 +08003518
AleX Pelosic1ba48c2021-01-16 13:49:59 -08003519static int gcpm_debug_dc_limit_demand_show(void *data, u64 *val)
3520{
3521 struct gcpm_drv *gcpm = data;
3522
3523 *val = gcpm->dc_limit_demand;
3524 return 0;
3525}
3526
3527static int gcpm_debug_dc_limit_demand_set(void *data, u64 val)
3528{
3529 struct gcpm_drv *gcpm = data;
3530 const int intval = val;
3531
3532 mutex_lock(&gcpm->chg_psy_lock);
3533 if (gcpm->dc_limit_demand != intval) {
3534 gcpm->dc_limit_demand = intval;
3535 gcpm->new_dc_limit = true;
3536 }
3537
3538 mutex_unlock(&gcpm->chg_psy_lock);
3539 return 0;
3540}
3541
AleX Pelosif3776622021-01-18 13:32:08 -08003542
AleX Pelosic1ba48c2021-01-16 13:49:59 -08003543DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_dc_limit_demand_fops,
3544 gcpm_debug_dc_limit_demand_show,
3545 gcpm_debug_dc_limit_demand_set,
3546 "%llu\n");
3547
3548
Ken Tsou8acade12020-07-09 03:17:35 +08003549static int gcpm_debug_pps_stage_get(void *data, u64 *val)
3550{
3551 struct gcpm_drv *gcpm = data;
AleX Pelosif3776622021-01-18 13:32:08 -08003552 struct pd_pps_data *pps_data;
Ken Tsou8acade12020-07-09 03:17:35 +08003553
3554 mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosif3776622021-01-18 13:32:08 -08003555 pps_data = gcpm_pps_data(gcpm);
3556 if (pps_data)
3557 *val = pps_data->stage;
Ken Tsou8acade12020-07-09 03:17:35 +08003558 mutex_unlock(&gcpm->chg_psy_lock);
3559 return 0;
3560}
3561
3562static int gcpm_debug_pps_stage_set(void *data, u64 val)
3563{
3564 struct gcpm_drv *gcpm = data;
3565 const int intval = (int)val;
AleX Pelosif3776622021-01-18 13:32:08 -08003566 struct pd_pps_data *pps_data;
Ken Tsou8acade12020-07-09 03:17:35 +08003567
3568 if (intval < PPS_DISABLED || intval > PPS_ACTIVE)
3569 return -EINVAL;
3570
3571 mutex_lock(&gcpm->chg_psy_lock);
AleX Pelosif3776622021-01-18 13:32:08 -08003572 pps_data = gcpm_pps_data(gcpm);
3573 if (pps_data)
3574 pps_data->stage = intval;
Ken Tsou8acade12020-07-09 03:17:35 +08003575 gcpm->force_pps = !pps_is_disabled(intval);
3576 mod_delayed_work(system_wq, &gcpm->pps_work, 0);
3577 mutex_unlock(&gcpm->chg_psy_lock);
3578
3579 return 0;
3580}
3581
3582DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_pps_stage_fops, gcpm_debug_pps_stage_get,
3583 gcpm_debug_pps_stage_set, "%llu\n");
3584
AleX Pelosif3776622021-01-18 13:32:08 -08003585static int gcpm_debug_dc_state_get(void *data, u64 *val)
3586{
3587 struct gcpm_drv *gcpm = data;
3588
3589 mutex_lock(&gcpm->chg_psy_lock);
3590 *val = gcpm->dc_state;
3591 mutex_unlock(&gcpm->chg_psy_lock);
3592 return 0;
3593}
3594
3595static int gcpm_debug_dc_state_set(void *data, u64 val)
3596{
3597 struct gcpm_drv *gcpm = data;
3598 const int intval = (int)val;
AleX Pelosif3776622021-01-18 13:32:08 -08003599
3600 if (intval < DC_DISABLED || intval > DC_PASSTHROUGH)
3601 return -EINVAL;
3602
3603 mutex_lock(&gcpm->chg_psy_lock);
3604 gcpm->dc_state = intval;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08003605 mod_delayed_work(system_wq, &gcpm->select_work, 0);
AleX Pelosif3776622021-01-18 13:32:08 -08003606 mutex_unlock(&gcpm->chg_psy_lock);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08003607
AleX Pelosif3776622021-01-18 13:32:08 -08003608 return 0;
3609}
3610
3611DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_dc_state_fops, gcpm_debug_dc_state_get,
3612 gcpm_debug_dc_state_set, "%llu\n");
3613
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003614
3615static int gcpm_debug_taper_ctl_get(void *data, u64 *val)
3616{
3617 struct gcpm_drv *gcpm = data;
3618
3619 mutex_lock(&gcpm->chg_psy_lock);
3620 *val = gcpm->taper_step;
3621 mutex_unlock(&gcpm->chg_psy_lock);
3622 return 0;
3623}
3624
3625static int gcpm_debug_taper_ctl_set(void *data, u64 val)
3626{
3627 struct gcpm_drv *gcpm = data;
3628 bool ta_check;
3629
3630 mutex_lock(&gcpm->chg_psy_lock);
3631
3632 /* ta_check set when taper control changes value */
3633 ta_check = gcpm_taper_ctl(gcpm, val);
3634 if (ta_check)
3635 mod_delayed_work(system_wq, &gcpm->select_work, 0);
3636 mutex_unlock(&gcpm->chg_psy_lock);
3637 return 0;
3638}
3639
3640DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_ctl_fops, gcpm_debug_taper_ctl_get,
3641 gcpm_debug_taper_ctl_set, "%llu\n");
3642
Jack Wu1c6320c2021-06-17 19:47:20 +08003643static int gcpm_debug_taper_step_fv_margin_get(void *data, u64 *val)
3644{
3645 struct gcpm_drv *gcpm = data;
3646
3647 mutex_lock(&gcpm->chg_psy_lock);
3648 *val = gcpm->taper_step_fv_margin;
3649 mutex_unlock(&gcpm->chg_psy_lock);
3650 return 0;
3651}
3652
3653static int gcpm_debug_taper_step_fv_margin_set(void *data, u64 val)
3654{
3655 struct gcpm_drv *gcpm = data;
3656 const int intval = (int)val;
3657
3658 mutex_lock(&gcpm->chg_psy_lock);
3659 gcpm->taper_step_fv_margin = intval;
3660 mutex_unlock(&gcpm->chg_psy_lock);
3661
3662 return 0;
3663}
3664
3665DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_fv_margin_fops, gcpm_debug_taper_step_fv_margin_get,
3666 gcpm_debug_taper_step_fv_margin_set, "%llu\n");
3667
3668static int gcpm_debug_taper_step_cc_step_get(void *data, u64 *val)
3669{
3670 struct gcpm_drv *gcpm = data;
3671
3672 mutex_lock(&gcpm->chg_psy_lock);
3673 *val = gcpm->taper_step_cc_step;
3674 mutex_unlock(&gcpm->chg_psy_lock);
3675 return 0;
3676}
3677
3678static int gcpm_debug_taper_step_cc_step_set(void *data, u64 val)
3679{
3680 struct gcpm_drv *gcpm = data;
3681 const int intval = (int)val;
3682
3683 mutex_lock(&gcpm->chg_psy_lock);
3684 gcpm->taper_step_cc_step = intval;
3685 mutex_unlock(&gcpm->chg_psy_lock);
3686
3687 return 0;
3688}
3689
3690DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_cc_step_fops, gcpm_debug_taper_step_cc_step_get,
3691 gcpm_debug_taper_step_cc_step_set, "%llu\n");
3692
3693static int gcpm_debug_taper_step_count_get(void *data, u64 *val)
3694{
3695 struct gcpm_drv *gcpm = data;
3696
3697 mutex_lock(&gcpm->chg_psy_lock);
3698 *val = gcpm->taper_step_count;
3699 mutex_unlock(&gcpm->chg_psy_lock);
3700 return 0;
3701}
3702
3703static int gcpm_debug_taper_step_count_set(void *data, u64 val)
3704{
3705 struct gcpm_drv *gcpm = data;
3706 const int intval = (int)val;
3707
3708 mutex_lock(&gcpm->chg_psy_lock);
3709 gcpm->taper_step_count = intval;
3710 mutex_unlock(&gcpm->chg_psy_lock);
3711
3712 return 0;
3713}
3714
3715DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_count_fops, gcpm_debug_taper_step_count_get,
3716 gcpm_debug_taper_step_count_set, "%llu\n");
3717
3718static int gcpm_debug_taper_step_grace_get(void *data, u64 *val)
3719{
3720 struct gcpm_drv *gcpm = data;
3721
3722 mutex_lock(&gcpm->chg_psy_lock);
3723 *val = gcpm->taper_step_grace;
3724 mutex_unlock(&gcpm->chg_psy_lock);
3725 return 0;
3726}
3727
3728static int gcpm_debug_taper_step_grace_set(void *data, u64 val)
3729{
3730 struct gcpm_drv *gcpm = data;
3731 const int intval = (int)val;
3732
3733 mutex_lock(&gcpm->chg_psy_lock);
3734 gcpm->taper_step_grace = intval;
3735 mutex_unlock(&gcpm->chg_psy_lock);
3736
3737 return 0;
3738}
3739
3740DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_grace_fops, gcpm_debug_taper_step_grace_get,
3741 gcpm_debug_taper_step_grace_set, "%llu\n");
3742
3743static int gcpm_debug_taper_step_voltage_get(void *data, u64 *val)
3744{
3745 struct gcpm_drv *gcpm = data;
3746
3747 mutex_lock(&gcpm->chg_psy_lock);
3748 *val = gcpm->taper_step_voltage;
3749 mutex_unlock(&gcpm->chg_psy_lock);
3750 return 0;
3751}
3752
3753static int gcpm_debug_taper_step_voltage_set(void *data, u64 val)
3754{
3755 struct gcpm_drv *gcpm = data;
3756 const int intval = (int)val;
3757
3758 mutex_lock(&gcpm->chg_psy_lock);
3759 gcpm->taper_step_voltage = intval;
3760 mutex_unlock(&gcpm->chg_psy_lock);
3761
3762 return 0;
3763}
3764
3765DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_voltage_fops, gcpm_debug_taper_step_voltage_get,
3766 gcpm_debug_taper_step_voltage_set, "%llu\n");
3767
3768static int gcpm_debug_taper_step_current_get(void *data, u64 *val)
3769{
3770 struct gcpm_drv *gcpm = data;
3771
3772 mutex_lock(&gcpm->chg_psy_lock);
3773 *val = gcpm->taper_step_current;
3774 mutex_unlock(&gcpm->chg_psy_lock);
3775 return 0;
3776}
3777
3778static int gcpm_debug_taper_step_current_set(void *data, u64 val)
3779{
3780 struct gcpm_drv *gcpm = data;
3781 const int intval = (int)val;
3782
3783 mutex_lock(&gcpm->chg_psy_lock);
3784 gcpm->taper_step_current = intval;
3785 mutex_unlock(&gcpm->chg_psy_lock);
3786
3787 return 0;
3788}
3789
3790DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_current_fops, gcpm_debug_taper_step_current_get,
3791 gcpm_debug_taper_step_current_set, "%llu\n");
3792
3793static int gcpm_debug_taper_step_interval_get(void *data, u64 *val)
3794{
3795 struct gcpm_drv *gcpm = data;
3796
3797 mutex_lock(&gcpm->chg_psy_lock);
3798 *val = gcpm->taper_step_interval;
3799 mutex_unlock(&gcpm->chg_psy_lock);
3800 return 0;
3801}
3802
3803static int gcpm_debug_taper_step_interval_set(void *data, u64 val)
3804{
3805 struct gcpm_drv *gcpm = data;
3806 const int intval = (int)val;
3807
3808 mutex_lock(&gcpm->chg_psy_lock);
3809 gcpm->taper_step_interval = intval;
3810 mutex_unlock(&gcpm->chg_psy_lock);
3811
3812 return 0;
3813}
3814
3815DEFINE_SIMPLE_ATTRIBUTE(gcpm_debug_taper_step_interval_fops, gcpm_debug_taper_step_interval_get,
3816 gcpm_debug_taper_step_interval_set, "%llu\n");
3817
Ken Tsou8acade12020-07-09 03:17:35 +08003818static struct dentry *gcpm_init_fs(struct gcpm_drv *gcpm)
3819{
3820 struct dentry *de;
3821
3822 de = debugfs_create_dir("google_cpm", 0);
3823 if (IS_ERR_OR_NULL(de))
3824 return NULL;
3825
AleX Pelosif3776622021-01-18 13:32:08 -08003826 debugfs_create_file("dc_state", 0644, de, gcpm, &gcpm_debug_dc_state_fops);
Ken Tsou8acade12020-07-09 03:17:35 +08003827 debugfs_create_file("active", 0644, de, gcpm, &gcpm_debug_active_fops);
AleX Pelosic1ba48c2021-01-16 13:49:59 -08003828 debugfs_create_file("dc_limit_demand", 0644, de, gcpm,
3829 &gcpm_debug_dc_limit_demand_fops);
AleX Pelosi87e78af2022-02-08 15:08:43 -08003830
3831 debugfs_create_u32("dc_limit_soc_high", 0644, de, &gcpm->dc_limit_soc_high);
3832
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003833 debugfs_create_file("pps_stage", 0644, de, gcpm, &gcpm_debug_pps_stage_fops);
AleX Pelosi87e78af2022-02-08 15:08:43 -08003834
3835 /* smooth exit from DC */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07003836 debugfs_create_file("taper_ctl", 0644, de, gcpm, &gcpm_debug_taper_ctl_fops);
Jack Wu1c6320c2021-06-17 19:47:20 +08003837 debugfs_create_file("taper_step_fv_margin", 0644, de, gcpm, &gcpm_debug_taper_step_fv_margin_fops);
3838 debugfs_create_file("taper_step_cc_step", 0644, de, gcpm, &gcpm_debug_taper_step_cc_step_fops);
3839 debugfs_create_file("taper_step_count", 0644, de, gcpm, &gcpm_debug_taper_step_count_fops);
3840 debugfs_create_file("taper_step_grace", 0644, de, gcpm, &gcpm_debug_taper_step_grace_fops);
3841 debugfs_create_file("taper_step_voltage", 0644, de, gcpm, &gcpm_debug_taper_step_voltage_fops);
3842 debugfs_create_file("taper_step_current", 0644, de, gcpm, &gcpm_debug_taper_step_current_fops);
3843 debugfs_create_file("taper_step_interval", 0644, de, gcpm, &gcpm_debug_taper_step_interval_fops);
Ken Tsou8acade12020-07-09 03:17:35 +08003844
3845 return de;
3846}
3847
AleX Pelosif3776622021-01-18 13:32:08 -08003848/* ------------------------------------------------------------------------ */
3849
Ken Tsou8acade12020-07-09 03:17:35 +08003850static int gcpm_probe_psy_names(struct gcpm_drv *gcpm)
3851{
3852 struct device *dev = gcpm->device;
3853 int i, count, ret;
3854
3855 if (!gcpm->device)
3856 return -EINVAL;
3857
3858 count = of_property_count_strings(dev->of_node,
3859 "google,chg-power-supplies");
3860 if (count <= 0 || count > GCPM_MAX_CHARGERS)
3861 return -ERANGE;
3862
3863 ret = of_property_read_string_array(dev->of_node,
3864 "google,chg-power-supplies",
3865 (const char**)&gcpm->chg_psy_names,
3866 count);
3867 if (ret != count)
3868 return -ERANGE;
3869
3870 for (i = 0; i < count; i++)
3871 dev_info(gcpm->device, "%d:%s\n", i, gcpm->chg_psy_names[i]);
3872
3873 return count;
3874}
3875
AleX Pelosif3776622021-01-18 13:32:08 -08003876/* -------------------------------------------------------------------------
3877 * Use to abstract the PPS adapter if needed.
3878 */
3879
3880static int gcpm_pps_psy_set_property(struct power_supply *psy,
3881 enum power_supply_property prop,
3882 const union power_supply_propval *val)
3883{
3884 struct gcpm_drv *gcpm = power_supply_get_drvdata(psy);
3885 struct pd_pps_data *pps_data;
3886 int ret = 0;
3887
3888 mutex_lock(&gcpm->chg_psy_lock);
3889
3890 pps_data = gcpm_pps_data(gcpm);
3891 if (!pps_data || !pps_data->pps_psy) {
3892 pr_debug("%s: no target prop=%d ret=%d\n", __func__, prop, ret);
3893 mutex_unlock(&gcpm->chg_psy_lock);
3894 return -EAGAIN;
3895 }
3896
3897 switch (prop) {
3898 default:
3899 ret = power_supply_set_property(pps_data->pps_psy, prop, val);
3900 break;
3901 }
3902
3903 mutex_unlock(&gcpm->chg_psy_lock);
3904 pr_debug("%s: prop=%d val=%d ret=%d\n", __func__,
3905 prop, val->intval, ret);
3906
3907 return ret;
3908}
3909
3910static int gcpm_pps_psy_get_property(struct power_supply *psy,
3911 enum power_supply_property prop,
3912 union power_supply_propval *val)
3913{
3914 struct gcpm_drv *gcpm = power_supply_get_drvdata(psy);
3915 struct pd_pps_data *pps_data;
3916 int ret = 0;
3917
3918 mutex_lock(&gcpm->chg_psy_lock);
3919
3920 pps_data = gcpm_pps_data(gcpm);
AleX Pelosi41a89df2021-02-04 00:46:53 -08003921 if (pps_data && pps_data->pps_psy) {
3922 ret = power_supply_get_property(pps_data->pps_psy, prop, val);
3923 pr_debug("%s: prop=%d val=%d ret=%d\n", __func__,
3924 prop, val->intval, ret);
3925 goto done;
AleX Pelosif3776622021-01-18 13:32:08 -08003926 }
3927
3928 switch (prop) {
AleX Pelosi41a89df2021-02-04 00:46:53 -08003929 case POWER_SUPPLY_PROP_USB_TYPE:
3930 val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
3931 break;
AleX Pelosif3776622021-01-18 13:32:08 -08003932 default:
AleX Pelosi41a89df2021-02-04 00:46:53 -08003933 val->intval = 0;
AleX Pelosif3776622021-01-18 13:32:08 -08003934 break;
3935 }
3936
AleX Pelosi41a89df2021-02-04 00:46:53 -08003937done:
AleX Pelosif3776622021-01-18 13:32:08 -08003938 mutex_unlock(&gcpm->chg_psy_lock);
AleX Pelosif3776622021-01-18 13:32:08 -08003939 return ret;
3940}
3941
3942/* check pps_is_avail(), pps_prog_online() and pps_check_type() */
3943static enum power_supply_property gcpm_pps_psy_properties[] = {
3944 POWER_SUPPLY_PROP_VOLTAGE_MAX,
3945 POWER_SUPPLY_PROP_VOLTAGE_MIN,
3946 POWER_SUPPLY_PROP_CURRENT_MAX,
3947 POWER_SUPPLY_PROP_CURRENT_NOW, /* 17 */
3948 POWER_SUPPLY_PROP_ONLINE, /* 4 */
3949 POWER_SUPPLY_PROP_PRESENT, /* 3 */
3950 POWER_SUPPLY_PROP_TYPE, /* */
3951 POWER_SUPPLY_PROP_USB_TYPE, /* */
3952 POWER_SUPPLY_PROP_VOLTAGE_NOW, /* */
3953};
3954
3955static int gcpm_pps_psy_is_writeable(struct power_supply *psy,
3956 enum power_supply_property psp)
3957{
3958 switch (psp) {
3959 case POWER_SUPPLY_PROP_PRESENT:
3960 case POWER_SUPPLY_PROP_ONLINE:
3961 case POWER_SUPPLY_PROP_CURRENT_NOW:
3962 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3963 return 1;
3964 default:
3965 break;
3966 }
3967
3968 return 0;
3969}
3970
3971static enum power_supply_usb_type gcpm_pps_usb_types[] = {
AleX Pelosi41a89df2021-02-04 00:46:53 -08003972 POWER_SUPPLY_USB_TYPE_UNKNOWN,
AleX Pelosif3776622021-01-18 13:32:08 -08003973 POWER_SUPPLY_USB_TYPE_PD_PPS
3974};
3975
3976static const struct power_supply_desc gcpm_pps_psy_desc = {
3977 .name = "gcpm_pps",
3978 .type = POWER_SUPPLY_TYPE_UNKNOWN,
3979 .get_property = gcpm_pps_psy_get_property,
3980 .set_property = gcpm_pps_psy_set_property,
3981 .properties = gcpm_pps_psy_properties,
3982 .property_is_writeable = gcpm_pps_psy_is_writeable,
3983 .num_properties = ARRAY_SIZE(gcpm_pps_psy_properties),
3984
3985 /* POWER_SUPPLY_PROP_USB_TYPE requires an array of these */
3986 .usb_types = gcpm_pps_usb_types,
3987 .num_usb_types = ARRAY_SIZE(gcpm_pps_usb_types),
3988};
3989
3990/* ------------------------------------------------------------------------- */
3991
Ken Tsou8acade12020-07-09 03:17:35 +08003992#define LOG_PSY_RATELIMIT_CNT 200
3993
3994static int google_cpm_probe(struct platform_device *pdev)
3995{
AleX Pelosif3776622021-01-18 13:32:08 -08003996 struct power_supply_config gcpm_pps_psy_cfg = { 0 };
Ken Tsou8acade12020-07-09 03:17:35 +08003997 struct power_supply_config psy_cfg = { 0 };
3998 const char *tmp_name = NULL;
3999 struct gcpm_drv *gcpm;
4000 int ret;
4001
4002 gcpm = devm_kzalloc(&pdev->dev, sizeof(*gcpm), GFP_KERNEL);
4003 if (!gcpm)
4004 return -ENOMEM;
4005
4006 gcpm->device = &pdev->dev;
4007 gcpm->force_active = -1;
Ted Lind35c7422021-05-17 11:32:58 +08004008 gcpm->dc_ctl = GCPM_DC_CTL_DEFAULT;
Ken Tsou8acade12020-07-09 03:17:35 +08004009 gcpm->log_psy_ratelimit = LOG_PSY_RATELIMIT_CNT;
4010 gcpm->chg_psy_retries = 10; /* chg_psy_retries * INIT_RETRY_DELAY_MS */
4011 gcpm->out_uv = -1;
4012 gcpm->out_ua = -1;
AleX Pelosi0937c4c2022-03-28 22:22:10 -07004013 gcpm->cp_fcc_hold_limit = -1;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07004014
AleX Pelosif3776622021-01-18 13:32:08 -08004015 INIT_DELAYED_WORK(&gcpm->pps_work, gcpm_pps_wlc_dc_work);
AleX Pelosi49ac41c2021-02-18 18:13:42 -08004016 INIT_DELAYED_WORK(&gcpm->select_work, gcpm_chg_select_work);
Ken Tsou8acade12020-07-09 03:17:35 +08004017 INIT_DELAYED_WORK(&gcpm->init_work, gcpm_init_work);
4018 mutex_init(&gcpm->chg_psy_lock);
4019
Wasb Liu61720712022-11-16 19:19:53 +08004020 gcpm->gcpm_ws = wakeup_source_register(NULL, "google-cpm");
Wasb Liucf32f212022-10-05 16:50:30 +08004021 if (!gcpm->gcpm_ws) {
4022 dev_err(gcpm->device, "Failed to register wakeup source\n");
4023 return -ENODEV;
4024 }
4025
Ken Tsou8acade12020-07-09 03:17:35 +08004026 /* this is my name */
4027 ret = of_property_read_string(pdev->dev.of_node, "google,psy-name",
4028 &tmp_name);
4029 if (ret == 0) {
4030 gcpm_psy_desc.name = devm_kstrdup(&pdev->dev, tmp_name,
4031 GFP_KERNEL);
4032 if (!gcpm_psy_desc.name)
4033 return -ENOMEM;
4034 }
4035
AleX Pelosif3776622021-01-18 13:32:08 -08004036 /* subs power supply names */
Ken Tsou8acade12020-07-09 03:17:35 +08004037 gcpm->chg_psy_count = gcpm_probe_psy_names(gcpm);
4038 if (gcpm->chg_psy_count <= 0)
4039 return -ENODEV;
4040
AleX Pelosif3776622021-01-18 13:32:08 -08004041 /* DC/PPS needs at least one power supply of this type */
Ken Tsou8acade12020-07-09 03:17:35 +08004042 ret = of_property_read_u32(pdev->dev.of_node,
4043 "google,tcpm-power-supply",
4044 &gcpm->tcpm_phandle);
4045 if (ret < 0)
4046 pr_warn("google,tcpm-power-supply not defined\n");
4047
AleX Pelosif3776622021-01-18 13:32:08 -08004048 ret = of_property_read_string(pdev->dev.of_node,
4049 "google,wlc_dc-power-supply",
4050 &tmp_name);
4051 if (ret == 0) {
4052 gcpm->wlc_dc_name = devm_kstrdup(&pdev->dev, tmp_name,
4053 GFP_KERNEL);
4054 if (!gcpm->wlc_dc_name)
4055 return -ENOMEM;
4056 }
4057
4058 /* GCPM might need a gpio to enable/disable DC/PPS */
AleX Pelosi568ddbf2021-03-23 23:56:50 -07004059 gcpm->dcen_gpio = of_get_named_gpio(pdev->dev.of_node, "google,dc-en", 0);
Ken Tsou8acade12020-07-09 03:17:35 +08004060 if (gcpm->dcen_gpio >= 0) {
AleX Pelosi30afcb82021-07-13 10:50:57 -07004061 unsigned long init_flags = GPIOF_OUT_INIT_LOW;
4062
Ken Tsou8acade12020-07-09 03:17:35 +08004063 of_property_read_u32(pdev->dev.of_node, "google,dc-en-value",
4064 &gcpm->dcen_gpio_default);
AleX Pelosi30afcb82021-07-13 10:50:57 -07004065 if (gcpm->dcen_gpio_default)
4066 init_flags = GPIOF_OUT_INIT_HIGH;
Ken Tsou8acade12020-07-09 03:17:35 +08004067
AleX Pelosi30afcb82021-07-13 10:50:57 -07004068 ret = devm_gpio_request_one(&pdev->dev, gcpm->dcen_gpio,
4069 init_flags, "dc_pu_pin");
4070 pr_info("google,dc-en value =%d ret=%d\n",
Ken Tsou8acade12020-07-09 03:17:35 +08004071 gcpm->dcen_gpio_default, ret);
4072 }
4073
AleX Pelosif3776622021-01-18 13:32:08 -08004074 /* Triggers to enable dc charging */
AleX Pelosic1ba48c2021-01-16 13:49:59 -08004075 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-demand",
4076 &gcpm->dc_limit_demand);
4077 if (ret < 0)
4078 gcpm->dc_limit_demand = GCPM_DEFAULT_DC_LIMIT_DEMAND;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08004079
AleX Pelosibc7f0a22021-04-03 15:17:41 -07004080 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-cc_min",
4081 &gcpm->dc_limit_cc_min);
4082 if (ret < 0)
4083 gcpm->dc_limit_cc_min = GCPM_DEFAULT_DC_LIMIT_CC_MIN;
4084
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07004085 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-cc_min_wlc",
Alice Shengbfafbf12023-02-21 14:11:57 -08004086 &gcpm->dc_limit_cc_min_wlc);
AleX Pelosi58ddf5c2021-06-16 11:48:58 -07004087 if (ret < 0)
4088 gcpm->dc_limit_cc_min_wlc = GCPM_DEFAULT_DC_LIMIT_CC_MIN_WLC;
AleX Pelosibc7f0a22021-04-03 15:17:41 -07004089
4090
AleX Pelosi49ac41c2021-02-18 18:13:42 -08004091 /* voltage lower bound */
AleX Pelosif20ccc82021-02-12 22:57:34 -08004092 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-vbatt_min",
4093 &gcpm->dc_limit_vbatt_min);
AleX Pelosic1ba48c2021-01-16 13:49:59 -08004094 if (ret < 0)
AleX Pelosif20ccc82021-02-12 22:57:34 -08004095 gcpm->dc_limit_vbatt_min = GCPM_DEFAULT_DC_LIMIT_VBATT_MIN;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08004096 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-vbatt_low",
4097 &gcpm->dc_limit_vbatt_low);
4098 if (ret < 0)
4099 gcpm->dc_limit_vbatt_low = gcpm->dc_limit_vbatt_min -
4100 GCPM_DEFAULT_DC_LIMIT_DELTA_LOW;
4101 if (gcpm->dc_limit_vbatt_low > gcpm->dc_limit_vbatt_min)
4102 gcpm->dc_limit_vbatt_low = gcpm->dc_limit_vbatt_min;
4103
4104 /* voltage upper bound */
AleX Pelosif20ccc82021-02-12 22:57:34 -08004105 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-vbatt_max",
4106 &gcpm->dc_limit_vbatt_max);
4107 if (ret < 0)
4108 gcpm->dc_limit_vbatt_max = GCPM_DEFAULT_DC_LIMIT_VBATT_MAX;
AleX Pelosi49ac41c2021-02-18 18:13:42 -08004109 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-vbatt_high",
4110 &gcpm->dc_limit_vbatt_high);
4111 if (ret < 0)
4112 gcpm->dc_limit_vbatt_high = gcpm->dc_limit_vbatt_max -
4113 GCPM_DEFAULT_DC_LIMIT_DELTA_HIGH;
4114 if (gcpm->dc_limit_vbatt_high > gcpm->dc_limit_vbatt_max)
4115 gcpm->dc_limit_vbatt_high = gcpm->dc_limit_vbatt_max;
Ken Tsou8acade12020-07-09 03:17:35 +08004116
AleX Pelosi87e78af2022-02-08 15:08:43 -08004117 /* state of charge based limits */
4118 ret = of_property_read_u32(pdev->dev.of_node, "google,dc_limit-soc_high",
4119 &gcpm->dc_limit_soc_high);
4120 if (ret < 0)
4121 gcpm->dc_limit_soc_high = GCPM_DEFAULT_DC_LIMIT_SOC_HIGH;
4122
AleX Pelosi568ddbf2021-03-23 23:56:50 -07004123 /* taper control */
4124 gcpm->taper_step = -1;
Jack Wu1c6320c2021-06-17 19:47:20 +08004125 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-fv-margin",
4126 &gcpm->taper_step_fv_margin);
4127 if (ret < 0)
4128 gcpm->taper_step_fv_margin = GCPM_TAPER_STEP_FV_MARGIN;
4129 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-cc-step",
4130 &gcpm->taper_step_cc_step);
4131 if (ret < 0)
4132 gcpm->taper_step_cc_step = GCPM_TAPER_STEP_CC_STEP;
AleX Pelosi568ddbf2021-03-23 23:56:50 -07004133 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-interval",
4134 &gcpm->taper_step_interval);
4135 if (ret < 0)
4136 gcpm->taper_step_interval = GCPM_TAPER_STEP_INTERVAL_S;
4137
4138 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-count",
4139 &gcpm->taper_step_count);
4140 if (ret < 0)
4141 gcpm->taper_step_count = GCPM_TAPER_STEP_COUNT;
4142 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-grace",
4143 &gcpm->taper_step_grace);
4144 if (ret < 0)
4145 gcpm->taper_step_grace = GCPM_TAPER_STEP_GRACE;
4146 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-voltage",
4147 &gcpm->taper_step_voltage);
4148 if (ret < 0)
4149 gcpm->taper_step_voltage = GCPM_TAPER_STEP_VOLTAGE;
AleX Pelosi87f4b472021-05-20 02:30:14 -07004150 ret = of_property_read_u32(pdev->dev.of_node, "google,taper_step-current",
4151 &gcpm->taper_step_current);
4152 if (ret < 0)
4153 gcpm->taper_step_current = GCPM_TAPER_STEP_CURRENT;
4154
AleX Pelosib961e472022-02-09 19:33:47 -08004155 dev_info(gcpm->device, "taper ts_m=%d ts_ccs=%d ts_i=%d ts_cnt=%d ts_g=%d ts_v=%d ts_c=%d\n",
4156 gcpm->taper_step_fv_margin, gcpm->taper_step_cc_step,
4157 gcpm->taper_step_interval, gcpm->taper_step_count,
4158 gcpm->taper_step_grace, gcpm->taper_step_voltage,
4159 gcpm->taper_step_current);
AleX Pelosi568ddbf2021-03-23 23:56:50 -07004160
AleX Pelosi2fba3db2022-06-02 00:23:22 +00004161 /* GCPM_FCC has the current cc_max for the selected charger */
4162 gcpm->cp_votable =
4163 gvotable_create_int_election(NULL, gvotable_comparator_int_min,
4164 gcpm_fcc_callback, gcpm);
4165 if (IS_ERR_OR_NULL(gcpm->cp_votable)) {
4166 ret = PTR_ERR(gcpm->cp_votable);
AleX Pelosi02431162022-06-03 21:06:40 +00004167 dev_err(gcpm->device, "no GCPM_FCC votable (%d)\n", ret);
AleX Pelosi2fba3db2022-06-02 00:23:22 +00004168 return ret;
4169 }
4170
4171 gvotable_set_default(gcpm->cp_votable, (void *)-1);
4172 gvotable_set_vote2str(gcpm->cp_votable, gvotable_v2s_int);
4173 gvotable_election_set_name(gcpm->cp_votable, "GCPM_FCC");
4174
AleX Pelosib961e472022-02-09 19:33:47 -08004175 /*
4176 * WirelessDC and Wireless charging use different thermal limit.
4177 * The limit (level) comes from the thermal cooling zone msc_fcc and is
4178 * mutually exclusive with the vote on dc_icl
4179 */
AleX Pelosief75a072021-06-12 17:38:36 -07004180 gcpm->dc_fcc_votable =
4181 gvotable_create_int_election(NULL, gvotable_comparator_int_min,
4182 gcpm_dc_fcc_callback, gcpm);
4183 if (IS_ERR_OR_NULL(gcpm->dc_fcc_votable)) {
4184 ret = PTR_ERR(gcpm->dc_fcc_votable);
4185 dev_err(gcpm->device, "no dc_fcc votable (%d)\n", ret);
4186 return ret;
4187 }
4188
4189 gvotable_set_default(gcpm->dc_fcc_votable, (void *)-1);
4190 gvotable_set_vote2str(gcpm->dc_fcc_votable, gvotable_v2s_int);
4191 gvotable_election_set_name(gcpm->dc_fcc_votable, "DC_FCC");
4192
Prasanna Prapancham19203302022-09-09 20:58:11 +00004193 gcpm->dc_chg_avail_votable = gvotable_create_int_election(
Wasb Liu4f9b0232022-07-28 17:43:09 +08004194 NULL, gvotable_comparator_int_min,
4195 gcpm_dc_chg_avail_callback, gcpm);
Prasanna Prapancham19203302022-09-09 20:58:11 +00004196
4197 if (IS_ERR_OR_NULL(gcpm->dc_chg_avail_votable)) {
4198 ret = PTR_ERR(gcpm->dc_chg_avail_votable);
4199 dev_err(gcpm->device, "no DC chg avail votable %d\n", ret);
4200 return ret;
4201 }
4202
4203 gvotable_set_default(gcpm->dc_chg_avail_votable, (void *)1);
4204 gvotable_set_vote2str(gcpm->dc_chg_avail_votable, gvotable_v2s_int);
4205 gvotable_election_set_name(gcpm->dc_chg_avail_votable, VOTABLE_DC_CHG_AVAIL);
4206 gvotable_use_default(gcpm->dc_chg_avail_votable, true);
4207
Ken Tsou8acade12020-07-09 03:17:35 +08004208 /* sysfs & debug */
4209 gcpm->debug_entry = gcpm_init_fs(gcpm);
4210 if (!gcpm->debug_entry)
4211 pr_warn("No debug control\n");
4212
4213 platform_set_drvdata(pdev, gcpm);
4214
4215 psy_cfg.drv_data = gcpm;
4216 psy_cfg.of_node = pdev->dev.of_node;
AleX Pelosif3776622021-01-18 13:32:08 -08004217 gcpm->psy = devm_power_supply_register(gcpm->device,
4218 &gcpm_psy_desc,
Ken Tsou8acade12020-07-09 03:17:35 +08004219 &psy_cfg);
4220 if (IS_ERR(gcpm->psy)) {
4221 ret = PTR_ERR(gcpm->psy);
4222 if (ret == -EPROBE_DEFER)
4223 return -EPROBE_DEFER;
4224
AleX Pelosif3776622021-01-18 13:32:08 -08004225 dev_err(gcpm->device, "Couldn't register gcpm, (%d)\n", ret);
4226 return -ENODEV;
4227 }
4228
AleX Pelosid301b6d2021-04-27 20:18:32 -07004229 gcpm->log = logbuffer_register("cpm");
4230 if (IS_ERR(gcpm->log)) {
4231 dev_err(gcpm->device, "Couldn't register logbuffer, (%ld)\n",
4232 PTR_ERR(gcpm->log));
4233 gcpm->log = NULL;
4234 }
4235
AleX Pelosif3776622021-01-18 13:32:08 -08004236 /* gcpm_pps_psy_cfg.of_node is used to find out the snk_pdos */
4237 gcpm_pps_psy_cfg.drv_data = gcpm;
4238 gcpm_pps_psy_cfg.of_node = pdev->dev.of_node;
4239 gcpm->pps_psy = devm_power_supply_register(gcpm->device,
4240 &gcpm_pps_psy_desc,
4241 &gcpm_pps_psy_cfg);
4242 if (IS_ERR(gcpm->pps_psy)) {
4243 ret = PTR_ERR(gcpm->pps_psy);
4244 if (ret == -EPROBE_DEFER)
4245 return -EPROBE_DEFER;
4246
4247 dev_err(gcpm->device, "Couldn't register gcpm_pps (%d)\n", ret);
4248 return -ENODEV;
Ken Tsou8acade12020-07-09 03:17:35 +08004249 }
4250
Ted Line29ae8a2021-05-20 13:05:02 +08004251 ret = device_create_file(gcpm->device, &dev_attr_dc_limit_demand);
4252 if (ret)
4253 dev_err(gcpm->device, "Failed to create dc_limit_demand\n");
4254
4255 ret = device_create_file(gcpm->device, &dev_attr_dc_limit_vbatt_max);
4256 if (ret)
4257 dev_err(gcpm->device, "Failed to create dc_limit_vbatt_max\n");
4258
4259 ret = device_create_file(gcpm->device, &dev_attr_dc_limit_vbatt_min);
4260 if (ret)
4261 dev_err(gcpm->device, "Failed to create dc_limit_vbatt_min\n");
4262
Ted Lind35c7422021-05-17 11:32:58 +08004263 ret = device_create_file(gcpm->device, &dev_attr_dc_ctl);
4264 if (ret)
4265 dev_err(gcpm->device, "Failed to create dc_crl\n");
4266
Jenny Hoa6dfac42022-09-14 14:41:43 +08004267 ret = device_create_file(gcpm->device, &dev_attr_thermal_mdis_fan_alarm);
4268 if (ret)
4269 dev_err(gcpm->device, "Failed to create thermal_mdis_fan_alarm\n");
4270
Ken Tsou8acade12020-07-09 03:17:35 +08004271 /* give time to fg driver to start */
4272 schedule_delayed_work(&gcpm->init_work,
4273 msecs_to_jiffies(INIT_DELAY_MS));
4274
4275 return 0;
4276}
4277
4278static int google_cpm_remove(struct platform_device *pdev)
4279{
4280 struct gcpm_drv *gcpm = platform_get_drvdata(pdev);
4281 int i;
4282
4283 if (!gcpm)
4284 return 0;
4285
AleX Pelosief75a072021-06-12 17:38:36 -07004286 gvotable_destroy_election(gcpm->dc_fcc_votable);
4287
Ken Tsou8acade12020-07-09 03:17:35 +08004288 for (i = 0; i < gcpm->chg_psy_count; i++) {
4289 if (!gcpm->chg_psy_avail[i])
4290 continue;
4291
4292 power_supply_put(gcpm->chg_psy_avail[i]);
4293 gcpm->chg_psy_avail[i] = NULL;
4294 }
4295
AleX Pelosi59aef952021-04-29 14:27:49 -07004296 pps_free(&gcpm->wlc_pps_data);
4297 pps_free(&gcpm->tcpm_pps_data);
4298
Wasb Liucf32f212022-10-05 16:50:30 +08004299 wakeup_source_unregister(gcpm->gcpm_ws);
4300
AleX Pelosif3776622021-01-18 13:32:08 -08004301 if (gcpm->wlc_dc_psy)
4302 power_supply_put(gcpm->wlc_dc_psy);
AleX Pelosid301b6d2021-04-27 20:18:32 -07004303 if (gcpm->log)
4304 logbuffer_unregister(gcpm->log);
4305
Ken Tsou8acade12020-07-09 03:17:35 +08004306 return 0;
4307}
4308
Wasb Liucbf95fd2022-02-10 18:03:24 +08004309static int __maybe_unused gcpm_pm_suspend(struct device *dev)
4310{
4311 struct platform_device *pdev = to_platform_device(dev);
4312 struct gcpm_drv *gcpm = platform_get_drvdata(pdev);
4313
4314 if (gcpm->init_complete) {
4315 pm_runtime_get_sync(gcpm->device);
4316 gcpm->resume_complete = false;
4317 pm_runtime_put_sync(gcpm->device);
4318 }
4319
4320 return 0;
4321}
4322
4323static int __maybe_unused gcpm_pm_resume(struct device *dev)
4324{
4325 struct platform_device *pdev = to_platform_device(dev);
4326 struct gcpm_drv *gcpm = platform_get_drvdata(pdev);
4327
4328 if (gcpm->init_complete) {
4329 pm_runtime_get_sync(gcpm->device);
4330 gcpm->resume_complete = true;
4331 pm_runtime_put_sync(gcpm->device);
4332 }
4333
4334 return 0;
4335}
4336
4337static SIMPLE_DEV_PM_OPS(gcpm_pm_ops,
4338 gcpm_pm_suspend,
4339 gcpm_pm_resume);
4340
Ken Tsou8acade12020-07-09 03:17:35 +08004341static const struct of_device_id google_cpm_of_match[] = {
4342 {.compatible = "google,cpm"},
4343 {},
4344};
4345MODULE_DEVICE_TABLE(of, google_cpm_of_match);
4346
4347
4348static struct platform_driver google_cpm_driver = {
4349 .driver = {
4350 .name = "google_cpm",
4351 .owner = THIS_MODULE,
4352 .of_match_table = google_cpm_of_match,
AleX Pelosi32892282020-09-11 02:29:20 -07004353 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
Wasb Liucbf95fd2022-02-10 18:03:24 +08004354 .pm = &gcpm_pm_ops,
Ken Tsou8acade12020-07-09 03:17:35 +08004355 },
4356 .probe = google_cpm_probe,
4357 .remove = google_cpm_remove,
4358};
4359
AleX Pelosi32892282020-09-11 02:29:20 -07004360module_platform_driver(google_cpm_driver);
Ken Tsou8acade12020-07-09 03:17:35 +08004361
Ken Tsou8acade12020-07-09 03:17:35 +08004362MODULE_DESCRIPTION("Google Charging Policy Manager");
4363MODULE_AUTHOR("AleX Pelosi <apelosi@google.com>");
4364MODULE_LICENSE("GPL");
AleX Pelosif3776622021-01-18 13:32:08 -08004365
4366#if 0
4367
4368/* NOTE: call with a lock around gcpm->chg_psy_lock */
4369static int gcpm_dc_charging(struct gcpm_drv *gcpm)
4370{
4371 struct power_supply *dc_psy;
4372 int vchg, ichg, status;
4373
4374 dc_psy = gcpm_chg_get_active(gcpm);
4375 if (!dc_psy) {
4376 pr_err("DC_CHG: invalid charger\n");
4377 return -ENODEV;
4378 }
4379
4380 vchg = GPSY_GET_PROP(dc_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
4381 ichg = GPSY_GET_PROP(dc_psy, POWER_SUPPLY_PROP_CURRENT_NOW);
4382 status = GPSY_GET_PROP(dc_psy, POWER_SUPPLY_PROP_STATUS);
4383
4384 pr_err("DC_CHG: vchg=%d, ichg=%d status=%d\n",
4385 vchg, ichg, status);
4386
4387 return 0;
4388}
4389
4390static void gcpm_pps_dc_charging(struct gcpm_drv *gcpm)
4391{
4392 struct pd_pps_data *pps_data = &gcpm->pps_data;
4393 struct power_supply *pps_psy = gcpm->tcpm_psy;
4394 const int pre_out_ua = pps_data->op_ua;
4395 const int pre_out_uv = pps_data->out_uv;
4396 int ret, pps_ui = -ENODEV;
4397
4398 if (gcpm->dc_state == DC_ENABLE) {
4399 struct pd_pps_data *pps_data = &gcpm->pps_data;
4400 bool pwr_ok;
4401
4402 /* must run at the end of PPS negotiation */
4403 if (gcpm->out_ua == -1)
4404 gcpm->out_ua = min(gcpm->cc_max, pps_data->max_ua);
4405 if (gcpm->out_uv == -1) {
4406 struct power_supply *chg_psy =
4407 gcpm_chg_get_active(gcpm);
4408 unsigned long ta_max_v, value;
4409 int vbatt = -1;
4410
4411 ta_max_v = pps_data->max_ua * pps_data->max_uv;
4412 ta_max_v /= gcpm->out_ua;
4413 if (ta_max_v > DC_TA_VMAX_MV)
4414 ta_max_v = DC_TA_VMAX_MV;
4415
4416 if (chg_psy)
4417 vbatt = GPSY_GET_PROP(chg_psy,
4418 POWER_SUPPLY_PROP_VOLTAGE_NOW);
4419 if (vbatt < 0)
4420 vbatt = gcpm->fv_uv;
4421 if (vbatt < 0)
4422 vbatt = 0;
4423
4424 /* good for pca9468 */
4425 value = 2 * vbatt + DC_VBATT_HEADROOM_MV;
4426 if (value < DC_TA_VMIN_MV)
4427 value = DC_TA_VMIN_MV;
4428
4429 /* PPS voltage in 20mV steps */
4430 gcpm->out_uv = value - value % 20000;
4431 }
4432
4433 pr_info("CHG_CHK: max_uv=%d,max_ua=%d out_uv=%d,out_ua=%d\n",
4434 pps_data->max_uv, pps_data->max_ua,
4435 gcpm->out_uv, gcpm->out_ua);
4436
4437 pps_ui = pps_update_adapter(pps_data, gcpm->out_uv,
4438 gcpm->out_ua, pps_psy);
4439 if (pps_ui < 0)
4440 pps_ui = PPS_ERROR_RETRY_MS;
4441
4442 /* wait until adapter is at or over request */
4443 pwr_ok = pps_data->out_uv == gcpm->out_uv &&
4444 pps_data->op_ua == gcpm->out_ua;
4445 if (pwr_ok) {
4446 ret = gcpm_chg_offline(gcpm);
4447 if (ret == 0)
4448 ret = gcpm_dc_start(gcpm, gcpm->dc_index);
4449 if (ret == 0) {
4450 gcpm->dc_state = DC_RUNNING;
4451 pps_ui = DC_RUN_DELAY_MS;
4452 } else if (pps_ui > DC_ERROR_RETRY_MS) {
4453 pps_ui = DC_ERROR_RETRY_MS;
4454 }
4455 }
4456
4457 /*
4458 * TODO: add retries and switch to DC_ENABLE again or to
4459 * DC_DISABLED on timeout.
4460 */
4461
4462 pr_info("PPS_DC: dc_state=%d out_uv=%d %d->%d, out_ua=%d %d->%d\n",
4463 gcpm->dc_state,
4464 pps_data->out_uv, pre_out_uv, gcpm->out_uv,
4465 pps_data->op_ua, pre_out_ua, gcpm->out_ua);
4466 } else if (gcpm->dc_state == DC_RUNNING) {
4467
4468 ret = gcpm_chg_ping(gcpm, 0, 0);
4469 if (ret < 0)
4470 pr_err("PPS_DC: ping failed with %d\n", ret);
4471
4472 /* update gcpm->out_uv, gcpm->out_ua */
4473 pr_info("PPS_DC: dc_state=%d out_uv=%d %d->%d out_ua=%d %d->%d\n",
4474 gcpm->dc_state,
4475 pps_data->out_uv, pre_out_uv, gcpm->out_uv,
4476 pps_data->op_ua, pre_out_ua, gcpm->out_ua);
4477
4478 ret = gcpm_dc_charging(gcpm);
4479 if (ret < 0)
4480 pps_ui = DC_ERROR_RETRY_MS;
4481
4482 ret = pps_update_adapter(&gcpm->pps_data,
4483 gcpm->out_uv, gcpm->out_ua,
4484 pps_psy);
4485 if (ret < 0)
4486 pps_ui = PPS_ERROR_RETRY_MS;
4487 }
4488
4489 return pps_ui;
4490}
Jack Wu1d714342021-05-27 11:37:37 +08004491#endif