1
0
Fork 0

Tag/Merge point for adding typeC power supply support

This is a signed tag/merge point to handle the cross-tree merge of the
 USB and power supply subsystems for the patch series:
 	Subject: [PATCH v8 0/6] typec: tcpm: Add sink side support for PPS
 
 It is based on the usb.git tree, in the usb-next branch, for merging in
 4.18-rc1.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWuGASg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylqPACcDdrowGIQp0vVa7VrOJNMy9pL5K0An1cjnaUt
 0sXkKK8YWC3EQSSYtr3Q
 =McRU
 -----END PGP SIGNATURE-----

Merge tag 'tags/tcpm-pps-4.18' into psy-next

Tag/Merge point for adding typeC power supply support

This is a signed tag/merge point to handle the cross-tree merge of the
USB and power supply subsystems for the patch series:
	Subject: [PATCH v8 0/6] typec: tcpm: Add sink side support for PPS

It is based on the usb.git tree, in the usb-next branch, for merging in
4.18-rc1.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
hifive-unleashed-5.1
Sebastian Reichel 2018-04-26 12:18:30 +02:00
commit 1f140ff467
52 changed files with 2248 additions and 570 deletions

View File

@ -236,3 +236,21 @@ Description:
Supported values are 0 - 15.
More information on how besl values map to microseconds can be found in
USB 2.0 ECN Errata for Link Power Management, section 4.10)
What: /sys/bus/usb/devices/.../rx_lanes
Date: March 2018
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
Description:
Number of rx lanes the device is using.
USB 3.2 adds Dual-lane support, 2 rx and 2 tx lanes over Type-C.
Inter-Chip SSIC devices support asymmetric lanes up to 4 lanes per
direction. Devices before USB 3.2 are single lane (rx_lanes = 1)
What: /sys/bus/usb/devices/.../tx_lanes
Date: March 2018
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
Description:
Number of tx lanes the device is using.
USB 3.2 adds Dual-lane support, 2 rx and 2 tx -lanes over Type-C.
Inter-Chip SSIC devices support asymmetric lanes up to 4 lanes per
direction. Devices before USB 3.2 are single lane (tx_lanes = 1)

View File

@ -1,3 +1,458 @@
===== General Properties =====
What: /sys/class/power_supply/<supply_name>/manufacturer
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the name of the device manufacturer.
Access: Read
Valid values: Represented as string
What: /sys/class/power_supply/<supply_name>/model_name
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the name of the device model.
Access: Read
Valid values: Represented as string
What: /sys/class/power_supply/<supply_name>/serial_number
Date: January 2008
Contact: linux-pm@vger.kernel.org
Description:
Reports the serial number of the device.
Access: Read
Valid values: Represented as string
What: /sys/class/power_supply/<supply_name>/type
Date: May 2010
Contact: linux-pm@vger.kernel.org
Description:
Describes the main type of the supply.
Access: Read
Valid values: "Battery", "UPS", "Mains", "USB"
===== Battery Properties =====
What: /sys/class/power_supply/<supply_name>/capacity
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Fine grain representation of battery capacity.
Access: Read
Valid values: 0 - 100 (percent)
What: /sys/class/power_supply/<supply_name>/capacity_alert_max
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Maximum battery capacity trip-wire value where the supply will
notify user-space of the event. This is normally used for the
battery discharging scenario where user-space needs to know the
battery has dropped to an upper level so it can take
appropriate action (e.g. warning user that battery level is
low).
Access: Read, Write
Valid values: 0 - 100 (percent)
What: /sys/class/power_supply/<supply_name>/capacity_alert_min
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Minimum battery capacity trip-wire value where the supply will
notify user-space of the event. This is normally used for the
battery discharging scenario where user-space needs to know the
battery has dropped to a lower level so it can take
appropriate action (e.g. warning user that battery level is
critically low).
Access: Read, Write
Valid values: 0 - 100 (percent)
What: /sys/class/power_supply/<supply_name>/capacity_level
Date: June 2009
Contact: linux-pm@vger.kernel.org
Description:
Coarse representation of battery capacity.
Access: Read
Valid values: "Unknown", "Critical", "Low", "Normal", "High",
"Full"
What: /sys/class/power_supply/<supply_name>/current_avg
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports an average IBAT current reading for the battery, over a
fixed period. Normally devices will provide a fixed interval in
which they average readings to smooth out the reported value.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/current_max
Date: October 2010
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum IBAT current allowed into the battery.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/current_now
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports an instant, single IBAT current reading for the battery.
This value is not averaged/smoothed.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/charge_type
Date: July 2009
Contact: linux-pm@vger.kernel.org
Description:
Represents the type of charging currently being applied to the
battery.
Access: Read
Valid values: "Unknown", "N/A", "Trickle", "Fast"
What: /sys/class/power_supply/<supply_name>/charge_term_current
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Reports the charging current value which is used to determine
when the battery is considered full and charging should end.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/health
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the health of the battery or battery side of charger
functionality.
Access: Read
Valid values: "Unknown", "Good", "Overheat", "Dead",
"Over voltage", "Unspecified failure", "Cold",
"Watchdog timer expire", "Safety timer expire"
What: /sys/class/power_supply/<supply_name>/precharge_current
Date: June 2017
Contact: linux-pm@vger.kernel.org
Description:
Reports the charging current applied during pre-charging phase
for a battery charge cycle.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/present
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports whether a battery is present or not in the system.
Access: Read
Valid values:
0: Absent
1: Present
What: /sys/class/power_supply/<supply_name>/status
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Represents the charging status of the battery. Normally this
is read-only reporting although for some supplies this can be
used to enable/disable charging to the battery.
Access: Read, Write
Valid values: "Unknown", "Charging", "Discharging",
"Not charging", "Full"
What: /sys/class/power_supply/<supply_name>/technology
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Describes the battery technology supported by the supply.
Access: Read
Valid values: "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe",
"NiCd", "LiMn"
What: /sys/class/power_supply/<supply_name>/temp
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the current TBAT battery temperature reading.
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_alert_max
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Maximum TBAT temperature trip-wire value where the supply will
notify user-space of the event. This is normally used for the
battery charging scenario where user-space needs to know the
battery temperature has crossed an upper threshold so it can
take appropriate action (e.g. warning user that battery level is
critically high, and charging has stopped).
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_alert_min
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Minimum TBAT temperature trip-wire value where the supply will
notify user-space of the event. This is normally used for the
battery charging scenario where user-space needs to know the
battery temperature has crossed a lower threshold so it can take
appropriate action (e.g. warning user that battery level is
high, and charging current has been reduced accordingly to
remedy the situation).
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_max
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum allowed TBAT battery temperature for
charging.
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_min
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Reports the minimum allowed TBAT battery temperature for
charging.
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/voltage_avg,
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports an average VBAT voltage reading for the battery, over a
fixed period. Normally devices will provide a fixed interval in
which they average readings to smooth out the reported value.
Access: Read
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/voltage_max,
Date: January 2008
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum safe VBAT voltage permitted for the battery,
during charging.
Access: Read
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/voltage_min,
Date: January 2008
Contact: linux-pm@vger.kernel.org
Description:
Reports the minimum safe VBAT voltage permitted for the battery,
during discharging.
Access: Read
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/voltage_now,
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports an instant, single VBAT voltage reading for the battery.
This value is not averaged/smoothed.
Access: Read
Valid values: Represented in microvolts
===== USB Properties =====
What: /sys/class/power_supply/<supply_name>/current_avg
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports an average IBUS current reading over a fixed period.
Normally devices will provide a fixed interval in which they
average readings to smooth out the reported value.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/current_max
Date: October 2010
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum IBUS current the supply can support.
Access: Read
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/current_now
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the IBUS current supplied now. This value is generally
read-only reporting, unless the 'online' state of the supply
is set to be programmable, in which case this value can be set
within the reported min/max range.
Access: Read, Write
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/input_current_limit
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Details the incoming IBUS current limit currently set in the
supply. Normally this is configured based on the type of
connection made (e.g. A configured SDP should output a maximum
of 500mA so the input current limit is set to the same value).
Access: Read, Write
Valid values: Represented in microamps
What: /sys/class/power_supply/<supply_name>/online,
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Indicates if VBUS is present for the supply. When the supply is
online, and the supply allows it, then it's possible to switch
between online states (e.g. Fixed -> Programmable for a PD_PPS
USB supply so voltage and current can be controlled).
Access: Read, Write
Valid values:
0: Offline
1: Online Fixed - Fixed Voltage Supply
2: Online Programmable - Programmable Voltage Supply
What: /sys/class/power_supply/<supply_name>/temp
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the current supply temperature reading. This would
normally be the internal temperature of the device itself (e.g
TJUNC temperature of an IC)
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_alert_max
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Maximum supply temperature trip-wire value where the supply will
notify user-space of the event. This is normally used for the
charging scenario where user-space needs to know the supply
temperature has crossed an upper threshold so it can take
appropriate action (e.g. warning user that the supply
temperature is critically high, and charging has stopped to
remedy the situation).
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_alert_min
Date: July 2012
Contact: linux-pm@vger.kernel.org
Description:
Minimum supply temperature trip-wire value where the supply will
notify user-space of the event. This is normally used for the
charging scenario where user-space needs to know the supply
temperature has crossed a lower threshold so it can take
appropriate action (e.g. warning user that the supply
temperature is high, and charging current has been reduced
accordingly to remedy the situation).
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_max
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum allowed supply temperature for operation.
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/temp_min
Date: July 2014
Contact: linux-pm@vger.kernel.org
Description:
Reports the mainimum allowed supply temperature for operation.
Access: Read
Valid values: Represented in 1/10 Degrees Celsius
What: /sys/class/power_supply/<supply_name>/usb_type
Date: March 2018
Contact: linux-pm@vger.kernel.org
Description:
Reports what type of USB connection is currently active for
the supply, for example it can show if USB-PD capable source
is attached.
Access: Read-Only
Valid values: "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD",
"PD_DRP", "PD_PPS", "BrickID"
What: /sys/class/power_supply/<supply_name>/voltage_max
Date: January 2008
Contact: linux-pm@vger.kernel.org
Description:
Reports the maximum VBUS voltage the supply can support.
Access: Read
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/voltage_min
Date: January 2008
Contact: linux-pm@vger.kernel.org
Description:
Reports the minimum VBUS voltage the supply can support.
Access: Read
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/voltage_now
Date: May 2007
Contact: linux-pm@vger.kernel.org
Description:
Reports the VBUS voltage supplied now. This value is generally
read-only reporting, unless the 'online' state of the supply
is set to be programmable, in which case this value can be set
within the reported min/max range.
Access: Read, Write
Valid values: Represented in microvolts
===== Device Specific Properties =====
What: /sys/class/power/ds2760-battery.*/charge_now
Date: May 2010
KernelVersion: 2.6.35

