]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/extcon/extcon-max8997.c
extcon: max8997: Move defined constant to header file
[karo-tx-linux.git] / drivers / extcon / extcon-max8997.c
1 /*
2  * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
3  *
4  *  Copyright (C) 2012 Samsung Electronics
5  *  Donggeun Kim <dg77.kim@samsung.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 as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/i2c.h>
21 #include <linux/slab.h>
22 #include <linux/interrupt.h>
23 #include <linux/err.h>
24 #include <linux/platform_device.h>
25 #include <linux/kobject.h>
26 #include <linux/mfd/max8997.h>
27 #include <linux/mfd/max8997-private.h>
28 #include <linux/extcon.h>
29 #include <linux/irqdomain.h>
30
31 #define DEV_NAME                        "max8997-muic"
32
33 struct max8997_muic_irq {
34         unsigned int irq;
35         const char *name;
36         unsigned int virq;
37 };
38
39 static struct max8997_muic_irq muic_irqs[] = {
40         { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
41         { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
42         { MAX8997_MUICIRQ_ADC, "muic-ADC" },
43         { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
44         { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
45         { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
46         { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
47         { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
48         { MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
49 };
50
51 struct max8997_muic_info {
52         struct device *dev;
53         struct i2c_client *muic;
54         struct max8997_muic_platform_data *muic_pdata;
55
56         int irq;
57         struct work_struct irq_work;
58
59         enum max8997_muic_charger_type pre_charger_type;
60         int pre_adc;
61
62         struct mutex mutex;
63
64         struct extcon_dev       *edev;
65 };
66
67 enum {
68         EXTCON_CABLE_USB = 0,
69         EXTCON_CABLE_USB_HOST,
70         EXTCON_CABLE_TA,
71         EXTCON_CABLE_FAST_CHARGER,
72         EXTCON_CABLE_SLOW_CHARGER,
73         EXTCON_CABLE_CHARGE_DOWNSTREAM,
74         EXTCON_CABLE_MHL,
75         EXTCON_CABLE_DOCK_DESK,
76         EXTCON_CABLE_DOCK_CARD,
77         EXTCON_CABLE_JIG,
78
79         _EXTCON_CABLE_NUM,
80 };
81
82 static const char *max8997_extcon_cable[] = {
83         [EXTCON_CABLE_USB]                      = "USB",
84         [EXTCON_CABLE_USB_HOST]                 = "USB-Host",
85         [EXTCON_CABLE_TA]                       = "TA",
86         [EXTCON_CABLE_FAST_CHARGER]             = "Fast-charger",
87         [EXTCON_CABLE_SLOW_CHARGER]             = "Slow-charger",
88         [EXTCON_CABLE_CHARGE_DOWNSTREAM]        = "Charge-downstream",
89         [EXTCON_CABLE_MHL]                      = "MHL",
90         [EXTCON_CABLE_DOCK_DESK]                = "Dock-Desk",
91         [EXTCON_CABLE_DOCK_CARD]                = "Dock-Card",
92         [EXTCON_CABLE_JIG]                      = "JIG",
93
94         NULL,
95 };
96
97 static int max8997_muic_handle_usb(struct max8997_muic_info *info,
98                         enum max8997_muic_usb_type usb_type, bool attached)
99 {
100         int ret = 0;
101
102         if (usb_type == MAX8997_USB_HOST) {
103                 /* switch to USB */
104                 ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
105                                 attached ? CONTROL1_SW_USB : CONTROL1_SW_OPEN,
106                                 CONTROL1_SW_MASK);
107                 if (ret) {
108                         dev_err(info->dev, "failed to update muic register\n");
109                         goto out;
110                 }
111         }
112
113         switch (usb_type) {
114         case MAX8997_USB_HOST:
115                 extcon_set_cable_state(info->edev, "USB-Host", attached);
116                 break;
117         case MAX8997_USB_DEVICE:
118                 extcon_set_cable_state(info->edev, "USB", attached);
119                 break;
120         default:
121                 ret = -EINVAL;
122                 break;
123         }
124
125 out:
126         return ret;
127 }
128
129 static int max8997_muic_handle_dock(struct max8997_muic_info *info,
130                         int adc, bool attached)
131 {
132         int ret = 0;
133
134         /* switch to AUDIO */
135         ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
136                                 attached ? CONTROL1_SW_AUDIO : CONTROL1_SW_OPEN,
137                                 CONTROL1_SW_MASK);
138         if (ret) {
139                 dev_err(info->dev, "failed to update muic register\n");
140                 goto out;
141         }
142
143         switch (adc) {
144         case MAX8997_ADC_DESKDOCK:
145                 extcon_set_cable_state(info->edev, "Dock-desk", attached);
146                 break;
147         case MAX8997_ADC_CARDOCK:
148                 extcon_set_cable_state(info->edev, "Dock-card", attached);
149                 break;
150         default:
151                 ret = -EINVAL;
152                 break;
153         }
154 out:
155         return ret;
156 }
157
158 static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
159                         bool attached)
160 {
161         int ret = 0;
162
163         /* switch to UART */
164         ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
165                                 attached ? CONTROL1_SW_UART : CONTROL1_SW_OPEN,
166                                 CONTROL1_SW_MASK);
167         if (ret) {
168                 dev_err(info->dev, "failed to update muic register\n");
169                 goto out;
170         }
171
172         extcon_set_cable_state(info->edev, "JIG", attached);
173 out:
174         return ret;
175 }
176
177 static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
178 {
179         int ret = 0;
180
181         switch (info->pre_adc) {
182         case MAX8997_ADC_GROUND:
183                 ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
184                 break;
185         case MAX8997_ADC_MHL:
186                 extcon_set_cable_state(info->edev, "MHL", false);
187                 break;
188         case MAX8997_ADC_JIG_USB_1:
189         case MAX8997_ADC_JIG_USB_2:
190                 ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
191                 break;
192         case MAX8997_ADC_DESKDOCK:
193         case MAX8997_ADC_CARDOCK:
194                 ret = max8997_muic_handle_dock(info, info->pre_adc, false);
195                 break;
196         case MAX8997_ADC_JIG_UART:
197                 ret = max8997_muic_handle_jig_uart(info, false);
198                 break;
199         default:
200                 break;
201         }
202
203         return ret;
204 }
205
206 static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
207 {
208         int ret = 0;
209
210         switch (adc) {
211         case MAX8997_ADC_GROUND:
212                 ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
213                 break;
214         case MAX8997_ADC_MHL:
215                 extcon_set_cable_state(info->edev, "MHL", true);
216                 break;
217         case MAX8997_ADC_JIG_USB_1:
218         case MAX8997_ADC_JIG_USB_2:
219                 ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
220                 break;
221         case MAX8997_ADC_DESKDOCK:
222         case MAX8997_ADC_CARDOCK:
223                 ret = max8997_muic_handle_dock(info, adc, true);
224                 break;
225         case MAX8997_ADC_JIG_UART:
226                 ret = max8997_muic_handle_jig_uart(info, true);
227                 break;
228         case MAX8997_ADC_OPEN:
229                 ret = max8997_muic_handle_adc_detach(info);
230                 break;
231         default:
232                 ret = -EINVAL;
233                 goto out;
234         }
235
236         info->pre_adc = adc;
237 out:
238         return ret;
239 }
240
241 static int max8997_muic_handle_charger_type_detach(
242                                 struct max8997_muic_info *info)
243 {
244         switch (info->pre_charger_type) {
245         case MAX8997_CHARGER_TYPE_USB:
246                 extcon_set_cable_state(info->edev, "USB", false);
247                 break;
248         case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
249                 extcon_set_cable_state(info->edev, "Charge-downstream", false);
250                 break;
251         case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
252                 extcon_set_cable_state(info->edev, "TA", false);
253                 break;
254         case MAX8997_CHARGER_TYPE_500MA:
255                 extcon_set_cable_state(info->edev, "Slow-charger", false);
256                 break;
257         case MAX8997_CHARGER_TYPE_1A:
258                 extcon_set_cable_state(info->edev, "Fast-charger", false);
259                 break;
260         default:
261                 return -EINVAL;
262         }
263
264         return 0;
265 }
266
267 static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
268                                 enum max8997_muic_charger_type charger_type)
269 {
270         u8 adc;
271         int ret;
272
273         ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
274         if (ret) {
275                 dev_err(info->dev, "failed to read muic register\n");
276                 goto out;
277         }
278
279         switch (charger_type) {
280         case MAX8997_CHARGER_TYPE_NONE:
281                 ret = max8997_muic_handle_charger_type_detach(info);
282                 break;
283         case MAX8997_CHARGER_TYPE_USB:
284                 if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
285                         max8997_muic_handle_usb(info,
286                                         MAX8997_USB_DEVICE, true);
287                 }
288                 break;
289         case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
290                 extcon_set_cable_state(info->edev, "Charge-downstream", true);
291                 break;
292         case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
293                 extcon_set_cable_state(info->edev, "TA", true);
294                 break;
295         case MAX8997_CHARGER_TYPE_500MA:
296                 extcon_set_cable_state(info->edev, "Slow-charger", true);
297                 break;
298         case MAX8997_CHARGER_TYPE_1A:
299                 extcon_set_cable_state(info->edev, "Fast-charger", true);
300                 break;
301         default:
302                 ret = -EINVAL;
303                 goto out;
304         }
305
306         info->pre_charger_type = charger_type;
307 out:
308         return ret;
309 }
310
311 static void max8997_muic_irq_work(struct work_struct *work)
312 {
313         struct max8997_muic_info *info = container_of(work,
314                         struct max8997_muic_info, irq_work);
315         u8 status[2];
316         u8 adc, chg_type;
317         int irq_type = 0;
318         int i, ret;
319
320         mutex_lock(&info->mutex);
321
322         ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
323                                 2, status);
324         if (ret) {
325                 dev_err(info->dev, "failed to read muic register\n");
326                 mutex_unlock(&info->mutex);
327                 return;
328         }
329
330         dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
331                         status[0], status[1]);
332
333         for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++)
334                 if (info->irq == muic_irqs[i].virq)
335                         irq_type = muic_irqs[i].irq;
336
337         switch (irq_type) {
338         case MAX8997_MUICIRQ_ADC:
339                 adc = status[0] & STATUS1_ADC_MASK;
340                 adc >>= STATUS1_ADC_SHIFT;
341
342                 max8997_muic_handle_adc(info, adc);
343                 break;
344         case MAX8997_MUICIRQ_ChgTyp:
345                 chg_type = status[1] & STATUS2_CHGTYP_MASK;
346                 chg_type >>= STATUS2_CHGTYP_SHIFT;
347
348                 max8997_muic_handle_charger_type(info, chg_type);
349                 break;
350         default:
351                 dev_info(info->dev, "misc interrupt: irq %d occurred\n",
352                                 irq_type);
353                 break;
354         }
355
356         mutex_unlock(&info->mutex);
357
358         return;
359 }
360
361 static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
362 {
363         struct max8997_muic_info *info = data;
364
365         dev_dbg(info->dev, "irq:%d\n", irq);
366         info->irq = irq;
367
368         schedule_work(&info->irq_work);
369
370         return IRQ_HANDLED;
371 }
372
373 static void max8997_muic_detect_dev(struct max8997_muic_info *info)
374 {
375         int ret;
376         u8 status[2], adc, chg_type;
377
378         ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
379                                 2, status);
380         if (ret) {
381                 dev_err(info->dev, "failed to read muic register\n");
382                 return;
383         }
384
385         dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
386                         status[0], status[1]);
387
388         adc = status[0] & STATUS1_ADC_MASK;
389         adc >>= STATUS1_ADC_SHIFT;
390
391         chg_type = status[1] & STATUS2_CHGTYP_MASK;
392         chg_type >>= STATUS2_CHGTYP_SHIFT;
393
394         max8997_muic_handle_adc(info, adc);
395         max8997_muic_handle_charger_type(info, chg_type);
396 }
397
398 static int max8997_muic_probe(struct platform_device *pdev)
399 {
400         struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
401         struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
402         struct max8997_muic_info *info;
403         int ret, i;
404
405         info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info),
406                             GFP_KERNEL);
407         if (!info) {
408                 dev_err(&pdev->dev, "failed to allocate memory\n");
409                 return -ENOMEM;
410         }
411
412         info->dev = &pdev->dev;
413         info->muic = max8997->muic;
414
415         platform_set_drvdata(pdev, info);
416         mutex_init(&info->mutex);
417
418         INIT_WORK(&info->irq_work, max8997_muic_irq_work);
419
420         for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
421                 struct max8997_muic_irq *muic_irq = &muic_irqs[i];
422                 unsigned int virq = 0;
423
424                 virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq);
425                 if (!virq) {
426                         ret = -EINVAL;
427                         goto err_irq;
428                 }
429                 muic_irq->virq = virq;
430
431                 ret = request_threaded_irq(virq, NULL,
432                                 max8997_muic_irq_handler,
433                                 IRQF_NO_SUSPEND,
434                                 muic_irq->name, info);
435                 if (ret) {
436                         dev_err(&pdev->dev,
437                                 "failed: irq request (IRQ: %d,"
438                                 " error :%d)\n",
439                                 muic_irq->irq, ret);
440                         goto err_irq;
441                 }
442         }
443
444         /* External connector */
445         info->edev = devm_kzalloc(&pdev->dev, sizeof(struct extcon_dev),
446                                   GFP_KERNEL);
447         if (!info->edev) {
448                 dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
449                 ret = -ENOMEM;
450                 goto err_irq;
451         }
452         info->edev->name = DEV_NAME;
453         info->edev->supported_cable = max8997_extcon_cable;
454         ret = extcon_dev_register(info->edev, NULL);
455         if (ret) {
456                 dev_err(&pdev->dev, "failed to register extcon device\n");
457                 goto err_irq;
458         }
459
460         /* Initialize registers according to platform data */
461         if (pdata->muic_pdata) {
462                 struct max8997_muic_platform_data *mdata = info->muic_pdata;
463
464                 for (i = 0; i < mdata->num_init_data; i++) {
465                         max8997_write_reg(info->muic, mdata->init_data[i].addr,
466                                         mdata->init_data[i].data);
467                 }
468         }
469
470         /* Initial device detection */
471         max8997_muic_detect_dev(info);
472
473         return ret;
474
475 err_irq:
476         while (--i >= 0)
477                 free_irq(muic_irqs[i].virq, info);
478         return ret;
479 }
480
481 static int max8997_muic_remove(struct platform_device *pdev)
482 {
483         struct max8997_muic_info *info = platform_get_drvdata(pdev);
484         int i;
485
486         for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
487                 free_irq(muic_irqs[i].virq, info);
488         cancel_work_sync(&info->irq_work);
489
490         extcon_dev_unregister(info->edev);
491
492         return 0;
493 }
494
495 static struct platform_driver max8997_muic_driver = {
496         .driver         = {
497                 .name   = DEV_NAME,
498                 .owner  = THIS_MODULE,
499         },
500         .probe          = max8997_muic_probe,
501         .remove         = max8997_muic_remove,
502 };
503
504 module_platform_driver(max8997_muic_driver);
505
506 MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
507 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
508 MODULE_LICENSE("GPL");