Skip to content

Commit 72159f9

Browse files
Shunqing Chenrkhuangtao
authored andcommitted
power: charger: add dc detect support for sy6982c
Change-Id: I4050eb8b8760a12a2a2df6ce3c38dc801e822b9f Signed-off-by: Shunqing Chen <csq@rock-chips.com>
1 parent f6fac8b commit 72159f9

1 file changed

Lines changed: 109 additions & 1 deletion

File tree

drivers/power/sy6982c_charger.c

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@
1515
*/
1616

1717
#include <linux/extcon.h>
18+
#include <linux/interrupt.h>
19+
#include <linux/irq.h>
1820
#include <linux/kernel.h>
1921
#include <linux/module.h>
22+
#include <linux/of_gpio.h>
2023
#include <linux/platform_device.h>
2124
#include <linux/power_supply.h>
2225
#include <linux/power/rk_usbbc.h>
2326
#include <linux/property.h>
27+
#include <linux/rk_keys.h>
2428
#include <linux/workqueue.h>
2529

2630
enum charger_t {
@@ -29,20 +33,27 @@ enum charger_t {
2933
USB_TYPE_USB_CHARGER,
3034
USB_TYPE_AC_CHARGER,
3135
USB_TYPE_CDP_CHARGER,
36+
DC_TYPE_DC_CHARGER,
37+
DC_TYPE_NONE_CHARGER,
3238
};
3339

3440
struct sy6982c_charger {
3541
struct device *dev;
3642
struct power_supply *usb_psy;
3743
struct workqueue_struct *usb_charger_wq;
3844
struct delayed_work usb_work;
45+
struct workqueue_struct *dc_charger_wq;
46+
struct delayed_work dc_work;
3947
struct delayed_work discnt_work;
4048
struct notifier_block cable_cg_nb;
4149
struct notifier_block cable_discnt_nb;
4250
unsigned int bc_event;
4351
enum charger_t usb_charger;
52+
enum charger_t dc_charger;
4453
bool extcon;
4554
struct extcon_dev *cable_edev;
55+
struct gpio_desc *dc_det_pin;
56+
bool support_dc_det;
4657
};
4758

4859
static void sy6982c_cg_bc_evt_worker(struct work_struct *work)
@@ -190,6 +201,8 @@ static int sy6982c_cg_usb_get_property(struct power_supply *psy,
190201
if (cg->usb_charger != USB_TYPE_UNKNOWN_CHARGER &&
191202
cg->usb_charger != USB_TYPE_NONE_CHARGER)
192203
online = 1;
204+
if (cg->dc_charger != DC_TYPE_NONE_CHARGER)
205+
online = 1;
193206
switch (psp) {
194207
case POWER_SUPPLY_PROP_ONLINE:
195208
val->intval = online;
@@ -234,6 +247,97 @@ static int sy6982c_cg_init_power_supply(struct sy6982c_charger *cg)
234247
return 0;
235248
}
236249

250+
#ifdef CONFIG_OF
251+
static int sy6982c_charger_parse_dt(struct sy6982c_charger *cg)
252+
{
253+
struct device *dev = cg->dev;
254+
255+
cg->dc_det_pin = devm_gpiod_get_optional(dev, "dc-det",
256+
GPIOD_IN);
257+
if (!IS_ERR_OR_NULL(cg->dc_det_pin)) {
258+
cg->support_dc_det = true;
259+
} else {
260+
dev_err(dev, "invalid dc det gpio!\n");
261+
cg->support_dc_det = false;
262+
}
263+
264+
return 0;
265+
}
266+
#else
267+
static int sy6982c_charger_parse_dt(struct sy6982c_charger *cg)
268+
{
269+
return -ENODEV;
270+
}
271+
#endif
272+
273+
static enum charger_t sy6982c_charger_get_dc_state(struct sy6982c_charger *cg)
274+
{
275+
return (gpiod_get_value(cg->dc_det_pin)) ?
276+
DC_TYPE_DC_CHARGER : DC_TYPE_NONE_CHARGER;
277+
}
278+
279+
static void sy6982c_charger_dc_det_worker(struct work_struct *work)
280+
{
281+
enum charger_t charger;
282+
struct sy6982c_charger *cg = container_of(work,
283+
struct sy6982c_charger, dc_work.work);
284+
285+
charger = sy6982c_charger_get_dc_state(cg);
286+
if (charger == DC_TYPE_DC_CHARGER)
287+
cg->dc_charger = charger;
288+
else
289+
cg->dc_charger = DC_TYPE_NONE_CHARGER;
290+
291+
rk_send_wakeup_key();
292+
}
293+
294+
static irqreturn_t sy6982c_charger_dc_det_isr(int irq, void *charger)
295+
{
296+
struct sy6982c_charger *cg = (struct sy6982c_charger *)charger;
297+
298+
queue_delayed_work(cg->dc_charger_wq, &cg->dc_work,
299+
msecs_to_jiffies(10));
300+
301+
return IRQ_HANDLED;
302+
}
303+
304+
static int sy6982c_charger_init_dc(struct sy6982c_charger *cg)
305+
{
306+
int ret;
307+
unsigned long irq_flags;
308+
unsigned int dc_det_irq;
309+
310+
if (!cg->support_dc_det)
311+
return 0;
312+
313+
cg->dc_charger_wq = alloc_ordered_workqueue("%s",
314+
WQ_MEM_RECLAIM | WQ_FREEZABLE,
315+
"sy6982c-dc-wq");
316+
if (!cg->dc_charger_wq)
317+
return -EINVAL;
318+
319+
INIT_DELAYED_WORK(&cg->dc_work, sy6982c_charger_dc_det_worker);
320+
cg->dc_charger = DC_TYPE_NONE_CHARGER;
321+
322+
if (gpiod_get_value(cg->dc_det_pin))
323+
cg->dc_charger = DC_TYPE_DC_CHARGER;
324+
else
325+
cg->dc_charger = DC_TYPE_NONE_CHARGER;
326+
327+
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
328+
dc_det_irq = gpiod_to_irq(cg->dc_det_pin);
329+
ret = devm_request_irq(cg->dev, dc_det_irq, sy6982c_charger_dc_det_isr,
330+
irq_flags, "sy6982c_dc_det", cg);
331+
if (ret != 0) {
332+
dev_err(cg->dev, "sy6982c_dc_det_irq request failed!\n");
333+
return ret;
334+
}
335+
336+
enable_irq_wake(dc_det_irq);
337+
338+
return 0;
339+
}
340+
237341
static int sy6982c_charger_probe(struct platform_device *pdev)
238342
{
239343
struct sy6982c_charger *cg;
@@ -244,6 +348,8 @@ static int sy6982c_charger_probe(struct platform_device *pdev)
244348
return -ENOMEM;
245349

246350
cg->dev = &pdev->dev;
351+
sy6982c_charger_parse_dt(cg);
352+
sy6982c_charger_init_dc(cg);
247353
cg->extcon = device_property_read_bool(cg->dev, "extcon");
248354
ret = sy6982c_cg_init_usb(cg);
249355
if (ret) {
@@ -262,12 +368,14 @@ static int sy6982c_charger_probe(struct platform_device *pdev)
262368
return 0;
263369
}
264370

265-
static void sy6982c_charger_remove(struct platform_device *pdev)
371+
static int sy6982c_charger_remove(struct platform_device *pdev)
266372
{
267373
struct sy6982c_charger *cg = platform_get_drvdata(pdev);
268374

269375
if (cg->usb_charger_wq)
270376
destroy_workqueue(cg->usb_charger_wq);
377+
378+
return 0;
271379
}
272380

273381
static const struct of_device_id sy6982c_charger_match[] = {

0 commit comments

Comments
 (0)