View File

@ -76,6 +76,10 @@ Optional properties:
needs to make sure it does not send more than 90%
maximum_periodic_data_per_frame. The use case is multiple transactions, but
less frame rate.
- mux-controls: The mux control for toggling host/device output of this
controller. It's expected that a mux state of 0 indicates device mode and a
mux state of 1 indicates host mode.
- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
i.mx specific properties
- fsl,usbmisc: phandler of non-core register device, with one
@ -102,4 +106,6 @@ Example:
rx-burst-size-dword = <0x10>;
extcon = <0>, <&usb_id>;
phy-clkgate-delay-us = <400>;
mux-controls = <&usb_switch>;
mux-control-names = "usb_switch";
};

View File

@ -6,12 +6,6 @@ Required properties :
- interrupts : Interrupt specifier
Optional properties :
- fcs,max-sink-microvolt : Maximum voltage to negotiate when configured as sink
- fcs,max-sink-microamp : Maximum current to negotiate when configured as sink
- fcs,max-sink-microwatt : Maximum power to negotiate when configured as sink
If this is less then max-sink-microvolt *
max-sink-microamp then the configured current will
be clamped.
- fcs,operating-sink-microwatt :
Minimum amount of power accepted from a sink
when negotiating

View File

@ -0,0 +1,17 @@
Richtek RT1711H TypeC PD Controller.
Required properties:
- compatible : Must be "richtek,rt1711h".
- reg : Must be 0x4e, it's slave address of RT1711H.
- interrupt-parent : the phandle for the interrupt controller that
provides interrupts for this device.
- interrupts : <a b> where a is the interrupt number and b represents an
encoding of the sense and level information for the interrupt.
Example :
rt1711h@4e {
compatible = "richtek,rt1711h";
reg = <0x4e>;
interrupt-parent = <&gpio26>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
};

View File

@ -28,7 +28,10 @@ Required properties:
- interrupts: one XHCI interrupt should be described here.
Optional properties:
- clocks: reference to a clock
- clocks: reference to the clocks
- clock-names: mandatory if there is a second clock, in this case
the name must be "core" for the first clock and "reg" for the
second one
- usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
- usb3-lpm-capable: determines if platform is USB3 LPM capable
- quirk-broken-port-ped: set if the controller has broken port disable mechanism

View File

@ -11270,6 +11270,7 @@ M: Sebastian Reichel <sre@kernel.org>
L: linux-pm@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
S: Maintained
F: Documentation/ABI/testing/sysfs-class-power
F: Documentation/devicetree/bindings/power/supply/
F: include/linux/power_supply.h
F: drivers/power/supply/

View File

