Update extcon for 4.12
Detailed description for this pull request: 1. Add new 'extcon-intel-cht-wc.c' driver - Intel Cherrytrail Whiskey Cove PMIC extcon driver supports the detection of the charger connectors and the control. 2. Add new extcon API to monitor the all external connectors. - The extcon consumer might need to monitor the all supported external connectors from the extcon device. Before, the extcon consumer should have each notifier_block structure for each external connector. In order to support the requirement, the extcon adds new extcon_register_notifier_all() API. The extcon consumer is able to monitor the state change of all supported external connectors from the extcon device by using only one notifier_block. - extcon_(register|unregister)_notifier_all(struct extcon_dev *edev struct notifier_block *nb) - devm_extcon_(register|unregister)_notifier_all(struct device *dev, struct extcon_dev *edev struct notifier_block *nb) 3. Remove porting compatibility of old switch class - The extcon removes the porting compatibility of old switch class because there are no any use-case and requirement of switch class. 4. Update the extcon drivers and Fix the minor issues - Revert the ACPI gpio interface on the extcon-usb-gpioc.c. - Fix the issues related to the suspend-to-ram for both extcon-usb-gpio.c and extcon-palmas.c. - Add warning message for extcon-arizona.c when headphone detection is not finished. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJY6xdjAAoJEJzN3yze689TKp4QAIRtX/6/8SsF29wI6ViQvJCi OcBhiaKPqUJqJB5lK5wHvXR898Zx3PibAY4RNhcFCbXfiTgGeIGtG3OiN5+PpZ+i +gUbVR2ec6G6YMTOmpiatKX8kdaknDMet6Czj9Ap4i8qW7XVZrx8k5rX3eQygb+9 kPG8VGYkdTWpJwqZ/GR5DiOe0tSlzH9jDBFxBYEUEQSfXLvwmieDWrKVZHXcI4lB BaCy/v0yh/jWXe+/ZgM9Fff0a+NJLbIfVmVGmrUhy7iAyDfeP91Df5uv6PPzPX9b GKIqAbJB1B//MK8pON2ZL0RuTssD/7akENrmd+eHDuqA7eFf1+aL2Em8eBJ3S+Xh uBFt4dWR6Gctwsmkyu5GOOFgAzPB+9aCFEEOTjnzBszj3U7lIzqDq6G2Mrg4gb7b 3Y4pS2JjA2V6lpflGomfhfIEq7hDmr7LB4/kl8Odf1C3pJI3lwmIux883qm+zmIO zl0vKVpWoskxl7yMxLGALhiRN/gUQF4grcSGDWHQ6lmcREgo5Ixw8IUUcnpabmqy UAZgixdNutquaAF+QvZ8VshktcleMYxWZhvJ/ttPee8RNvh6yTqgcRM/8ujrQPPT xVamXHOgs92K1Ljw1Er+YnmCH3C6nL6Amsr7Ya2VmIPtXDuWxIRmk5NAFTc+XVb1 IK8Me7KVb0FF910in2/m =UAR0 -----END PGP SIGNATURE----- Merge tag 'extcon-next-for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next Update extcon for 4.12 Detailed description for this pull request: 1. Add new 'extcon-intel-cht-wc.c' driver - Intel Cherrytrail Whiskey Cove PMIC extcon driver supports the detection of the charger connectors and the control. 2. Add new extcon API to monitor the all external connectors. - The extcon consumer might need to monitor the all supported external connectors from the extcon device. Before, the extcon consumer should have each notifier_block structure for each external connector. In order to support the requirement, the extcon adds new extcon_register_notifier_all() API. The extcon consumer is able to monitor the state change of all supported external connectors from the extcon device by using only one notifier_block. - extcon_(register|unregister)_notifier_all(struct extcon_dev *edev struct notifier_block *nb) - devm_extcon_(register|unregister)_notifier_all(struct device *dev, struct extcon_dev *edev struct notifier_block *nb) 3. Remove porting compatibility of old switch class - The extcon removes the porting compatibility of old switch class because there are no any use-case and requirement of switch class. 4. Update the extcon drivers and Fix the minor issues - Revert the ACPI gpio interface on the extcon-usb-gpioc.c. - Fix the issues related to the suspend-to-ram for both extcon-usb-gpio.c and extcon-palmas.c. - Add warning message for extcon-arizona.c when headphone detection is not finished.
This commit is contained in:
commit
073a457d9e
|
@ -1,123 +0,0 @@
|
|||
|
||||
Staging/Android Switch Class Porting Guide
|
||||
(linux/drivers/staging/android/switch)
|
||||
(c) Copyright 2012 Samsung Electronics
|
||||
|
||||
AUTHORS
|
||||
MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
|
||||
/*****************************************************************
|
||||
* CHAPTER 1. *
|
||||
* PORTING SWITCH CLASS DEVICE DRIVERS *
|
||||
*****************************************************************/
|
||||
|
||||
****** STEP 1. Basic Functionality
|
||||
No extcon extended feature, but switch features only.
|
||||
|
||||
- struct switch_dev (fed to switch_dev_register/unregister)
|
||||
@name: no change
|
||||
@dev: no change
|
||||
@index: drop (not used in switch device driver side anyway)
|
||||
@state: no change
|
||||
If you have used @state with magic numbers, keep it
|
||||
at this step.
|
||||
@print_name: no change but type change (switch_dev->extcon_dev)
|
||||
@print_state: no change but type change (switch_dev->extcon_dev)
|
||||
|
||||
- switch_dev_register(sdev, dev)
|
||||
=> extcon_dev_register(edev)
|
||||
: type change (sdev->edev)
|
||||
: remove second param('dev'). if edev has parent device, should store
|
||||
'dev' to 'edev.dev.parent' before registering extcon device
|
||||
- switch_dev_unregister(sdev)
|
||||
=> extcon_dev_unregister(edev)
|
||||
: no change but type change (sdev->edev)
|
||||
- switch_get_state(sdev)
|
||||
=> extcon_get_state(edev)
|
||||
: no change but type change (sdev->edev) and (return: int->u32)
|
||||
- switch_set_state(sdev, state)
|
||||
=> extcon_set_state(edev, state)
|
||||
: no change but type change (sdev->edev) and (state: int->u32)
|
||||
|
||||
With this changes, the ex-switch extcon class device works as it once
|
||||
worked as switch class device. However, it will now have additional
|
||||
interfaces (both ABI and in-kernel API) and different ABI locations.
|
||||
However, if CONFIG_ANDROID is enabled without CONFIG_ANDROID_SWITCH,
|
||||
/sys/class/switch/* will be symbolically linked to /sys/class/extcon/
|
||||
so that they are still compatible with legacy userspace processes.
|
||||
|
||||
****** STEP 2. Multistate (no more magic numbers in state value)
|
||||
Extcon's extended features for switch device drivers with
|
||||
complex features usually required magic numbers in state
|
||||
value of switch_dev. With extcon, such magic numbers that
|
||||
support multiple cables are no more required or supported.
|
||||
|
||||
1. Define cable names at edev->supported_cable.
|
||||
2. (Recommended) remove print_state callback.
|
||||
3. Use extcon_get_cable_state_(edev, index) or
|
||||
extcon_get_cable_state(edev, cable_name) instead of
|
||||
extcon_get_state(edev) if you intend to get a state of a specific
|
||||
cable. Same for set_state. This way, you can remove the usage of
|
||||
magic numbers in state value.
|
||||
4. Use extcon_update_state() if you are updating specific bits of
|
||||
the state value.
|
||||
|
||||
Example: a switch device driver w/ magic numbers for two cables.
|
||||
"0x00": no cables connected.
|
||||
"0x01": cable 1 connected
|
||||
"0x02": cable 2 connected
|
||||
"0x03": cable 1 and 2 connected
|
||||
1. edev->supported_cable = {"1", "2", NULL};
|
||||
2. edev->print_state = NULL;
|
||||
3. extcon_get_cable_state_(edev, 0) shows cable 1's state.
|
||||
extcon_get_cable_state(edev, "1") shows cable 1's state.
|
||||
extcon_set_cable_state_(edev, 1) sets cable 2's state.
|
||||
extcon_set_cable_state(edev, "2") sets cable 2's state
|
||||
4. extcon_update_state(edev, 0x01, 0) sets the least bit's 0.
|
||||
|
||||
****** STEP 3. Notify other device drivers
|
||||
|
||||
You can notify others of the cable attach/detach events with
|
||||
notifier chains.
|
||||
|
||||
At the side of other device drivers (the extcon device itself
|
||||
does not need to get notified of its own events), there are two
|
||||
methods to register notifier_block for cable events:
|
||||
(a) for a specific cable or (b) for every cable.
|
||||
|
||||
(a) extcon_register_interest(obj, extcon_name, cable_name, nb)
|
||||
Example: want to get news of "MAX8997_MUIC"'s "USB" cable
|
||||
|
||||
obj = kzalloc(sizeof(struct extcon_specific_cable_nb),
|
||||
GFP_KERNEL);
|
||||
nb->notifier_call = the_callback_to_handle_usb;
|
||||
|
||||
extcon_register_intereset(obj, "MAX8997_MUIC", "USB", nb);
|
||||
|
||||
(b) extcon_register_notifier(edev, nb)
|
||||
Call nb for any changes in edev.
|
||||
|
||||
Please note that in order to properly behave with method (a),
|
||||
the extcon device driver should support multistate feature (STEP 2).
|
||||
|
||||
****** STEP 4. Inter-cable relation (mutually exclusive)
|
||||
|
||||
You can provide inter-cable mutually exclusiveness information
|
||||
for an extcon device. When cables A and B are declared to be mutually
|
||||
exclusive, the two cables cannot be in ATTACHED state simulteneously.
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CHAPTER 2. *
|
||||
* PORTING USERSPACE w/ SWITCH CLASS DEVICE SUPPORT *
|
||||
*****************************************************************/
|
||||
|
||||
****** ABI Location
|
||||
|
||||
If "CONFIG_ANDROID" is enabled, /sys/class/switch/* are created
|
||||
as symbolic links to /sys/class/extcon/*.
|
||||
|
||||
The two files of switch class, name and state, are provided with
|
||||
extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
|
||||
not enabled or print_state callback is supplied, the output of
|
||||
state ABI is same with switch class.
|
|
@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
|
|||
This ACPI device is typically found on Intel Baytrail or Cherrytrail
|
||||
based tablets, or other Baytrail / Cherrytrail devices.
|
||||
|
||||
config EXTCON_INTEL_CHT_WC
|
||||
tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
|
||||
depends on INTEL_SOC_PMIC_CHTWC
|
||||
help
|
||||
Say Y here to enable extcon support for charger detection / control
|
||||
on the Intel Cherrytrail Whiskey Cove PMIC.
|
||||
|
||||
config EXTCON_MAX14577
|
||||
tristate "Maxim MAX14577/77836 EXTCON Support"
|
||||
depends on MFD_MAX14577
|
||||
|
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
|
|||
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
|
||||
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
|
||||
obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
|
||||
obj-$(CONFIG_EXTCON_INTEL_CHT_WC) += extcon-intel-cht-wc.o
|
||||
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
|
||||
obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o
|
||||
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
|
||||
|
|
|
@ -50,6 +50,13 @@ static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
|
|||
extcon_unregister_notifier(this->edev, this->id, this->nb);
|
||||
}
|
||||
|
||||
static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
|
||||
{
|
||||
struct extcon_dev_notifier_devres *this = res;
|
||||
|
||||
extcon_unregister_notifier_all(this->edev, this->nb);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_extcon_dev_allocate - Allocate managed extcon device
|
||||
* @dev: device owning the extcon device being created
|
||||
|
@ -214,3 +221,57 @@ void devm_extcon_unregister_notifier(struct device *dev,
|
|||
devm_extcon_dev_match, edev));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_extcon_unregister_notifier);
|
||||
|
||||
/**
|
||||
* devm_extcon_register_notifier_all()
|
||||
* - Resource-managed extcon_register_notifier_all()
|
||||
* @dev: device to allocate extcon device
|
||||
* @edev: the extcon device that has the external connecotr.
|
||||
* @nb: a notifier block to be registered.
|
||||
*
|
||||
* This function manages automatically the notifier of extcon device using
|
||||
* device resource management and simplify the control of unregistering
|
||||
* the notifier of extcon device. To get more information, refer that function.
|
||||
*
|
||||
* Returns 0 if success or negaive error number if failure.
|
||||
*/
|
||||
int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct extcon_dev_notifier_devres *ptr;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = extcon_register_notifier_all(edev, nb);
|
||||
if (ret) {
|
||||
devres_free(ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptr->edev = edev;
|
||||
ptr->nb = nb;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_extcon_register_notifier_all);
|
||||
|
||||
/**
|
||||
* devm_extcon_unregister_notifier_all()
|
||||
* - Resource-managed extcon_unregister_notifier_all()
|
||||
* @dev: device to allocate extcon device
|
||||
* @edev: the extcon device that has the external connecotr.
|
||||
* @nb: a notifier block to be registered.
|
||||
*/
|
||||
void devm_extcon_unregister_notifier_all(struct device *dev,
|
||||
struct extcon_dev *edev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
|
||||
devm_extcon_dev_match, edev));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
#define HPDET_DEBOUNCE 500
|
||||
#define DEFAULT_MICD_TIMEOUT 2000
|
||||
|
||||
#define ARIZONA_HPDET_WAIT_COUNT 15
|
||||
#define ARIZONA_HPDET_WAIT_DELAY_MS 20
|
||||
|
||||
#define QUICK_HEADPHONE_MAX_OHM 3
|
||||
#define MICROPHONE_MIN_OHM 1257
|
||||
#define MICROPHONE_MAX_OHM 30000
|
||||
|
@ -1049,6 +1052,40 @@ static void arizona_hpdet_work(struct work_struct *work)
|
|||
mutex_unlock(&info->lock);
|
||||
}
|
||||
|
||||
static int arizona_hpdet_wait(struct arizona_extcon_info *info)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
unsigned int val;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
|
||||
&val);
|
||||
if (ret) {
|
||||
dev_err(arizona->dev,
|
||||
"Failed to read HPDET state: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (info->hpdet_ip_version) {
|
||||
case 0:
|
||||
if (val & ARIZONA_HP_DONE)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
if (val & ARIZONA_HP_DONE_B)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
|
||||
}
|
||||
|
||||
dev_warn(arizona->dev, "HPDET did not appear to complete\n");
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||
{
|
||||
struct arizona_extcon_info *info = data;
|
||||
|
@ -1155,6 +1192,15 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
|||
"Removal report failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the jack was removed during a headphone detection we
|
||||
* need to wait for the headphone detection to finish, as
|
||||
* it can not be aborted. We don't want to be able to start
|
||||
* a new headphone detection from a fresh insert until this
|
||||
* one is finished.
|
||||
*/
|
||||
arizona_hpdet_wait(info);
|
||||
|
||||
regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_JACK_DETECT_DEBOUNCE,
|
||||
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
|
||||
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
|
||||
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, 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/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define CHT_WC_PHYCTRL 0x5e07
|
||||
|
||||
#define CHT_WC_CHGRCTRL0 0x5e16
|
||||
#define CHT_WC_CHGRCTRL0_CHGRRESET BIT(0)
|
||||
#define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1)
|
||||
#define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2)
|
||||
#define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3)
|
||||
#define CHT_WC_CHGRCTRL0_TTLCK_MASK BIT(4)
|
||||
#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK BIT(5)
|
||||
#define CHT_WC_CHGRCTRL0_DBPOFF_MASK BIT(6)
|
||||
#define CHT_WC_CHGRCTRL0_WDT_NOKICK BIT(7)
|
||||
|
||||
#define CHT_WC_CHGRCTRL1 0x5e17
|
||||
|
||||
#define CHT_WC_USBSRC 0x5e29
|
||||
#define CHT_WC_USBSRC_STS_MASK GENMASK(1, 0)
|
||||
#define CHT_WC_USBSRC_STS_SUCCESS 2
|
||||
#define CHT_WC_USBSRC_STS_FAIL 3
|
||||
#define CHT_WC_USBSRC_TYPE_SHIFT 2
|
||||
#define CHT_WC_USBSRC_TYPE_MASK GENMASK(5, 2)
|
||||
#define CHT_WC_USBSRC_TYPE_NONE 0
|
||||
#define CHT_WC_USBSRC_TYPE_SDP 1
|
||||
#define CHT_WC_USBSRC_TYPE_DCP 2
|
||||
#define CHT_WC_USBSRC_TYPE_CDP 3
|
||||
#define CHT_WC_USBSRC_TYPE_ACA 4
|
||||
#define CHT_WC_USBSRC_TYPE_SE1 5
|
||||
#define CHT_WC_USBSRC_TYPE_MHL 6
|
||||
#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN 7
|
||||
#define CHT_WC_USBSRC_TYPE_OTHER 8
|
||||
#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9
|
||||
|
||||
#define CHT_WC_PWRSRC_IRQ 0x6e03
|
||||
#define CHT_WC_PWRSRC_IRQ_MASK 0x6e0f
|
||||
#define CHT_WC_PWRSRC_STS 0x6e1e
|
||||
#define CHT_WC_PWRSRC_VBUS BIT(0)
|
||||
#define CHT_WC_PWRSRC_DC BIT(1)
|
||||
#define CHT_WC_PWRSRC_BAT BIT(2)
|
||||
#define CHT_WC_PWRSRC_ID_GND BIT(3)
|
||||
#define CHT_WC_PWRSRC_ID_FLOAT BIT(4)
|
||||
|
||||
#define CHT_WC_VBUS_GPIO_CTLO 0x6e2d
|
||||
#define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0)
|
||||
|
||||
enum cht_wc_usb_id {
|
||||
USB_ID_OTG,
|
||||
USB_ID_GND,
|
||||
USB_ID_FLOAT,
|
||||
USB_RID_A,
|
||||
USB_RID_B,
|
||||
USB_RID_C,
|
||||
};
|
||||
|
||||
enum cht_wc_mux_select {
|
||||
MUX_SEL_PMIC = 0,
|
||||
MUX_SEL_SOC,
|
||||
};
|
||||
|
||||
static const unsigned int cht_wc_extcon_cables[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
EXTCON_CHG_USB_SDP,
|
||||
EXTCON_CHG_USB_CDP,
|
||||
EXTCON_CHG_USB_DCP,
|
||||
EXTCON_CHG_USB_ACA,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
struct cht_wc_extcon_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct extcon_dev *edev;
|
||||
unsigned int previous_cable;
|
||||
bool usb_host;
|
||||
};
|
||||
|
||||
static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
|
||||
{
|
||||
if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
|
||||
return USB_ID_GND;
|
||||
if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
|
||||
return USB_ID_FLOAT;
|
||||
|
||||
/*
|
||||
* Once we have iio support for the gpadc we should read the USBID
|
||||
* gpadc channel here and determine ACA role based on that.
|
||||
*/
|
||||
return USB_ID_FLOAT;
|
||||
}
|
||||
|
||||
static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
|
||||
bool ignore_errors)
|
||||
{
|
||||
int ret, usbsrc, status;
|
||||
unsigned long timeout;
|
||||
|
||||
/* Charger detection can take upto 600ms, wait 800ms max. */
|
||||
timeout = jiffies + msecs_to_jiffies(800);
|
||||
do {
|
||||
ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = usbsrc & CHT_WC_USBSRC_STS_MASK;
|
||||
if (status == CHT_WC_USBSRC_STS_SUCCESS ||
|
||||
status == CHT_WC_USBSRC_STS_FAIL)
|
||||
break;
|
||||
|
||||
msleep(50); /* Wait a bit before retrying */
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
if (status != CHT_WC_USBSRC_STS_SUCCESS) {
|
||||
if (ignore_errors)
|
||||
return EXTCON_CHG_USB_SDP; /* Save fallback */
|
||||
|
||||
if (status == CHT_WC_USBSRC_STS_FAIL)
|
||||
dev_warn(ext->dev, "Could not detect charger type\n");
|
||||
else
|
||||
dev_warn(ext->dev, "Timeout detecting charger type\n");
|
||||
return EXTCON_CHG_USB_SDP; /* Save fallback */
|
||||
}
|
||||
|
||||
usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
|
||||
switch (usbsrc) {
|
||||
default:
|
||||
dev_warn(ext->dev,
|
||||
"Unhandled charger type %d, defaulting to SDP\n",
|
||||
ret);
|
||||
/* Fall through, treat as SDP */
|
||||
case CHT_WC_USBSRC_TYPE_SDP:
|
||||
case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
|
||||
case CHT_WC_USBSRC_TYPE_OTHER:
|
||||
return EXTCON_CHG_USB_SDP;
|
||||
case CHT_WC_USBSRC_TYPE_CDP:
|
||||
return EXTCON_CHG_USB_CDP;
|
||||
case CHT_WC_USBSRC_TYPE_DCP:
|
||||
case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
|
||||
case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
|
||||
return EXTCON_CHG_USB_DCP;
|
||||
case CHT_WC_USBSRC_TYPE_ACA:
|
||||
return EXTCON_CHG_USB_ACA;
|
||||
}
|
||||
}
|
||||
|
||||
static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
|
||||
if (ret)
|
||||
dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
|
||||
}
|
||||
|
||||
static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext,
|
||||
bool enable)
|
||||
{
|
||||
int ret, val;
|
||||
|
||||
val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0;
|
||||
|
||||
/*
|
||||
* The 5V boost converter is enabled through a gpio on the PMIC, since
|
||||
* there currently is no gpio driver we access the gpio reg directly.
|
||||
*/
|
||||
ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO,
|
||||
CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val);
|
||||
if (ret)
|
||||
dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */
|
||||
static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext,
|
||||
unsigned int cable, bool state)
|
||||
{
|
||||
extcon_set_state_sync(ext->edev, cable, state);
|
||||
if (cable == EXTCON_CHG_USB_SDP)
|
||||
extcon_set_state_sync(ext->edev, EXTCON_USB, state);
|
||||
}
|
||||
|
||||
static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext)
|
||||
{
|
||||
int ret, pwrsrc_sts, id;
|
||||
unsigned int cable = EXTCON_NONE;
|
||||
/* Ignore errors in host mode, as the 5v boost converter is on then */
|
||||
bool ignore_get_charger_errors = ext->usb_host;
|
||||
|
||||
ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
|
||||
if (id == USB_ID_GND) {
|
||||
/* The 5v boost causes a false VBUS / SDP detect, skip */
|
||||
goto charger_det_done;
|
||||
}
|
||||
|
||||
/* Plugged into a host/charger or not connected? */
|
||||
if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
|
||||
/* Route D+ and D- to PMIC for future charger detection */
|
||||
cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
|
||||
goto set_state;
|
||||
}
|
||||
|
||||
ret = cht_wc_extcon_get_charger(ext, ignore_get_charger_errors);
|
||||
if (ret >= 0)
|
||||
cable = ret;
|
||||
|
||||
charger_det_done:
|
||||
/* Route D+ and D- to SoC for the host or gadget controller */
|
||||
cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
|
||||
|
||||
set_state:
|
||||
if (cable != ext->previous_cable) {
|
||||
cht_wc_extcon_set_state(ext, cable, true);
|
||||
cht_wc_extcon_set_state(ext, ext->previous_cable, false);
|
||||
ext->previous_cable = cable;
|
||||
}
|
||||
|
||||
ext->usb_host = ((id == USB_ID_GND) || (id == USB_RID_A));
|
||||
extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host);
|
||||
}
|
||||
|
||||
static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
|
||||
{
|
||||
struct cht_wc_extcon_data *ext = data;
|
||||
int ret, irqs;
|
||||
|
||||
ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error reading irqs: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
cht_wc_extcon_pwrsrc_event(ext);
|
||||
|
||||
ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error writing irqs: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable)
|
||||
{
|
||||
int ret, mask, val;
|
||||
|
||||
mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK;
|
||||
val = enable ? mask : 0;
|
||||
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val);
|
||||
if (ret)
|
||||
dev_err(ext->dev, "Error setting sw control: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cht_wc_extcon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
|
||||
struct cht_wc_extcon_data *ext;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
|
||||
if (!ext)
|
||||
return -ENOMEM;
|
||||
|
||||
ext->dev = &pdev->dev;
|
||||
ext->regmap = pmic->regmap;
|
||||
ext->previous_cable = EXTCON_NONE;
|
||||
|
||||
/* Initialize extcon device */
|
||||
ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
|
||||
if (IS_ERR(ext->edev))
|
||||
return PTR_ERR(ext->edev);
|
||||
|
||||
/*
|
||||
* When a host-cable is detected the BIOS enables an external 5v boost
|
||||
* converter to power connected devices there are 2 problems with this:
|
||||
* 1) This gets seen by the external battery charger as a valid Vbus
|
||||
* supply and it then tries to feed Vsys from this creating a
|
||||
* feedback loop which causes aprox. 300 mA extra battery drain
|
||||
* (and unless we drive the external-charger-disable pin high it
|
||||
* also tries to charge the battery causing even more feedback).
|
||||
* 2) This gets seen by the pwrsrc block as a SDP USB Vbus supply
|
||||
* Since the external battery charger has its own 5v boost converter
|
||||
* which does not have these issues, we simply turn the separate
|
||||
* external 5v boost converter off and leave it off entirely.
|
||||
*/
|
||||
cht_wc_extcon_set_5v_boost(ext, false);
|
||||
|
||||
/* Enable sw control */
|
||||
ret = cht_wc_extcon_sw_control(ext, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register extcon device */
|
||||
ret = devm_extcon_dev_register(ext->dev, ext->edev);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error registering extcon device: %d\n", ret);
|
||||
goto disable_sw_control;
|
||||
}
|
||||
|
||||
/* Route D+ and D- to PMIC for initial charger detection */
|
||||
cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
|
||||
|
||||
/* Get initial state */
|
||||
cht_wc_extcon_pwrsrc_event(ext);
|
||||
|
||||
ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
|
||||
IRQF_ONESHOT, pdev->name, ext);
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error requesting interrupt: %d\n", ret);
|
||||
goto disable_sw_control;
|
||||
}
|
||||
|
||||
/* Unmask irqs */
|
||||
ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
|
||||
(int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
|
||||
CHT_WC_PWRSRC_ID_FLOAT));
|
||||
if (ret) {
|
||||
dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
|
||||
goto disable_sw_control;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ext);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_sw_control:
|
||||
cht_wc_extcon_sw_control(ext, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cht_wc_extcon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
|
||||
|
||||
cht_wc_extcon_sw_control(ext, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id cht_wc_extcon_table[] = {
|
||||
{ .name = "cht_wcove_pwrsrc" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
|
||||
|
||||
static struct platform_driver cht_wc_extcon_driver = {
|
||||
.probe = cht_wc_extcon_probe,
|
||||
.remove = cht_wc_extcon_remove,
|
||||
.id_table = cht_wc_extcon_table,
|
||||
.driver = {
|
||||
.name = "cht_wcove_pwrsrc",
|
||||
},
|
||||
};
|
||||
module_platform_driver(cht_wc_extcon_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -413,6 +413,12 @@ static int palmas_usb_resume(struct device *dev)
|
|||
if (palmas_usb->enable_gpio_id_detection)
|
||||
disable_irq_wake(palmas_usb->gpio_id_irq);
|
||||
}
|
||||
|
||||
/* check if GPIO states changed while suspend/resume */
|
||||
if (palmas_usb->enable_gpio_vbus_detection)
|
||||
palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb);
|
||||
palmas_gpio_id_detect(&palmas_usb->wq_detectid.work);
|
||||
|
||||
return 0;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#define USB_GPIO_DEBOUNCE_MS 20 /* ms */
|
||||
|
@ -111,7 +110,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
|
|||
struct usb_extcon_info *info;
|
||||
int ret;
|
||||
|
||||
if (!np && !ACPI_HANDLE(dev))
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
|
@ -195,7 +194,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_init_wakeup(dev, true);
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
|
||||
/* Perform initial detection */
|
||||
usb_extcon_detect_cable(&info->wq_detcable.work);
|
||||
|
@ -282,9 +281,8 @@ static int usb_extcon_resume(struct device *dev)
|
|||
if (info->vbus_gpiod)
|
||||
enable_irq(info->vbus_irq);
|
||||
|
||||
if (!device_may_wakeup(dev))
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&info->wq_detcable, 0);
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&info->wq_detcable, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -230,9 +230,6 @@ struct extcon_cable {
|
|||
};
|
||||
|
||||
static struct class *extcon_class;
|
||||
#if defined(CONFIG_ANDROID)
|
||||
static struct class_compat *switch_class;
|
||||
#endif /* CONFIG_ANDROID */
|
||||
|
||||
static LIST_HEAD(extcon_dev_list);
|
||||
static DEFINE_MUTEX(extcon_dev_list_lock);
|
||||
|
@ -380,7 +377,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
|
|||
for (i = 0; i < edev->max_supported; i++) {
|
||||
count += sprintf(buf + count, "%s=%d\n",
|
||||
extcon_info[edev->supported_cable[i]].name,
|
||||
!!(edev->state & (1 << i)));
|
||||
!!(edev->state & BIT(i)));
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -448,8 +445,19 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id)
|
|||
spin_lock_irqsave(&edev->lock, flags);
|
||||
|
||||
state = !!(edev->state & BIT(index));
|
||||
|
||||
/*
|
||||
* Call functions in a raw notifier chain for the specific one
|
||||
* external connector.
|
||||
*/
|
||||
raw_notifier_call_chain(&edev->nh[index], state, edev);
|
||||
|
||||
/*
|
||||
* Call functions in a raw notifier chain for the all supported
|
||||
* external connectors.
|
||||
*/
|
||||
raw_notifier_call_chain(&edev->nh_all, state, edev);
|
||||
|
||||
/* This could be in interrupt handler */
|
||||
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
|
||||
if (!prop_buf) {
|
||||
|
@ -954,6 +962,59 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
|
||||
|
||||
/**
|
||||
* extcon_register_notifier_all() - Register a notifier block for all connectors
|
||||
* @edev: the extcon device that has the external connecotr.
|
||||
* @nb: a notifier block to be registered.
|
||||
*
|
||||
* This fucntion registers a notifier block in order to receive the state
|
||||
* change of all supported external connectors from extcon device.
|
||||
* And The second parameter given to the callback of nb (val) is
|
||||
* the current state and third parameter is the edev pointer.
|
||||
*
|
||||
* Returns 0 if success or error number if fail
|
||||
*/
|
||||
int extcon_register_notifier_all(struct extcon_dev *edev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!edev || !nb)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&edev->lock, flags);
|
||||
ret = raw_notifier_chain_register(&edev->nh_all, nb);
|
||||
spin_unlock_irqrestore(&edev->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_register_notifier_all);
|
||||
|
||||
/**
|
||||
* extcon_unregister_notifier_all() - Unregister a notifier block from extcon.
|
||||
* @edev: the extcon device that has the external connecotr.
|
||||
* @nb: a notifier block to be registered.
|
||||
*
|
||||
* Returns 0 if success or error number if fail
|
||||
*/
|
||||
int extcon_unregister_notifier_all(struct extcon_dev *edev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!edev || !nb)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&edev->lock, flags);
|
||||
ret = raw_notifier_chain_unregister(&edev->nh_all, nb);
|
||||
spin_unlock_irqrestore(&edev->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all);
|
||||
|
||||
static struct attribute *extcon_attrs[] = {
|
||||
&dev_attr_state.attr,
|
||||
&dev_attr_name.attr,
|
||||
|
@ -968,12 +1029,6 @@ static int create_extcon_class(void)
|
|||
if (IS_ERR(extcon_class))
|
||||
return PTR_ERR(extcon_class);
|
||||
extcon_class->dev_groups = extcon_groups;
|
||||
|
||||
#if defined(CONFIG_ANDROID)
|
||||
switch_class = class_compat_register("switch");
|
||||
if (WARN(!switch_class, "cannot allocate"))
|
||||
return -ENOMEM;
|
||||
#endif /* CONFIG_ANDROID */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1195,10 +1250,6 @@ int extcon_dev_register(struct extcon_dev *edev)
|
|||
put_device(&edev->dev);
|
||||
goto err_dev;
|
||||
}
|
||||
#if defined(CONFIG_ANDROID)
|
||||
if (switch_class)
|
||||
ret = class_compat_create_link(switch_class, &edev->dev, NULL);
|
||||
#endif /* CONFIG_ANDROID */
|
||||
|
||||
spin_lock_init(&edev->lock);
|
||||
|
||||
|
@ -1212,6 +1263,8 @@ int extcon_dev_register(struct extcon_dev *edev)
|
|||
for (index = 0; index < edev->max_supported; index++)
|
||||
RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
|
||||
|
||||
RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);
|
||||
|
||||
dev_set_drvdata(&edev->dev, edev);
|
||||
edev->state = 0;
|
||||
|
||||
|
@ -1284,10 +1337,6 @@ void extcon_dev_unregister(struct extcon_dev *edev)
|
|||
kfree(edev->cables);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ANDROID)
|
||||
if (switch_class)
|
||||
class_compat_remove_link(switch_class, &edev->dev, NULL);
|
||||
#endif
|
||||
put_device(&edev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
|
||||
|
@ -1358,9 +1407,6 @@ module_init(extcon_class_init);
|
|||
|
||||
static void __exit extcon_class_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_ANDROID)
|
||||
class_compat_unregister(switch_class);
|
||||
#endif
|
||||
class_destroy(extcon_class);
|
||||
}
|
||||
module_exit(extcon_class_exit);
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
* @dev: Device of this extcon.
|
||||
* @state: Attach/detach state of this extcon. Do not provide at
|
||||
* register-time.
|
||||
* @nh_all: Notifier for the state change events for all supported
|
||||
* external connectors from this extcon.
|
||||
* @nh: Notifier for the state change events from this extcon
|
||||
* @entry: To support list of extcon devices so that users can
|
||||
* search for extcon devices based on the extcon name.
|
||||
|
@ -43,6 +45,7 @@ struct extcon_dev {
|
|||
|
||||
/* Internal data. Please do not set. */
|
||||
struct device dev;
|
||||
struct raw_notifier_head nh_all;
|
||||
struct raw_notifier_head *nh;
|
||||
struct list_head entry;
|
||||
int max_supported;
|
||||
|
|
|
@ -236,11 +236,11 @@ extern int extcon_set_property_capability(struct extcon_dev *edev,
|
|||
unsigned int id, unsigned int prop);
|
||||
|
||||
/*
|
||||
* Following APIs are to monitor every action of a notifier.
|
||||
* Registrar gets notified for every external port of a connection device.
|
||||
* Probably this could be used to debug an action of notifier; however,
|
||||
* we do not recommend to use this for normal 'notifiee' device drivers who
|
||||
* want to be notified by a specific external port of the notifier.
|
||||
* Following APIs are to monitor the status change of the external connectors.
|
||||
* extcon_register_notifier(*edev, id, *nb) : Register a notifier block
|
||||
* for specific external connector of the extcon.
|
||||
* extcon_register_notifier_all(*edev, *nb) : Register a notifier block
|
||||
* for all supported external connectors of the extcon.
|
||||
*/
|
||||
extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
|
||||
struct notifier_block *nb);
|
||||
|
@ -253,6 +253,17 @@ extern void devm_extcon_unregister_notifier(struct device *dev,
|
|||
struct extcon_dev *edev, unsigned int id,
|
||||
struct notifier_block *nb);
|
||||
|
||||
extern int extcon_register_notifier_all(struct extcon_dev *edev,
|
||||
struct notifier_block *nb);
|
||||
extern int extcon_unregister_notifier_all(struct extcon_dev *edev,
|
||||
struct notifier_block *nb);
|
||||
extern int devm_extcon_register_notifier_all(struct device *dev,
|
||||
struct extcon_dev *edev,
|
||||
struct notifier_block *nb);
|
||||
extern void devm_extcon_unregister_notifier_all(struct device *dev,
|
||||
struct extcon_dev *edev,
|
||||
struct notifier_block *nb);
|
||||
|
||||
/*
|
||||
* Following API get the extcon device from devicetree.
|
||||
* This function use phandle of devicetree to get extcon device directly.
|
||||
|
|
Loading…
Reference in New Issue