extcon: Modify the device name as extcon[X] for sysfs
[firefly-linux-kernel-4.4.55.git] / drivers / extcon / extcon-axp288.c
1 /*
2  * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
3  *
4  * Copyright (C) 2015 Intel Corporation
5  * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/io.h>
20 #include <linux/slab.h>
21 #include <linux/interrupt.h>
22 #include <linux/platform_device.h>
23 #include <linux/property.h>
24 #include <linux/usb/phy.h>
25 #include <linux/notifier.h>
26 #include <linux/extcon.h>
27 #include <linux/regmap.h>
28 #include <linux/gpio.h>
29 #include <linux/gpio/consumer.h>
30 #include <linux/mfd/axp20x.h>
31
32 /* Power source status register */
33 #define PS_STAT_VBUS_TRIGGER            BIT(0)
34 #define PS_STAT_BAT_CHRG_DIR            BIT(2)
35 #define PS_STAT_VBUS_ABOVE_VHOLD        BIT(3)
36 #define PS_STAT_VBUS_VALID              BIT(4)
37 #define PS_STAT_VBUS_PRESENT            BIT(5)
38
39 /* BC module global register */
40 #define BC_GLOBAL_RUN                   BIT(0)
41 #define BC_GLOBAL_DET_STAT              BIT(2)
42 #define BC_GLOBAL_DBP_TOUT              BIT(3)
43 #define BC_GLOBAL_VLGC_COM_SEL          BIT(4)
44 #define BC_GLOBAL_DCD_TOUT_MASK         (BIT(6)|BIT(5))
45 #define BC_GLOBAL_DCD_TOUT_300MS        0
46 #define BC_GLOBAL_DCD_TOUT_100MS        1
47 #define BC_GLOBAL_DCD_TOUT_500MS        2
48 #define BC_GLOBAL_DCD_TOUT_900MS        3
49 #define BC_GLOBAL_DCD_DET_SEL           BIT(7)
50
51 /* BC module vbus control and status register */
52 #define VBUS_CNTL_DPDM_PD_EN            BIT(4)
53 #define VBUS_CNTL_DPDM_FD_EN            BIT(5)
54 #define VBUS_CNTL_FIRST_PO_STAT         BIT(6)
55
56 /* BC USB status register */
57 #define USB_STAT_BUS_STAT_MASK          (BIT(3)|BIT(2)|BIT(1)|BIT(0))
58 #define USB_STAT_BUS_STAT_SHIFT         0
59 #define USB_STAT_BUS_STAT_ATHD          0
60 #define USB_STAT_BUS_STAT_CONN          1
61 #define USB_STAT_BUS_STAT_SUSP          2
62 #define USB_STAT_BUS_STAT_CONF          3
63 #define USB_STAT_USB_SS_MODE            BIT(4)
64 #define USB_STAT_DEAD_BAT_DET           BIT(6)
65 #define USB_STAT_DBP_UNCFG              BIT(7)
66
67 /* BC detect status register */
68 #define DET_STAT_MASK                   (BIT(7)|BIT(6)|BIT(5))
69 #define DET_STAT_SHIFT                  5
70 #define DET_STAT_SDP                    1
71 #define DET_STAT_CDP                    2
72 #define DET_STAT_DCP                    3
73
74 /* IRQ enable-1 register */
75 #define PWRSRC_IRQ_CFG_MASK             (BIT(4)|BIT(3)|BIT(2))
76
77 /* IRQ enable-6 register */
78 #define BC12_IRQ_CFG_MASK               BIT(1)
79
80 #define AXP288_EXTCON_SLOW_CHARGER              "SLOW-CHARGER"
81 #define AXP288_EXTCON_DOWNSTREAM_CHARGER        "CHARGE-DOWNSTREAM"
82 #define AXP288_EXTCON_FAST_CHARGER              "FAST-CHARGER"
83
84 enum axp288_extcon_reg {
85         AXP288_PS_STAT_REG              = 0x00,
86         AXP288_PS_BOOT_REASON_REG       = 0x02,
87         AXP288_BC_GLOBAL_REG            = 0x2c,
88         AXP288_BC_VBUS_CNTL_REG         = 0x2d,
89         AXP288_BC_USB_STAT_REG          = 0x2e,
90         AXP288_BC_DET_STAT_REG          = 0x2f,
91         AXP288_PWRSRC_IRQ_CFG_REG       = 0x40,
92         AXP288_BC12_IRQ_CFG_REG         = 0x45,
93 };
94
95 enum axp288_mux_select {
96         EXTCON_GPIO_MUX_SEL_PMIC = 0,
97         EXTCON_GPIO_MUX_SEL_SOC,
98 };
99
100 enum axp288_extcon_irq {
101         VBUS_FALLING_IRQ = 0,
102         VBUS_RISING_IRQ,
103         MV_CHNG_IRQ,
104         BC_USB_CHNG_IRQ,
105         EXTCON_IRQ_END,
106 };
107
108 static const char *axp288_extcon_cables[] = {
109         AXP288_EXTCON_SLOW_CHARGER,
110         AXP288_EXTCON_DOWNSTREAM_CHARGER,
111         AXP288_EXTCON_FAST_CHARGER,
112         NULL,
113 };
114
115 struct axp288_extcon_info {
116         struct device *dev;
117         struct regmap *regmap;
118         struct regmap_irq_chip_data *regmap_irqc;
119         struct axp288_extcon_pdata *pdata;
120         int irq[EXTCON_IRQ_END];
121         struct extcon_dev *edev;
122         struct notifier_block extcon_nb;
123         struct usb_phy *otg;
124 };
125
126 /* Power up/down reason string array */
127 static char *axp288_pwr_up_down_info[] = {
128         "Last wake caused by user pressing the power button",
129         "Last wake caused by a charger insertion",
130         "Last wake caused by a battery insertion",
131         "Last wake caused by SOC initiated global reset",
132         "Last wake caused by cold reset",
133         "Last shutdown caused by PMIC UVLO threshold",
134         "Last shutdown caused by SOC initiated cold off",
135         "Last shutdown caused by user pressing the power button",
136         NULL,
137 };
138
139 /*
140  * Decode and log the given "reset source indicator" (rsi)
141  * register and then clear it.
142  */
143 static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
144 {
145         char **rsi;
146         unsigned int val, i, clear_mask = 0;
147         int ret;
148
149         ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val);
150         for (i = 0, rsi = axp288_pwr_up_down_info; *rsi; rsi++, i++) {
151                 if (val & BIT(i)) {
152                         dev_dbg(info->dev, "%s\n", *rsi);
153                         clear_mask |= BIT(i);
154                 }
155         }
156
157         /* Clear the register value for next reboot (write 1 to clear bit) */
158         regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
159 }
160
161 static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
162 {
163         static bool notify_otg, notify_charger;
164         static char *cable;
165         int ret, stat, cfg, pwr_stat;
166         u8 chrg_type;
167         bool vbus_attach = false;
168
169         ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
170         if (ret < 0) {
171                 dev_err(info->dev, "failed to read vbus status\n");
172                 return ret;
173         }
174
175         vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT);
176         if (!vbus_attach)
177                 goto notify_otg;
178
179         /* Check charger detection completion status */
180         ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
181         if (ret < 0)
182                 goto dev_det_ret;
183         if (cfg & BC_GLOBAL_DET_STAT) {
184                 dev_dbg(info->dev, "can't complete the charger detection\n");
185                 goto dev_det_ret;
186         }
187
188         ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat);
189         if (ret < 0)
190                 goto dev_det_ret;
191
192         chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT;
193
194         switch (chrg_type) {
195         case DET_STAT_SDP:
196                 dev_dbg(info->dev, "sdp cable is connecetd\n");
197                 notify_otg = true;
198                 notify_charger = true;
199                 cable = AXP288_EXTCON_SLOW_CHARGER;
200                 break;
201         case DET_STAT_CDP:
202                 dev_dbg(info->dev, "cdp cable is connecetd\n");
203                 notify_otg = true;
204                 notify_charger = true;
205                 cable = AXP288_EXTCON_DOWNSTREAM_CHARGER;
206                 break;
207         case DET_STAT_DCP:
208                 dev_dbg(info->dev, "dcp cable is connecetd\n");
209                 notify_charger = true;
210                 cable = AXP288_EXTCON_FAST_CHARGER;
211                 break;
212         default:
213                 dev_warn(info->dev,
214                         "disconnect or unknown or ID event\n");
215         }
216
217 notify_otg:
218         if (notify_otg) {
219                 /*
220                  * If VBUS is absent Connect D+/D- lines to PMIC for BC
221                  * detection. Else connect them to SOC for USB communication.
222                  */
223                 if (info->pdata->gpio_mux_cntl)
224                         gpiod_set_value(info->pdata->gpio_mux_cntl,
225                                 vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
226                                                 : EXTCON_GPIO_MUX_SEL_PMIC);
227
228                 atomic_notifier_call_chain(&info->otg->notifier,
229                         vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL);
230         }
231
232         if (notify_charger)
233                 extcon_set_cable_state(info->edev, cable, vbus_attach);
234
235         /* Clear the flags on disconnect event */
236         if (!vbus_attach)
237                 notify_otg = notify_charger = false;
238
239         return 0;
240
241 dev_det_ret:
242         if (ret < 0)
243                 dev_err(info->dev, "failed to detect BC Mod\n");
244
245         return ret;
246 }
247
248 static irqreturn_t axp288_extcon_isr(int irq, void *data)
249 {
250         struct axp288_extcon_info *info = data;
251         int ret;
252
253         ret = axp288_handle_chrg_det_event(info);
254         if (ret < 0)
255                 dev_err(info->dev, "failed to handle the interrupt\n");
256
257         return IRQ_HANDLED;
258 }
259
260 static void axp288_extcon_enable_irq(struct axp288_extcon_info *info)
261 {
262         /* Unmask VBUS interrupt */
263         regmap_write(info->regmap, AXP288_PWRSRC_IRQ_CFG_REG,
264                                                 PWRSRC_IRQ_CFG_MASK);
265         regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
266                                                 BC_GLOBAL_RUN, 0);
267         /* Unmask the BC1.2 complete interrupts */
268         regmap_write(info->regmap, AXP288_BC12_IRQ_CFG_REG, BC12_IRQ_CFG_MASK);
269         /* Enable the charger detection logic */
270         regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
271                                         BC_GLOBAL_RUN, BC_GLOBAL_RUN);
272 }
273
274 static int axp288_extcon_probe(struct platform_device *pdev)
275 {
276         struct axp288_extcon_info *info;
277         struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
278         int ret, i, pirq, gpio;
279
280         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
281         if (!info)
282                 return -ENOMEM;
283
284         info->dev = &pdev->dev;
285         info->regmap = axp20x->regmap;
286         info->regmap_irqc = axp20x->regmap_irqc;
287         info->pdata = pdev->dev.platform_data;
288
289         if (!info->pdata) {
290                 /* Try ACPI provided pdata via device properties */
291                 if (!device_property_present(&pdev->dev,
292                                         "axp288_extcon_data\n"))
293                         dev_err(&pdev->dev, "failed to get platform data\n");
294                 return -ENODEV;
295         }
296         platform_set_drvdata(pdev, info);
297
298         axp288_extcon_log_rsi(info);
299
300         /* Initialize extcon device */
301         info->edev = devm_extcon_dev_allocate(&pdev->dev,
302                                               axp288_extcon_cables);
303         if (IS_ERR(info->edev)) {
304                 dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
305                 return PTR_ERR(info->edev);
306         }
307
308         /* Register extcon device */
309         ret = devm_extcon_dev_register(&pdev->dev, info->edev);
310         if (ret) {
311                 dev_err(&pdev->dev, "failed to register extcon device\n");
312                 return ret;
313         }
314
315         /* Get otg transceiver phy */
316         info->otg = usb_get_phy(USB_PHY_TYPE_USB2);
317         if (IS_ERR(info->otg)) {
318                 dev_err(&pdev->dev, "failed to get otg transceiver\n");
319                 return PTR_ERR(info->otg);
320         }
321
322         /* Set up gpio control for USB Mux */
323         if (info->pdata->gpio_mux_cntl) {
324                 gpio = desc_to_gpio(info->pdata->gpio_mux_cntl);
325                 ret = gpio_request(gpio, "USB_MUX");
326                 if (ret < 0) {
327                         dev_err(&pdev->dev,
328                                 "failed to request the gpio=%d\n", gpio);
329                         goto gpio_req_failed;
330                 }
331                 gpiod_direction_output(info->pdata->gpio_mux_cntl,
332                                                 EXTCON_GPIO_MUX_SEL_PMIC);
333         }
334
335         for (i = 0; i < EXTCON_IRQ_END; i++) {
336                 pirq = platform_get_irq(pdev, i);
337                 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
338                 if (info->irq[i] < 0) {
339                         dev_err(&pdev->dev,
340                                 "failed to get virtual interrupt=%d\n", pirq);
341                         ret = info->irq[i];
342                         goto gpio_req_failed;
343                 }
344
345                 ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
346                                 NULL, axp288_extcon_isr,
347                                 IRQF_ONESHOT | IRQF_NO_SUSPEND,
348                                 pdev->name, info);
349                 if (ret) {
350                         dev_err(&pdev->dev, "failed to request interrupt=%d\n",
351                                                         info->irq[i]);
352                         goto gpio_req_failed;
353                 }
354         }
355
356         /* Enable interrupts */
357         axp288_extcon_enable_irq(info);
358
359         return 0;
360
361 gpio_req_failed:
362         usb_put_phy(info->otg);
363         return ret;
364 }
365
366 static int axp288_extcon_remove(struct platform_device *pdev)
367 {
368         struct axp288_extcon_info *info = platform_get_drvdata(pdev);
369
370         usb_put_phy(info->otg);
371         return 0;
372 }
373
374 static struct platform_driver axp288_extcon_driver = {
375         .probe = axp288_extcon_probe,
376         .remove = axp288_extcon_remove,
377         .driver = {
378                 .name = "axp288_extcon",
379         },
380 };
381 module_platform_driver(axp288_extcon_driver);
382
383 MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
384 MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
385 MODULE_LICENSE("GPL v2");