@ -843,12 +843,21 @@ __power_supply_register(struct device *parent,
{
struct device *dev;
struct power_supply *psy;
int rc;
int i, rc;
if (!parent)
pr_warn("%s: Expected proper parent device for '%s'\n",
__func__, desc->name);
if (!desc || !desc->name || !desc->properties || !desc->num_properties)
return ERR_PTR(-EINVAL);
for (i = 0; i < desc->num_properties; ++i) {
if ((desc->properties[i] == POWER_SUPPLY_PROP_USB_TYPE) &&
(!desc->usb_types || !desc->num_usb_types))
return ERR_PTR(-EINVAL);
}
psy = kzalloc(sizeof(*psy), GFP_KERNEL);
if (!psy)
return ERR_PTR(-ENOMEM);

View File

@ -46,6 +46,11 @@ static const char * const power_supply_type_text[] = {
"USB_PD", "USB_PD_DRP", "BrickID"
};
static const char * const power_supply_usb_type_text[] = {
"Unknown", "SDP", "DCP", "CDP", "ACA", "C",
"PD", "PD_DRP", "PD_PPS", "BrickID"
};
static const char * const power_supply_status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
};
@ -73,6 +78,41 @@ static const char * const power_supply_scope_text[] = {
"Unknown", "System", "Device"
};
static ssize_t power_supply_show_usb_type(struct device *dev,
enum power_supply_usb_type *usb_types,
ssize_t num_usb_types,
union power_supply_propval *value,
char *buf)
{
enum power_supply_usb_type usb_type;
ssize_t count = 0;
bool match = false;
int i;
for (i = 0; i < num_usb_types; ++i) {
usb_type = usb_types[i];
if (value->intval == usb_type) {
count += sprintf(buf + count, "[%s] ",
power_supply_usb_type_text[usb_type]);
match = true;
} else {
count += sprintf(buf + count, "%s ",
power_supply_usb_type_text[usb_type]);
}
}
if (!match) {
dev_warn(dev, "driver reporting unsupported connected type\n");
return -EINVAL;
}
if (count)
buf[count - 1] = '\n';
return count;
}
static ssize_t power_supply_show_property(struct device *dev,
struct device_attribute *attr,
char *buf) {
@ -122,6 +162,11 @@ static ssize_t power_supply_show_property(struct device *dev,
ret = sprintf(buf, "%s\n",
power_supply_type_text[value.intval]);
break;
case POWER_SUPPLY_PROP_USB_TYPE:
ret = power_supply_show_usb_type(dev, psy->desc->usb_types,
psy->desc->num_usb_types,
&value, buf);
break;
case POWER_SUPPLY_PROP_SCOPE:
ret = sprintf(buf, "%s\n",
power_supply_scope_text[value.intval]);
@ -252,6 +297,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(time_to_full_now),
POWER_SUPPLY_ATTR(time_to_full_avg),
POWER_SUPPLY_ATTR(type),
POWER_SUPPLY_ATTR(usb_type),
POWER_SUPPLY_ATTR(scope),
POWER_SUPPLY_ATTR(precharge_current),
POWER_SUPPLY_ATTR(charge_term_current),

View File

@ -9,6 +9,14 @@ config TYPEC_TCPCI
help
Type-C Port Controller driver for TCPCI-compliant controller.
config TYPEC_RT1711H
tristate "Richtek RT1711H Type-C chip driver"
select TYPEC_TCPCI
help
Richtek RT1711H Type-C chip driver that works with
Type-C Port Controller Manager to provide USB PD and USB
Type-C functionalities.
endif
endmenu

View File

@ -1 +1,2 @@
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o

View File

@ -59,6 +59,7 @@
#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
#define TCPC_CC_STATUS 0x1d
#define TCPC_CC_STATUS_TOGGLING BIT(5)
#define TCPC_CC_STATUS_TERM BIT(4)
#define TCPC_CC_STATUS_CC2_SHIFT 2
#define TCPC_CC_STATUS_CC2_MASK 0x3

View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Richtek Technology Corporation
*
* Richtek RT1711H Type-C Chip Driver
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <linux/usb/tcpm.h>
#include <linux/regmap.h>
#include "tcpci.h"
#define RT1711H_VID 0x29CF
#define RT1711H_PID 0x1711
#define RT1711H_RTCTRL8 0x9B
/* Autoidle timeout = (tout * 2 + 1) * 6.4ms */
#define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \
(((ck300) << 7) | ((ship_off) << 5) | \
((auto_idle) << 3) | ((tout) & 0x07))
#define RT1711H_RTCTRL11 0x9E
/* I2C timeout = (tout + 1) * 12.5ms */
#define RT1711H_RTCTRL11_SET(en, tout) \
(((en) << 7) | ((tout) & 0x0F))
#define RT1711H_RTCTRL13 0xA0
#define RT1711H_RTCTRL14 0xA1
#define RT1711H_RTCTRL15 0xA2
#define RT1711H_RTCTRL16 0xA3
struct rt1711h_chip {
struct tcpci_data data;
struct tcpci *tcpci;
struct device *dev;
};
static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
}
static int rt1711h_write16(struct rt1711h_chip *chip, unsigned int reg, u16 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
}
static int rt1711h_read8(struct rt1711h_chip *chip, unsigned int reg, u8 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
}
static int rt1711h_write8(struct rt1711h_chip *chip, unsigned int reg, u8 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
}
static const struct regmap_config rt1711h_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */
};
static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata)
{
return container_of(tdata, struct rt1711h_chip, data);
}
static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
{
int ret;
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
/* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */
ret = rt1711h_write8(chip, RT1711H_RTCTRL8,
RT1711H_RTCTRL8_SET(0, 1, 1, 2));
if (ret < 0)
return ret;
/* I2C reset : (val + 1) * 12.5ms */
ret = rt1711h_write8(chip, RT1711H_RTCTRL11,
RT1711H_RTCTRL11_SET(1, 0x0F));
if (ret < 0)
return ret;
/* tTCPCfilter : (26.7 * val) us */
ret = rt1711h_write8(chip, RT1711H_RTCTRL14, 0x0F);
if (ret < 0)
return ret;
/* tDRP : (51.2 + 6.4 * val) ms */
ret = rt1711h_write8(chip, RT1711H_RTCTRL15, 0x04);
if (ret < 0)
return ret;
/* dcSRC.DRP : 33% */
return rt1711h_write16(chip, RT1711H_RTCTRL16, 330);
}
static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata,
bool enable)
{
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
return rt1711h_write8(chip, RT1711H_RTCTRL8,
RT1711H_RTCTRL8_SET(0, 1, !enable, 2));
}
static int rt1711h_start_drp_toggling(struct tcpci *tcpci,
struct tcpci_data *tdata,
enum typec_cc_status cc)
{
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
int ret;
unsigned int reg = 0;
switch (cc) {
default:
case TYPEC_CC_RP_DEF:
reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF <<
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
break;
case TYPEC_CC_RP_1_5:
reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
break;
case TYPEC_CC_RP_3_0:
reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
break;
}
if (cc == TYPEC_CC_RD)
reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
else
reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT);
ret = rt1711h_write8(chip, TCPC_ROLE_CTRL, reg);
if (ret < 0)
return ret;
usleep_range(500, 1000);
return 0;
}
static irqreturn_t rt1711h_irq(int irq, void *dev_id)
{
int ret;
u16 alert;
u8 status;
struct rt1711h_chip *chip = dev_id;
if (!chip->tcpci)
return IRQ_HANDLED;
ret = rt1711h_read16(chip, TCPC_ALERT, &alert);
if (ret < 0)
goto out;
if (alert & TCPC_ALERT_CC_STATUS) {
ret = rt1711h_read8(chip, TCPC_CC_STATUS, &status);
if (ret < 0)
goto out;
/* Clear cc change event triggered by starting toggling */
if (status & TCPC_CC_STATUS_TOGGLING)
rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS);
}
out:
return tcpci_irq(chip->tcpci);
}
static int rt1711h_init_alert(struct rt1711h_chip *chip,
struct i2c_client *client)
{
int ret;
/* Disable chip interrupts before requesting irq */
ret = rt1711h_write16(chip, TCPC_ALERT_MASK, 0);
if (ret < 0)
return ret;
ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
rt1711h_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
dev_name(chip->dev), chip);
if (ret < 0)
return ret;
enable_irq_wake(client->irq);
return 0;
}
static int rt1711h_sw_reset(struct rt1711h_chip *chip)
{
int ret;
ret = rt1711h_write8(chip, RT1711H_RTCTRL13, 0x01);
if (ret < 0)
return ret;
usleep_range(1000, 2000);
return 0;
}
static int rt1711h_check_revision(struct i2c_client *i2c)
{
int ret;
ret = i2c_smbus_read_word_data(i2c, TCPC_VENDOR_ID);
if (ret < 0)
return ret;
if (ret != RT1711H_VID) {
dev_err(&i2c->dev, "vid is not correct, 0x%04x\n", ret);
return -ENODEV;
}
ret = i2c_smbus_read_word_data(i2c, TCPC_PRODUCT_ID);
if (ret < 0)
return ret;
if (ret != RT1711H_PID) {
dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret);
return -ENODEV;
}
return 0;
}
static int rt1711h_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
int ret;
struct rt1711h_chip *chip;
ret = rt1711h_check_revision(client);
if (ret < 0) {
dev_err(&client->dev, "check vid/pid fail\n");
return ret;
}
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->data.regmap = devm_regmap_init_i2c(client,
&rt1711h_regmap_config);
if (IS_ERR(chip->data.regmap))
return PTR_ERR(chip->data.regmap);
chip->dev = &client->dev;
i2c_set_clientdata(client, chip);
ret = rt1711h_sw_reset(chip);
if (ret < 0)
return ret;
ret = rt1711h_init_alert(chip, client);
if (ret < 0)
return ret;
chip->data.init = rt1711h_init;
chip->data.set_vconn = rt1711h_set_vconn;
chip->data.start_drp_toggling = rt1711h_start_drp_toggling;
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
if (IS_ERR_OR_NULL(chip->tcpci))
return PTR_ERR(chip->tcpci);
return 0;
}
static int rt1711h_remove(struct i2c_client *client)
{
struct rt1711h_chip *chip = i2c_get_clientdata(client);
tcpci_unregister_port(chip->tcpci);
return 0;
}
static const struct i2c_device_id rt1711h_id[] = {
{ "rt1711h", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1711h_id);
#ifdef CONFIG_OF
static const struct of_device_id rt1711h_of_match[] = {
{ .compatible = "richtek,rt1711h", },
{},
};
MODULE_DEVICE_TABLE(of, rt1711h_of_match);
#endif
static struct i2c_driver rt1711h_i2c_driver = {
.driver = {
.name = "rt1711h",
.of_match_table = of_match_ptr(rt1711h_of_match),
},
.probe = rt1711h_probe,
.remove = rt1711h_remove,
.id_table = rt1711h_id,
};
module_i2c_driver(rt1711h_i2c_driver);
MODULE_AUTHOR("ShuFan Lee <shufan_lee@richtek.com>");
MODULE_DESCRIPTION("RT1711H USB Type-C Port Controller Interface Driver");
MODULE_LICENSE("GPL");

View File

@ -33,7 +33,6 @@
#include <linux/phy/phy.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/phy.h>
#include <linux/usb/otg.h>
#include "usb.h"
@ -568,6 +567,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
switch (wValue & 0xff00) {
case USB_DT_DEVICE << 8:
switch (hcd->speed) {
case HCD_USB32:
case HCD_USB31:
bufp = usb31_rh_dev_descriptor;
break;
@ -592,6 +592,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
break;
case USB_DT_CONFIG << 8:
switch (hcd->speed) {
case HCD_USB32:
case HCD_USB31:
case HCD_USB3:
bufp = ss_rh_config_descriptor;
@ -2739,30 +2740,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
int retval;
struct usb_device *rhdev;
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->skip_phy_initialization) {
struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
if (IS_ERR(phy)) {
retval = PTR_ERR(phy);
if (retval == -EPROBE_DEFER)
return retval;
} else {
retval = usb_phy_init(phy);
if (retval) {
usb_put_phy(phy);
return retval;
}
hcd->usb_phy = phy;
hcd->remove_phy = 1;
}
}
if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
hcd->phy_roothub = usb_phy_roothub_init(hcd->self.sysdev);
if (IS_ERR(hcd->phy_roothub)) {
retval = PTR_ERR(hcd->phy_roothub);
goto err_phy_roothub_init;
}
if (IS_ERR(hcd->phy_roothub))
return PTR_ERR(hcd->phy_roothub);
retval = usb_phy_roothub_power_on(hcd->phy_roothub);
if (retval)
@ -2812,6 +2793,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
hcd->self.root_hub = rhdev;
mutex_unlock(&usb_port_peer_mutex);
rhdev->rx_lanes = 1;
rhdev->tx_lanes = 1;
switch (hcd->speed) {
case HCD_USB11:
rhdev->speed = USB_SPEED_FULL;
@ -2825,6 +2809,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
case HCD_USB3:
rhdev->speed = USB_SPEED_SUPER;
break;
case HCD_USB32:
rhdev->rx_lanes = 2;
rhdev->tx_lanes = 2;
/* fall through */
case HCD_USB31:
rhdev->speed = USB_SPEED_SUPER_PLUS;
break;
@ -2936,12 +2924,7 @@ err_create_buf:
usb_phy_roothub_power_off(hcd->phy_roothub);
err_usb_phy_roothub_power_on:
usb_phy_roothub_exit(hcd->phy_roothub);
err_phy_roothub_init:
if (hcd->remove_phy && hcd->usb_phy) {
usb_phy_shutdown(hcd->usb_phy);
usb_put_phy(hcd->usb_phy);
hcd->usb_phy = NULL;
}
return retval;
}
EXPORT_SYMBOL_GPL(usb_add_hcd);
@ -3017,12 +3000,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_phy_roothub_power_off(hcd->phy_roothub);
usb_phy_roothub_exit(hcd->phy_roothub);
if (hcd->remove_phy && hcd->usb_phy) {
usb_phy_shutdown(hcd->usb_phy);
usb_put_phy(hcd->usb_phy);
hcd->usb_phy = NULL;
}
usb_put_invalidate_rhdev(hcd);
hcd->flags = 0;
}

View File

@ -2746,6 +2746,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (!udev)
return 0;
if (hub_is_superspeedplus(hub->hdev)) {
/* extended portstatus Rx and Tx lane count are zero based */
udev->rx_lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
udev->tx_lanes = USB_EXT_PORT_TX_LANES(ext_portstatus) + 1;
} else {
udev->rx_lanes = 1;
udev->tx_lanes = 1;
}
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
else if (hub_is_superspeedplus(hub->hdev) &&
@ -3371,6 +3379,10 @@ static int wait_for_connected(struct usb_device *udev,
while (delay_ms < 2000) {
if (status || *portstatus & USB_PORT_STAT_CONNECTION)
break;
if (!port_is_power_on(hub, *portstatus)) {
status = -ENODEV;
break;
}
msleep(20);
delay_ms += 20;
status = hub_port_status(hub, *port1, portstatus, portchange);
@ -4543,7 +4555,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* reset. But only on the first attempt,
* lest we get into a time out/reset loop
*/
if (r == 0 || (r == -ETIMEDOUT && retries == 0))
if (r == 0 || (r == -ETIMEDOUT &&
retries == 0 &&
udev->speed > USB_SPEED_FULL))
break;
}
udev->descriptor.bMaxPacketSize0 =
@ -4590,9 +4604,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
if (udev->speed >= USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
"%s SuperSpeed%s USB device number %d using %s\n",
"%s SuperSpeed%s%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
(udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
(udev->speed == USB_SPEED_SUPER_PLUS) ?
"Plus Gen 2" : " Gen 1",
(udev->rx_lanes == 2 && udev->tx_lanes == 2) ?
"x2" : "",
devnum, driver_name);
}

View File

@ -175,6 +175,26 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(speed);
static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->rx_lanes);
}
static DEVICE_ATTR_RO(rx_lanes);
static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->tx_lanes);
}
static DEVICE_ATTR_RO(tx_lanes);
static ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -790,6 +810,8 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bNumConfigurations.attr,
&dev_attr_bMaxPacketSize0.attr,
&dev_attr_speed.attr,
&dev_attr_rx_lanes.attr,
&dev_attr_tx_lanes.attr,
&dev_attr_busnum.attr,
&dev_attr_devnum.attr,
&dev_attr_devpath.attr,

