Merge branch 'ib-extcon-drm-dt-v4.17' into extcon-next
This commit is contained in:
commit
eb7768e774
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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,12 +2379,19 @@ 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);
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue