Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
15dec834
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
15dec834
编写于
7月 17, 2017
作者:
C
Chanwoo Choi
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'origin/ib-extcon-mfd-4.14' into extcon-next
上级
ff890bc0
a8a5549f
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
522 addition
and
0 deletion
+522
-0
Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.txt
...tation/devicetree/bindings/extcon/extcon-usbc-cros-ec.txt
+24
-0
drivers/extcon/Kconfig
drivers/extcon/Kconfig
+7
-0
drivers/extcon/Makefile
drivers/extcon/Makefile
+1
-0
drivers/extcon/extcon-usbc-cros-ec.c
drivers/extcon/extcon-usbc-cros-ec.c
+415
-0
include/linux/mfd/cros_ec_commands.h
include/linux/mfd/cros_ec_commands.h
+75
-0
未找到文件。
Documentation/devicetree/bindings/extcon/extcon-usbc-cros-ec.txt
0 → 100644
浏览文件 @
15dec834
ChromeOS EC USB Type-C cable and accessories detection
On ChromeOS systems with USB Type C ports, the ChromeOS Embedded Controller is
able to detect the state of external accessories such as display adapters
or USB devices when said accessories are attached or detached.
The node for this device must be under a cros-ec node like google,cros-ec-spi
or google,cros-ec-i2c.
Required properties:
- compatible: Should be "google,extcon-usbc-cros-ec".
- google,usb-port-id: Specifies the USB port ID to use.
Example:
cros-ec@0 {
compatible = "google,cros-ec-i2c";
...
extcon {
compatible = "google,extcon-usbc-cros-ec";
google,usb-port-id = <0>;
};
}
drivers/extcon/Kconfig
浏览文件 @
15dec834
...
...
@@ -150,4 +150,11 @@ config EXTCON_USB_GPIO
Say Y here to enable GPIO based USB cable detection extcon support.
Used typically if GPIO is used for USB ID pin detection.
config EXTCON_USBC_CROS_EC
tristate "ChromeOS Embedded Controller EXTCON support"
depends on MFD_CROS_EC
help
Say Y here to enable USB Type C cable detection extcon support when
using Chrome OS EC based USB Type-C ports.
endif
drivers/extcon/Makefile
浏览文件 @
15dec834
...
...
@@ -20,3 +20,4 @@ obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o
obj-$(CONFIG_EXTCON_RT8973A)
+=
extcon-rt8973a.o
obj-$(CONFIG_EXTCON_SM5502)
+=
extcon-sm5502.o
obj-$(CONFIG_EXTCON_USB_GPIO)
+=
extcon-usb-gpio.o
obj-$(CONFIG_EXTCON_USBC_CROS_EC)
+=
extcon-usbc-cros-ec.o
drivers/extcon/extcon-usbc-cros-ec.c
0 → 100644
浏览文件 @
15dec834
/**
* drivers/extcon/extcon-usbc-cros-ec - ChromeOS Embedded Controller extcon
*
* Copyright (C) 2017 Google, Inc
* Author: Benson Leung <bleung@chromium.org>
*
* 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.
*/
#include <linux/extcon.h>
#include <linux/kernel.h>
#include <linux/mfd/cros_ec.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sched.h>
struct
cros_ec_extcon_info
{
struct
device
*
dev
;
struct
extcon_dev
*
edev
;
int
port_id
;
struct
cros_ec_device
*
ec
;
struct
notifier_block
notifier
;
bool
dp
;
/* DisplayPort enabled */
bool
mux
;
/* SuperSpeed (usb3) enabled */
unsigned
int
power_type
;
};
static
const
unsigned
int
usb_type_c_cable
[]
=
{
EXTCON_DISP_DP
,
EXTCON_NONE
,
};
/**
* cros_ec_pd_command() - Send a command to the EC.
* @info: pointer to struct cros_ec_extcon_info
* @command: EC command
* @version: EC command version
* @outdata: EC command output data
* @outsize: Size of outdata
* @indata: EC command input data
* @insize: Size of indata
*
* Return: 0 on success, <0 on failure.
*/
static
int
cros_ec_pd_command
(
struct
cros_ec_extcon_info
*
info
,
unsigned
int
command
,
unsigned
int
version
,
void
*
outdata
,
unsigned
int
outsize
,
void
*
indata
,
unsigned
int
insize
)
{
struct
cros_ec_command
*
msg
;
int
ret
;
msg
=
kzalloc
(
sizeof
(
*
msg
)
+
max
(
outsize
,
insize
),
GFP_KERNEL
);
msg
->
version
=
version
;
msg
->
command
=
command
;
msg
->
outsize
=
outsize
;
msg
->
insize
=
insize
;
if
(
outsize
)
memcpy
(
msg
->
data
,
outdata
,
outsize
);
ret
=
cros_ec_cmd_xfer_status
(
info
->
ec
,
msg
);
if
(
ret
>=
0
&&
insize
)
memcpy
(
indata
,
msg
->
data
,
insize
);
kfree
(
msg
);
return
ret
;
}
/**
* cros_ec_usb_get_power_type() - Get power type info about PD device attached
* to given port.
* @info: pointer to struct cros_ec_extcon_info
*
* Return: power type on success, <0 on failure.
*/
static
int
cros_ec_usb_get_power_type
(
struct
cros_ec_extcon_info
*
info
)
{
struct
ec_params_usb_pd_power_info
req
;
struct
ec_response_usb_pd_power_info
resp
;
int
ret
;
req
.
port
=
info
->
port_id
;
ret
=
cros_ec_pd_command
(
info
,
EC_CMD_USB_PD_POWER_INFO
,
0
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
));
if
(
ret
<
0
)
return
ret
;
return
resp
.
type
;
}
/**
* cros_ec_usb_get_pd_mux_state() - Get PD mux state for given port.
* @info: pointer to struct cros_ec_extcon_info
*
* Return: PD mux state on success, <0 on failure.
*/
static
int
cros_ec_usb_get_pd_mux_state
(
struct
cros_ec_extcon_info
*
info
)
{
struct
ec_params_usb_pd_mux_info
req
;
struct
ec_response_usb_pd_mux_info
resp
;
int
ret
;
req
.
port
=
info
->
port_id
;
ret
=
cros_ec_pd_command
(
info
,
EC_CMD_USB_PD_MUX_INFO
,
0
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
));
if
(
ret
<
0
)
return
ret
;
return
resp
.
flags
;
}
/**
* cros_ec_usb_get_role() - Get role info about possible PD device attached to a
* given port.
* @info: pointer to struct cros_ec_extcon_info
* @polarity: pointer to cable polarity (return value)
*
* Return: role info on success, -ENOTCONN if no cable is connected, <0 on
* failure.
*/
static
int
cros_ec_usb_get_role
(
struct
cros_ec_extcon_info
*
info
,
bool
*
polarity
)
{
struct
ec_params_usb_pd_control
pd_control
;
struct
ec_response_usb_pd_control_v1
resp
;
int
ret
;
pd_control
.
port
=
info
->
port_id
;
pd_control
.
role
=
USB_PD_CTRL_ROLE_NO_CHANGE
;
pd_control
.
mux
=
USB_PD_CTRL_MUX_NO_CHANGE
;
ret
=
cros_ec_pd_command
(
info
,
EC_CMD_USB_PD_CONTROL
,
1
,
&
pd_control
,
sizeof
(
pd_control
),
&
resp
,
sizeof
(
resp
));
if
(
ret
<
0
)
return
ret
;
if
(
!
(
resp
.
enabled
&
PD_CTRL_RESP_ENABLED_CONNECTED
))
return
-
ENOTCONN
;
*
polarity
=
resp
.
polarity
;
return
resp
.
role
;
}
/**
* cros_ec_pd_get_num_ports() - Get number of EC charge ports.
* @info: pointer to struct cros_ec_extcon_info
*
* Return: number of ports on success, <0 on failure.
*/
static
int
cros_ec_pd_get_num_ports
(
struct
cros_ec_extcon_info
*
info
)
{
struct
ec_response_usb_pd_ports
resp
;
int
ret
;
ret
=
cros_ec_pd_command
(
info
,
EC_CMD_USB_PD_PORTS
,
0
,
NULL
,
0
,
&
resp
,
sizeof
(
resp
));
if
(
ret
<
0
)
return
ret
;
return
resp
.
num_ports
;
}
static
int
extcon_cros_ec_detect_cable
(
struct
cros_ec_extcon_info
*
info
,
bool
force
)
{
struct
device
*
dev
=
info
->
dev
;
int
role
,
power_type
;
bool
polarity
=
false
;
bool
dp
=
false
;
bool
mux
=
false
;
bool
hpd
=
false
;
power_type
=
cros_ec_usb_get_power_type
(
info
);
if
(
power_type
<
0
)
{
dev_err
(
dev
,
"failed getting power type err = %d
\n
"
,
power_type
);
return
power_type
;
}
role
=
cros_ec_usb_get_role
(
info
,
&
polarity
);
if
(
role
<
0
)
{
if
(
role
!=
-
ENOTCONN
)
{
dev_err
(
dev
,
"failed getting role err = %d
\n
"
,
role
);
return
role
;
}
}
else
{
int
pd_mux_state
;
pd_mux_state
=
cros_ec_usb_get_pd_mux_state
(
info
);
if
(
pd_mux_state
<
0
)
pd_mux_state
=
USB_PD_MUX_USB_ENABLED
;
dp
=
pd_mux_state
&
USB_PD_MUX_DP_ENABLED
;
mux
=
pd_mux_state
&
USB_PD_MUX_USB_ENABLED
;
hpd
=
pd_mux_state
&
USB_PD_MUX_HPD_IRQ
;
}
if
(
force
||
info
->
dp
!=
dp
||
info
->
mux
!=
mux
||
info
->
power_type
!=
power_type
)
{
info
->
dp
=
dp
;
info
->
mux
=
mux
;
info
->
power_type
=
power_type
;
extcon_set_state
(
info
->
edev
,
EXTCON_DISP_DP
,
dp
);
extcon_set_property
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_USB_TYPEC_POLARITY
,
(
union
extcon_property_value
)(
int
)
polarity
);
extcon_set_property
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_USB_SS
,
(
union
extcon_property_value
)(
int
)
mux
);
extcon_set_property
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_DISP_HPD
,
(
union
extcon_property_value
)(
int
)
hpd
);
extcon_sync
(
info
->
edev
,
EXTCON_DISP_DP
);
}
else
if
(
hpd
)
{
extcon_set_property
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_DISP_HPD
,
(
union
extcon_property_value
)(
int
)
hpd
);
extcon_sync
(
info
->
edev
,
EXTCON_DISP_DP
);
}
return
0
;
}
static
int
extcon_cros_ec_event
(
struct
notifier_block
*
nb
,
unsigned
long
queued_during_suspend
,
void
*
_notify
)
{
struct
cros_ec_extcon_info
*
info
;
struct
cros_ec_device
*
ec
;
u32
host_event
;
info
=
container_of
(
nb
,
struct
cros_ec_extcon_info
,
notifier
);
ec
=
info
->
ec
;
host_event
=
cros_ec_get_host_event
(
ec
);
if
(
host_event
&
(
EC_HOST_EVENT_MASK
(
EC_HOST_EVENT_PD_MCU
)
|
EC_HOST_EVENT_MASK
(
EC_HOST_EVENT_USB_MUX
)))
{
extcon_cros_ec_detect_cable
(
info
,
false
);
return
NOTIFY_OK
;
}
return
NOTIFY_DONE
;
}
static
int
extcon_cros_ec_probe
(
struct
platform_device
*
pdev
)
{
struct
cros_ec_extcon_info
*
info
;
struct
cros_ec_device
*
ec
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
device
*
dev
=
&
pdev
->
dev
;
struct
device_node
*
np
=
dev
->
of_node
;
int
numports
,
ret
;
info
=
devm_kzalloc
(
dev
,
sizeof
(
*
info
),
GFP_KERNEL
);
if
(
!
info
)
return
-
ENOMEM
;
info
->
dev
=
dev
;
info
->
ec
=
ec
;
if
(
np
)
{
u32
port
;
ret
=
of_property_read_u32
(
np
,
"google,usb-port-id"
,
&
port
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Missing google,usb-port-id property
\n
"
);
return
ret
;
}
info
->
port_id
=
port
;
}
else
{
info
->
port_id
=
pdev
->
id
;
}
numports
=
cros_ec_pd_get_num_ports
(
info
);
if
(
numports
<
0
)
{
dev_err
(
dev
,
"failed getting number of ports! ret = %d
\n
"
,
numports
);
return
numports
;
}
if
(
info
->
port_id
>=
numports
)
{
dev_err
(
dev
,
"This system only supports %d ports
\n
"
,
numports
);
return
-
ENODEV
;
}
info
->
edev
=
devm_extcon_dev_allocate
(
dev
,
usb_type_c_cable
);
if
(
IS_ERR
(
info
->
edev
))
{
dev_err
(
dev
,
"failed to allocate extcon device
\n
"
);
return
-
ENOMEM
;
}
ret
=
devm_extcon_dev_register
(
dev
,
info
->
edev
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to register extcon device
\n
"
);
return
ret
;
}
extcon_set_property_capability
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_USB_TYPEC_POLARITY
);
extcon_set_property_capability
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_USB_SS
);
extcon_set_property_capability
(
info
->
edev
,
EXTCON_DISP_DP
,
EXTCON_PROP_DISP_HPD
);
platform_set_drvdata
(
pdev
,
info
);
/* Get PD events from the EC */
info
->
notifier
.
notifier_call
=
extcon_cros_ec_event
;
ret
=
blocking_notifier_chain_register
(
&
info
->
ec
->
event_notifier
,
&
info
->
notifier
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to register notifier
\n
"
);
return
ret
;
}
/* Perform initial detection */
ret
=
extcon_cros_ec_detect_cable
(
info
,
true
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to detect initial cable state
\n
"
);
goto
unregister_notifier
;
}
return
0
;
unregister_notifier:
blocking_notifier_chain_unregister
(
&
info
->
ec
->
event_notifier
,
&
info
->
notifier
);
return
ret
;
}
static
int
extcon_cros_ec_remove
(
struct
platform_device
*
pdev
)
{
struct
cros_ec_extcon_info
*
info
=
platform_get_drvdata
(
pdev
);
blocking_notifier_chain_unregister
(
&
info
->
ec
->
event_notifier
,
&
info
->
notifier
);
return
0
;
}
#ifdef CONFIG_PM_SLEEP
static
int
extcon_cros_ec_suspend
(
struct
device
*
dev
)
{
return
0
;
}
static
int
extcon_cros_ec_resume
(
struct
device
*
dev
)
{
int
ret
;
struct
cros_ec_extcon_info
*
info
=
dev_get_drvdata
(
dev
);
ret
=
extcon_cros_ec_detect_cable
(
info
,
true
);
if
(
ret
<
0
)
dev_err
(
dev
,
"failed to detect cable state on resume
\n
"
);
return
0
;
}
static
const
struct
dev_pm_ops
extcon_cros_ec_dev_pm_ops
=
{
SET_SYSTEM_SLEEP_PM_OPS
(
extcon_cros_ec_suspend
,
extcon_cros_ec_resume
)
};
#define DEV_PM_OPS (&extcon_cros_ec_dev_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
/* CONFIG_PM_SLEEP */
#ifdef CONFIG_OF
static
const
struct
of_device_id
extcon_cros_ec_of_match
[]
=
{
{
.
compatible
=
"google,extcon-usbc-cros-ec"
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
extcon_cros_ec_of_match
);
#endif
/* CONFIG_OF */
static
struct
platform_driver
extcon_cros_ec_driver
=
{
.
driver
=
{
.
name
=
"extcon-usbc-cros-ec"
,
.
of_match_table
=
of_match_ptr
(
extcon_cros_ec_of_match
),
.
pm
=
DEV_PM_OPS
,
},
.
remove
=
extcon_cros_ec_remove
,
.
probe
=
extcon_cros_ec_probe
,
};
module_platform_driver
(
extcon_cros_ec_driver
);
MODULE_DESCRIPTION
(
"ChromeOS Embedded Controller extcon driver"
);
MODULE_AUTHOR
(
"Benson Leung <bleung@chromium.org>"
);
MODULE_LICENSE
(
"GPL"
);
include/linux/mfd/cros_ec_commands.h
浏览文件 @
15dec834
...
...
@@ -285,6 +285,11 @@ enum host_event_code {
EC_HOST_EVENT_HANG_DETECT
=
20
,
/* Hang detect logic detected a hang and warm rebooted the AP */
EC_HOST_EVENT_HANG_REBOOT
=
21
,
/* PD MCU triggering host event */
EC_HOST_EVENT_PD_MCU
=
22
,
/* EC desires to change state of host-controlled USB mux */
EC_HOST_EVENT_USB_MUX
=
28
,
/*
* The high bit of the event mask is not used as a host event code. If
...
...
@@ -2905,6 +2910,76 @@ struct ec_params_usb_pd_control {
uint8_t
mux
;
}
__packed
;
#define PD_CTRL_RESP_ENABLED_COMMS (1 << 0)
/* Communication enabled */
#define PD_CTRL_RESP_ENABLED_CONNECTED (1 << 1)
/* Device connected */
#define PD_CTRL_RESP_ENABLED_PD_CAPABLE (1 << 2)
/* Partner is PD capable */
struct
ec_response_usb_pd_control_v1
{
uint8_t
enabled
;
uint8_t
role
;
uint8_t
polarity
;
char
state
[
32
];
}
__packed
;
#define EC_CMD_USB_PD_PORTS 0x102
struct
ec_response_usb_pd_ports
{
uint8_t
num_ports
;
}
__packed
;
#define EC_CMD_USB_PD_POWER_INFO 0x103
#define PD_POWER_CHARGING_PORT 0xff
struct
ec_params_usb_pd_power_info
{
uint8_t
port
;
}
__packed
;
enum
usb_chg_type
{
USB_CHG_TYPE_NONE
,
USB_CHG_TYPE_PD
,
USB_CHG_TYPE_C
,
USB_CHG_TYPE_PROPRIETARY
,
USB_CHG_TYPE_BC12_DCP
,
USB_CHG_TYPE_BC12_CDP
,
USB_CHG_TYPE_BC12_SDP
,
USB_CHG_TYPE_OTHER
,
USB_CHG_TYPE_VBUS
,
USB_CHG_TYPE_UNKNOWN
,
};
struct
usb_chg_measures
{
uint16_t
voltage_max
;
uint16_t
voltage_now
;
uint16_t
current_max
;
uint16_t
current_lim
;
}
__packed
;
struct
ec_response_usb_pd_power_info
{
uint8_t
role
;
uint8_t
type
;
uint8_t
dualrole
;
uint8_t
reserved1
;
struct
usb_chg_measures
meas
;
uint32_t
max_power
;
}
__packed
;
/* Get info about USB-C SS muxes */
#define EC_CMD_USB_PD_MUX_INFO 0x11a
struct
ec_params_usb_pd_mux_info
{
uint8_t
port
;
/* USB-C port number */
}
__packed
;
/* Flags representing mux state */
#define USB_PD_MUX_USB_ENABLED (1 << 0)
#define USB_PD_MUX_DP_ENABLED (1 << 1)
#define USB_PD_MUX_POLARITY_INVERTED (1 << 2)
#define USB_PD_MUX_HPD_IRQ (1 << 3)
struct
ec_response_usb_pd_mux_info
{
uint8_t
flags
;
/* USB_PD_MUX_*-encoded USB mux state */
}
__packed
;
/*****************************************************************************/
/*
* Passthru commands
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录