View File

@ -179,7 +179,7 @@ config USB_R8A66597
config USB_RENESAS_USBHS_UDC
tristate 'Renesas USBHS controller'
depends on USB_RENESAS_USBHS && HAS_DMA
depends on USB_RENESAS_USBHS
help
Renesas USBHS is a discrete USB host and peripheral controller chip
that supports both full and high speed USB 2.0 data transfers.
@ -192,7 +192,7 @@ config USB_RENESAS_USBHS_UDC
config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST
depends on EXTCON && HAS_DMA
depends on EXTCON
help
Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers.

View File

@ -234,9 +234,7 @@ config USB_EHCI_TEGRA
tristate "NVIDIA Tegra HCD support"
depends on ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
select USB_PHY
select USB_ULPI
select USB_ULPI_VIEWPORT
select USB_TEGRA_PHY
help
This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.

View File

@ -157,10 +157,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
struct usb_phy *phy;
/* get the PHY device */
if (dev->of_node)
phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
else
phy = devm_usb_get_phy_dev(dev, i);
phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
if (IS_ERR(phy)) {
/* Don't bail out if PHY is not absolutely necessary */
if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)

View File

@ -36,7 +36,6 @@
#define DRV_NAME "tegra-ehci"
static struct hc_driver __read_mostly tegra_ehci_hc_driver;
static bool usb1_reset_attempted;
struct tegra_ehci_soc_config {
bool has_hostpc;
@ -51,68 +50,55 @@ struct tegra_ehci_hcd {
enum tegra_usb_phy_port_speed port_speed;
};
/*
* The 1st USB controller contains some UTMI pad registers that are global for
* all the controllers on the chip. Those registers are also cleared when
* reset is asserted to the 1st controller. This means that the 1st controller
* can only be reset when no other controlled has finished probing. So we'll
* reset the 1st controller before doing any other setup on any of the
* controllers, and then never again.
*
* Since this is a PHY issue, the Tegra PHY driver should probably be doing
* the resetting of the USB controllers. But to keep compatibility with old
* device trees that don't have reset phandles in the PHYs, do it here.
* Those old DTs will be vulnerable to total USB breakage if the 1st EHCI
* device isn't the first one to finish probing, so warn them.
*/
static int tegra_reset_usb_controller(struct platform_device *pdev)
{
struct device_node *phy_np;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
bool has_utmi_pad_registers = false;
struct reset_control *rst;
int err;
phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
if (!phy_np)
return -ENOENT;
if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
has_utmi_pad_registers = true;
if (!usb1_reset_attempted) {
struct reset_control *usb1_reset;
if (!has_utmi_pad_registers)
usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
else
usb1_reset = tegra->rst;
if (IS_ERR(usb1_reset)) {
dev_warn(&pdev->dev,
"can't get utmi-pads reset from the PHY\n");
dev_warn(&pdev->dev,
"continuing, but please update your DT\n");
} else {
reset_control_assert(usb1_reset);
udelay(1);
reset_control_deassert(usb1_reset);
if (!has_utmi_pad_registers)
reset_control_put(usb1_reset);
}
usb1_reset_attempted = true;
}
if (!has_utmi_pad_registers) {
reset_control_assert(tegra->rst);
udelay(1);
reset_control_deassert(tegra->rst);
/*
* The 1st USB controller contains some UTMI pad registers that are
* global for all the controllers on the chip. Those registers are
* also cleared when reset is asserted to the 1st controller.
*/
rst = of_reset_control_get_shared(phy_np, "utmi-pads");
if (IS_ERR(rst)) {
dev_warn(&pdev->dev,
"can't get utmi-pads reset from the PHY\n");
dev_warn(&pdev->dev,
"continuing, but please update your DT\n");
} else {
/*
* PHY driver performs UTMI-pads reset in a case of
* non-legacy DT.
*/
reset_control_put(rst);
}
of_node_put(phy_np);
/* reset control is shared, hence initialize it first */
err = reset_control_deassert(tegra->rst);
if (err)
return err;
err = reset_control_assert(tegra->rst);
if (err)
return err;
udelay(1);
err = reset_control_deassert(tegra->rst);
if (err)
return err;
return 0;
}
@ -440,7 +426,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_hcd_create;
}
tegra->rst = devm_reset_control_get(&pdev->dev, "usb");
tegra->rst = devm_reset_control_get_shared(&pdev->dev, "usb");
if (IS_ERR(tegra->rst)) {
dev_err(&pdev->dev, "Can't get ehci reset\n");
err = PTR_ERR(tegra->rst);
@ -452,8 +438,10 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_hcd_create;
err = tegra_reset_usb_controller(pdev);
if (err)
if (err) {
dev_err(&pdev->dev, "Failed to reset controller\n");
goto cleanup_clk_en;
}
u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
if (IS_ERR(u_phy)) {
@ -538,6 +526,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
usb_phy_shutdown(hcd->usb_phy);
usb_remove_hcd(hcd);
reset_control_assert(tegra->rst);
udelay(1);
clk_disable_unprepare(tegra->clk);
usb_put_hcd(hcd);

View File

@ -157,6 +157,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
struct resource *res;
struct usb_hcd *hcd;
struct clk *clk;
struct clk *reg_clk;
int ret;
int irq;
@ -226,17 +227,27 @@ static int xhci_plat_probe(struct platform_device *pdev)
hcd->rsrc_len = resource_size(res);
/*
* Not all platforms have a clk so it is not an error if the
* clock does not exists.
* Not all platforms have clks so it is not an error if the
* clock do not exist.
*/
reg_clk = devm_clk_get(&pdev->dev, "reg");
if (!IS_ERR(reg_clk)) {
ret = clk_prepare_enable(reg_clk);
if (ret)
goto put_hcd;
} else if (PTR_ERR(reg_clk) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto put_hcd;
}
clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) {
ret = clk_prepare_enable(clk);
if (ret)
goto put_hcd;
goto disable_reg_clk;
} else if (PTR_ERR(clk) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto put_hcd;
goto disable_reg_clk;
}
xhci = hcd_to_xhci(hcd);
@ -252,6 +263,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
device_wakeup_enable(hcd->self.controller);
xhci->clk = clk;
xhci->reg_clk = reg_clk;
xhci->main_hcd = hcd;
xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
dev_name(&pdev->dev), hcd);
@ -320,8 +332,10 @@ put_usb3_hcd:
usb_put_hcd(xhci->shared_hcd);
disable_clk:
if (!IS_ERR(clk))
clk_disable_unprepare(clk);
clk_disable_unprepare(clk);
disable_reg_clk:
clk_disable_unprepare(reg_clk);
put_hcd:
usb_put_hcd(hcd);
@ -338,6 +352,7 @@ static int xhci_plat_remove(struct platform_device *dev)
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct clk *clk = xhci->clk;
struct clk *reg_clk = xhci->reg_clk;
xhci->xhc_state |= XHCI_STATE_REMOVING;
@ -347,8 +362,8 @@ static int xhci_plat_remove(struct platform_device *dev)
usb_remove_hcd(hcd);
usb_put_hcd(xhci->shared_hcd);
if (!IS_ERR(clk))
clk_disable_unprepare(clk);
clk_disable_unprepare(clk);
clk_disable_unprepare(reg_clk);
usb_put_hcd(hcd);
pm_runtime_set_suspended(&dev->dev);

View File

@ -1729,8 +1729,9 @@ struct xhci_hcd {
int page_shift;
/* msi-x vectors */
int msix_count;
/* optional clock */
/* optional clocks */
struct clk *clk;
struct clk *reg_clk;
/* data structures */
struct xhci_device_context_array *dcbaa;
struct xhci_ring *cmd_ring;

View File

@ -31,7 +31,7 @@ static void isp1760_init_core(struct isp1760_device *isp)
/* Low-level chip reset */
if (isp->rst_gpio) {
gpiod_set_value_cansleep(isp->rst_gpio, 1);
mdelay(50);
msleep(50);
gpiod_set_value_cansleep(isp->rst_gpio, 0);
}

View File

@ -2093,7 +2093,7 @@ static void isp1760_stop(struct usb_hcd *hcd)
isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
NULL, 0);
mdelay(20);
msleep(20);
spin_lock_irq(&priv->lock);
ehci_reset(hcd);

View File

@ -1227,7 +1227,7 @@ static void mon_bin_vma_close(struct vm_area_struct *vma)
/*
* Map ring pages to user space.
*/
static int mon_bin_vma_fault(struct vm_fault *vmf)
static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf)
{
struct mon_reader_bin *rp = vmf->vma->vm_private_data;
unsigned long offset, chunk_idx;

View File

@ -2,7 +2,7 @@
config USB_MTU3
tristate "MediaTek USB3 Dual Role controller"
depends on EXTCON && (USB || USB_GADGET) && HAS_DMA
depends on EXTCON && (USB || USB_GADGET)
depends on ARCH_MEDIATEK || COMPILE_TEST
select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
help

View File

@ -447,8 +447,7 @@ static int mtu3_remove(struct platform_device *pdev)
*/
static int __maybe_unused mtu3_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
dev_dbg(dev, "%s\n", __func__);
@ -466,8 +465,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
static int __maybe_unused mtu3_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
int ret;
dev_dbg(dev, "%s\n", __func__);

View File

@ -239,21 +239,15 @@ static int omap2430_musb_init(struct musb *musb)
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
if (dev->parent->of_node) {
musb->phy = devm_phy_get(dev->parent, "usb2-phy");
musb->phy = devm_phy_get(dev->parent, "usb2-phy");
/* We can't totally remove musb->xceiv as of now because
* musb core uses xceiv.state and xceiv.otg. Once we have
* a separate state machine to handle otg, these can be moved
* out of xceiv and then we can start using the generic PHY
* framework
*/
musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent,
"usb-phy", 0);
} else {
musb->xceiv = devm_usb_get_phy_dev(dev, 0);
musb->phy = devm_phy_get(dev, "usb");
}
/* We can't totally remove musb->xceiv as of now because
* musb core uses xceiv.state and xceiv.otg. Once we have
* a separate state machine to handle otg, these can be moved
* out of xceiv and then we can start using the generic PHY
* framework
*/
musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0);
if (IS_ERR(musb->xceiv)) {
status = PTR_ERR(musb->xceiv);
@ -391,8 +385,13 @@ static int omap2430_probe(struct platform_device *pdev)
struct omap2430_glue *glue;
struct device_node *np = pdev->dev.of_node;
struct musb_hdrc_config *config;
struct device_node *control_node;
struct platform_device *control_pdev;
int ret = -ENOMEM, val;
if (!np)
return -ENODEV;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
goto err0;
@ -412,47 +411,43 @@ static int omap2430_probe(struct platform_device *pdev)
glue->status = MUSB_UNKNOWN;
glue->control_otghs = ERR_PTR(-ENODEV);
if (np) {
struct device_node *control_node;
struct platform_device *control_pdev;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
goto err2;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
goto err2;
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
if (!config)
goto err2;
of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
of_property_read_u32(np, "interface-type",
(u32 *)&data->interface_type);
of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
of_property_read_u32(np, "power", (u32 *)&pdata->power);
ret = of_property_read_u32(np, "multipoint", &val);
if (!ret && val)
config->multipoint = true;
pdata->board_data = data;
pdata->config = config;
control_node = of_parse_phandle(np, "ctrl-module", 0);
if (control_node) {
control_pdev = of_find_device_by_node(control_node);
if (!control_pdev) {
dev_err(&pdev->dev, "Failed to get control device\n");
ret = -EINVAL;
goto err2;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
goto err2;
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
if (!config)
goto err2;
of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
of_property_read_u32(np, "interface-type",
(u32 *)&data->interface_type);
of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
of_property_read_u32(np, "power", (u32 *)&pdata->power);
ret = of_property_read_u32(np, "multipoint", &val);
if (!ret && val)
config->multipoint = true;
pdata->board_data = data;
pdata->config = config;
control_node = of_parse_phandle(np, "ctrl-module", 0);
if (control_node) {
control_pdev = of_find_device_by_node(control_node);
if (!control_pdev) {
dev_err(&pdev->dev, "Failed to get control device\n");
ret = -EINVAL;
goto err2;
}
glue->control_otghs = &control_pdev->dev;
}
glue->control_otghs = &control_pdev->dev;
}
pdata->platform_ops = &omap2430_ops;
platform_set_drvdata(pdev, glue);

View File

@ -159,6 +159,15 @@ config USB_MXS_PHY
MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
config USB_TEGRA_PHY
tristate "NVIDIA Tegra USB PHY Driver"
depends on ARCH_TEGRA
select USB_PHY
select USB_ULPI
help
This driver provides PHY support for the USB controllers found
on NVIDIA Tegra SoC's.
config USB_ULPI
bool "Generic ULPI Transceiver Driver"
depends on ARM || ARM64

View File

@ -16,7 +16,7 @@ obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o
obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o
obj-$(CONFIG_OMAP_OTG) += phy-omap-otg.o
obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o
obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o
obj-$(CONFIG_USB_TEGRA_PHY) += phy-tegra-usb.o
obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o
obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o

View File

@ -96,8 +96,7 @@ static int am335x_phy_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int am335x_phy_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
struct am335x_phy *am_phy = dev_get_drvdata(dev);
/*
* Enable phy wakeup only if dev->power.can_wakeup is true.
@ -117,8 +116,7 @@ static int am335x_phy_suspend(struct device *dev)
static int am335x_phy_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
struct am335x_phy *am_phy = dev_get_drvdata(dev);
phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true);

View File

@ -236,13 +236,83 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable)
static int utmip_pad_open(struct tegra_usb_phy *phy)
{
int ret;
phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads");
if (IS_ERR(phy->pad_clk)) {
pr_err("%s: can't get utmip pad clock\n", __func__);
return PTR_ERR(phy->pad_clk);
ret = PTR_ERR(phy->pad_clk);
dev_err(phy->u_phy.dev,
"Failed to get UTMIP pad clock: %d\n", ret);
return ret;
}
return 0;
phy->pad_rst = devm_reset_control_get_optional_shared(
phy->u_phy.dev, "utmi-pads");
if (IS_ERR(phy->pad_rst)) {
ret = PTR_ERR(phy->pad_rst);
dev_err(phy->u_phy.dev,
"Failed to get UTMI-pads reset: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(phy->pad_clk);
if (ret) {
dev_err(phy->u_phy.dev,
"Failed to enable UTMI-pads clock: %d\n", ret);
return ret;
}
spin_lock(&utmip_pad_lock);
ret = reset_control_deassert(phy->pad_rst);
if (ret) {
dev_err(phy->u_phy.dev,
"Failed to initialize UTMI-pads reset: %d\n", ret);
goto unlock;
}
ret = reset_control_assert(phy->pad_rst);
if (ret) {
dev_err(phy->u_phy.dev,
"Failed to assert UTMI-pads reset: %d\n", ret);
goto unlock;
}
udelay(1);
ret = reset_control_deassert(phy->pad_rst);
if (ret)
dev_err(phy->u_phy.dev,
"Failed to deassert UTMI-pads reset: %d\n", ret);
unlock:
spin_unlock(&utmip_pad_lock);
clk_disable_unprepare(phy->pad_clk);
return ret;
}
static int utmip_pad_close(struct tegra_usb_phy *phy)
{
int ret;
ret = clk_prepare_enable(phy->pad_clk);
if (ret) {
dev_err(phy->u_phy.dev,
"Failed to enable UTMI-pads clock: %d\n", ret);
return ret;
}
ret = reset_control_assert(phy->pad_rst);
if (ret)
dev_err(phy->u_phy.dev,
"Failed to assert UTMI-pads reset: %d\n", ret);
udelay(1);
clk_disable_unprepare(phy->pad_clk);
return ret;
}
static void utmip_pad_power_on(struct tegra_usb_phy *phy)
@ -282,7 +352,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
void __iomem *base = phy->pad_regs;
if (!utmip_pad_count) {
pr_err("%s: utmip pad already powered off\n", __func__);
dev_err(phy->u_phy.dev, "UTMIP pad already powered off\n");
return -EINVAL;
}
@ -338,7 +408,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
set_phcd(phy, true);
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
dev_err(phy->u_phy.dev,
"Timeout waiting for PHY to stabilize on disable\n");
}
static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
@ -370,7 +441,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID))
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
dev_err(phy->u_phy.dev,
"Timeout waiting for PHY to stabilize on enable\n");
}
static int utmi_phy_power_on(struct tegra_usb_phy *phy)
@ -617,15 +689,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
ret = gpio_direction_output(phy->reset_gpio, 0);
if (ret < 0) {
dev_err(phy->u_phy.dev, "gpio %d not set to 0\n",
phy->reset_gpio);
dev_err(phy->u_phy.dev, "GPIO %d not set to 0: %d\n",
phy->reset_gpio, ret);
return ret;
}
msleep(5);
ret = gpio_direction_output(phy->reset_gpio, 1);
if (ret < 0) {
dev_err(phy->u_phy.dev, "gpio %d not set to 1\n",
phy->reset_gpio);
dev_err(phy->u_phy.dev, "GPIO %d not set to 1: %d\n",
phy->reset_gpio, ret);
return ret;
}
@ -661,13 +733,13 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
/* Fix VbusInvalid due to floating VBUS */
ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", ret);
return ret;
}
ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", ret);
return ret;
}
@ -694,6 +766,9 @@ static void tegra_usb_phy_close(struct tegra_usb_phy *phy)
if (!IS_ERR(phy->vbus))
regulator_disable(phy->vbus);
if (!phy->is_ulpi_phy)
utmip_pad_close(phy);
clk_disable_unprepare(phy->pll_u);
}
@ -728,28 +803,30 @@ static int ulpi_open(struct tegra_usb_phy *phy)
phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link");
if (IS_ERR(phy->clk)) {
pr_err("%s: can't get ulpi clock\n", __func__);
return PTR_ERR(phy->clk);
err = PTR_ERR(phy->clk);
dev_err(phy->u_phy.dev, "Failed to get ULPI clock: %d\n", err);
return err;
}
err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio,
"ulpi_phy_reset_b");
if (err < 0) {
dev_err(phy->u_phy.dev, "request failed for gpio: %d\n",
phy->reset_gpio);
dev_err(phy->u_phy.dev, "Request failed for GPIO %d: %d\n",
phy->reset_gpio, err);
return err;
}
err = gpio_direction_output(phy->reset_gpio, 0);
if (err < 0) {
dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n",
phy->reset_gpio);
dev_err(phy->u_phy.dev,
"GPIO %d direction not set to output: %d\n",
phy->reset_gpio, err);
return err;
}
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
if (!phy->ulpi) {
dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n");
dev_err(phy->u_phy.dev, "Failed to create ULPI OTG\n");
err = -ENOMEM;
return err;
}
@ -766,8 +843,10 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u");
if (IS_ERR(phy->pll_u)) {
pr_err("Can't get pll_u clock\n");
return PTR_ERR(phy->pll_u);
err = PTR_ERR(phy->pll_u);
dev_err(phy->u_phy.dev,
"Failed to get pll_u clock: %d\n", err);
return err;
}
err = clk_prepare_enable(phy->pll_u);
@ -782,7 +861,8 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
}
}
if (!phy->freq) {
pr_err("invalid pll_u parent rate %ld\n", parent_rate);
dev_err(phy->u_phy.dev, "Invalid pll_u parent rate %ld\n",
parent_rate);
err = -EINVAL;
goto fail;
}
@ -791,7 +871,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
err = regulator_enable(phy->vbus);
if (err) {
dev_err(phy->u_phy.dev,
"failed to enable usb vbus regulator: %d\n",
"Failed to enable USB VBUS regulator: %d\n",
err);
goto fail;
}
@ -855,7 +935,8 @@ static int read_utmi_param(struct platform_device *pdev, const char *param,
int err = of_property_read_u32(pdev->dev.of_node, param, &value);
*dest = (u8)value;
if (err < 0)
dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n",
dev_err(&pdev->dev,
"Failed to read USB UTMI parameter %s: %d\n",
param, err);
return err;
}
@ -871,14 +952,14 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
dev_err(&pdev->dev, "Failed to get UTMI pad regs\n");
return -ENXIO;
}
tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!tegra_phy->pad_regs) {
dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
dev_err(&pdev->dev, "Failed to remap UTMI pad regs\n");
return -ENOMEM;
}
@ -1020,15 +1101,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
tegra_phy->reset_gpio =
of_get_named_gpio(np, "nvidia,phy-reset-gpio", 0);
if (!gpio_is_valid(tegra_phy->reset_gpio)) {
dev_err(&pdev->dev, "invalid gpio: %d\n",
tegra_phy->reset_gpio);
dev_err(&pdev->dev,
"Invalid GPIO: %d\n", tegra_phy->reset_gpio);
return tegra_phy->reset_gpio;
}
tegra_phy->config = NULL;
break;
default:
dev_err(&pdev->dev, "phy_type is invalid or unsupported\n");
dev_err(&pdev->dev, "phy_type %u is invalid or unsupported\n",
phy_type);
return -EINVAL;
}

