blob: ee094f553d7970df9a169ad0a2843bf752efcc65 [file] [log] [blame]
Jack Wuf1f6be22021-07-01 21:50:38 +08001/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright 2021 Google, LLC
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
Jack Wuc6b941d2022-05-31 21:29:09 +080018#include <linux/debugfs.h>
Jack Wuf1f6be22021-07-01 21:50:38 +080019#include <linux/kernel.h>
20#include <linux/printk.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/of_gpio.h>
25#include <linux/of_irq.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28#include <linux/interrupt.h>
Ken Tsoua15d1fa2022-01-24 14:42:27 +080029#include <misc/gvotable.h>
Jack Wuf1f6be22021-07-01 21:50:38 +080030#include "gbms_power_supply.h"
31#include "google_bms.h"
32#include "google_psy.h"
Jack Wuf1f6be22021-07-01 21:50:38 +080033
34#define DOCK_USER_VOTER "DOCK_USER_VOTER"
35#define DOCK_AICL_VOTER "DOCK_AICL_VOTER"
Jack Wuc6b941d2022-05-31 21:29:09 +080036#define DOCK_VOUT_VOTER "DOCK_VOUT_VOTER"
Jack Wuf1f6be22021-07-01 21:50:38 +080037
38#define DOCK_DELAY_INIT_MS 500
39#define DOCK_NOTIFIER_DELAY_MS 100
40#define DOCK_ICL_DEFAULT_UA 500000
41#define DOCK_15W_ILIM_UA 1250000
42#define DOCK_13_5W_ILIM_UA 1500000
43#define DOCK_13_5W_VOUT_UV 9000000
Jack Wue8d14732021-08-23 18:06:50 +080044#define DOCK_ICL_RAMP_DELAY_DEFAULT_MS (4 * 1000) /* 4 seconds */
Jack Wuf1f6be22021-07-01 21:50:38 +080045
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +000046/* type detection */
47#define EXT_DETECT_DELAY_MS (1000)
48#define EXT_DETECT_RETRIES (3)
49
Jack Wuf1f6be22021-07-01 21:50:38 +080050struct dock_drv {
51 struct device *device;
52 struct power_supply *psy;
53 const char *dc_psy_name;
54 struct power_supply *dc_psy;
55 struct mutex dock_lock;
56 struct delayed_work init_work;
57 struct delayed_work notifier_work;
58 struct delayed_work icl_ramp_work;
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +000059 struct delayed_work detect_work;
Jack Wuf1f6be22021-07-01 21:50:38 +080060 struct alarm icl_ramp_alarm;
61 struct notifier_block nb;
Ken Tsoua15d1fa2022-01-24 14:42:27 +080062 struct gvotable_election *dc_icl_votable;
Jack Wuc6b941d2022-05-31 21:29:09 +080063 struct gvotable_election *chg_mode_votable;
Jack Wuf1f6be22021-07-01 21:50:38 +080064
65 bool init_complete;
66 bool check_dc;
67 bool icl_ramp;
68 u32 icl_ramp_ua;
69 u32 icl_ramp_delay_ms;
Jack Wue8d14732021-08-23 18:06:50 +080070 int online;
Jack Wub77d7182021-09-01 15:20:30 +080071 int pogo_ovp_en;
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +000072 int voltage_max; /* > 10.5V mean Ext1 else > 5V mean Ext2. */
73 int detect_retries;
74 struct wakeup_source *detect_ws;
Jack Wuf1f6be22021-07-01 21:50:38 +080075};
76
Jack Wu961f12a2022-09-01 22:14:27 +080077/* ------------------------------------------------------------------------- */
78
79static bool google_dock_find_mode_votable(struct dock_drv *dock)
80{
81 if (!dock->chg_mode_votable) {
82 dock->chg_mode_votable = gvotable_election_get_handle(GBMS_MODE_VOTABLE);
83 if (!dock->chg_mode_votable) {
84 dev_err(dock->device, "Could not get CHARGER_MODE votable\n");
85 return false;
86 }
87 }
88
89 return true;
90}
91
92static int google_dock_set_pogo_vout(struct dock_drv *dock,
93 int enabled)
94{
95 if (!google_dock_find_mode_votable(dock))
96 return -EINVAL;
97
98 dev_dbg(dock->device, "pogo_vout_enabled=%d\n", enabled);
99
100 return gvotable_cast_long_vote(dock->chg_mode_votable,
101 DOCK_VOUT_VOTER,
Jack Wu15abe932022-11-14 20:11:24 +0800102 GBMS_POGO_VOUT,
Jack Wu961f12a2022-09-01 22:14:27 +0800103 enabled != 0);
104}
Jack Wue872f582022-01-13 16:38:17 +0800105
106/* ------------------------------------------------------------------------- */
107static ssize_t is_dock_show(struct device *dev,
Jack Wuc6b941d2022-05-31 21:29:09 +0800108 struct device_attribute *attr, char *buf)
Jack Wue872f582022-01-13 16:38:17 +0800109{
110 struct power_supply *psy = container_of(dev, struct power_supply, dev);
111 struct dock_drv *dock = power_supply_get_drvdata(psy);
112 int online;
113
114 online = GPSY_GET_PROP(dock->dc_psy, POWER_SUPPLY_PROP_ONLINE);
115
116 return scnprintf(buf, PAGE_SIZE, "%d\n", online);
117}
118
119static DEVICE_ATTR_RO(is_dock);
120
Jack Wuc6b941d2022-05-31 21:29:09 +0800121static int debug_pogo_vout_write(void *data, u64 val)
122{
123 struct dock_drv *dock = (struct dock_drv *)data;
Jack Wu961f12a2022-09-01 22:14:27 +0800124 int ret;
Jack Wuc6b941d2022-05-31 21:29:09 +0800125
126 if (val < 0 || val > 1)
127 return -EINVAL;
128
Jack Wu961f12a2022-09-01 22:14:27 +0800129 ret = google_dock_set_pogo_vout(dock, val);
130 if (ret)
131 dev_err(dock->device, "Failed to set pogo vout: %d\n", ret);
Jack Wuc6b941d2022-05-31 21:29:09 +0800132
133 return 0;
134}
135
136DEFINE_SIMPLE_ATTRIBUTE(debug_pogo_vout_fops, NULL,
137 debug_pogo_vout_write, "%llu\n");
138
Jack Wue872f582022-01-13 16:38:17 +0800139static int dock_init_fs(struct dock_drv *dock)
140{
141 int ret;
142
143 /* is_dock */
144 ret = device_create_file(&dock->psy->dev, &dev_attr_is_dock);
145 if (ret)
146 dev_err(&dock->psy->dev, "Failed to create is_dock\n");
147
148 return ret;
149}
Jack Wuc6b941d2022-05-31 21:29:09 +0800150
151static int dock_init_debugfs(struct dock_drv *dock)
152{
153 struct dentry *de = NULL;
154
155 de = debugfs_create_dir("google_dock", 0);
156 if (IS_ERR_OR_NULL(de))
157 return 0;
158
159 /* pogo_vout */
160 debugfs_create_file("pogo_vout", 0600, de, dock,
161 &debug_pogo_vout_fops);
162
163 return 0;
164}
Jack Wue872f582022-01-13 16:38:17 +0800165/* ------------------------------------------------------------------------- */
166
Jack Wuf1f6be22021-07-01 21:50:38 +0800167static int dock_has_dc_in(struct dock_drv *dock)
168{
169 union power_supply_propval prop;
170 int ret;
171
172 if (!dock->dc_psy) {
173 dock->dc_psy = power_supply_get_by_name("dc");
174 if (!dock->dc_psy)
175 return -EINVAL;
176 }
177
178 ret = power_supply_get_property(dock->dc_psy,
179 POWER_SUPPLY_PROP_PRESENT, &prop);
180 if (ret < 0) {
181 dev_err(dock->device, "Error getting charging status: %d\n", ret);
182 return -EINVAL;
183 }
184
185 return prop.intval != 0;
186}
187
188static bool google_dock_find_votable(struct dock_drv *dock)
189{
190 if (!dock->dc_icl_votable) {
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800191 dock->dc_icl_votable = gvotable_election_get_handle("DC_ICL");
Jack Wuf1f6be22021-07-01 21:50:38 +0800192 if (!dock->dc_icl_votable) {
193 dev_err(dock->device, "Could not get votable: DC_ICL\n");
194 return false;
195 }
196 }
197
198 return true;
199}
200
201static void google_dock_set_icl(struct dock_drv *dock)
202{
203 int icl;
204
205 if (!google_dock_find_votable(dock))
206 return;
207
208 /* Default ICL */
209 icl = DOCK_ICL_DEFAULT_UA;
210
211 if (dock->icl_ramp)
212 icl = dock->icl_ramp_ua;
213
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800214 gvotable_cast_int_vote(dock->dc_icl_votable,
215 DOCK_AICL_VOTER, icl, true);
Jack Wuf1f6be22021-07-01 21:50:38 +0800216
217 dev_info(dock->device, "Setting ICL %duA ramp=%d\n", icl, dock->icl_ramp);
218}
219
220static void google_dock_vote_defaults(struct dock_drv *dock)
221{
222 if (!google_dock_find_votable(dock))
223 return;
224
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800225 gvotable_cast_int_vote(dock->dc_icl_votable, DOCK_AICL_VOTER, 0, false);
Jack Wuf1f6be22021-07-01 21:50:38 +0800226}
227
Jack Wue8d14732021-08-23 18:06:50 +0800228static enum alarmtimer_restart google_dock_icl_ramp_alarm_cb(struct alarm
229 *alarm,
230 ktime_t now)
Jack Wuf1f6be22021-07-01 21:50:38 +0800231{
Jack Wue8d14732021-08-23 18:06:50 +0800232 struct dock_drv *dock = container_of(alarm, struct dock_drv,
233 icl_ramp_alarm);
Jack Wuf1f6be22021-07-01 21:50:38 +0800234
235 /* Alarm is in atomic context, schedule work to complete the task */
236 schedule_delayed_work(&dock->icl_ramp_work, msecs_to_jiffies(100));
237
238 return ALARMTIMER_NORESTART;
239}
240
241static void google_dock_icl_ramp_work(struct work_struct *work)
242{
243 struct dock_drv *dock = container_of(work, struct dock_drv,
Jack Wue8d14732021-08-23 18:06:50 +0800244 icl_ramp_work.work);
245 int online, voltage;
246
247 online = GPSY_GET_PROP(dock->dc_psy, POWER_SUPPLY_PROP_ONLINE);
Jack Wuf1f6be22021-07-01 21:50:38 +0800248 voltage = GPSY_GET_PROP(dock->dc_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
Jack Wu7703c2f2021-08-24 10:17:34 +0800249 if (voltage > DOCK_13_5W_VOUT_UV)
Jack Wuf1f6be22021-07-01 21:50:38 +0800250 dock->icl_ramp_ua = DOCK_15W_ILIM_UA;
251 else
252 dock->icl_ramp_ua = DOCK_13_5W_ILIM_UA;
253
Jack Wuf52f0852021-12-30 10:55:07 +0800254 if (online)
255 dock->icl_ramp = true;
Jack Wuf1f6be22021-07-01 21:50:38 +0800256
257 dev_info(dock->device, "ICL ramp work, ramp=%d icl=%d\n",
258 dock->icl_ramp, dock->icl_ramp_ua);
259
260 google_dock_set_icl(dock);
Jack Wue8d14732021-08-23 18:06:50 +0800261
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800262 dev_info(dock->device, "%s: online: %d->%d\n",
263 __func__, dock->online, online);
Jack Wue8d14732021-08-23 18:06:50 +0800264 dock->online = online;
Jack Wuf1f6be22021-07-01 21:50:38 +0800265}
266
267static void google_dock_icl_ramp_reset(struct dock_drv *dock)
268{
Jack Wu9b704782022-01-05 17:41:30 +0800269 dev_info(dock->device, "ICL ramp reset\n");
Jack Wuf1f6be22021-07-01 21:50:38 +0800270
271 dock->icl_ramp = false;
272
273 if (alarm_try_to_cancel(&dock->icl_ramp_alarm) < 0)
274 dev_warn(dock->device, "Couldn't cancel icl_ramp_alarm\n");
275 cancel_delayed_work(&dock->icl_ramp_work);
276}
277
278static void google_dock_icl_ramp_start(struct dock_drv *dock)
279{
Jack Wu9b704782022-01-05 17:41:30 +0800280 dev_info(dock->device, "ICL ramp set alarm %dms\n", dock->icl_ramp_delay_ms);
Jack Wuf1f6be22021-07-01 21:50:38 +0800281 alarm_start_relative(&dock->icl_ramp_alarm,
282 ms_to_ktime(dock->icl_ramp_delay_ms));
283}
284
Jack Wuf1f6be22021-07-01 21:50:38 +0800285static void google_dock_notifier_check_dc(struct dock_drv *dock)
286{
287 int dc_in;
288
289 dock->check_dc = false;
290
291 dc_in = dock_has_dc_in(dock);
292 if (dc_in < 0)
293 return;
294
295 dev_info(dock->device, "dc status is %d\n", dc_in);
296
297 if (dc_in) {
298 google_dock_set_icl(dock);
Jack Wu9b704782022-01-05 17:41:30 +0800299 google_dock_icl_ramp_reset(dock);
Jack Wuf1f6be22021-07-01 21:50:38 +0800300 google_dock_icl_ramp_start(dock);
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000301 dock->voltage_max = -1; /* Dock detection started, but not done */
302 schedule_delayed_work(&dock->detect_work,
303 msecs_to_jiffies(EXT_DETECT_DELAY_MS));
Jack Wuf1f6be22021-07-01 21:50:38 +0800304 } else {
305 google_dock_vote_defaults(dock);
306 google_dock_icl_ramp_reset(dock);
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000307 dock->voltage_max = 0;
Jack Wu9b704782022-01-05 17:41:30 +0800308
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800309 dev_info(dock->device, "%s: online: %d->0\n",
310 __func__, dock->online);
Jack Wu9b704782022-01-05 17:41:30 +0800311 dock->online = 0;
Jack Wuf1f6be22021-07-01 21:50:38 +0800312 }
313
314 power_supply_changed(dock->psy);
315}
316
317static void google_dock_notifier_work(struct work_struct *work)
318{
319 struct dock_drv *dock = container_of(work, struct dock_drv,
Jack Wue8d14732021-08-23 18:06:50 +0800320 notifier_work.work);
Jack Wuf1f6be22021-07-01 21:50:38 +0800321
322 dev_info(dock->device, "notifier_work\n");
323
324 if (dock->check_dc)
325 google_dock_notifier_check_dc(dock);
326}
327
Jack Wue8d14732021-08-23 18:06:50 +0800328static int google_dock_notifier_cb(struct notifier_block *nb,
329 unsigned long event, void *data)
330{
331 struct power_supply *psy = data;
332 struct dock_drv *dock = container_of(nb, struct dock_drv, nb);
333
334 if (event != PSY_EVENT_PROP_CHANGED)
335 goto out;
336
Jack Wu9b704782022-01-05 17:41:30 +0800337 if (dock->dc_psy_name && !strcmp(psy->desc->name, dock->dc_psy_name))
Jack Wue8d14732021-08-23 18:06:50 +0800338 dock->check_dc = true;
339
340 if (!dock->check_dc)
341 goto out;
342
343 schedule_delayed_work(&dock->notifier_work,
344 msecs_to_jiffies(DOCK_NOTIFIER_DELAY_MS));
345
346out:
347 return NOTIFY_OK;
348}
349
Jack Wub77d7182021-09-01 15:20:30 +0800350static int google_dock_parse_dt(struct device *dev,
Jack Wuc6b941d2022-05-31 21:29:09 +0800351 struct dock_drv *dock)
Jack Wub77d7182021-09-01 15:20:30 +0800352{
353 int ret = 0;
354 struct device_node *node = dev->of_node;
355
356 /* POGO_OVP_EN */
357 ret = of_get_named_gpio(node, "google,pogo_ovp_en", 0);
358 dock->pogo_ovp_en = ret;
359 if (ret < 0)
360 dev_warn(dev, "unable to read google,pogo_ovp_en from dt: %d\n",
361 ret);
362 else
363 dev_info(dev, "POGO_OVP_EN gpio:%d", dock->pogo_ovp_en);
364
365 return 0;
366}
367
Jack Wuf1f6be22021-07-01 21:50:38 +0800368static enum power_supply_property dock_props[] = {
369 POWER_SUPPLY_PROP_PRESENT,
370 POWER_SUPPLY_PROP_ONLINE,
371 POWER_SUPPLY_PROP_VOLTAGE_NOW,
372 POWER_SUPPLY_PROP_CURRENT_MAX,
373 POWER_SUPPLY_PROP_CURRENT_NOW,
374 POWER_SUPPLY_PROP_VOLTAGE_MAX,
375};
376
377static int dock_get_property(struct power_supply *psy,
Jack Wue8d14732021-08-23 18:06:50 +0800378 enum power_supply_property psp,
379 union power_supply_propval *val)
Jack Wuf1f6be22021-07-01 21:50:38 +0800380{
381 struct dock_drv *dock = (struct dock_drv *)
382 power_supply_get_drvdata(psy);
383 int ret = 0;
384
385 if (!dock->init_complete)
386 return -EAGAIN;
387
388 if (!dock->dc_psy && dock->dc_psy_name)
389 dock->dc_psy = power_supply_get_by_name(dock->dc_psy_name);
390
391 switch (psp) {
392 case POWER_SUPPLY_PROP_PRESENT:
393 val->intval = dock_has_dc_in(dock);
394 if (val->intval < 0)
395 val->intval = 0;
396 break;
397
398 case POWER_SUPPLY_PROP_CURRENT_MAX:
399 if (!dock->dc_icl_votable)
400 return -EAGAIN;
401
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800402 ret = gvotable_get_current_int_vote(dock->dc_icl_votable);
Jack Wuf1f6be22021-07-01 21:50:38 +0800403 if (ret < 0)
404 break;
405
406 val->intval = ret;
407
408 /* success */
409 ret = 0;
410 break;
411
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000412 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
413 val->intval = dock->voltage_max;
414 break;
415
Jack Wuf1f6be22021-07-01 21:50:38 +0800416 default:
417 ret = power_supply_get_property(dock->dc_psy, psp, val);
418 break;
419 }
420
421 if (ret)
422 dev_dbg(dock->device, "Couldn't get prop %d, ret=%d\n", psp, ret);
423
424 return 0;
425}
426
427static int dock_set_property(struct power_supply *psy,
Jack Wue8d14732021-08-23 18:06:50 +0800428 enum power_supply_property psp,
429 const union power_supply_propval *val)
Jack Wuf1f6be22021-07-01 21:50:38 +0800430{
431 struct dock_drv *dock = (struct dock_drv *)
432 power_supply_get_drvdata(psy);
433 bool changed = false;
434 int ret = 0;
435
436 if (!dock->init_complete)
437 return -EAGAIN;
438
439 switch (psp) {
440 case POWER_SUPPLY_PROP_CURRENT_MAX:
441 if (val->intval < 0) {
442 ret = -EINVAL;
443 break;
444 }
445
446 if (!dock->dc_icl_votable) {
447 ret = -EAGAIN;
448 break;
449 }
450
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800451 ret = gvotable_cast_int_vote(dock->dc_icl_votable,
452 DOCK_USER_VOTER,
453 val->intval, true);
Jack Wuf1f6be22021-07-01 21:50:38 +0800454 changed = true;
455 break;
456 default:
457 return -EINVAL;
458 }
459
460 if (ret)
461 dev_dbg(dock->device, "Couldn't set prop %d, ret=%d\n", psp, ret);
462
463 if (changed)
464 power_supply_changed(psy);
465
466 return 0;
467}
468
469static int dock_property_is_writeable(struct power_supply *psy,
Jack Wue8d14732021-08-23 18:06:50 +0800470 enum power_supply_property psp)
Jack Wuf1f6be22021-07-01 21:50:38 +0800471{
472 switch (psp) {
473 case POWER_SUPPLY_PROP_CURRENT_MAX:
474 return 1;
475 default:
476 break;
477 }
478
479 return 0;
480}
481
482static struct power_supply_desc dock_psy_desc = {
483 .name = "dock",
484 .type = POWER_SUPPLY_TYPE_BATTERY,
485 .get_property = dock_get_property,
486 .set_property = dock_set_property,
487 .property_is_writeable = dock_property_is_writeable,
488 .properties = dock_props,
489 .num_properties = ARRAY_SIZE(dock_props),
490};
491
492/* ------------------------------------------------------------------------ */
493
494static void google_dock_init_work(struct work_struct *work)
495{
496 struct dock_drv *dock = container_of(work, struct dock_drv,
Jack Wue8d14732021-08-23 18:06:50 +0800497 init_work.work);
Jack Wuf1f6be22021-07-01 21:50:38 +0800498 struct power_supply *dc_psy = dock->dc_psy;
499 union power_supply_propval val;
500 int err = 0;
501
502 if (!dock->dc_psy && dock->dc_psy_name) {
503 dc_psy = power_supply_get_by_name(dock->dc_psy_name);
504 if (!dc_psy) {
505 dev_info(dock->device,
Jack Wue8d14732021-08-23 18:06:50 +0800506 "failed to get \"%s\" power supply, retrying...\n",
507 dock->dc_psy_name);
Jack Wuf1f6be22021-07-01 21:50:38 +0800508 goto retry_init_work;
509 }
510 dock->dc_psy = dc_psy;
511
512 /* FIXME */
513 err = power_supply_get_property(dc_psy,
Jack Wue8d14732021-08-23 18:06:50 +0800514 POWER_SUPPLY_PROP_PRESENT,
515 &val);
Jack Wuf1f6be22021-07-01 21:50:38 +0800516 if (err == -EAGAIN)
517 goto retry_init_work;
518 }
519
Jack Wue872f582022-01-13 16:38:17 +0800520 (void)dock_init_fs(dock);
Jack Wuc6b941d2022-05-31 21:29:09 +0800521 (void)dock_init_debugfs(dock);
Jack Wue872f582022-01-13 16:38:17 +0800522
Jack Wuf1f6be22021-07-01 21:50:38 +0800523 dock->init_complete = true;
524 dev_info(dock->device, "google_dock_init_work done\n");
525
526 return;
527
528retry_init_work:
529 schedule_delayed_work(&dock->init_work,
530 msecs_to_jiffies(DOCK_DELAY_INIT_MS));
531}
532
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000533static void google_dock_detect_work(struct work_struct *work)
534{
535 struct dock_drv *dock = container_of(work, struct dock_drv,
536 detect_work.work);
537 union power_supply_propval val;
538 int err = 0;
539
540 if (!dock->dc_psy)
541 return;
542
543 __pm_stay_awake(dock->detect_ws);
544 err = power_supply_get_property(dock->dc_psy, POWER_SUPPLY_PROP_PRESENT, &val);
545 if (err < 0 || val.intval == 0) {
546 if (err < 0)
547 dev_dbg(dock->device, "Error getting charging status: %d\n", err);
548 else
549 dev_dbg(dock->device, "dc_psy not present. Retrying detection\n");
550 goto dock_detect_retry;
551 }
552
553 err = power_supply_get_property(dock->dc_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
554 if (err) {
555 if (err != -EAGAIN)
556 dev_dbg(dock->device, "failed to read dc supply voltage err: %d\n", err);
557
558 goto dock_detect_retry;
559 }
560
561 dev_info(dock->device, "dc_psy v=%d, retries=%d\n", val.intval, dock->detect_retries);
562
563 dock->voltage_max = val.intval;
564 dock->detect_retries = EXT_DETECT_RETRIES;
565 __pm_relax(dock->detect_ws);
566 power_supply_changed(dock->psy);
567 return;
568
569dock_detect_retry:
570 if (dock->detect_retries) {
571 dock->detect_retries--;
572 schedule_delayed_work(&dock->detect_work, msecs_to_jiffies(EXT_DETECT_DELAY_MS));
573 } else {
574 dock->detect_retries = EXT_DETECT_RETRIES;
575 __pm_relax(dock->detect_ws);
576 }
577}
578
Jack Wuf1f6be22021-07-01 21:50:38 +0800579static int google_dock_probe(struct platform_device *pdev)
580{
581 const char *dc_psy_name;
582 struct dock_drv *dock;
583 int ret;
584 struct power_supply_config psy_cfg = {};
585
586 dock = devm_kzalloc(&pdev->dev, sizeof(*dock), GFP_KERNEL);
587 if (!dock)
588 return -ENOMEM;
589
590 dock->device = &pdev->dev;
591
592 ret = of_property_read_string(pdev->dev.of_node, "google,dc-psy-name",
593 &dc_psy_name);
594 if (ret == 0) {
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800595 dev_info(dock->device, "google,dc-psy-name=%s\n", dc_psy_name);
Jack Wuf1f6be22021-07-01 21:50:38 +0800596 dock->dc_psy_name = devm_kstrdup(&pdev->dev,
597 dc_psy_name, GFP_KERNEL);
598 if (!dock->dc_psy_name) {
599 devm_kfree(&pdev->dev, dock);
600 return -ENOMEM;
601 }
602 }
603
Jack Wub77d7182021-09-01 15:20:30 +0800604 google_dock_parse_dt(dock->device, dock);
Jack Wuf1f6be22021-07-01 21:50:38 +0800605 mutex_init(&dock->dock_lock);
606 INIT_DELAYED_WORK(&dock->init_work, google_dock_init_work);
607 INIT_DELAYED_WORK(&dock->icl_ramp_work, google_dock_icl_ramp_work);
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000608 INIT_DELAYED_WORK(&dock->detect_work, google_dock_detect_work);
Jack Wuf1f6be22021-07-01 21:50:38 +0800609 alarm_init(&dock->icl_ramp_alarm, ALARM_BOOTTIME,
610 google_dock_icl_ramp_alarm_cb);
611
612 dock->icl_ramp_delay_ms = DOCK_ICL_RAMP_DELAY_DEFAULT_MS;
Jack Wue8d14732021-08-23 18:06:50 +0800613 dock->online = 0;
Jack Wuf1f6be22021-07-01 21:50:38 +0800614
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000615 dock->voltage_max = 0;
616 dock->detect_retries = EXT_DETECT_RETRIES;
617
618 dock->detect_ws = wakeup_source_register(NULL, "Detect");
619 if (!dock->detect_ws) {
620 dev_err(dock->device, "Failed to register dock detect wakeup source\n");
621 return -ENOMEM;
622 }
623
Jack Wuf1f6be22021-07-01 21:50:38 +0800624 platform_set_drvdata(pdev, dock);
625
626 psy_cfg.drv_data = dock;
627 psy_cfg.of_node = pdev->dev.of_node;
628
629 if (of_property_read_bool(pdev->dev.of_node, "google,psy-type-unknown"))
630 dock_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
631
632 dock->psy = devm_power_supply_register(dock->device,
633 &dock_psy_desc, &psy_cfg);
634 if (IS_ERR(dock->psy)) {
635 ret = PTR_ERR(dock->psy);
636 dev_err(dock->device, "Couldn't register as power supply, ret=%d\n", ret);
637 devm_kfree(&pdev->dev, dock);
638 return ret;
639 }
640
641 /*
642 * Find the DC_ICL votable
643 */
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800644 dock->dc_icl_votable = gvotable_election_get_handle("DC_ICL");
Jack Wuf1f6be22021-07-01 21:50:38 +0800645 if (!dock->dc_icl_votable)
646 dev_warn(dock->device, "Could not find DC_ICL votable\n");
647
648 /*
649 * Register notifier so we can detect changes on DC_IN
650 */
651 INIT_DELAYED_WORK(&dock->notifier_work, google_dock_notifier_work);
652 dock->nb.notifier_call = google_dock_notifier_cb;
653 ret = power_supply_reg_notifier(&dock->nb);
654 if (ret) {
655 dev_err(dock->device, "Fail to register notifier: %d\n", ret);
656 devm_kfree(&pdev->dev, dock);
657 return ret;
658 }
659
Jack Wub77d7182021-09-01 15:20:30 +0800660 if (dock->pogo_ovp_en >= 0)
661 gpio_direction_output(dock->pogo_ovp_en, 1);
662
Jack Wuf1f6be22021-07-01 21:50:38 +0800663 schedule_delayed_work(&dock->init_work,
Jack Wue8d14732021-08-23 18:06:50 +0800664 msecs_to_jiffies(DOCK_DELAY_INIT_MS));
Jack Wuf1f6be22021-07-01 21:50:38 +0800665
Ken Tsoua15d1fa2022-01-24 14:42:27 +0800666 dev_info(dock->device, "google_dock_probe done\n");
Jack Wuf1f6be22021-07-01 21:50:38 +0800667
668 return 0;
669}
670
671static int google_dock_remove(struct platform_device *pdev)
672{
673 struct dock_drv *dock = platform_get_drvdata(pdev);
674
675 cancel_delayed_work(&dock->init_work);
676 cancel_delayed_work(&dock->notifier_work);
677 cancel_delayed_work(&dock->icl_ramp_work);
678 alarm_try_to_cancel(&dock->icl_ramp_alarm);
Prasanna Prapanchamcce2a9b2022-07-08 22:46:01 +0000679 cancel_delayed_work(&dock->detect_work);
680 wakeup_source_unregister(dock->detect_ws);
Jack Wuf1f6be22021-07-01 21:50:38 +0800681
682 return 0;
683}
684
685static const struct of_device_id google_dock_of_match[] = {
686 {.compatible = "google,dock"},
687 {},
688};
689MODULE_DEVICE_TABLE(of, google_dock_of_match);
690
691static struct platform_driver google_dock_driver = {
692 .driver = {
693 .name = "google,dock",
694 .owner = THIS_MODULE,
695 .of_match_table = google_dock_of_match,
696 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
697 },
698 .probe = google_dock_probe,
699 .remove = google_dock_remove,
700};
701
702module_platform_driver(google_dock_driver);
703
704MODULE_DESCRIPTION("Google Dock Driver");
705MODULE_AUTHOR("Jack Wu <wjack@google.com>");
706MODULE_LICENSE("GPL");