Update extcon for 4.17
Detailed description for this pull request: 1. Add exported extcon function in order to support OF graph binding - The extcon consumer driver used the "extcon = <&extcon's phandle" property in device-tree in order to bind between extcon provider and consumer driver. But, OF graph method is better than 'extcon' property. So, extcon subsystem adds the following function to support OF graph binding. : extcon_find_edev_by_node(struct device_node *node) - Create the immutable branch ("ib-extcon-drm-dt-v4.17") for both drm-misc and device-tree subsystem. This immutable branch contains the use-case of OF graph binding for EXTCON_HDMI connector between MHL device driver and extcon provider driver. 2. Fix minor issues of extcon device drivers - Remove platform_data and covert to fully use GPIO descriptor for extcon-gpio.c - Remove workaround code for id pin direction from extcon-inte-int3496.c because GPIO ACPI library does support it with generic way. - Set direction and drv flags for V5 boost GPIO because of fixing the firmware bug. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJasefUAAoJEJzN3yze689TdjAQAIs5QC3qxLqsPVRUAUPBcWrg wsx9RSm7UF2RrSSDN1P01lPlVrlEepJds4n+EDbRNmKNjDvx9G3Ws6wktYXu5VES +1TPo1I3dmuMtFAcXc4IWxPehWSwGqHbl5UPg73lUz6Nkx2ycSeZCFTmi3yrgeOH EDBlAeHd63dKBbP9YQZjMMHxazFocT7xI3QAq4Xblm+jDXUXX4I3JVkeaDwC2QWP vmsZg6NRgRLrBxzoT/Z9Dqk7Jy2Xj9jAOYFbo3mIahH+wx1SLcfKCJiWrJgT8G8y WoTlP1bsfvw+a4bTDh6PsKcqvSSk4D1iJrS/hsp9yJchQjnvDPFGgnyNjNcylA45 g8AnqBGelEEavJfQJahjMObB7Kdr9my5e8Y0nDK5LI+u+hm5bYMdmldripZC0qak LUTtgxTamShkdZ3Cu9alq3d90yqXu6CJRZP482jFtHUjWnzihKLi0JoHD8QaVMCK jIQHNQHQ/Uu0J0DYvArrbyjWlRYyrNNxywuqXMZQoxd/XhzzjW7La9Wv174UPTqD 6tFQN50HkGQkj/Hj8A1oA3vKSrVbiG3TvrDlWr3gmP57Ni6qqrLsF9nqDZmyyuVN lLO8Hqm35W4xtutZwKdSn/d0A99hSDNoqroGprvdFeUvR0NYPCRDEUnZfl1ML15P PBlJixTADCekzpy8bGFy =gEVD -----END PGP SIGNATURE----- Merge tag 'extcon-next-for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next Chanwoo writes: Update extcon for 4.17 Detailed description for this pull request: 1. Add exported extcon function in order to support OF graph binding - The extcon consumer driver used the "extcon = <&extcon's phandle" property in device-tree in order to bind between extcon provider and consumer driver. But, OF graph method is better than 'extcon' property. So, extcon subsystem adds the following function to support OF graph binding. : extcon_find_edev_by_node(struct device_node *node) - Create the immutable branch ("ib-extcon-drm-dt-v4.17") for both drm-misc and device-tree subsystem. This immutable branch contains the use-case of OF graph binding for EXTCON_HDMI connector between MHL device driver and extcon provider driver. 2. Fix minor issues of extcon device drivers - Remove platform_data and covert to fully use GPIO descriptor for extcon-gpio.c - Remove workaround code for id pin direction from extcon-inte-int3496.c because GPIO ACPI library does support it with generic way. - Set direction and drv flags for V5 boost GPIO because of fixing the firmware bug.
This commit is contained in:
commit
c50099f856
|
@ -0,0 +1,49 @@
|
|||
Samsung micro-USB 11-pin connector
|
||||
==================================
|
||||
|
||||
Samsung micro-USB 11-pin connector is an extension of micro-USB connector.
|
||||
It is present in multiple Samsung mobile devices.
|
||||
It has additional pins to route MHL traffic simultanously with USB.
|
||||
|
||||
The bindings are superset of usb-connector bindings for micro-USB connector[1].
|
||||
|
||||
Required properties:
|
||||
- compatible: must be: "samsung,usb-connector-11pin", "usb-b-connector",
|
||||
- type: must be "micro".
|
||||
|
||||
Required nodes:
|
||||
- any data bus to the connector should be modeled using the OF graph bindings
|
||||
specified in bindings/graph.txt, unless the bus is between parent node and
|
||||
the connector. Since single connector can have multpile data buses every bus
|
||||
has assigned OF graph port number as follows:
|
||||
0: High Speed (HS),
|
||||
3: Mobile High-Definition Link (MHL), specific to 11-pin Samsung micro-USB.
|
||||
|
||||
[1]: bindings/connector/usb-connector.txt
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Micro-USB connector with HS lines routed via controller (MUIC) and MHL lines
|
||||
connected to HDMI-MHL bridge (sii8620):
|
||||
|
||||
muic-max77843@66 {
|
||||
...
|
||||
usb_con: connector {
|
||||
compatible = "samsung,usb-connector-11pin", "usb-b-connector";
|
||||
label = "micro-USB";
|
||||
type = "micro";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
usb_con_mhl: endpoint {
|
||||
remote-endpoint = <&sii8620_mhl>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,75 @@
|
|||
USB Connector
|
||||
=============
|
||||
|
||||
USB connector node represents physical USB connector. It should be
|
||||
a child of USB interface controller.
|
||||
|
||||
Required properties:
|
||||
- compatible: describes type of the connector, must be one of:
|
||||
"usb-a-connector",
|
||||
"usb-b-connector",
|
||||
"usb-c-connector".
|
||||
|
||||
Optional properties:
|
||||
- label: symbolic name for the connector,
|
||||
- type: size of the connector, should be specified in case of USB-A, USB-B
|
||||
non-fullsize connectors: "mini", "micro".
|
||||
|
||||
Required nodes:
|
||||
- any data bus to the connector should be modeled using the OF graph bindings
|
||||
specified in bindings/graph.txt, unless the bus is between parent node and
|
||||
the connector. Since single connector can have multpile data buses every bus
|
||||
has assigned OF graph port number as follows:
|
||||
0: High Speed (HS), present in all connectors,
|
||||
1: Super Speed (SS), present in SS capable connectors,
|
||||
2: Sideband use (SBU), present in USB-C.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
1. Micro-USB connector with HS lines routed via controller (MUIC):
|
||||
|
||||
muic-max77843@66 {
|
||||
...
|
||||
usb_con: connector {
|
||||
compatible = "usb-b-connector";
|
||||
label = "micro-USB";
|
||||
type = "micro";
|
||||
};
|
||||
};
|
||||
|
||||
2. USB-C connector attached to CC controller (s2mm005), HS lines routed
|
||||
to companion PMIC (max77865), SS lines to USB3 PHY and SBU to DisplayPort.
|
||||
DisplayPort video lines are routed to the connector via SS mux in USB3 PHY.
|
||||
|
||||
ccic: s2mm005@33 {
|
||||
...
|
||||
usb_con: connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
usb_con_hs: endpoint {
|
||||
remote-endpoint = <&max77865_usbc_hs>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
usb_con_ss: endpoint {
|
||||
remote-endpoint = <&usbdrd_phy_ss>;
|
||||
};
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
usb_con_sbu: endpoint {
|
||||
remote-endpoint = <&dp_aux>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/extcon/extcon-gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -29,14 +27,30 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/**
|
||||
* struct gpio_extcon_data - A simple GPIO-controlled extcon device state container.
|
||||
* @edev: Extcon device.
|
||||
* @irq: Interrupt line for the external connector.
|
||||
* @work: Work fired by the interrupt.
|
||||
* @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce
|
||||
* value.
|
||||
* @gpiod: GPIO descriptor for this external connector.
|
||||
* @extcon_id: The unique id of specific external connector.
|
||||
* @debounce: Debounce time for GPIO IRQ in ms.
|
||||
* @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
|
||||
* @check_on_resume: Boolean describing whether to check the state of gpio
|
||||
* while resuming from sleep.
|
||||
*/
|
||||
struct gpio_extcon_data {
|
||||
struct extcon_dev *edev;
|
||||
int irq;
|
||||
struct delayed_work work;
|
||||
unsigned long debounce_jiffies;
|
||||
|
||||
struct gpio_desc *id_gpiod;
|
||||
struct gpio_extcon_pdata *pdata;
|
||||
struct gpio_desc *gpiod;
|
||||
unsigned int extcon_id;
|
||||
unsigned long debounce;
|
||||
unsigned long irq_flags;
|
||||
bool check_on_resume;
|
||||
};
|
||||
|
||||
static void gpio_extcon_work(struct work_struct *work)
|
||||
|
@ -46,11 +60,8 @@ static void gpio_extcon_work(struct work_struct *work)
|
|||
container_of(to_delayed_work(work), struct gpio_extcon_data,
|
||||
work);
|
||||
|
||||
state = gpiod_get_value_cansleep(data->id_gpiod);
|
||||
if (data->pdata->gpio_active_low)
|
||||
state = !state;
|
||||
|
||||
extcon_set_state_sync(data->edev, data->pdata->extcon_id, state);
|
||||
state = gpiod_get_value_cansleep(data->gpiod);
|
||||
extcon_set_state_sync(data->edev, data->extcon_id, state);
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
|
||||
|
@ -62,65 +73,41 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
|
|||
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_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct gpio_extcon_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!pdata)
|
||||
return -EBUSY;
|
||||
if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct gpio_extcon_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->pdata = pdata;
|
||||
|
||||
/* Initialize the gpio */
|
||||
ret = gpio_extcon_init(&pdev->dev, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* FIXME: extcon_id represents the unique identifier of external
|
||||
* connectors such as EXTCON_USB, EXTCON_DISP_HDMI and so on. extcon_id
|
||||
* is necessary to register the extcon device. But, it's not yet
|
||||
* developed to get the extcon id from device-tree or others.
|
||||
* On later, it have to be solved.
|
||||
*/
|
||||
if (!data->irq_flags || data->extcon_id > EXTCON_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
data->gpiod = devm_gpiod_get(dev, "extcon", GPIOD_IN);
|
||||
if (IS_ERR(data->gpiod))
|
||||
return PTR_ERR(data->gpiod);
|
||||
data->irq = gpiod_to_irq(data->gpiod);
|
||||
if (data->irq <= 0)
|
||||
return data->irq;
|
||||
|
||||
/* Allocate the memory of extcon devie and register extcon device */
|
||||
data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id);
|
||||
data->edev = devm_extcon_dev_allocate(dev, &data->extcon_id);
|
||||
if (IS_ERR(data->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||
dev_err(dev, "failed to allocate extcon device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, data->edev);
|
||||
ret = devm_extcon_dev_register(dev, data->edev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -130,8 +117,8 @@ static int gpio_extcon_probe(struct platform_device *pdev)
|
|||
* Request the interrupt 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,
|
||||
ret = devm_request_any_context_irq(dev, data->irq,
|
||||
gpio_irq_handler, data->irq_flags,
|
||||
pdev->name, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -158,7 +145,7 @@ static int gpio_extcon_resume(struct device *dev)
|
|||
struct gpio_extcon_data *data;
|
||||
|
||||
data = dev_get_drvdata(dev);
|
||||
if (data->pdata->check_on_resume)
|
||||
if (data->check_on_resume)
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&data->work, data->debounce_jiffies);
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
|
||||
#define CHT_WC_VBUS_GPIO_CTLO 0x6e2d
|
||||
#define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0)
|
||||
#define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4)
|
||||
#define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5)
|
||||
|
||||
enum cht_wc_usb_id {
|
||||
USB_ID_OTG,
|
||||
|
@ -183,14 +185,15 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext,
|
|||
{
|
||||
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);
|
||||
val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT;
|
||||
if (enable)
|
||||
val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT;
|
||||
|
||||
ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val);
|
||||
if (ret)
|
||||
dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,11 @@ static const struct acpi_gpio_params vbus_gpios = { INT3496_GPIO_VBUS_EN, 0, fal
|
|||
static const struct acpi_gpio_params mux_gpios = { INT3496_GPIO_USB_MUX, 0, false };
|
||||
|
||||
static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
|
||||
{ "id-gpios", &id_gpios, 1 },
|
||||
/*
|
||||
* Some platforms have a bug in ACPI GPIO description making IRQ
|
||||
* GPIO to be output only. Ask the GPIO core to ignore this limit.
|
||||
*/
|
||||
{ "id-gpios", &id_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION },
|
||||
{ "vbus-gpios", &vbus_gpios, 1 },
|
||||
{ "mux-gpios", &mux_gpios, 1 },
|
||||
{ },
|
||||
|
@ -112,9 +116,6 @@ static int int3496_probe(struct platform_device *pdev)
|
|||
ret = PTR_ERR(data->gpio_usb_id);
|
||||
dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
|
||||
return ret;
|
||||
} else if (gpiod_get_direction(data->gpio_usb_id) != GPIOF_DIR_IN) {
|
||||
dev_warn(dev, FW_BUG "USB ID GPIO not in input mode, fixing\n");
|
||||
gpiod_direction_input(data->gpio_usb_id);
|
||||
}
|
||||
|
||||
data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id);
|
||||
|
|
|
@ -1336,6 +1336,28 @@ void extcon_dev_unregister(struct extcon_dev *edev)
|
|||
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
/*
|
||||
* extcon_find_edev_by_node - Find the extcon device from devicetree.
|
||||
* @node : OF node identifying edev
|
||||
*
|
||||
* Return the pointer of extcon device if success or ERR_PTR(err) if fail.
|
||||
*/
|
||||
struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
|
||||
{
|
||||
struct extcon_dev *edev;
|
||||
|
||||
mutex_lock(&extcon_dev_list_lock);
|
||||
list_for_each_entry(edev, &extcon_dev_list, entry)
|
||||
if (edev->dev.parent && edev->dev.parent->of_node == node)
|
||||
goto out;
|
||||
edev = ERR_PTR(-EPROBE_DEFER);
|
||||
out:
|
||||
mutex_unlock(&extcon_dev_list_lock);
|
||||
|
||||
return edev;
|
||||
}
|
||||
|
||||
/*
|
||||
* extcon_get_edev_by_phandle - Get the extcon device from devicetree.
|
||||
* @dev : the instance to the given device
|
||||
|
@ -1363,25 +1385,27 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
|
|||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
mutex_lock(&extcon_dev_list_lock);
|
||||
list_for_each_entry(edev, &extcon_dev_list, entry) {
|
||||
if (edev->dev.parent && edev->dev.parent->of_node == node) {
|
||||
mutex_unlock(&extcon_dev_list_lock);
|
||||
of_node_put(node);
|
||||
return edev;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&extcon_dev_list_lock);
|
||||
edev = extcon_find_edev_by_node(node);
|
||||
of_node_put(node);
|
||||
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
return edev;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
EXPORT_SYMBOL_GPL(extcon_find_edev_by_node);
|
||||
EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -81,6 +83,10 @@ struct sii8620 {
|
|||
struct edid *edid;
|
||||
unsigned int gen2_write_burst:1;
|
||||
enum sii8620_mt_state mt_state;
|
||||
struct extcon_dev *extcon;
|
||||
struct notifier_block extcon_nb;
|
||||
struct work_struct extcon_wq;
|
||||
int cable_state;
|
||||
struct list_head mt_queue;
|
||||
struct {
|
||||
int r_size;
|
||||
|
@ -2170,6 +2176,77 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx)
|
|||
ctx->rc_dev = rc_dev;
|
||||
}
|
||||
|
||||
static void sii8620_cable_out(struct sii8620 *ctx)
|
||||
{
|
||||
disable_irq(to_i2c_client(ctx->dev)->irq);
|
||||
sii8620_hw_off(ctx);
|
||||
}
|
||||
|
||||
static void sii8620_extcon_work(struct work_struct *work)
|
||||
{
|
||||
struct sii8620 *ctx =
|
||||
container_of(work, struct sii8620, extcon_wq);
|
||||
int state = extcon_get_state(ctx->extcon, EXTCON_DISP_MHL);
|
||||
|
||||
if (state == ctx->cable_state)
|
||||
return;
|
||||
|
||||
ctx->cable_state = state;
|
||||
|
||||
if (state > 0)
|
||||
sii8620_cable_in(ctx);
|
||||
else
|
||||
sii8620_cable_out(ctx);
|
||||
}
|
||||
|
||||
static int sii8620_extcon_notifier(struct notifier_block *self,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct sii8620 *ctx =
|
||||
container_of(self, struct sii8620, extcon_nb);
|
||||
|
||||
schedule_work(&ctx->extcon_wq);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int sii8620_extcon_init(struct sii8620 *ctx)
|
||||
{
|
||||
struct extcon_dev *edev;
|
||||
struct device_node *musb, *muic;
|
||||
int ret;
|
||||
|
||||
/* get micro-USB connector node */
|
||||
musb = of_graph_get_remote_node(ctx->dev->of_node, 1, -1);
|
||||
/* next get micro-USB Interface Controller node */
|
||||
muic = of_get_next_parent(musb);
|
||||
|
||||
if (!muic) {
|
||||
dev_info(ctx->dev, "no extcon found, switching to 'always on' mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
edev = extcon_find_edev_by_node(muic);
|
||||
of_node_put(muic);
|
||||
if (IS_ERR(edev)) {
|
||||
if (PTR_ERR(edev) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(ctx->dev, "Invalid or missing extcon\n");
|
||||
return PTR_ERR(edev);
|
||||
}
|
||||
|
||||
ctx->extcon = edev;
|
||||
ctx->extcon_nb.notifier_call = sii8620_extcon_notifier;
|
||||
INIT_WORK(&ctx->extcon_wq, sii8620_extcon_work);
|
||||
ret = extcon_register_notifier(edev, EXTCON_DISP_MHL, &ctx->extcon_nb);
|
||||
if (ret) {
|
||||
dev_err(ctx->dev, "failed to register notifier for MHL\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct sii8620, bridge);
|
||||
|
@ -2302,13 +2379,20 @@ static int sii8620_probe(struct i2c_client *client,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sii8620_extcon_init(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "failed to initialize EXTCON\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ctx);
|
||||
|
||||
ctx->bridge.funcs = &sii8620_bridge_funcs;
|
||||
ctx->bridge.of_node = dev->of_node;
|
||||
drm_bridge_add(&ctx->bridge);
|
||||
|
||||
sii8620_cable_in(ctx);
|
||||
if (!ctx->extcon)
|
||||
sii8620_cable_in(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2317,8 +2401,15 @@ static int sii8620_remove(struct i2c_client *client)
|
|||
{
|
||||
struct sii8620 *ctx = i2c_get_clientdata(client);
|
||||
|
||||
disable_irq(to_i2c_client(ctx->dev)->irq);
|
||||
sii8620_hw_off(ctx);
|
||||
if (ctx->extcon) {
|
||||
extcon_unregister_notifier(ctx->extcon, EXTCON_DISP_MHL,
|
||||
&ctx->extcon_nb);
|
||||
flush_work(&ctx->extcon_wq);
|
||||
if (ctx->cable_state > 0)
|
||||
sii8620_cable_out(ctx);
|
||||
} else {
|
||||
sii8620_cable_out(ctx);
|
||||
}
|
||||
drm_bridge_remove(&ctx->bridge);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -230,6 +230,7 @@ extern void devm_extcon_unregister_notifier_all(struct device *dev,
|
|||
* Following APIs get the extcon_dev from devicetree or by through extcon name.
|
||||
*/
|
||||
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
|
||||
extern struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
|
||||
extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
|
||||
int index);
|
||||
|
||||
|
@ -283,6 +284,11 @@ static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
|
|||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
|
||||
int index)
|
||||
{
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Single-state GPIO extcon driver based on extcon class
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* Author: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
*
|
||||
* based on switch class driver
|
||||
* Copyright (C) 2008 Google, Inc.
|
||||
* Author: Mike Lockwood <lockwood@android.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*/
|
||||
#ifndef __EXTCON_GPIO_H__
|
||||
#define __EXTCON_GPIO_H__ __FILE__
|
||||
|
||||
#include <linux/extcon.h>
|
||||
|
||||
/**
|
||||
* struct gpio_extcon_pdata - A simple GPIO-controlled extcon device.
|
||||
* @extcon_id: The unique id of specific external connector.
|
||||
* @gpio: Corresponding GPIO.
|
||||
* @gpio_active_low: Boolean describing whether gpio active state is 1 or 0
|
||||
* If true, low state of gpio means active.
|
||||
* If false, high state of gpio means active.
|
||||
* @debounce: Debounce time for GPIO IRQ in ms.
|
||||
* @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
|
||||
* @check_on_resume: Boolean describing whether to check the state of gpio
|
||||
* while resuming from sleep.
|
||||
*/
|
||||
struct gpio_extcon_pdata {
|
||||
unsigned int extcon_id;
|
||||
unsigned gpio;
|
||||
bool gpio_active_low;
|
||||
unsigned long debounce;
|
||||
unsigned long irq_flags;
|
||||
|
||||
bool check_on_resume;
|
||||
};
|
||||
|
||||
#endif /* __EXTCON_GPIO_H__ */
|
Loading…
Reference in New Issue