View File

@ -27,7 +27,6 @@
#define DEFAULT_ACA_CUR_MAX 5000
static LIST_HEAD(phy_list);
static LIST_HEAD(phy_bind_list);
static DEFINE_SPINLOCK(phy_lock);
struct phy_devm {
@ -50,24 +49,6 @@ static struct usb_phy *__usb_find_phy(struct list_head *list,
return ERR_PTR(-ENODEV);
}
static struct usb_phy *__usb_find_phy_dev(struct device *dev,
struct list_head *list, u8 index)
{
struct usb_phy_bind *phy_bind = NULL;
list_for_each_entry(phy_bind, list, list) {
if (!(strcmp(phy_bind->dev_name, dev_name(dev))) &&
phy_bind->index == index) {
if (phy_bind->phy)
return phy_bind->phy;
else
return ERR_PTR(-EPROBE_DEFER);
}
}
return ERR_PTR(-ENODEV);
}
static struct usb_phy *__of_usb_find_phy(struct device_node *node)
{
struct usb_phy *phy;
@ -584,72 +565,6 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
/**
* usb_get_phy_dev - find the USB PHY
* @dev - device that requests this phy
* @index - the index of the phy
*
* Returns the phy driver, after getting a refcount to it; or
* -ENODEV if there is no such phy. The caller is responsible for
* calling usb_put_phy() to release that count.
*
* For use by USB host and peripheral drivers.
*/
struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
{
struct usb_phy *phy = NULL;
unsigned long flags;
spin_lock_irqsave(&phy_lock, flags);
phy = __usb_find_phy_dev(dev, &phy_bind_list, index);
if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
dev_dbg(dev, "unable to find transceiver\n");
if (!IS_ERR(phy))
phy = ERR_PTR(-ENODEV);
goto err0;
}
get_device(phy->dev);
err0:
spin_unlock_irqrestore(&phy_lock, flags);
return phy;
}
EXPORT_SYMBOL_GPL(usb_get_phy_dev);
/**
* devm_usb_get_phy_dev - find the USB PHY using device ptr and index
* @dev - device that requests this phy
* @index - the index of the phy
*
* Gets the phy using usb_get_phy_dev(), and associates a device with it using
* devres. On driver detach, release function is invoked on the devres data,
* then, devres data is freed.
*
* For use by USB host and peripheral drivers.
*/
struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
{
struct usb_phy **ptr, *phy;
ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
phy = usb_get_phy_dev(dev, index);
if (!IS_ERR(phy)) {
*ptr = phy;
devres_add(dev, ptr);
} else
devres_free(ptr);
return phy;
}
EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev);
/**
* devm_usb_put_phy - release the USB PHY
* @dev - device that wants to release this phy
@ -745,7 +660,6 @@ EXPORT_SYMBOL_GPL(usb_add_phy);
*/
int usb_add_phy_dev(struct usb_phy *x)
{
struct usb_phy_bind *phy_bind;
unsigned long flags;
int ret;
@ -762,13 +676,9 @@ int usb_add_phy_dev(struct usb_phy *x)
ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
spin_lock_irqsave(&phy_lock, flags);
list_for_each_entry(phy_bind, &phy_bind_list, list)
if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev))))
phy_bind->phy = x;
list_add_tail(&x->head, &phy_list);
spin_unlock_irqrestore(&phy_lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(usb_add_phy_dev);
@ -782,53 +692,14 @@ EXPORT_SYMBOL_GPL(usb_add_phy_dev);
void usb_remove_phy(struct usb_phy *x)
{
unsigned long flags;
struct usb_phy_bind *phy_bind;
spin_lock_irqsave(&phy_lock, flags);
if (x) {
list_for_each_entry(phy_bind, &phy_bind_list, list)
if (phy_bind->phy == x)
phy_bind->phy = NULL;
if (x)
list_del(&x->head);
}
spin_unlock_irqrestore(&phy_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_remove_phy);
/**
* usb_bind_phy - bind the phy and the controller that uses the phy
* @dev_name: the device name of the device that will bind to the phy
* @index: index to specify the port number
* @phy_dev_name: the device name of the phy
*
* Fills the phy_bind structure with the dev_name and phy_dev_name. This will
* be used when the phy driver registers the phy and when the controller
* requests this phy.
*
* To be used by platform specific initialization code.
*/
int usb_bind_phy(const char *dev_name, u8 index,
const char *phy_dev_name)
{
struct usb_phy_bind *phy_bind;
unsigned long flags;
phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL);
if (!phy_bind)
return -ENOMEM;
phy_bind->dev_name = dev_name;
phy_bind->phy_dev_name = phy_dev_name;
phy_bind->index = index;
spin_lock_irqsave(&phy_lock, flags);
list_add_tail(&phy_bind->list, &phy_bind_list);
spin_unlock_irqrestore(&phy_lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(usb_bind_phy);
/**
* usb_phy_set_event - set event to phy event
* @x: the phy returned by usb_get_phy();

View File

@ -276,7 +276,6 @@ struct usbhs_priv {
*/
struct usbhs_fifo_info fifo_info;
struct usb_phy *usb_phy;
struct phy *phy;
};

View File

@ -8,7 +8,6 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/usb/phy.h>
#include "common.h"
#include "rcar2.h"
@ -26,16 +25,6 @@ static int usbhs_rcar2_hardware_init(struct platform_device *pdev)
return 0;
}
if (IS_ENABLED(CONFIG_USB_PHY)) {
struct usb_phy *usb_phy = usb_get_phy_dev(&pdev->dev, 0);
if (IS_ERR(usb_phy))
return PTR_ERR(usb_phy);
priv->usb_phy = usb_phy;
return 0;
}
return -ENXIO;
}
@ -48,11 +37,6 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev)
priv->phy = NULL;
}
if (priv->usb_phy) {
usb_put_phy(priv->usb_phy);
priv->usb_phy = NULL;
}
return 0;
}
@ -75,19 +59,6 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev,
}
}
if (priv->usb_phy) {
if (enable) {
retval = usb_phy_init(priv->usb_phy);
if (!retval)
retval = usb_phy_set_suspend(priv->usb_phy, 0);
} else {
usb_phy_set_suspend(priv->usb_phy, 1);
usb_phy_shutdown(priv->usb_phy);
retval = 0;
}
}
return retval;
}

