Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8d96004 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'extcon-next-for-4.4' of...

Merge tag 'extcon-next-for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next

Chanwoo writes:

Update extcon for 4.4

Detailed description for patchset:
1. Update the extcon core:
- Modify the unique identification and name of each external connector
  with the additional prefix to clarify both attribute and meaning of
  external connector as following:
: EXTCON_CHG_* mean the charger connector.
: EXTCON_JACK_* mean the jack connector.
: EXTCON_DISP_* mean the display port connector.

- Keep the standard name of USB charging port by refering to the
  "Battery Charging v1.2 Spec and Adopters Agreement"[1] to use
  the standard name of USB charging port as following:
: EXTCON_CHG_USB_SDP /* Standard Downstream Port */
: EXTCON_CHG_USB_DCP /* Dedicated Charging Port */
: EXTCON_CHG_USB_CDP /* Charging Downstream Port */
: EXTCON_CHG_USB_ACA /* Accessory Charger Adapter */
[1] www.usb.org/developers/docs/devclass_docs/BCv1.2_070312.zip

2. Update the extcon-arizona.c driver:
- Support the WM8998 and WM1814 codec for jack detection.
- Support for the ADC mode microphone detection and the general
  purpose switch for pop suppression.
- Fix bug include fixing the headphone detection accuracy
  at the top end of the range and some corrections around
  the use of the microphone clamps.

3. Update the extcon-gpio.c driver:
- Clean-up the extcon-gpio driver and fix minor issue before
  supporting the Device tree binding of it.

4. Clean-up and fix the minor issue for extcon drivers:
- Export OF module alias information for extcon-rt8973a.c and extcon-sm5502.c.
- Fix wrong type of variable of for extcon-rt8973a.c and extcon-sm5502.c.
- Use resource managed API for extcon-axp288.c.
parents 4970c0cb 11eecf91
Loading
Loading
Loading
Loading
+124 −40
Original line number Diff line number Diff line
/*
 * extcon-arizona.c - Extcon driver Wolfson Arizona devices
 *
 *  Copyright (C) 2012 Wolfson Microelectronics plc
 *  Copyright (C) 2012-2014 Wolfson Microelectronics plc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -43,11 +43,18 @@
#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb

#define ARIZONA_TST_CAP_DEFAULT 0x3
#define ARIZONA_TST_CAP_CLAMP   0x1

#define ARIZONA_HPDET_MAX 10000

#define HPDET_DEBOUNCE 500
#define DEFAULT_MICD_TIMEOUT 2000

#define QUICK_HEADPHONE_MAX_OHM 3
#define MICROPHONE_MIN_OHM      1257
#define MICROPHONE_MAX_OHM      30000

#define MICD_DBTIME_TWO_READINGS 2
#define MICD_DBTIME_FOUR_READINGS 4

@@ -117,19 +124,22 @@ static const struct arizona_micd_range micd_default_ranges[] = {
	{ .max = 430, .key = BTN_5 },
};

/* The number of levels in arizona_micd_levels valid for button thresholds */
#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64

static const int arizona_micd_levels[] = {
	3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
	49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
	105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
	270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
	1257,
	1257, 30000,
};

static const unsigned int arizona_cable[] = {
	EXTCON_MECHANICAL,
	EXTCON_MICROPHONE,
	EXTCON_HEADPHONE,
	EXTCON_LINE_OUT,
	EXTCON_JACK_MICROPHONE,
	EXTCON_JACK_HEADPHONE,
	EXTCON_JACK_LINE_OUT,
	EXTCON_NONE,
};

@@ -140,17 +150,33 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
{
	struct arizona *arizona = info->arizona;
	unsigned int mask = 0, val = 0;
	unsigned int cap_sel = 0;
	int ret;

	switch (arizona->type) {
	case WM8998:
	case WM1814:
		mask = 0;
		break;
	case WM5110:
	case WM8280:
		mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
		       ARIZONA_HP1L_SHRTI;
		if (clamp)
		if (clamp) {
			val = ARIZONA_HP1L_SHRTO;
		else
			cap_sel = ARIZONA_TST_CAP_CLAMP;
		} else {
			val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
			cap_sel = ARIZONA_TST_CAP_DEFAULT;
		}

		ret = regmap_update_bits(arizona->regmap,
					 ARIZONA_HP_TEST_CTRL_1,
					 ARIZONA_HP1_TST_CAP_SEL_MASK,
					 cap_sel);
		if (ret != 0)
			dev_warn(arizona->dev,
				 "Failed to set TST_CAP_SEL: %d\n", ret);
		break;
	default:
		mask = ARIZONA_RMV_SHRT_HP1L;
@@ -175,6 +201,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
				 ret);
	}

	if (mask) {
		ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
					 mask, val);
		if (ret != 0)
