aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/extcon-adc-jack.c10
-rw-r--r--drivers/extcon/extcon-class.c142
-rw-r--r--drivers/extcon/extcon-gpio.c1
-rw-r--r--drivers/extcon/extcon-max77693.c46
-rw-r--r--drivers/extcon/extcon-max8997.c6
5 files changed, 124 insertions, 81 deletions
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 725eb5aa8d8c..e87196f6d2d2 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -14,6 +14,7 @@
14 * 14 *
15 */ 15 */
16 16
17#include <linux/module.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
18#include <linux/device.h> 19#include <linux/device.h>
19#include <linux/platform_device.h> 20#include <linux/platform_device.h>
@@ -161,13 +162,12 @@ static int __devinit adc_jack_probe(struct platform_device *pdev)
161 err = request_any_context_irq(data->irq, adc_jack_irq_thread, 162 err = request_any_context_irq(data->irq, adc_jack_irq_thread,
162 pdata->irq_flags, pdata->name, data); 163 pdata->irq_flags, pdata->name, data);
163 164
164 if (err) { 165 if (err < 0) {
165 dev_err(&pdev->dev, "error: irq %d\n", data->irq); 166 dev_err(&pdev->dev, "error: irq %d\n", data->irq);
166 err = -EINVAL;
167 goto err_irq; 167 goto err_irq;
168 } 168 }
169 169
170 goto out; 170 return 0;
171 171
172err_irq: 172err_irq:
173 extcon_dev_unregister(&data->edev); 173 extcon_dev_unregister(&data->edev);
@@ -196,3 +196,7 @@ static struct platform_driver adc_jack_driver = {
196}; 196};
197 197
198module_platform_driver(adc_jack_driver); 198module_platform_driver(adc_jack_driver);
199
200MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
201MODULE_DESCRIPTION("ADC Jack extcon driver");
202MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 946a3188b2b7..d398821097f3 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -41,7 +41,7 @@
41 * every single port-type of the following cable names. Please choose cable 41 * every single port-type of the following cable names. Please choose cable
42 * names that are actually used in your extcon device. 42 * names that are actually used in your extcon device.
43 */ 43 */
44const char *extcon_cable_name[] = { 44const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
45 [EXTCON_USB] = "USB", 45 [EXTCON_USB] = "USB",
46 [EXTCON_USB_HOST] = "USB-Host", 46 [EXTCON_USB_HOST] = "USB-Host",
47 [EXTCON_TA] = "TA", 47 [EXTCON_TA] = "TA",
@@ -62,8 +62,6 @@ const char *extcon_cable_name[] = {
62 [EXTCON_VIDEO_IN] = "Video-in", 62 [EXTCON_VIDEO_IN] = "Video-in",
63 [EXTCON_VIDEO_OUT] = "Video-out", 63 [EXTCON_VIDEO_OUT] = "Video-out",
64 [EXTCON_MECHANICAL] = "Mechanical", 64 [EXTCON_MECHANICAL] = "Mechanical",
65
66 NULL,
67}; 65};
68 66
69static struct class *extcon_class; 67static struct class *extcon_class;
@@ -91,17 +89,13 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
91 return 0; 89 return 0;
92 90
93 for (i = 0; edev->mutually_exclusive[i]; i++) { 91 for (i = 0; edev->mutually_exclusive[i]; i++) {
94 int count = 0, j; 92 int weight;
95 u32 correspondants = new_state & edev->mutually_exclusive[i]; 93 u32 correspondants = new_state & edev->mutually_exclusive[i];
96 u32 exp = 1; 94
97 95 /* calculate the total number of bits set */
98 for (j = 0; j < 32; j++) { 96 weight = hweight32(correspondants);
99 if (exp & correspondants) 97 if (weight > 1)
100 count++; 98 return i + 1;
101 if (count > 1)
102 return i + 1;
103 exp <<= 1;
104 }
105 } 99 }
106 100
107 return 0; 101 return 0;
@@ -362,7 +356,7 @@ int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
362EXPORT_SYMBOL_GPL(extcon_get_cable_state); 356EXPORT_SYMBOL_GPL(extcon_get_cable_state);
363 357
364/** 358/**
365 * extcon_get_cable_state_() - Set the status of a specific cable. 359 * extcon_set_cable_state_() - Set the status of a specific cable.
366 * @edev: the extcon device that has the cable. 360 * @edev: the extcon device that has the cable.
367 * @index: cable index that can be retrieved by extcon_find_cable_index(). 361 * @index: cable index that can be retrieved by extcon_find_cable_index().
368 * @cable_state: the new cable status. The default semantics is 362 * @cable_state: the new cable status. The default semantics is
@@ -382,7 +376,7 @@ int extcon_set_cable_state_(struct extcon_dev *edev,
382EXPORT_SYMBOL_GPL(extcon_set_cable_state_); 376EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
383 377
384/** 378/**
385 * extcon_get_cable_state() - Set the status of a specific cable. 379 * extcon_set_cable_state() - Set the status of a specific cable.
386 * @edev: the extcon device that has the cable. 380 * @edev: the extcon device that has the cable.
387 * @cable_name: cable name. 381 * @cable_name: cable name.
388 * @cable_state: the new cable status. The default semantics is 382 * @cable_state: the new cable status. The default semantics is
@@ -447,6 +441,8 @@ static int _call_per_cable(struct notifier_block *nb, unsigned long val,
447 * extcon device. 441 * extcon device.
448 * @obj: an empty extcon_specific_cable_nb object to be returned. 442 * @obj: an empty extcon_specific_cable_nb object to be returned.
449 * @extcon_name: the name of extcon device. 443 * @extcon_name: the name of extcon device.
444 * if NULL, extcon_register_interest will register
445 * every cable with the target cable_name given.
450 * @cable_name: the target cable name. 446 * @cable_name: the target cable name.
451 * @nb: the notifier block to get notified. 447 * @nb: the notifier block to get notified.
452 * 448 *
@@ -466,22 +462,44 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
466 const char *extcon_name, const char *cable_name, 462 const char *extcon_name, const char *cable_name,
467 struct notifier_block *nb) 463 struct notifier_block *nb)
468{ 464{
469 if (!obj || !extcon_name || !cable_name || !nb) 465 if (!obj || !cable_name || !nb)
470 return -EINVAL; 466 return -EINVAL;
471 467
472 obj->edev = extcon_get_extcon_dev(extcon_name); 468 if (extcon_name) {
473 if (!obj->edev) 469 obj->edev = extcon_get_extcon_dev(extcon_name);
474 return -ENODEV; 470 if (!obj->edev)
471 return -ENODEV;
475 472
476 obj->cable_index = extcon_find_cable_index(obj->edev, cable_name); 473 obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
477 if (obj->cable_index < 0) 474 if (obj->cable_index < 0)
478 return -ENODEV; 475 return -ENODEV;
476
477 obj->user_nb = nb;
479 478
480 obj->user_nb = nb; 479 obj->internal_nb.notifier_call = _call_per_cable;
481 480
482 obj->internal_nb.notifier_call = _call_per_cable; 481 return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
482 } else {
483 struct class_dev_iter iter;
484 struct extcon_dev *extd;
485 struct device *dev;
486
487 if (!extcon_class)
488 return -ENODEV;
489 class_dev_iter_init(&iter, extcon_class, NULL, NULL);
490 while ((dev = class_dev_iter_next(&iter))) {
491 extd = (struct extcon_dev *)dev_get_drvdata(dev);
492
493 if (extcon_find_cable_index(extd, cable_name) < 0)
494 continue;
495
496 class_dev_iter_exit(&iter);
497 return extcon_register_interest(obj, extd->name,
498 cable_name, nb);
499 }
483 500
484 return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb); 501 return -ENODEV;
502 }
485} 503}
486 504
487/** 505/**
@@ -551,43 +569,9 @@ static int create_extcon_class(void)
551 return 0; 569 return 0;
552} 570}
553 571
554static void extcon_cleanup(struct extcon_dev *edev, bool skip)
555{
556 mutex_lock(&extcon_dev_list_lock);
557 list_del(&edev->entry);
558 mutex_unlock(&extcon_dev_list_lock);
559
560 if (!skip && get_device(edev->dev)) {
561 int index;
562
563 if (edev->mutually_exclusive && edev->max_supported) {
564 for (index = 0; edev->mutually_exclusive[index];
565 index++)
566 kfree(edev->d_attrs_muex[index].attr.name);
567 kfree(edev->d_attrs_muex);
568 kfree(edev->attrs_muex);
569 }
570
571 for (index = 0; index < edev->max_supported; index++)
572 kfree(edev->cables[index].attr_g.name);
573
574 if (edev->max_supported) {
575 kfree(edev->extcon_dev_type.groups);
576 kfree(edev->cables);
577 }
578
579 device_unregister(edev->dev);
580 put_device(edev->dev);
581 }
582
583 kfree(edev->dev);
584}
585
586static void extcon_dev_release(struct device *dev) 572static void extcon_dev_release(struct device *dev)
587{ 573{
588 struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); 574 kfree(dev);
589
590 extcon_cleanup(edev, true);
591} 575}
592 576
593static const char *muex_name = "mutually_exclusive"; 577static const char *muex_name = "mutually_exclusive";
@@ -813,7 +797,40 @@ EXPORT_SYMBOL_GPL(extcon_dev_register);
813 */ 797 */
814void extcon_dev_unregister(struct extcon_dev *edev) 798void extcon_dev_unregister(struct extcon_dev *edev)
815{ 799{
816 extcon_cleanup(edev, false); 800 int index;
801
802 mutex_lock(&extcon_dev_list_lock);
803 list_del(&edev->entry);
804 mutex_unlock(&extcon_dev_list_lock);
805
806 if (IS_ERR_OR_NULL(get_device(edev->dev))) {
807 dev_err(edev->dev, "Failed to unregister extcon_dev (%s)\n",
808 dev_name(edev->dev));
809 return;
810 }
811
812 if (edev->mutually_exclusive && edev->max_supported) {
813 for (index = 0; edev->mutually_exclusive[index];
814 index++)
815 kfree(edev->d_attrs_muex[index].attr.name);
816 kfree(edev->d_attrs_muex);
817 kfree(edev->attrs_muex);
818 }
819
820 for (index = 0; index < edev->max_supported; index++)
821 kfree(edev->cables[index].attr_g.name);
822
823 if (edev->max_supported) {
824 kfree(edev->extcon_dev_type.groups);
825 kfree(edev->cables);
826 }
827
828#if defined(CONFIG_ANDROID)
829 if (switch_class)
830 class_compat_remove_link(switch_class, edev->dev, NULL);
831#endif
832 device_unregister(edev->dev);
833 put_device(edev->dev);
817} 834}
818EXPORT_SYMBOL_GPL(extcon_dev_unregister); 835EXPORT_SYMBOL_GPL(extcon_dev_unregister);
819 836
@@ -825,6 +842,9 @@ module_init(extcon_class_init);
825 842
826static void __exit extcon_class_exit(void) 843static void __exit extcon_class_exit(void)
827{ 844{
845#if defined(CONFIG_ANDROID)
846 class_compat_unregister(switch_class);
847#endif
828 class_destroy(extcon_class); 848 class_destroy(extcon_class);
829} 849}
830module_exit(extcon_class_exit); 850module_exit(extcon_class_exit);
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 3cc152e690b0..71d3ab7b3d8d 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -26,7 +26,6 @@
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/extcon.h>
30#include <linux/workqueue.h> 29#include <linux/workqueue.h>
31#include <linux/gpio.h> 30#include <linux/gpio.h>
32#include <linux/extcon.h> 31#include <linux/extcon.h>
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index e21387e2da5c..a17d0d91ada2 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -239,25 +239,19 @@ const char *max77693_extcon_cable[] = {
239static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, 239static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
240 enum max77693_muic_adc_debounce_time time) 240 enum max77693_muic_adc_debounce_time time)
241{ 241{
242 int ret = 0; 242 int ret;
243 u8 ctrl3;
244 243
245 switch (time) { 244 switch (time) {
246 case ADC_DEBOUNCE_TIME_5MS: 245 case ADC_DEBOUNCE_TIME_5MS:
247 case ADC_DEBOUNCE_TIME_10MS: 246 case ADC_DEBOUNCE_TIME_10MS:
248 case ADC_DEBOUNCE_TIME_25MS: 247 case ADC_DEBOUNCE_TIME_25MS:
249 case ADC_DEBOUNCE_TIME_38_62MS: 248 case ADC_DEBOUNCE_TIME_38_62MS:
250 ret = max77693_read_reg(info->max77693->regmap_muic, 249 ret = max77693_update_reg(info->max77693->regmap_muic,
251 MAX77693_MUIC_REG_CTRL3, &ctrl3); 250 MAX77693_MUIC_REG_CTRL3,
252 ctrl3 &= ~CONTROL3_ADCDBSET_MASK; 251 time << CONTROL3_ADCDBSET_SHIFT,
253 ctrl3 |= (time << CONTROL3_ADCDBSET_SHIFT); 252 CONTROL3_ADCDBSET_MASK);
254 253 if (ret)
255 ret = max77693_write_reg(info->max77693->regmap_muic,
256 MAX77693_MUIC_REG_CTRL3, ctrl3);
257 if (ret) {
258 dev_err(info->dev, "failed to set ADC debounce time\n"); 254 dev_err(info->dev, "failed to set ADC debounce time\n");
259 ret = -EINVAL;
260 }
261 break; 255 break;
262 default: 256 default:
263 dev_err(info->dev, "invalid ADC debounce time\n"); 257 dev_err(info->dev, "invalid ADC debounce time\n");
@@ -657,6 +651,8 @@ out:
657static int __devinit max77693_muic_probe(struct platform_device *pdev) 651static int __devinit max77693_muic_probe(struct platform_device *pdev)
658{ 652{
659 struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); 653 struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
654 struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
655 struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
660 struct max77693_muic_info *info; 656 struct max77693_muic_info *info;
661 int ret, i; 657 int ret, i;
662 u8 id; 658 u8 id;
@@ -727,6 +723,31 @@ static int __devinit max77693_muic_probe(struct platform_device *pdev)
727 goto err_extcon; 723 goto err_extcon;
728 } 724 }
729 725
726 /* Initialize MUIC register by using platform data */
727 for (i = 0 ; i < muic_pdata->num_init_data ; i++) {
728 enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR;
729
730 max77693_write_reg(info->max77693->regmap_muic,
731 muic_pdata->init_data[i].addr,
732 muic_pdata->init_data[i].data);
733
734 switch (muic_pdata->init_data[i].addr) {
735 case MAX77693_MUIC_REG_INTMASK1:
736 irq_src = MUIC_INT1;
737 break;
738 case MAX77693_MUIC_REG_INTMASK2:
739 irq_src = MUIC_INT2;
740 break;
741 case MAX77693_MUIC_REG_INTMASK3:
742 irq_src = MUIC_INT3;
743 break;
744 }
745
746 if (irq_src < MAX77693_IRQ_GROUP_NR)
747 info->max77693->irq_masks_cur[irq_src]
748 = muic_pdata->init_data[i].data;
749 }
750
730 /* Check revision number of MUIC device*/ 751 /* Check revision number of MUIC device*/
731 ret = max77693_read_reg(info->max77693->regmap_muic, 752 ret = max77693_read_reg(info->max77693->regmap_muic,
732 MAX77693_MUIC_REG_ID, &id); 753 MAX77693_MUIC_REG_ID, &id);
@@ -762,6 +783,7 @@ static int __devexit max77693_muic_remove(struct platform_device *pdev)
762 free_irq(muic_irqs[i].virq, info); 783 free_irq(muic_irqs[i].virq, info);
763 cancel_work_sync(&info->irq_work); 784 cancel_work_sync(&info->irq_work);
764 extcon_dev_unregister(info->edev); 785 extcon_dev_unregister(info->edev);
786 kfree(info->edev);
765 kfree(info); 787 kfree(info);
766 788
767 return 0; 789 return 0;
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index ef9090a4271d..77b66b0cc8f5 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -271,8 +271,6 @@ out:
271static int max8997_muic_handle_charger_type_detach( 271static int max8997_muic_handle_charger_type_detach(
272 struct max8997_muic_info *info) 272 struct max8997_muic_info *info)
273{ 273{
274 int ret = 0;
275
276 switch (info->pre_charger_type) { 274 switch (info->pre_charger_type) {
277 case MAX8997_CHARGER_TYPE_USB: 275 case MAX8997_CHARGER_TYPE_USB:
278 extcon_set_cable_state(info->edev, "USB", false); 276 extcon_set_cable_state(info->edev, "USB", false);
@@ -290,11 +288,11 @@ static int max8997_muic_handle_charger_type_detach(
290 extcon_set_cable_state(info->edev, "Fast-charger", false); 288 extcon_set_cable_state(info->edev, "Fast-charger", false);
291 break; 289 break;
292 default: 290 default:
293 ret = -EINVAL; 291 return -EINVAL;
294 break; 292 break;
295 } 293 }
296 294
297 return ret; 295 return 0;
298} 296}
299 297
300static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, 298static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,