View File

@ -144,6 +144,8 @@ static int intel_xhci_usb_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
data->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!data->base)
return -ENOMEM;

View File

@ -464,7 +464,7 @@ static int init_freecom(struct us_data *us)
usb_stor_dbg(us, "result from activate reset is %d\n", result);
/* wait 250ms */
mdelay(250);
msleep(250);
/* clear reset */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
@ -472,7 +472,7 @@ static int init_freecom(struct us_data *us)
usb_stor_dbg(us, "result from clear reset is %d\n", result);
/* wait 3 seconds */
mdelay(3 * 1000);
msleep(3 * 1000);
return USB_STOR_TRANSPORT_GOOD;
}

View File

@ -49,6 +49,7 @@ config TYPEC_TCPM
tristate "USB Type-C Port Controller Manager"
depends on USB
select USB_ROLE_SWITCH
select POWER_SUPPLY
help
The Type-C Port Controller Manager provides a USB PD and USB Type-C
state machine for use with Type-C Port Controllers.

View File

@ -1,6 +1,6 @@
config TYPEC_FUSB302
tristate "Fairchild FUSB302 Type-C chip driver"
depends on I2C && POWER_SUPPLY
depends on I2C
help
The Fairchild FUSB302 Type-C chip driver that works with
Type-C Port Controller Manager to provide USB PD and USB