@@ -186,6 +213,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
		if (ret != 0)
			dev_warn(arizona->dev, "Failed to do clamp: %d\n",
				 ret);
	}

	/* Restore the desired state while not doing the clamp */
	if (!clamp) {
@@ -270,6 +298,7 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
	struct arizona *arizona = info->arizona;
	bool change;
	int ret;
	unsigned int mode;

	/* Microphone detection can't use idle mode */
	pm_runtime_get(info->dev);
@@ -295,9 +324,14 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
		regmap_write(arizona->regmap, 0x80, 0x0);
	}

	if (info->detecting && arizona->pdata.micd_software_compare)
		mode = ARIZONA_ACCDET_MODE_ADC;
	else
		mode = ARIZONA_ACCDET_MODE_MIC;

	regmap_update_bits(arizona->regmap,
			   ARIZONA_ACCESSORY_DETECT_MODE_1,
			   ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
			   ARIZONA_ACCDET_MODE_MASK, mode);

	arizona_extcon_pulse_micbias(info);

@@ -443,9 +477,6 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
			   arizona_hpdet_b_ranges[range].factor_a);
		break;

	default:
		dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
			 info->hpdet_ip_version);
	case 2:
		if (!(val & ARIZONA_HP_DONE_B)) {
			dev_err(arizona->dev, "HPDET did not complete: %x\n",
@@ -482,6 +513,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
				arizona_hpdet_c_ranges[range].min);
			val = arizona_hpdet_c_ranges[range].min;
		}
		break;

	default:
		dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
			 info->hpdet_ip_version);
		return -EINVAL;
	}

	dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
@@ -563,7 +600,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
	struct arizona_extcon_info *info = data;
	struct arizona *arizona = info->arizona;
	int id_gpio = arizona->pdata.hpdet_id_gpio;
	unsigned int report = EXTCON_HEADPHONE;
	unsigned int report = EXTCON_JACK_HEADPHONE;
	int ret, reading;
	bool mic = false;

@@ -608,9 +645,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)

	/* Report high impedence cables as line outputs */
	if (reading >= 5000)
		report = EXTCON_LINE_OUT;
		report = EXTCON_JACK_LINE_OUT;
	else
		report = EXTCON_HEADPHONE;
		report = EXTCON_JACK_HEADPHONE;

	ret = extcon_set_cable_state_(info->edev, report, true);
	if (ret != 0)
@@ -695,7 +732,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
			   ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);

	/* Just report headphone */
	ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
	ret = extcon_set_cable_state_(info->edev, EXTCON_JACK_HEADPHONE, true);
	if (ret != 0)
		dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);

@@ -752,7 +789,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
			   ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);

	/* Just report headphone */
	ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
	ret = extcon_set_cable_state_(info->edev, EXTCON_JACK_HEADPHONE, true);
	if (ret != 0)
		dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);

@@ -804,6 +841,37 @@ static void arizona_micd_detect(struct work_struct *work)
		return;
	}

	if (info->detecting && arizona->pdata.micd_software_compare) {
		/* Must disable MICD before we read the ADCVAL */
		regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
				   ARIZONA_MICD_ENA, 0);
		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
		if (ret != 0) {
			dev_err(arizona->dev,
				"Failed to read MICDET_ADCVAL: %d\n",
				ret);
			mutex_unlock(&info->lock);
			return;
		}

		dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);

		val &= ARIZONA_MICDET_ADCVAL_MASK;
		if (val < ARRAY_SIZE(arizona_micd_levels))
			val = arizona_micd_levels[val];
		else
			val = INT_MAX;

		if (val <= QUICK_HEADPHONE_MAX_OHM)
			val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
		else if (val <= MICROPHONE_MIN_OHM)
			val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
		else if (val <= MICROPHONE_MAX_OHM)
			val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
		else
			val = ARIZONA_MICD_LVL_8;
	}

	for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
		ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
		if (ret != 0) {
@@ -847,7 +915,7 @@ static void arizona_micd_detect(struct work_struct *work)
		arizona_identify_headphone(info);

		ret = extcon_set_cable_state_(info->edev,
					      EXTCON_MICROPHONE, true);
					      EXTCON_JACK_MICROPHONE, true);
		if (ret != 0)
			dev_err(arizona->dev, "Headset report failed: %d\n",
				ret);
