drivers: media: arducam_64mp: Add V4L2_CID_LINK_FREQ control
[platform/kernel/linux-rpi.git] / drivers / extcon / extcon-axp288.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
4  *
5  * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
6  * Copyright (C) 2015 Intel Corporation
7  * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
8  */
9
10 #include <linux/acpi.h>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/io.h>
14 #include <linux/slab.h>
15 #include <linux/interrupt.h>
16 #include <linux/platform_device.h>
17 #include <linux/property.h>
18 #include <linux/notifier.h>
19 #include <linux/extcon-provider.h>
20 #include <linux/regmap.h>
21 #include <linux/mfd/axp20x.h>
22 #include <linux/usb/role.h>
23 #include <linux/workqueue.h>
24
25 #include <asm/cpu_device_id.h>
26 #include <asm/intel-family.h>
27 #include <asm/iosf_mbi.h>
28
29 /* Power source status register */
30 #define PS_STAT_VBUS_TRIGGER            BIT(0)
31 #define PS_STAT_BAT_CHRG_DIR            BIT(2)
32 #define PS_STAT_VBUS_ABOVE_VHOLD        BIT(3)
33 #define PS_STAT_VBUS_VALID              BIT(4)
34 #define PS_STAT_VBUS_PRESENT            BIT(5)
35
36 /* BC module global register */
37 #define BC_GLOBAL_RUN                   BIT(0)
38 #define BC_GLOBAL_DET_STAT              BIT(2)
39 #define BC_GLOBAL_DBP_TOUT              BIT(3)
40 #define BC_GLOBAL_VLGC_COM_SEL          BIT(4)
41 #define BC_GLOBAL_DCD_TOUT_MASK         (BIT(6)|BIT(5))
42 #define BC_GLOBAL_DCD_TOUT_300MS        0
43 #define BC_GLOBAL_DCD_TOUT_100MS        1
44 #define BC_GLOBAL_DCD_TOUT_500MS        2
45 #define BC_GLOBAL_DCD_TOUT_900MS        3
46 #define BC_GLOBAL_DCD_DET_SEL           BIT(7)
47
48 /* BC module vbus control and status register */
49 #define VBUS_CNTL_DPDM_PD_EN            BIT(4)
50 #define VBUS_CNTL_DPDM_FD_EN            BIT(5)
51 #define VBUS_CNTL_FIRST_PO_STAT         BIT(6)
52
53 /* BC USB status register */
54 #define USB_STAT_BUS_STAT_MASK          (BIT(3)|BIT(2)|BIT(1)|BIT(0))
55 #define USB_STAT_BUS_STAT_SHIFT         0
56 #define USB_STAT_BUS_STAT_ATHD          0
57 #define USB_STAT_BUS_STAT_CONN          1
58 #define USB_STAT_BUS_STAT_SUSP          2
59 #define USB_STAT_BUS_STAT_CONF          3
60 #define USB_STAT_USB_SS_MODE            BIT(4)
61 #define USB_STAT_DEAD_BAT_DET           BIT(6)
62 #define USB_STAT_DBP_UNCFG              BIT(7)
63
64 /* BC detect status register */
65 #define DET_STAT_MASK                   (BIT(7)|BIT(6)|BIT(5))
66 #define DET_STAT_SHIFT                  5
67 #define DET_STAT_SDP                    1
68 #define DET_STAT_CDP                    2
69 #define DET_STAT_DCP                    3
70
71 enum axp288_extcon_reg {
72         AXP288_PS_STAT_REG              = 0x00,
73         AXP288_PS_BOOT_REASON_REG       = 0x02,
74         AXP288_BC_GLOBAL_REG            = 0x2c,
75         AXP288_BC_VBUS_CNTL_REG         = 0x2d,
76         AXP288_BC_USB_STAT_REG          = 0x2e,
77         AXP288_BC_DET_STAT_REG          = 0x2f,
78 };
79
80 enum axp288_extcon_irq {
81         VBUS_FALLING_IRQ = 0,
82         VBUS_RISING_IRQ,
83         MV_CHNG_IRQ,
84         BC_USB_CHNG_IRQ,
85         EXTCON_IRQ_END,
86 };
87
88 static const unsigned int axp288_extcon_cables[] = {
89         EXTCON_CHG_USB_SDP,
90         EXTCON_CHG_USB_CDP,
91         EXTCON_CHG_USB_DCP,
92         EXTCON_USB,
93         EXTCON_NONE,
94 };
95
96 struct axp288_extcon_info {
97         struct device *dev;
98         struct regmap *regmap;
99         struct regmap_irq_chip_data *regmap_irqc;
100         struct usb_role_switch *role_sw;
101         struct work_struct role_work;
102         int irq[EXTCON_IRQ_END];
103         struct extcon_dev *edev;
104         struct extcon_dev *id_extcon;
105         struct notifier_block id_nb;
106         unsigned int previous_cable;
107         bool vbus_attach;
108 };
109
110 static const struct x86_cpu_id cherry_trail_cpu_ids[] = {
111         X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        NULL),
112         {}
113 };
114
115 /* Power up/down reason string array */
116 static const char * const axp288_pwr_up_down_info[] = {
117         "Last wake caused by user pressing the power button",
118         "Last wake caused by a charger insertion",
119         "Last wake caused by a battery insertion",
120         "Last wake caused by SOC initiated global reset",
121         "Last wake caused by cold reset",
122         "Last shutdown caused by PMIC UVLO threshold",
123         "Last shutdown caused by SOC initiated cold off",
124         "Last shutdown caused by user pressing the power button",
125 };
126
127 /*
128  * Decode and log the given "reset source indicator" (rsi)
129  * register and then clear it.
130  */
131 static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
132 {
133         unsigned int val, i, clear_mask = 0;
134         unsigned long bits;
135         int ret;
136
137         ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val);
138         if (ret < 0) {
139                 dev_err(info->dev, "failed to read reset source indicator\n");
140                 return;
141         }
142
143         bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0);
144         for_each_set_bit(i, &bits, ARRAY_SIZE(axp288_pwr_up_down_info))
145                 dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]);
146         clear_mask = bits;
147
148         /* Clear the register value for next reboot (write 1 to clear bit) */
149         regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
150 }
151
152 /*
153  * The below code to control the USB role-switch on devices with an AXP288
154  * may seem out of place, but there are 2 reasons why this is the best place
155  * to control the USB role-switch on such devices:
156  * 1) On many devices the USB role is controlled by AML code, but the AML code
157  *    only switches between the host and none roles, because of Windows not
158  *    really using device mode. To make device mode work we need to toggle
159  *    between the none/device roles based on Vbus presence, and this driver
160  *    gets interrupts on Vbus insertion / removal.
161  * 2) In order for our BC1.2 charger detection to work properly the role
162  *    mux must be properly set to device mode before we do the detection.
163  */
164
165 /* Returns the id-pin value, note pulled low / false == host-mode */
166 static bool axp288_get_id_pin(struct axp288_extcon_info *info)
167 {
168         enum usb_role role;
169
170         if (info->id_extcon)
171                 return extcon_get_state(info->id_extcon, EXTCON_USB_HOST) <= 0;
172
173         /* We cannot access the id-pin, see what mode the AML code has set */
174         role = usb_role_switch_get_role(info->role_sw);
175         return role != USB_ROLE_HOST;
176 }
177
178 static void axp288_usb_role_work(struct work_struct *work)
179 {
180         struct axp288_extcon_info *info =
181                 container_of(work, struct axp288_extcon_info, role_work);
182         enum usb_role role;
183         bool id_pin;
184         int ret;
185
186         id_pin = axp288_get_id_pin(info);
187         if (!id_pin)
188                 role = USB_ROLE_HOST;
189         else if (info->vbus_attach)
190                 role = USB_ROLE_DEVICE;
191         else
192                 role = USB_ROLE_NONE;
193
194         ret = usb_role_switch_set_role(info->role_sw, role);
195         if (ret)
196                 dev_err(info->dev, "failed to set role: %d\n", ret);
197 }
198
199 static bool axp288_get_vbus_attach(struct axp288_extcon_info *info)
200 {
201         int ret, pwr_stat;
202
203         ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
204         if (ret < 0) {
205                 dev_err(info->dev, "failed to read vbus status\n");
206                 return false;
207         }
208
209         return !!(pwr_stat & PS_STAT_VBUS_VALID);
210 }
211
212 static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
213 {
214         int ret, stat, cfg;
215         u8 chrg_type;
216         unsigned int cable = info->previous_cable;
217         bool vbus_attach = false;
218
219         ret = iosf_mbi_block_punit_i2c_access();
220         if (ret < 0)
221                 return ret;
222
223         vbus_attach = axp288_get_vbus_attach(info);
224         if (!vbus_attach)
225                 goto no_vbus;
226
227         /* Check charger detection completion status */
228         ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
229         if (ret < 0)
230                 goto dev_det_ret;
231         if (cfg & BC_GLOBAL_DET_STAT) {
232                 dev_dbg(info->dev, "can't complete the charger detection\n");
233                 goto dev_det_ret;
234         }
235
236         ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat);
237         if (ret < 0)
238                 goto dev_det_ret;
239
240         chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT;
241
242         switch (chrg_type) {
243         case DET_STAT_SDP:
244                 dev_dbg(info->dev, "sdp cable is connected\n");
245                 cable = EXTCON_CHG_USB_SDP;
246                 break;
247         case DET_STAT_CDP:
248                 dev_dbg(info->dev, "cdp cable is connected\n");
249                 cable = EXTCON_CHG_USB_CDP;
250                 break;
251         case DET_STAT_DCP:
252                 dev_dbg(info->dev, "dcp cable is connected\n");
253                 cable = EXTCON_CHG_USB_DCP;
254                 break;
255         default:
256                 dev_warn(info->dev, "unknown (reserved) bc detect result\n");
257                 cable = EXTCON_CHG_USB_SDP;
258         }
259
260 no_vbus:
261         iosf_mbi_unblock_punit_i2c_access();
262
263         extcon_set_state_sync(info->edev, info->previous_cable, false);
264         if (info->previous_cable == EXTCON_CHG_USB_SDP)
265                 extcon_set_state_sync(info->edev, EXTCON_USB, false);
266
267         if (vbus_attach) {
268                 extcon_set_state_sync(info->edev, cable, vbus_attach);
269                 if (cable == EXTCON_CHG_USB_SDP)
270                         extcon_set_state_sync(info->edev, EXTCON_USB,
271                                                 vbus_attach);
272
273                 info->previous_cable = cable;
274         }
275
276         if (info->role_sw && info->vbus_attach != vbus_attach) {
277                 info->vbus_attach = vbus_attach;
278                 /* Setting the role can take a while */
279                 queue_work(system_long_wq, &info->role_work);
280         }
281
282         return 0;
283
284 dev_det_ret:
285         iosf_mbi_unblock_punit_i2c_access();
286
287         if (ret < 0)
288                 dev_err(info->dev, "failed to detect BC Mod\n");
289
290         return ret;
291 }
292
293 static int axp288_extcon_id_evt(struct notifier_block *nb,
294                                 unsigned long event, void *param)
295 {
296         struct axp288_extcon_info *info =
297                 container_of(nb, struct axp288_extcon_info, id_nb);
298
299         /* We may not sleep and setting the role can take a while */
300         queue_work(system_long_wq, &info->role_work);
301
302         return NOTIFY_OK;
303 }
304
305 static irqreturn_t axp288_extcon_isr(int irq, void *data)
306 {
307         struct axp288_extcon_info *info = data;
308         int ret;
309
310         ret = axp288_handle_chrg_det_event(info);
311         if (ret < 0)
312                 dev_err(info->dev, "failed to handle the interrupt\n");
313
314         return IRQ_HANDLED;
315 }
316
317 static int axp288_extcon_enable(struct axp288_extcon_info *info)
318 {
319         int ret = 0;
320
321         ret = iosf_mbi_block_punit_i2c_access();
322         if (ret < 0)
323                 return ret;
324
325         regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
326                                                 BC_GLOBAL_RUN, 0);
327         /* Enable the charger detection logic */
328         regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
329                                         BC_GLOBAL_RUN, BC_GLOBAL_RUN);
330
331         iosf_mbi_unblock_punit_i2c_access();
332
333         return ret;
334 }
335
336 static void axp288_put_role_sw(void *data)
337 {
338         struct axp288_extcon_info *info = data;
339
340         cancel_work_sync(&info->role_work);
341         usb_role_switch_put(info->role_sw);
342 }
343
344 static int axp288_extcon_find_role_sw(struct axp288_extcon_info *info)
345 {
346         const struct software_node *swnode;
347         struct fwnode_handle *fwnode;
348
349         if (!x86_match_cpu(cherry_trail_cpu_ids))
350                 return 0;
351
352         swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
353         if (!swnode)
354                 return -EPROBE_DEFER;
355
356         fwnode = software_node_fwnode(swnode);
357         info->role_sw = usb_role_switch_find_by_fwnode(fwnode);
358         fwnode_handle_put(fwnode);
359
360         return info->role_sw ? 0 : -EPROBE_DEFER;
361 }
362
363 static int axp288_extcon_probe(struct platform_device *pdev)
364 {
365         struct axp288_extcon_info *info;
366         struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
367         struct device *dev = &pdev->dev;
368         struct acpi_device *adev;
369         int ret, i, pirq;
370
371         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
372         if (!info)
373                 return -ENOMEM;
374
375         info->dev = &pdev->dev;
376         info->regmap = axp20x->regmap;
377         info->regmap_irqc = axp20x->regmap_irqc;
378         info->previous_cable = EXTCON_NONE;
379         INIT_WORK(&info->role_work, axp288_usb_role_work);
380         info->id_nb.notifier_call = axp288_extcon_id_evt;
381
382         platform_set_drvdata(pdev, info);
383
384         ret = axp288_extcon_find_role_sw(info);
385         if (ret)
386                 return ret;
387
388         if (info->role_sw) {
389                 ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info);
390                 if (ret)
391                         return ret;
392
393                 adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1);
394                 if (adev) {
395                         info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
396                         acpi_dev_put(adev);
397                         if (IS_ERR(info->id_extcon))
398                                 return PTR_ERR(info->id_extcon);
399
400                         dev_info(dev, "controlling USB role\n");
401                 } else {
402                         dev_info(dev, "controlling USB role based on Vbus presence\n");
403                 }
404         }
405
406         ret = iosf_mbi_block_punit_i2c_access();
407         if (ret < 0)
408                 return ret;
409
410         info->vbus_attach = axp288_get_vbus_attach(info);
411
412         axp288_extcon_log_rsi(info);
413
414         iosf_mbi_unblock_punit_i2c_access();
415
416         /* Initialize extcon device */
417         info->edev = devm_extcon_dev_allocate(&pdev->dev,
418                                               axp288_extcon_cables);
419         if (IS_ERR(info->edev)) {
420                 dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
421                 return PTR_ERR(info->edev);
422         }
423
424         /* Register extcon device */
425         ret = devm_extcon_dev_register(&pdev->dev, info->edev);
426         if (ret) {
427                 dev_err(&pdev->dev, "failed to register extcon device\n");
428                 return ret;
429         }
430
431         for (i = 0; i < EXTCON_IRQ_END; i++) {
432                 pirq = platform_get_irq(pdev, i);
433                 if (pirq < 0)
434                         return pirq;
435
436                 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
437                 if (info->irq[i] < 0) {
438                         dev_err(&pdev->dev,
439                                 "failed to get virtual interrupt=%d\n", pirq);
440                         ret = info->irq[i];
441                         return ret;
442                 }
443
444                 ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
445                                 NULL, axp288_extcon_isr,
446                                 IRQF_ONESHOT | IRQF_NO_SUSPEND,
447                                 pdev->name, info);
448                 if (ret) {
449                         dev_err(&pdev->dev, "failed to request interrupt=%d\n",
450                                                         info->irq[i]);
451                         return ret;
452                 }
453         }
454
455         if (info->id_extcon) {
456                 ret = devm_extcon_register_notifier_all(dev, info->id_extcon,
457                                                         &info->id_nb);
458                 if (ret)
459                         return ret;
460         }
461
462         /* Make sure the role-sw is set correctly before doing BC detection */
463         if (info->role_sw) {
464                 queue_work(system_long_wq, &info->role_work);
465                 flush_work(&info->role_work);
466         }
467
468         /* Start charger cable type detection */
469         ret = axp288_extcon_enable(info);
470         if (ret < 0)
471                 return ret;
472
473         device_init_wakeup(dev, true);
474         platform_set_drvdata(pdev, info);
475
476         return 0;
477 }
478
479 static int __maybe_unused axp288_extcon_suspend(struct device *dev)
480 {
481         struct axp288_extcon_info *info = dev_get_drvdata(dev);
482
483         if (device_may_wakeup(dev))
484                 enable_irq_wake(info->irq[VBUS_RISING_IRQ]);
485
486         return 0;
487 }
488
489 static int __maybe_unused axp288_extcon_resume(struct device *dev)
490 {
491         struct axp288_extcon_info *info = dev_get_drvdata(dev);
492
493         /*
494          * Wakeup when a charger is connected to do charger-type
495          * connection and generate an extcon event which makes the
496          * axp288 charger driver set the input current limit.
497          */
498         if (device_may_wakeup(dev))
499                 disable_irq_wake(info->irq[VBUS_RISING_IRQ]);
500
501         return 0;
502 }
503
504 static SIMPLE_DEV_PM_OPS(axp288_extcon_pm_ops, axp288_extcon_suspend,
505                          axp288_extcon_resume);
506
507 static const struct platform_device_id axp288_extcon_table[] = {
508         { .name = "axp288_extcon" },
509         {},
510 };
511 MODULE_DEVICE_TABLE(platform, axp288_extcon_table);
512
513 static struct platform_driver axp288_extcon_driver = {
514         .probe = axp288_extcon_probe,
515         .id_table = axp288_extcon_table,
516         .driver = {
517                 .name = "axp288_extcon",
518                 .pm = &axp288_extcon_pm_ops,
519         },
520 };
521 module_platform_driver(axp288_extcon_driver);
522
523 MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
524 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
525 MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
526 MODULE_LICENSE("GPL v2");