View File

@ -18,7 +18,6 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/power_supply.h>
#include <linux/proc_fs.h>
#include <linux/regulator/consumer.h>
#include <linux/sched/clock.h>
@ -99,11 +98,6 @@ struct fusb302_chip {
/* lock for sharing chip states */
struct mutex lock;
/* psy + psy status */
struct power_supply *psy;
u32 current_limit;
u32 supply_voltage;
/* chip status */
enum toggling_mode toggling_mode;
enum src_current_status src_current_status;
@ -120,6 +114,7 @@ struct fusb302_chip {
enum typec_cc_polarity cc_polarity;
enum typec_cc_status cc1;
enum typec_cc_status cc2;
u32 snk_pdo[PDO_MAX_OBJECTS];
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
@ -861,13 +856,11 @@ static int tcpm_set_vbus(struct tcpc_dev *dev, bool on, bool charge)
chip->vbus_on = on;
fusb302_log(chip, "vbus := %s", on ? "On" : "Off");
}
if (chip->charge_on == charge) {
if (chip->charge_on == charge)
fusb302_log(chip, "charge is already %s",
charge ? "On" : "Off");
} else {
else
chip->charge_on = charge;
power_supply_changed(chip->psy);
}
done:
mutex_unlock(&chip->lock);
@ -883,11 +876,6 @@ static int tcpm_set_current_limit(struct tcpc_dev *dev, u32 max_ma, u32 mv)
fusb302_log(chip, "current limit: %d ma, %d mv (not implemented)",
max_ma, mv);
chip->supply_voltage = mv;
chip->current_limit = max_ma;
power_supply_changed(chip->psy);
return 0;
}
@ -1212,11 +1200,6 @@ static const u32 snk_pdo[] = {
static const struct tcpc_config fusb302_tcpc_config = {
.src_pdo = src_pdo,
.nr_src_pdo = ARRAY_SIZE(src_pdo),
.snk_pdo = snk_pdo,
.nr_snk_pdo = ARRAY_SIZE(snk_pdo),
.max_snk_mv = 5000,
.max_snk_ma = 3000,
.max_snk_mw = 15000,
.operating_snk_mw = 2500,
.type = TYPEC_PORT_DRP,
.data = TYPEC_PORT_DRD,
@ -1686,43 +1669,6 @@ done:
return IRQ_HANDLED;
}
static int fusb302_psy_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct fusb302_chip *chip = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = chip->charge_on;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = chip->supply_voltage * 1000; /* mV -> µV */
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
val->intval = chip->current_limit * 1000; /* mA -> µA */
break;
default:
return -ENODATA;
}
return 0;
}
static enum power_supply_property fusb302_psy_properties[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
};
static const struct power_supply_desc fusb302_psy_desc = {
.name = "fusb302-typec-source",
.type = POWER_SUPPLY_TYPE_USB_TYPE_C,
.properties = fusb302_psy_properties,
.num_properties = ARRAY_SIZE(fusb302_psy_properties),
.get_property = fusb302_psy_get_property,
};
static int init_gpio(struct fusb302_chip *chip)
{
struct device_node *node;
@ -1756,13 +1702,35 @@ static int init_gpio(struct fusb302_chip *chip)
return 0;
}
static int fusb302_composite_snk_pdo_array(struct fusb302_chip *chip)
{
struct device *dev = chip->dev;
u32 max_uv, max_ua;
chip->snk_pdo[0] = PDO_FIXED(5000, 400, PDO_FIXED_FLAGS);
/*
* As max_snk_ma/mv/mw is not needed for tcpc_config,
* those settings should be passed in via sink PDO, so
* "fcs, max-sink-*" properties will be deprecated, to
* perserve compatibility with existing users of them,
* we read those properties to convert them to be a var
* PDO.
*/
if (device_property_read_u32(dev, "fcs,max-sink-microvolt", &max_uv) ||
device_property_read_u32(dev, "fcs,max-sink-microamp", &max_ua))
return 1;
chip->snk_pdo[1] = PDO_VAR(5000, max_uv / 1000, max_ua / 1000);
return 2;
}
static int fusb302_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct fusb302_chip *chip;
struct i2c_adapter *adapter;
struct device *dev = &client->dev;
struct power_supply_config cfg = {};
const char *name;
int ret = 0;
u32 v;
@ -1784,18 +1752,13 @@ static int fusb302_probe(struct i2c_client *client,
chip->tcpc_dev.config = &chip->tcpc_config;
mutex_init(&chip->lock);
if (!device_property_read_u32(dev, "fcs,max-sink-microvolt", &v))
chip->tcpc_config.max_snk_mv = v / 1000;
if (!device_property_read_u32(dev, "fcs,max-sink-microamp", &v))
chip->tcpc_config.max_snk_ma = v / 1000;
if (!device_property_read_u32(dev, "fcs,max-sink-microwatt", &v))
chip->tcpc_config.max_snk_mw = v / 1000;
if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v))
chip->tcpc_config.operating_snk_mw = v / 1000;
/* Composite sink PDO */
chip->tcpc_config.nr_snk_pdo = fusb302_composite_snk_pdo_array(chip);
chip->tcpc_config.snk_pdo = chip->snk_pdo;
/*
* Devicetree platforms should get extcon via phandle (not yet
* supported). On ACPI platforms, we get the name from a device prop.
@ -1809,14 +1772,6 @@ static int fusb302_probe(struct i2c_client *client,
return -EPROBE_DEFER;
}
cfg.drv_data = chip;
chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg);
if (IS_ERR(chip->psy)) {
ret = PTR_ERR(chip->psy);
dev_err(chip->dev, "Error registering power-supply: %d\n", ret);
return ret;
}
ret = fusb302_debugfs_init(chip);
if (ret < 0)
return ret;

File diff suppressed because it is too large Load Diff

View File

@ -558,6 +558,7 @@ static const u32 src_pdo[] = {
static const u32 snk_pdo[] = {
PDO_FIXED(5000, 500, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |
PDO_FIXED_USB_COMM),
PDO_VAR(5000, 12000, 3000),
};
static struct tcpc_config wcove_typec_config = {
@ -566,9 +567,6 @@ static struct tcpc_config wcove_typec_config = {
.snk_pdo = snk_pdo,
.nr_snk_pdo = ARRAY_SIZE(snk_pdo),
.max_snk_mv = 12000,
.max_snk_ma = 3000,
.max_snk_mw = 36000,
.operating_snk_mw = 15000,
.type = TYPEC_PORT_DRP,

View File

@ -302,7 +302,7 @@ static int stub_probe(struct usb_device *udev)
struct bus_id_priv *busid_priv;
int rc;
dev_dbg(&udev->dev, "Enter\n");
dev_dbg(&udev->dev, "Enter probe\n");
/* check we should claim or not by busid_table */
busid_priv = get_busid_priv(udev_busid);
@ -404,7 +404,7 @@ static void stub_disconnect(struct usb_device *udev)
struct bus_id_priv *busid_priv;
int rc;
dev_dbg(&udev->dev, "Enter\n");
dev_dbg(&udev->dev, "Enter disconnect\n");
busid_priv = get_busid_priv(udev_busid);
if (!busid_priv) {

View File

@ -145,6 +145,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
@ -170,6 +171,19 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */
};
enum power_supply_usb_type {
POWER_SUPPLY_USB_TYPE_UNKNOWN = 0,
POWER_SUPPLY_USB_TYPE_SDP, /* Standard Downstream Port */
POWER_SUPPLY_USB_TYPE_DCP, /* Dedicated Charging Port */
POWER_SUPPLY_USB_TYPE_CDP, /* Charging Downstream Port */
POWER_SUPPLY_USB_TYPE_ACA, /* Accessory Charger Adapters */
POWER_SUPPLY_USB_TYPE_C, /* Type C Port */
POWER_SUPPLY_USB_TYPE_PD, /* Power Delivery Port */
POWER_SUPPLY_USB_TYPE_PD_DRP, /* PD Dual Role Port */
POWER_SUPPLY_USB_TYPE_PD_PPS, /* PD Programmable Power Supply */
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */
};
enum power_supply_notifier_events {
PSY_EVENT_PROP_CHANGED,
};
@ -196,6 +210,8 @@ struct power_supply_config {
struct power_supply_desc {
const char *name;
enum power_supply_type type;
enum power_supply_usb_type *usb_types;
size_t num_usb_types;
enum power_supply_property *properties;
size_t num_properties;

View File

@ -551,6 +551,8 @@ struct usb3_lpm_parameters {
* @route: tree topology hex string for use with xHCI
* @state: device state: configured, not attached, etc.
* @speed: device speed: high/full/low (or error)
* @rx_lanes: number of rx lanes in use, USB 3.2 adds dual-lane support
* @tx_lanes: number of tx lanes in use, USB 3.2 adds dual-lane support
* @tt: Transaction Translator info; used with low/full speed dev, highspeed hub
* @ttport: device port on that tt hub
* @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints
@ -624,6 +626,8 @@ struct usb_device {
u32 route;
enum usb_device_state state;
enum usb_device_speed speed;
unsigned int rx_lanes;
unsigned int tx_lanes;
struct usb_tt *tt;
int ttport;

View File

@ -94,7 +94,7 @@ struct uac_clock_selector_descriptor {
__u8 bClockID;
__u8 bNrInPins;
__u8 baCSourceID[];
/* bmControls, bAssocTerminal and iClockSource omitted */
/* bmControls and iClockSource omitted */
} __attribute__((packed));
/* 4.7.2.3 Clock Multiplier Descriptor */

View File

@ -150,7 +150,6 @@ struct usb_hcd {
unsigned rh_pollable:1; /* may we poll the root hub? */
unsigned msix_enabled:1; /* driver has MSI-X enabled? */
unsigned msi_enabled:1; /* driver has MSI enabled? */
unsigned remove_phy:1; /* auto-remove USB phy */
/*
* do not manage the PHY state in the HCD core, instead let the driver
* handle this (for example if the PHY can only be turned on after a
@ -261,6 +260,7 @@ struct hc_driver {
#define HCD_USB25 0x0030 /* Wireless USB 1.0 (USB 2.5)*/
#define HCD_USB3 0x0040 /* USB 3.0 */
#define HCD_USB31 0x0050 /* USB 3.1 */
#define HCD_USB32 0x0060 /* USB 3.2 */
#define HCD_MASK 0x0070
#define HCD_BH 0x0100 /* URB complete in BH context */

View File

@ -103,8 +103,8 @@ enum pd_ext_msg_type {
(((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT) | \
((ext_hdr) ? PD_HEADER_EXT_HDR : 0))
#define PD_HEADER_LE(type, pwr, data, id, cnt) \
cpu_to_le16(PD_HEADER((type), (pwr), (data), PD_REV20, (id), (cnt), (0)))
#define PD_HEADER_LE(type, pwr, data, rev, id, cnt) \
cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (0)))
static inline unsigned int pd_header_cnt(u16 header)
{

View File

@ -157,22 +157,6 @@ struct usb_phy {
enum usb_charger_type (*charger_detect)(struct usb_phy *x);
};
/**
* struct usb_phy_bind - represent the binding for the phy
* @dev_name: the device name of the device that will bind to the phy
* @phy_dev_name: the device name of the phy
* @index: used if a single controller uses multiple phys
* @phy: reference to the phy
* @list: to maintain a linked list of the binding information
*/
struct usb_phy_bind {
const char *dev_name;
const char *phy_dev_name;
u8 index;
struct usb_phy *phy;
struct list_head list;
};
/* for board-specific init logic */
extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
extern int usb_add_phy_dev(struct usb_phy *);
@ -234,16 +218,12 @@ usb_phy_vbus_off(struct usb_phy *x)
extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
extern struct usb_phy *devm_usb_get_phy(struct device *dev,
enum usb_phy_type type);
extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index);
extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index);
extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
const char *phandle, u8 index);
extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev,
struct device_node *node, struct notifier_block *nb);
extern void usb_put_phy(struct usb_phy *);
extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
extern int usb_bind_phy(const char *dev_name, u8 index,
const char *phy_dev_name);
extern void usb_phy_set_event(struct usb_phy *x, unsigned long event);
extern void usb_phy_set_charger_current(struct usb_phy *usb_phy,
unsigned int mA);
@ -263,16 +243,6 @@ static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
{
return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
{
return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
const char *phandle, u8 index)
{
@ -293,12 +263,6 @@ static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
{
}
static inline int usb_bind_phy(const char *dev_name, u8 index,
const char *phy_dev_name)
{
return -EOPNOTSUPP;
}
static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event)
{
}

View File

@ -36,6 +36,7 @@ enum typec_cc_polarity {
/* Time to wait for TCPC to complete transmit */
#define PD_T_TCPC_TX_TIMEOUT 100 /* in ms */
#define PD_ROLE_SWAP_TIMEOUT (MSEC_PER_SEC * 10)
#define PD_PPS_CTRL_TIMEOUT (MSEC_PER_SEC * 10)
enum tcpm_transmit_status {
TCPC_TX_SUCCESS = 0,
@ -62,9 +63,6 @@ enum tcpm_transmit_type {
* @snk_pdo: PDO parameters sent to partner as response to
* PD_CTRL_GET_SINK_CAP message
* @nr_snk_pdo: Number of entries in @snk_pdo
* @max_snk_mv: Maximum acceptable sink voltage in mV
* @max_snk_ma: Maximum sink current in mA
* @max_snk_mw: Maximum required sink power in mW
* @operating_snk_mw:
* Required operating sink power in mW
* @type: Port type (TYPEC_PORT_DFP, TYPEC_PORT_UFP, or
@ -85,9 +83,6 @@ struct tcpc_config {
const u32 *snk_vdo;
unsigned int nr_snk_vdo;
unsigned int max_snk_mv;
unsigned int max_snk_ma;
unsigned int max_snk_mw;
unsigned int operating_snk_mw;
enum typec_port_type type;
@ -174,9 +169,6 @@ int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
unsigned int nr_pdo);
int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
unsigned int nr_pdo,
unsigned int max_snk_mv,
unsigned int max_snk_ma,
unsigned int max_snk_mw,
unsigned int operating_snk_mw);
void tcpm_vbus_change(struct tcpm_port *port);

View File

@ -17,6 +17,7 @@
#define __TEGRA_USB_PHY_H
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/usb/otg.h>
/*
@ -76,6 +77,7 @@ struct tegra_usb_phy {
bool is_legacy_phy;
bool is_ulpi_phy;
int reset_gpio;
struct reset_control *pad_rst;
};
void tegra_usb_phy_preresume(struct usb_phy *phy);

View File

@ -197,6 +197,11 @@ struct usb_port_status {
#define USB_EXT_PORT_STAT_RX_LANES 0x00000f00
#define USB_EXT_PORT_STAT_TX_LANES 0x0000f000
#define USB_EXT_PORT_RX_LANES(p) \
(((p) & USB_EXT_PORT_STAT_RX_LANES) >> 8)
#define USB_EXT_PORT_TX_LANES(p) \
(((p) & USB_EXT_PORT_STAT_TX_LANES) >> 12)
/*
* wHubCharacteristics (masks)
* See USB 2.0 spec Table 11-13, offset 3