@@ -932,10 +1000,17 @@ static void arizona_micd_detect(struct work_struct *work)
	}

handled:
	if (info->detecting)
	if (info->detecting) {
		if (arizona->pdata.micd_software_compare)
			regmap_update_bits(arizona->regmap,
					   ARIZONA_MIC_DETECT_1,
					   ARIZONA_MICD_ENA,
					   ARIZONA_MICD_ENA);

		queue_delayed_work(system_power_efficient_wq,
				   &info->micd_timeout_work,
				   msecs_to_jiffies(info->micd_timeout));
	}

	pm_runtime_mark_last_busy(info->dev);
	mutex_unlock(&info->lock);
@@ -991,11 +1066,8 @@ static irqreturn_t arizona_jackdet(int irq, void *data)

	mutex_lock(&info->lock);

	if (arizona->pdata.jd_gpio5) {
	if (info->micd_clamp) {
		mask = ARIZONA_MICD_CLAMP_STS;
		if (arizona->pdata.jd_invert)
			present = ARIZONA_MICD_CLAMP_STS;
		else
		present = 0;
	} else {
		mask = ARIZONA_JD1_STS;
@@ -1055,9 +1127,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
					   msecs_to_jiffies(HPDET_DEBOUNCE));
		}

		if (info->micd_clamp || !arizona->pdata.jd_invert)
			regmap_update_bits(arizona->regmap,
					   ARIZONA_JACK_DETECT_DEBOUNCE,
				   ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
					   ARIZONA_MICD_CLAMP_DB |
					   ARIZONA_JD1_DB, 0);
	} else {
		dev_dbg(arizona->dev, "Detected jack removal\n");

@@ -1224,6 +1298,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
			break;
		}
		break;
	case WM8998:
	case WM1814:
		info->micd_clamp = true;
		info->hpdet_ip_version = 2;
		break;
	default:
		break;
	}
@@ -1259,6 +1338,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)
		info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
	}

	if (arizona->pdata.gpsw > 0)
		regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
				ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);

	if (arizona->pdata.micd_pol_gpio > 0) {
		if (info->micd_modes[0].gpio)
			mode = GPIOF_OUT_INIT_HIGH;
@@ -1335,7 +1418,8 @@ static int arizona_extcon_probe(struct platform_device *pdev)
		break;
	}

	BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
	BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
		     ARIZONA_NUM_MICD_BUTTON_LEVELS);

	if (arizona->pdata.num_micd_ranges) {
		info->micd_ranges = pdata->micd_ranges;
@@ -1368,11 +1452,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)

	/* Set up all the buttons the user specified */
	for (i = 0; i < info->num_micd_ranges; i++) {
		for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
		for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
			if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
				break;

		if (j == ARRAY_SIZE(arizona_micd_levels)) {
		if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
			dev_err(arizona->dev, "Unsupported MICD level %d\n",
				info->micd_ranges[i].max);
			ret = -EINVAL;
@@ -1436,7 +1520,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
	pm_runtime_idle(&pdev->dev);
	pm_runtime_get_sync(&pdev->dev);

	if (arizona->pdata.jd_gpio5) {
	if (info->micd_clamp) {
		jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
		jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
	} else {
@@ -1541,7 +1625,7 @@ static int arizona_extcon_remove(struct platform_device *pdev)
			   ARIZONA_MICD_CLAMP_CONTROL,
			   ARIZONA_MICD_CLAMP_MODE_MASK, 0);

	if (arizona->pdata.jd_gpio5) {
	if (info->micd_clamp) {
		jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
		jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
	} else {
+11 −24
Original line number Diff line number Diff line
@@ -102,9 +102,9 @@ enum axp288_extcon_irq {
};

static const unsigned int axp288_extcon_cables[] = {
	EXTCON_SLOW_CHARGER,
	EXTCON_CHARGE_DOWNSTREAM,
	EXTCON_FAST_CHARGER,
	EXTCON_CHG_USB_SDP,
	EXTCON_CHG_USB_CDP,
	EXTCON_CHG_USB_DCP,
	EXTCON_NONE,
};

@@ -192,18 +192,18 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
		dev_dbg(info->dev, "sdp cable is connecetd\n");
		notify_otg = true;
		notify_charger = true;
		cable = EXTCON_SLOW_CHARGER;
		cable = EXTCON_CHG_USB_SDP;
		break;
	case DET_STAT_CDP:
		dev_dbg(info->dev, "cdp cable is connecetd\n");
		notify_otg = true;
		notify_charger = true;
		cable = EXTCON_CHARGE_DOWNSTREAM;
		cable = EXTCON_CHG_USB_CDP;
		break;
	case DET_STAT_DCP:
		dev_dbg(info->dev, "dcp cable is connecetd\n");
		notify_charger = true;
		cable = EXTCON_FAST_CHARGER;
		cable = EXTCON_CHG_USB_DCP;
		break;
	default:
		dev_warn(info->dev,
@@ -309,7 +309,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
	}

	/* Get otg transceiver phy */
	info->otg = usb_get_phy(USB_PHY_TYPE_USB2);
	info->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
	if (IS_ERR(info->otg)) {
		dev_err(&pdev->dev, "failed to get otg transceiver\n");
		return PTR_ERR(info->otg);
@@ -318,11 +318,11 @@ static int axp288_extcon_probe(struct platform_device *pdev)
	/* Set up gpio control for USB Mux */
	if (info->pdata->gpio_mux_cntl) {
		gpio = desc_to_gpio(info->pdata->gpio_mux_cntl);
		ret = gpio_request(gpio, "USB_MUX");
		ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX");
		if (ret < 0) {
			dev_err(&pdev->dev,
				"failed to request the gpio=%d\n", gpio);
			goto gpio_req_failed;
			return ret;
		}
		gpiod_direction_output(info->pdata->gpio_mux_cntl,
						EXTCON_GPIO_MUX_SEL_PMIC);
@@ -335,7 +335,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
			dev_err(&pdev->dev,
				"failed to get virtual interrupt=%d\n", pirq);
			ret = info->irq[i];
			goto gpio_req_failed;
			return ret;
		}

		ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
@@ -345,7 +345,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
		if (ret) {
			dev_err(&pdev->dev, "failed to request interrupt=%d\n",
							info->irq[i]);
			goto gpio_req_failed;
			return ret;
		}
	}

@@ -353,23 +353,10 @@ static int axp288_extcon_probe(struct platform_device *pdev)
	axp288_extcon_enable_irq(info);

	return 0;

gpio_req_failed:
	usb_put_phy(info->otg);
	return ret;
}

static int axp288_extcon_remove(struct platform_device *pdev)
{
	struct axp288_extcon_info *info = platform_get_drvdata(pdev);

	usb_put_phy(info->otg);
	return 0;
}

static struct platform_driver axp288_extcon_driver = {
	.probe = axp288_extcon_probe,
	.remove = axp288_extcon_remove,
	.driver = {
		.name = "axp288_extcon",
	},
+70 −60
Original line number Diff line number Diff line
/*
 *  drivers/extcon/extcon_gpio.c
 *
 *  Single-state GPIO extcon driver based on extcon class
 * extcon_gpio.c - Single-state GPIO extcon driver based on extcon class
 *
 * Copyright (C) 2008 Google, Inc.
 * Author: Mike Lockwood <lockwood@android.com>
@@ -17,12 +15,12 @@
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/extcon.h>
#include <linux/extcon/extcon-gpio.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -33,14 +31,12 @@

struct gpio_extcon_data {
	struct extcon_dev *edev;
	unsigned gpio;
	bool gpio_active_low;
	const char *state_on;
	const char *state_off;
	int irq;
	struct delayed_work work;
	unsigned long debounce_jiffies;
	bool check_on_resume;

	struct gpio_desc *id_gpiod;
	struct gpio_extcon_pdata *pdata;
};

static void gpio_extcon_work(struct work_struct *work)
@@ -50,93 +46,107 @@ static void gpio_extcon_work(struct work_struct *work)
		container_of(to_delayed_work(work), struct gpio_extcon_data,
			     work);

	state = gpio_get_value(data->gpio);
	if (data->gpio_active_low)
	state = gpiod_get_value_cansleep(data->id_gpiod);
	if (data->pdata->gpio_active_low)
		state = !state;
	extcon_set_state(data->edev, state);
}

static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
	struct gpio_extcon_data *extcon_data = dev_id;
	struct gpio_extcon_data *data = dev_id;

	queue_delayed_work(system_power_efficient_wq, &extcon_data->work,
			      extcon_data->debounce_jiffies);
	queue_delayed_work(system_power_efficient_wq, &data->work,
			      data->debounce_jiffies);
	return IRQ_HANDLED;
}

static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data)
{
	struct gpio_extcon_pdata *pdata = data->pdata;
	int ret;

	ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_DIR_IN,
				dev_name(dev));
	if (ret < 0)
		return ret;

	data->id_gpiod = gpio_to_desc(pdata->gpio);
	if (!data->id_gpiod)
		return -EINVAL;

	if (pdata->debounce) {
		ret = gpiod_set_debounce(data->id_gpiod,
					pdata->debounce * 1000);
		if (ret < 0)
			data->debounce_jiffies =
				msecs_to_jiffies(pdata->debounce);
	}

	data->irq = gpiod_to_irq(data->id_gpiod);
	if (data->irq < 0)
		return data->irq;

	return 0;
}

static int gpio_extcon_probe(struct platform_device *pdev)
{
	struct gpio_extcon_platform_data *pdata = dev_get_platdata(&pdev->dev);
	struct gpio_extcon_data *extcon_data;
	struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev);
	struct gpio_extcon_data *data;
	int ret;

	if (!pdata)
		return -EBUSY;
	if (!pdata->irq_flags) {
		dev_err(&pdev->dev, "IRQ flag is not specified.\n");
	if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE)
		return -EINVAL;
	}

	extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
	data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
				   GFP_KERNEL);
	if (!extcon_data)
	if (!data)
		return -ENOMEM;
	data->pdata = pdata;

	extcon_data->edev = devm_extcon_dev_allocate(&pdev->dev, NULL);
	if (IS_ERR(extcon_data->edev)) {
		dev_err(&pdev->dev, "failed to allocate extcon device\n");
		return -ENOMEM;
	}

	extcon_data->gpio = pdata->gpio;
	extcon_data->gpio_active_low = pdata->gpio_active_low;
	extcon_data->state_on = pdata->state_on;
	extcon_data->state_off = pdata->state_off;
	extcon_data->check_on_resume = pdata->check_on_resume;

	ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
				    pdev->name);
	/* Initialize the gpio */
	ret = gpio_extcon_init(&pdev->dev, data);
	if (ret < 0)
		return ret;

	if (pdata->debounce) {
		ret = gpio_set_debounce(extcon_data->gpio,
					pdata->debounce * 1000);
		if (ret < 0)
			extcon_data->debounce_jiffies =
				msecs_to_jiffies(pdata->debounce);
	/* Allocate the memory of extcon devie and register extcon device */
	data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id);
	if (IS_ERR(data->edev)) {
		dev_err(&pdev->dev, "failed to allocate extcon device\n");
		return -ENOMEM;
	}

	ret = devm_extcon_dev_register(&pdev->dev, extcon_data->edev);
	ret = devm_extcon_dev_register(&pdev->dev, data->edev);
	if (ret < 0)
		return ret;

	INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);

	extcon_data->irq = gpio_to_irq(extcon_data->gpio);
	if (extcon_data->irq < 0)
		return extcon_data->irq;
	INIT_DELAYED_WORK(&data->work, gpio_extcon_work);

	ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
				      pdata->irq_flags, pdev->name,
				      extcon_data);
	/*
	 * Request the interrput of gpio to detect whether external connector
	 * is attached or detached.
	 */
	ret = devm_request_any_context_irq(&pdev->dev, data->irq,
					gpio_irq_handler, pdata->irq_flags,
					pdev->name, data);
	if (ret < 0)
		return ret;

	platform_set_drvdata(pdev, extcon_data);
	platform_set_drvdata(pdev, data);
	/* Perform initial detection */
	gpio_extcon_work(&extcon_data->work.work);
	gpio_extcon_work(&data->work.work);

	return 0;
}

static int gpio_extcon_remove(struct platform_device *pdev)
{
	struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
	struct gpio_extcon_data *data = platform_get_drvdata(pdev);

	cancel_delayed_work_sync(&extcon_data->work);
	free_irq(extcon_data->irq, extcon_data);
	cancel_delayed_work_sync(&data->work);

	return 0;
}
@@ -144,12 +154,12 @@ static int gpio_extcon_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int gpio_extcon_resume(struct device *dev)
{
	struct gpio_extcon_data *extcon_data;
	struct gpio_extcon_data *data;

	extcon_data = dev_get_drvdata(dev);
	if (extcon_data->check_on_resume)
	data = dev_get_drvdata(dev);
	if (data->pdata->check_on_resume)
		queue_delayed_work(system_power_efficient_wq,
			&extcon_data->work, extcon_data->debounce_jiffies);
			&data->work, data->debounce_jiffies);

	return 0;
}
+9 −8
Original line number Diff line number Diff line
@@ -150,10 +150,10 @@ enum max14577_muic_acc_type {

static const unsigned int max14577_extcon_cable[] = {
	EXTCON_USB,
	EXTCON_TA,
	EXTCON_FAST_CHARGER,
	EXTCON_SLOW_CHARGER,
	EXTCON_CHARGE_DOWNSTREAM,
	EXTCON_CHG_USB_DCP,
	EXTCON_CHG_USB_FAST,
	EXTCON_CHG_USB_SLOW,
	EXTCON_CHG_USB_CDP,
	EXTCON_JIG,
	EXTCON_NONE,
};
@@ -456,18 +456,19 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info)
		extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
		break;
	case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
		extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP,
					attached);
		break;
	case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
		extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP,
					attached);
		break;
	case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
		extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW,
					attached);
		break;
	case MAX14577_CHARGER_TYPE_SPECIAL_1A:
		extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST,
					attached);
		break;
	case MAX14577_CHARGER_TYPE_NONE:
+17 −15
Original line number Diff line number Diff line
@@ -204,11 +204,11 @@ enum max77693_muic_acc_type {
static const unsigned int max77693_extcon_cable[] = {
	EXTCON_USB,
	EXTCON_USB_HOST,
	EXTCON_TA,
	EXTCON_FAST_CHARGER,
	EXTCON_SLOW_CHARGER,
	EXTCON_CHARGE_DOWNSTREAM,
	EXTCON_MHL,
	EXTCON_CHG_USB_DCP,
	EXTCON_CHG_USB_FAST,
	EXTCON_CHG_USB_SLOW,
	EXTCON_CHG_USB_CDP,
	EXTCON_DISP_MHL,
	EXTCON_JIG,
	EXTCON_DOCK,
	EXTCON_NONE,
@@ -505,7 +505,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
			return ret;

		extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached);
		extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
		extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached);
		goto out;
	case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE:	/* Dock-Desk */
		dock_id = EXTCON_DOCK;
@@ -605,7 +605,7 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
	case MAX77693_MUIC_GND_MHL:
	case MAX77693_MUIC_GND_MHL_VB:
		/* MHL or MHL with USB/TA cable */
		extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
		extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached);
		break;
	default:
		dev_err(info->dev, "failed to detect %s cable of gnd type\n",
@@ -801,10 +801,11 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
			 * - Support charging through micro-usb port without
			 *   data connection
			 */
			extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
			extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP,
						attached);
			if (!cable_attached)
				extcon_set_cable_state_(info->edev, EXTCON_MHL,
							cable_attached);
				extcon_set_cable_state_(info->edev,
					EXTCON_DISP_MHL, cable_attached);
			break;
		}

@@ -862,7 +863,7 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)

			extcon_set_cable_state_(info->edev, EXTCON_DOCK,
						attached);
			extcon_set_cable_state_(info->edev, EXTCON_MHL,
			extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL,
						attached);
			break;
		}
@@ -901,20 +902,21 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
			break;
		case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
			/* Only TA cable */
			extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
			extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP,
						attached);
			break;
		}
		break;
	case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
		extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP,
					attached);
		break;
	case MAX77693_CHARGER_TYPE_APPLE_500MA:
		extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW,
					attached);
		break;
	case MAX77693_CHARGER_TYPE_APPLE_1A_2A:
		extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
		extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST,
					attached);
		break;
	case MAX77693_CHARGER_TYPE_DEAD_BATTERY:
Loading