Immutable branch for both MFD and EXTCON tree.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJaTKdFAAoJEJzN3yze689T/vMP/irsEslIVpSWTmKkJVt4UGXC pCQwG0xozPF/tZ5dZ+dHznUcQLZE/FxDFzfJGb9pMFHKFt5NNCVXraUOKgVMv3Qv Cmy+q9XO6AwKNSm9xj9Bson7gJ5qHNpesG/BSptHshH61QgCUJK3fIG6Q+p6+El4 P5XHE4iK7aYxHhMfkTDbMiFOl0PmGSliCnTZTpwhkVjq/q0tDdFVgayjltrwhUkH vNFRW7monJqeCFcYU85JotVxluMbCK2OuljCCPnQae8TOhvJTLE+QfJsSqtxxUEq gXTqqY3pxHWac3YaXzhopV46whODZnft/U7E917OoaNPK4Bf3rgqLTxgEPRU3uHu mvDSFPILH2F0lqBQ/WUrFndjmI/kWNvQanFzr07++hg1d0qRH4erax45F6ZoEafP 73VpXJcTJJ+dyhtaTNKNE/dSRsdHx6gJD38W0J/ZWiSMQNPbQ/RJJSxYJFIjQgrZ c3kTCbXzedBjo3jeSMoZjeoomh8ed+PDH/59ISYE7ar16AoHV0KGNVUoTWQUdEhg txPVq9Xt6/0cR8u7ZgJi0I88K7plRPne/y/OgHcL5IcDDqXZYOJ5Xi3RTwlm0NO2 NKmkg+Rt0+yb9zbaIEYulpLZ4WIsXi5Rf1ByhIqJO7Cy5YxSqznDNxtQqnP48jBd u9ecKNrScz//pHgGEqTT =97Us -----END PGP SIGNATURE----- Merge branches 'ib-mfd-leds-4.16', 'ib-mfd-memstick-misc-mmc-4.16', 'ib-mfd-platform-4.16' and 'ib-mfd-tty-watchdog-4.16', tag 'ib-extcon-mfd-4.16-1' into ibs-for-mfd-merged Immutable branch for both MFD and EXTCON tree.
This commit is contained in:
commit
8848ff4206
52 changed files with 2659 additions and 146 deletions
|
@ -0,0 +1,39 @@
|
|||
Zodiac Inflight Innovations RAVE Supervisory Processor Watchdog Bindings
|
||||
|
||||
RAVE SP watchdog device is a "MFD cell" device corresponding to
|
||||
watchdog functionality of RAVE Supervisory Processor. It is expected
|
||||
that its Device Tree node is specified as a child of the node
|
||||
corresponding to the parent RAVE SP device (as documented in
|
||||
Documentation/devicetree/bindings/mfd/zii,rave-sp.txt)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Depending on wire protocol implemented by RAVE SP
|
||||
firmware, should be one of:
|
||||
- "zii,rave-sp-watchdog"
|
||||
- "zii,rave-sp-watchdog-legacy"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- wdt-timeout: Two byte nvmem cell specified as per
|
||||
Documentation/devicetree/bindings/nvmem/nvmem.txt
|
||||
|
||||
Example:
|
||||
|
||||
rave-sp {
|
||||
compatible = "zii,rave-sp-rdu1";
|
||||
current-speed = <38400>;
|
||||
|
||||
eeprom {
|
||||
wdt_timeout: wdt-timeout@8E {
|
||||
reg = <0x8E 2>;
|
||||
};
|
||||
};
|
||||
|
||||
watchdog {
|
||||
compatible = "zii,rave-sp-watchdog";
|
||||
nvmem-cells = <&wdt_timeout>;
|
||||
nvmem-cell-names = "wdt-timeout";
|
||||
};
|
||||
}
|
||||
|
|
@ -384,6 +384,9 @@ RESET
|
|||
devm_reset_control_get()
|
||||
devm_reset_controller_register()
|
||||
|
||||
SERDEV
|
||||
devm_serdev_device_open()
|
||||
|
||||
SLAVE DMA ENGINE
|
||||
devm_acpi_dma_controller_register()
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <linux/notifier.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
|
||||
/* Power source status register */
|
||||
|
@ -79,11 +77,6 @@ enum axp288_extcon_reg {
|
|||
AXP288_BC_DET_STAT_REG = 0x2f,
|
||||
};
|
||||
|
||||
enum axp288_mux_select {
|
||||
EXTCON_GPIO_MUX_SEL_PMIC = 0,
|
||||
EXTCON_GPIO_MUX_SEL_SOC,
|
||||
};
|
||||
|
||||
enum axp288_extcon_irq {
|
||||
VBUS_FALLING_IRQ = 0,
|
||||
VBUS_RISING_IRQ,
|
||||
|
@ -104,10 +97,8 @@ struct axp288_extcon_info {
|
|||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *regmap_irqc;
|
||||
struct gpio_desc *gpio_mux_cntl;
|
||||
int irq[EXTCON_IRQ_END];
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block extcon_nb;
|
||||
unsigned int previous_cable;
|
||||
};
|
||||
|
||||
|
@ -197,15 +188,6 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
|
|||
}
|
||||
|
||||
no_vbus:
|
||||
/*
|
||||
* If VBUS is absent Connect D+/D- lines to PMIC for BC
|
||||
* detection. Else connect them to SOC for USB communication.
|
||||
*/
|
||||
if (info->gpio_mux_cntl)
|
||||
gpiod_set_value(info->gpio_mux_cntl,
|
||||
vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
|
||||
: EXTCON_GPIO_MUX_SEL_PMIC);
|
||||
|
||||
extcon_set_state_sync(info->edev, info->previous_cable, false);
|
||||
if (info->previous_cable == EXTCON_CHG_USB_SDP)
|
||||
extcon_set_state_sync(info->edev, EXTCON_USB, false);
|
||||
|
@ -253,8 +235,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct axp288_extcon_info *info;
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct axp288_extcon_pdata *pdata = pdev->dev.platform_data;
|
||||
int ret, i, pirq, gpio;
|
||||
int ret, i, pirq;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
|
@ -264,8 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
|||
info->regmap = axp20x->regmap;
|
||||
info->regmap_irqc = axp20x->regmap_irqc;
|
||||
info->previous_cable = EXTCON_NONE;
|
||||
if (pdata)
|
||||
info->gpio_mux_cntl = pdata->gpio_mux_cntl;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
|
@ -286,21 +265,11 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Set up gpio control for USB Mux */
|
||||
if (info->gpio_mux_cntl) {
|
||||
gpio = desc_to_gpio(info->gpio_mux_cntl);
|
||||
ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to request the gpio=%d\n", gpio);
|
||||
return ret;
|
||||
}
|
||||
gpiod_direction_output(info->gpio_mux_cntl,
|
||||
EXTCON_GPIO_MUX_SEL_PMIC);
|
||||
}
|
||||
|
||||
for (i = 0; i < EXTCON_IRQ_END; i++) {
|
||||
pirq = platform_get_irq(pdev, i);
|
||||
if (pirq < 0)
|
||||
return pirq;
|
||||
|
||||
info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
|
||||
if (info->irq[i] < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
|
|
|
@ -34,16 +34,26 @@ struct cros_ec_extcon_info {
|
|||
|
||||
struct notifier_block notifier;
|
||||
|
||||
unsigned int dr; /* data role */
|
||||
bool pr; /* power role (true if VBUS enabled) */
|
||||
bool dp; /* DisplayPort enabled */
|
||||
bool mux; /* SuperSpeed (usb3) enabled */
|
||||
unsigned int power_type;
|
||||
};
|
||||
|
||||
static const unsigned int usb_type_c_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
EXTCON_DISP_DP,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
enum usb_data_roles {
|
||||
DR_NONE,
|
||||
DR_HOST,
|
||||
DR_DEVICE,
|
||||
};
|
||||
|
||||
/**
|
||||
* cros_ec_pd_command() - Send a command to the EC.
|
||||
* @info: pointer to struct cros_ec_extcon_info
|
||||
|
@ -150,6 +160,7 @@ static int cros_ec_usb_get_role(struct cros_ec_extcon_info *info,
|
|||
pd_control.port = info->port_id;
|
||||
pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE;
|
||||
pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE;
|
||||
pd_control.swap = USB_PD_CTRL_SWAP_NONE;
|
||||
ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1,
|
||||
&pd_control, sizeof(pd_control),
|
||||
&resp, sizeof(resp));
|
||||
|
@ -183,11 +194,72 @@ static int cros_ec_pd_get_num_ports(struct cros_ec_extcon_info *info)
|
|||
return resp.num_ports;
|
||||
}
|
||||
|
||||
static const char *cros_ec_usb_role_string(unsigned int role)
|
||||
{
|
||||
return role == DR_NONE ? "DISCONNECTED" :
|
||||
(role == DR_HOST ? "DFP" : "UFP");
|
||||
}
|
||||
|
||||
static const char *cros_ec_usb_power_type_string(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case USB_CHG_TYPE_NONE:
|
||||
return "USB_CHG_TYPE_NONE";
|
||||
case USB_CHG_TYPE_PD:
|
||||
return "USB_CHG_TYPE_PD";
|
||||
case USB_CHG_TYPE_PROPRIETARY:
|
||||
return "USB_CHG_TYPE_PROPRIETARY";
|
||||
case USB_CHG_TYPE_C:
|
||||
return "USB_CHG_TYPE_C";
|
||||
case USB_CHG_TYPE_BC12_DCP:
|
||||
return "USB_CHG_TYPE_BC12_DCP";
|
||||
case USB_CHG_TYPE_BC12_CDP:
|
||||
return "USB_CHG_TYPE_BC12_CDP";
|
||||
case USB_CHG_TYPE_BC12_SDP:
|
||||
return "USB_CHG_TYPE_BC12_SDP";
|
||||
case USB_CHG_TYPE_OTHER:
|
||||
return "USB_CHG_TYPE_OTHER";
|
||||
case USB_CHG_TYPE_VBUS:
|
||||
return "USB_CHG_TYPE_VBUS";
|
||||
case USB_CHG_TYPE_UNKNOWN:
|
||||
return "USB_CHG_TYPE_UNKNOWN";
|
||||
default:
|
||||
return "USB_CHG_TYPE_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static bool cros_ec_usb_power_type_is_wall_wart(unsigned int type,
|
||||
unsigned int role)
|
||||
{
|
||||
switch (type) {
|
||||
/* FIXME : Guppy, Donnettes, and other chargers will be miscategorized
|
||||
* because they identify with USB_CHG_TYPE_C, but we can't return true
|
||||
* here from that code because that breaks Suzy-Q and other kinds of
|
||||
* USB Type-C cables and peripherals.
|
||||
*/
|
||||
case USB_CHG_TYPE_PROPRIETARY:
|
||||
case USB_CHG_TYPE_BC12_DCP:
|
||||
return true;
|
||||
case USB_CHG_TYPE_PD:
|
||||
case USB_CHG_TYPE_C:
|
||||
case USB_CHG_TYPE_BC12_CDP:
|
||||
case USB_CHG_TYPE_BC12_SDP:
|
||||
case USB_CHG_TYPE_OTHER:
|
||||
case USB_CHG_TYPE_VBUS:
|
||||
case USB_CHG_TYPE_UNKNOWN:
|
||||
case USB_CHG_TYPE_NONE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
|
||||
bool force)
|
||||
{
|
||||
struct device *dev = info->dev;
|
||||
int role, power_type;
|
||||
unsigned int dr = DR_NONE;
|
||||
bool pr = false;
|
||||
bool polarity = false;
|
||||
bool dp = false;
|
||||
bool mux = false;
|
||||
|
@ -206,9 +278,12 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
|
|||
dev_err(dev, "failed getting role err = %d\n", role);
|
||||
return role;
|
||||
}
|
||||
dev_dbg(dev, "disconnected\n");
|
||||
} else {
|
||||
int pd_mux_state;
|
||||
|
||||
dr = (role & PD_CTRL_RESP_ROLE_DATA) ? DR_HOST : DR_DEVICE;
|
||||
pr = (role & PD_CTRL_RESP_ROLE_POWER);
|
||||
pd_mux_state = cros_ec_usb_get_pd_mux_state(info);
|
||||
if (pd_mux_state < 0)
|
||||
pd_mux_state = USB_PD_MUX_USB_ENABLED;
|
||||
|
@ -216,20 +291,62 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
|
|||
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;
|
||||
|
||||
dev_dbg(dev,
|
||||
"connected role 0x%x pwr type %d dr %d pr %d pol %d mux %d dp %d hpd %d\n",
|
||||
role, power_type, dr, pr, polarity, mux, dp, hpd);
|
||||
}
|
||||
|
||||
if (force || info->dp != dp || info->mux != mux ||
|
||||
info->power_type != power_type) {
|
||||
/*
|
||||
* When there is no USB host (e.g. USB PD charger),
|
||||
* we are not really a UFP for the AP.
|
||||
*/
|
||||
if (dr == DR_DEVICE &&
|
||||
cros_ec_usb_power_type_is_wall_wart(power_type, role))
|
||||
dr = DR_NONE;
|
||||
|
||||
if (force || info->dr != dr || info->pr != pr || info->dp != dp ||
|
||||
info->mux != mux || info->power_type != power_type) {
|
||||
bool host_connected = false, device_connected = false;
|
||||
|
||||
dev_dbg(dev, "Type/Role switch! type = %s role = %s\n",
|
||||
cros_ec_usb_power_type_string(power_type),
|
||||
cros_ec_usb_role_string(dr));
|
||||
info->dr = dr;
|
||||
info->pr = pr;
|
||||
info->dp = dp;
|
||||
info->mux = mux;
|
||||
info->power_type = power_type;
|
||||
|
||||
extcon_set_state(info->edev, EXTCON_DISP_DP, dp);
|
||||
if (dr == DR_DEVICE)
|
||||
device_connected = true;
|
||||
else if (dr == DR_HOST)
|
||||
host_connected = true;
|
||||
|
||||
extcon_set_state(info->edev, EXTCON_USB, device_connected);
|
||||
extcon_set_state(info->edev, EXTCON_USB_HOST, host_connected);
|
||||
extcon_set_state(info->edev, EXTCON_DISP_DP, dp);
|
||||
extcon_set_property(info->edev, EXTCON_USB,
|
||||
EXTCON_PROP_USB_VBUS,
|
||||
(union extcon_property_value)(int)pr);
|
||||
extcon_set_property(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_VBUS,
|
||||
(union extcon_property_value)(int)pr);
|
||||
extcon_set_property(info->edev, EXTCON_USB,
|
||||
EXTCON_PROP_USB_TYPEC_POLARITY,
|
||||
(union extcon_property_value)(int)polarity);
|
||||
extcon_set_property(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_TYPEC_POLARITY,
|
||||
(union extcon_property_value)(int)polarity);
|
||||
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_USB,
|
||||
EXTCON_PROP_USB_SS,
|
||||
(union extcon_property_value)(int)mux);
|
||||
extcon_set_property(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_SS,
|
||||
(union extcon_property_value)(int)mux);
|
||||
extcon_set_property(info->edev, EXTCON_DISP_DP,
|
||||
EXTCON_PROP_USB_SS,
|
||||
(union extcon_property_value)(int)mux);
|
||||
|
@ -237,6 +354,8 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
|
|||
EXTCON_PROP_DISP_HPD,
|
||||
(union extcon_property_value)(int)hpd);
|
||||
|
||||
extcon_sync(info->edev, EXTCON_USB);
|
||||
extcon_sync(info->edev, EXTCON_USB_HOST);
|
||||
extcon_sync(info->edev, EXTCON_DISP_DP);
|
||||
|
||||
} else if (hpd) {
|
||||
|
@ -322,13 +441,28 @@ static int extcon_cros_ec_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB,
|
||||
EXTCON_PROP_USB_VBUS);
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_VBUS);
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB,
|
||||
EXTCON_PROP_USB_TYPEC_POLARITY);
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_TYPEC_POLARITY);
|
||||
extcon_set_property_capability(info->edev, EXTCON_DISP_DP,
|
||||
EXTCON_PROP_USB_TYPEC_POLARITY);
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB,
|
||||
EXTCON_PROP_USB_SS);
|
||||
extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
|
||||
EXTCON_PROP_USB_SS);
|
||||
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);
|
||||
|
||||
info->dr = DR_NONE;
|
||||
info->pr = false;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
/* Get PD events from the EC */
|
||||
|
|
|
@ -106,7 +106,7 @@ static int pm8058_led_probe(struct platform_device *pdev)
|
|||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
led->ledtype = (u32)of_device_get_match_data(&pdev->dev);
|
||||
led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
map = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!map) {
|
||||
|
|
|
@ -45,7 +45,7 @@ config MEMSTICK_R592
|
|||
|
||||
config MEMSTICK_REALTEK_PCI
|
||||
tristate "Realtek PCI-E Memstick Card Interface Driver"
|
||||
depends on MFD_RTSX_PCI
|
||||
depends on MISC_RTSX_PCI
|
||||
help
|
||||
Say Y here to include driver code to support Memstick card interface
|
||||
of Realtek PCI-E card reader
|
||||
|
@ -55,7 +55,7 @@ config MEMSTICK_REALTEK_PCI
|
|||
|
||||
config MEMSTICK_REALTEK_USB
|
||||
tristate "Realtek USB Memstick Card Interface Driver"
|
||||
depends on MFD_RTSX_USB
|
||||
depends on MISC_RTSX_USB
|
||||
help
|
||||
Say Y here to include driver code to support Memstick card interface
|
||||
of Realtek RTS5129/39 series USB card reader
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/memstick.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
struct realtek_pci_ms {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/memstick.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mfd/rtsx_usb.h>
|
||||
#include <linux/rtsx_usb.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
|
@ -222,6 +222,16 @@ config MFD_CROS_EC_SPI
|
|||
response time cannot be guaranteed, we support ignoring
|
||||
'pre-amble' bytes before the response actually starts.
|
||||
|
||||
config MFD_CROS_EC_CHARDEV
|
||||
tristate "Chrome OS Embedded Controller userspace device interface"
|
||||
depends on MFD_CROS_EC
|
||||
select CROS_EC_CTL
|
||||
---help---
|
||||
This driver adds support to talk with the ChromeOS EC from userspace.
|
||||
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called cros_ec_dev.
|
||||
|
||||
config MFD_ASIC3
|
||||
bool "Compaq ASIC3"
|
||||
depends on GPIOLIB && ARM
|
||||
|
@ -929,17 +939,6 @@ config MFD_RDC321X
|
|||
southbridge which provides access to GPIOs and Watchdog using the
|
||||
southbridge PCI device configuration space.
|
||||
|
||||
config MFD_RTSX_PCI
|
||||
tristate "Realtek PCI-E card reader"
|
||||
depends on PCI
|
||||
select MFD_CORE
|
||||
help
|
||||
This supports for Realtek PCI-Express card reader including rts5209,
|
||||
rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, etc.
|
||||
Realtek card reader supports access to many types of memory cards,
|
||||
such as Memory Stick, Memory Stick Pro, Secure Digital and
|
||||
MultiMediaCard.
|
||||
|
||||
config MFD_RT5033
|
||||
tristate "Richtek RT5033 Power Management IC"
|
||||
depends on I2C
|
||||
|
@ -953,16 +952,6 @@ config MFD_RT5033
|
|||
sub-devices like charger, fuel gauge, flash LED, current source,
|
||||
LDO and Buck.
|
||||
|
||||
config MFD_RTSX_USB
|
||||
tristate "Realtek USB card reader"
|
||||
depends on USB
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this option to get support for Realtek USB 2.0 card readers
|
||||
including RTS5129, RTS5139, RTS5179 and RTS5170.
|
||||
Realtek card reader supports access to many types of memory cards,
|
||||
such as Memory Stick Pro, Secure Digital and MultiMediaCard.
|
||||
|
||||
config MFD_RC5T583
|
||||
bool "Ricoh RC5T583 Power Management system device"
|
||||
depends on I2C=y
|
||||
|
@ -1859,5 +1848,13 @@ config MFD_VEXPRESS_SYSREG
|
|||
System Registers are the platform configuration block
|
||||
on the ARM Ltd. Versatile Express board.
|
||||
|
||||
config RAVE_SP_CORE
|
||||
tristate "RAVE SP MCU core driver"
|
||||
depends on SERIAL_DEV_BUS
|
||||
select CRC_CCITT
|
||||
help
|
||||
Select this to get support for the Supervisory Processor
|
||||
device found on several devices in RAVE line of hardware.
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
|
|
@ -17,12 +17,9 @@ cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o
|
|||
obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o
|
||||
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
|
||||
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
|
||||
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
|
||||
obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o
|
||||
|
||||
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
|
||||
obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
|
||||
|
||||
|
@ -230,3 +227,5 @@ obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
|
|||
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
|
||||
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
|
||||
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
|
||||
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
|
||||
|
||||
|
|
|
@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = {
|
|||
};
|
||||
|
||||
static const struct mfd_cell ec_cell = {
|
||||
.name = "cros-ec-ctl",
|
||||
.name = "cros-ec-dev",
|
||||
.platform_data = &ec_p,
|
||||
.pdata_size = sizeof(ec_p),
|
||||
};
|
||||
|
||||
static const struct mfd_cell ec_pd_cell = {
|
||||
.name = "cros-ec-ctl",
|
||||
.name = "cros-ec-dev",
|
||||
.platform_data = &pd_p,
|
||||
.pdata_size = sizeof(pd_p),
|
||||
};
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "cros_ec_debugfs.h"
|
||||
#include "cros_ec_dev.h"
|
||||
|
||||
#define DRV_NAME "cros-ec-dev"
|
||||
|
||||
/* Device variables */
|
||||
#define CROS_MAX_DEV 128
|
||||
static int ec_major;
|
||||
|
@ -461,7 +462,7 @@ static int ec_device_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct platform_device_id cros_ec_id[] = {
|
||||
{ "cros-ec-ctl", 0 },
|
||||
{ DRV_NAME, 0 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cros_ec_id);
|
||||
|
@ -493,7 +494,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = {
|
|||
|
||||
static struct platform_driver cros_ec_dev_driver = {
|
||||
.driver = {
|
||||
.name = "cros-ec-ctl",
|
||||
.name = DRV_NAME,
|
||||
.pm = &cros_ec_dev_pm_ops,
|
||||
},
|
||||
.probe = ec_device_probe,
|
||||
|
@ -544,6 +545,7 @@ static void __exit cros_ec_dev_exit(void)
|
|||
module_init(cros_ec_dev_init);
|
||||
module_exit(cros_ec_dev_exit);
|
||||
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>");
|
||||
MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller");
|
||||
MODULE_VERSION("1.0");
|
710
drivers/mfd/rave-sp.c
Normal file
710
drivers/mfd/rave-sp.c
Normal file
|
@ -0,0 +1,710 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/*
|
||||
* Multifunction core driver for Zodiac Inflight Innovations RAVE
|
||||
* Supervisory Processor(SP) MCU that is connected via dedicated UART
|
||||
* port
|
||||
*
|
||||
* Copyright (C) 2017 Zodiac Inflight Innovations
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/rave-sp.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/*
|
||||
* UART protocol using following entities:
|
||||
* - message to MCU => ACK response
|
||||
* - event from MCU => event ACK
|
||||
*
|
||||
* Frame structure:
|
||||
* <STX> <DATA> <CHECKSUM> <ETX>
|
||||
* Where:
|
||||
* - STX - is start of transmission character
|
||||
* - ETX - end of transmission
|
||||
* - DATA - payload
|
||||
* - CHECKSUM - checksum calculated on <DATA>
|
||||
*
|
||||
* If <DATA> or <CHECKSUM> contain one of control characters, then it is
|
||||
* escaped using <DLE> control code. Added <DLE> does not participate in
|
||||
* checksum calculation.
|
||||
*/
|
||||
#define RAVE_SP_STX 0x02
|
||||
#define RAVE_SP_ETX 0x03
|
||||
#define RAVE_SP_DLE 0x10
|
||||
|
||||
#define RAVE_SP_MAX_DATA_SIZE 64
|
||||
#define RAVE_SP_CHECKSUM_SIZE 2 /* Worst case scenario on RDU2 */
|
||||
/*
|
||||
* We don't store STX, ETX and unescaped bytes, so Rx is only
|
||||
* DATA + CSUM
|
||||
*/
|
||||
#define RAVE_SP_RX_BUFFER_SIZE \
|
||||
(RAVE_SP_MAX_DATA_SIZE + RAVE_SP_CHECKSUM_SIZE)
|
||||
|
||||
#define RAVE_SP_STX_ETX_SIZE 2
|
||||
/*
|
||||
* For Tx we have to have space for everything, STX, EXT and
|
||||
* potentially stuffed DATA + CSUM data + csum
|
||||
*/
|
||||
#define RAVE_SP_TX_BUFFER_SIZE \
|
||||
(RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE)
|
||||
|
||||
#define RAVE_SP_BOOT_SOURCE_GET 0
|
||||
#define RAVE_SP_BOOT_SOURCE_SET 1
|
||||
|
||||
#define RAVE_SP_RDU2_BOARD_TYPE_RMB 0
|
||||
#define RAVE_SP_RDU2_BOARD_TYPE_DEB 1
|
||||
|
||||
#define RAVE_SP_BOOT_SOURCE_SD 0
|
||||
#define RAVE_SP_BOOT_SOURCE_EMMC 1
|
||||
#define RAVE_SP_BOOT_SOURCE_NOR 2
|
||||
|
||||
/**
|
||||
* enum rave_sp_deframer_state - Possible state for de-framer
|
||||
*
|
||||
* @RAVE_SP_EXPECT_SOF: Scanning input for start-of-frame marker
|
||||
* @RAVE_SP_EXPECT_DATA: Got start of frame marker, collecting frame
|
||||
* @RAVE_SP_EXPECT_ESCAPED_DATA: Got escape character, collecting escaped byte
|
||||
*/
|
||||
enum rave_sp_deframer_state {
|
||||
RAVE_SP_EXPECT_SOF,
|
||||
RAVE_SP_EXPECT_DATA,
|
||||
RAVE_SP_EXPECT_ESCAPED_DATA,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_deframer - Device protocol deframer
|
||||
*
|
||||
* @state: Current state of the deframer
|
||||
* @data: Buffer used to collect deframed data
|
||||
* @length: Number of bytes de-framed so far
|
||||
*/
|
||||
struct rave_sp_deframer {
|
||||
enum rave_sp_deframer_state state;
|
||||
unsigned char data[RAVE_SP_RX_BUFFER_SIZE];
|
||||
size_t length;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_reply - Reply as per RAVE device protocol
|
||||
*
|
||||
* @length: Expected reply length
|
||||
* @data: Buffer to store reply payload in
|
||||
* @code: Expected reply code
|
||||
* @ackid: Expected reply ACK ID
|
||||
* @completion: Successful reply reception completion
|
||||
*/
|
||||
struct rave_sp_reply {
|
||||
size_t length;
|
||||
void *data;
|
||||
u8 code;
|
||||
u8 ackid;
|
||||
struct completion received;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_checksum - Variant specific checksum implementation details
|
||||
*
|
||||
* @length: Caculated checksum length
|
||||
* @subroutine: Utilized checksum algorithm implementation
|
||||
*/
|
||||
struct rave_sp_checksum {
|
||||
size_t length;
|
||||
void (*subroutine)(const u8 *, size_t, u8 *);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_variant_cmds - Variant specific command routines
|
||||
*
|
||||
* @translate: Generic to variant specific command mapping routine
|
||||
*
|
||||
*/
|
||||
struct rave_sp_variant_cmds {
|
||||
int (*translate)(enum rave_sp_command);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_variant - RAVE supervisory processor core variant
|
||||
*
|
||||
* @checksum: Variant specific checksum implementation
|
||||
* @cmd: Variant specific command pointer table
|
||||
*
|
||||
*/
|
||||
struct rave_sp_variant {
|
||||
const struct rave_sp_checksum *checksum;
|
||||
struct rave_sp_variant_cmds cmd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp - RAVE supervisory processor core
|
||||
*
|
||||
* @serdev: Pointer to underlying serdev
|
||||
* @deframer: Stored state of the protocol deframer
|
||||
* @ackid: ACK ID used in last reply sent to the device
|
||||
* @bus_lock: Lock to serialize access to the device
|
||||
* @reply_lock: Lock protecting @reply
|
||||
* @reply: Pointer to memory to store reply payload
|
||||
*
|
||||
* @variant: Device variant specific information
|
||||
* @event_notifier_list: Input event notification chain
|
||||
*
|
||||
*/
|
||||
struct rave_sp {
|
||||
struct serdev_device *serdev;
|
||||
struct rave_sp_deframer deframer;
|
||||
atomic_t ackid;
|
||||
struct mutex bus_lock;
|
||||
struct mutex reply_lock;
|
||||
struct rave_sp_reply *reply;
|
||||
|
||||
const struct rave_sp_variant *variant;
|
||||
struct blocking_notifier_head event_notifier_list;
|
||||
};
|
||||
|
||||
static bool rave_sp_id_is_event(u8 code)
|
||||
{
|
||||
return (code & 0xF0) == RAVE_SP_EVNT_BASE;
|
||||
}
|
||||
|
||||
static void rave_sp_unregister_event_notifier(struct device *dev, void *res)
|
||||
{
|
||||
struct rave_sp *sp = dev_get_drvdata(dev->parent);
|
||||
struct notifier_block *nb = *(struct notifier_block **)res;
|
||||
struct blocking_notifier_head *bnh = &sp->event_notifier_list;
|
||||
|
||||
WARN_ON(blocking_notifier_chain_unregister(bnh, nb));
|
||||
}
|
||||
|
||||
int devm_rave_sp_register_event_notifier(struct device *dev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct rave_sp *sp = dev_get_drvdata(dev->parent);
|
||||
struct notifier_block **rcnb;
|
||||
int ret;
|
||||
|
||||
rcnb = devres_alloc(rave_sp_unregister_event_notifier,
|
||||
sizeof(*rcnb), GFP_KERNEL);
|
||||
if (!rcnb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = blocking_notifier_chain_register(&sp->event_notifier_list, nb);
|
||||
if (!ret) {
|
||||
*rcnb = nb;
|
||||
devres_add(dev, rcnb);
|
||||
} else {
|
||||
devres_free(rcnb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_rave_sp_register_event_notifier);
|
||||
|
||||
static void csum_8b2c(const u8 *buf, size_t size, u8 *crc)
|
||||
{
|
||||
*crc = *buf++;
|
||||
size--;
|
||||
|
||||
while (size--)
|
||||
*crc += *buf++;
|
||||
|
||||
*crc = 1 + ~(*crc);
|
||||
}
|
||||
|
||||
static void csum_ccitt(const u8 *buf, size_t size, u8 *crc)
|
||||
{
|
||||
const u16 calculated = crc_ccitt_false(0xffff, buf, size);
|
||||
|
||||
/*
|
||||
* While the rest of the wire protocol is little-endian,
|
||||
* CCITT-16 CRC in RDU2 device is sent out in big-endian order.
|
||||
*/
|
||||
put_unaligned_be16(calculated, crc);
|
||||
}
|
||||
|
||||
static void *stuff(unsigned char *dest, const unsigned char *src, size_t n)
|
||||
{
|
||||
while (n--) {
|
||||
const unsigned char byte = *src++;
|
||||
|
||||
switch (byte) {
|
||||
case RAVE_SP_STX:
|
||||
case RAVE_SP_ETX:
|
||||
case RAVE_SP_DLE:
|
||||
*dest++ = RAVE_SP_DLE;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
*dest++ = byte;
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static int rave_sp_write(struct rave_sp *sp, const u8 *data, u8 data_size)
|
||||
{
|
||||
const size_t checksum_length = sp->variant->checksum->length;
|
||||
unsigned char frame[RAVE_SP_TX_BUFFER_SIZE];
|
||||
unsigned char crc[RAVE_SP_CHECKSUM_SIZE];
|
||||
unsigned char *dest = frame;
|
||||
size_t length;
|
||||
|
||||
if (WARN_ON(checksum_length > sizeof(crc)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (WARN_ON(data_size > sizeof(frame)))
|
||||
return -ENOMEM;
|
||||
|
||||
sp->variant->checksum->subroutine(data, data_size, crc);
|
||||
|
||||
*dest++ = RAVE_SP_STX;
|
||||
dest = stuff(dest, data, data_size);
|
||||
dest = stuff(dest, crc, checksum_length);
|
||||
*dest++ = RAVE_SP_ETX;
|
||||
|
||||
length = dest - frame;
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "rave-sp tx: ", DUMP_PREFIX_NONE,
|
||||
16, 1, frame, length, false);
|
||||
|
||||
return serdev_device_write(sp->serdev, frame, length, HZ);
|
||||
}
|
||||
|
||||
static u8 rave_sp_reply_code(u8 command)
|
||||
{
|
||||
/*
|
||||
* There isn't a single rule that describes command code ->
|
||||
* ACK code transformation, but, going through various
|
||||
* versions of ICDs, there appear to be three distinct groups
|
||||
* that can be described by simple transformation.
|
||||
*/
|
||||
switch (command) {
|
||||
case 0xA0 ... 0xBE:
|
||||
/*
|
||||
* Commands implemented by firmware found in RDU1 and
|
||||
* older devices all seem to obey the following rule
|
||||
*/
|
||||
return command + 0x20;
|
||||
case 0xE0 ... 0xEF:
|
||||
/*
|
||||
* Events emitted by all versions of the firmare use
|
||||
* least significant bit to get an ACK code
|
||||
*/
|
||||
return command | 0x01;
|
||||
default:
|
||||
/*
|
||||
* Commands implemented by firmware found in RDU2 are
|
||||
* similar to "old" commands, but they use slightly
|
||||
* different offset
|
||||
*/
|
||||
return command + 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
int rave_sp_exec(struct rave_sp *sp,
|
||||
void *__data, size_t data_size,
|
||||
void *reply_data, size_t reply_data_size)
|
||||
{
|
||||
struct rave_sp_reply reply = {
|
||||
.data = reply_data,
|
||||
.length = reply_data_size,
|
||||
.received = COMPLETION_INITIALIZER_ONSTACK(reply.received),
|
||||
};
|
||||
unsigned char *data = __data;
|
||||
int command, ret = 0;
|
||||
u8 ackid;
|
||||
|
||||
command = sp->variant->cmd.translate(data[0]);
|
||||
if (command < 0)
|
||||
return command;
|
||||
|
||||
ackid = atomic_inc_return(&sp->ackid);
|
||||
reply.ackid = ackid;
|
||||
reply.code = rave_sp_reply_code((u8)command),
|
||||
|
||||
mutex_lock(&sp->bus_lock);
|
||||
|
||||
mutex_lock(&sp->reply_lock);
|
||||
sp->reply = &reply;
|
||||
mutex_unlock(&sp->reply_lock);
|
||||
|
||||
data[0] = command;
|
||||
data[1] = ackid;
|
||||
|
||||
rave_sp_write(sp, data, data_size);
|
||||
|
||||
if (!wait_for_completion_timeout(&reply.received, HZ)) {
|
||||
dev_err(&sp->serdev->dev, "Command timeout\n");
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
mutex_lock(&sp->reply_lock);
|
||||
sp->reply = NULL;
|
||||
mutex_unlock(&sp->reply_lock);
|
||||
}
|
||||
|
||||
mutex_unlock(&sp->bus_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rave_sp_exec);
|
||||
|
||||
static void rave_sp_receive_event(struct rave_sp *sp,
|
||||
const unsigned char *data, size_t length)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = rave_sp_reply_code(data[0]),
|
||||
[1] = data[1],
|
||||
};
|
||||
|
||||
rave_sp_write(sp, cmd, sizeof(cmd));
|
||||
|
||||
blocking_notifier_call_chain(&sp->event_notifier_list,
|
||||
rave_sp_action_pack(data[0], data[2]),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void rave_sp_receive_reply(struct rave_sp *sp,
|
||||
const unsigned char *data, size_t length)
|
||||
{
|
||||
struct device *dev = &sp->serdev->dev;
|
||||
struct rave_sp_reply *reply;
|
||||
const size_t payload_length = length - 2;
|
||||
|
||||
mutex_lock(&sp->reply_lock);
|
||||
reply = sp->reply;
|
||||
|
||||
if (reply) {
|
||||
if (reply->code == data[0] && reply->ackid == data[1] &&
|
||||
payload_length >= reply->length) {
|
||||
/*
|
||||
* We are relying on memcpy(dst, src, 0) to be a no-op
|
||||
* when handling commands that have a no-payload reply
|
||||
*/
|
||||
memcpy(reply->data, &data[2], reply->length);
|
||||
complete(&reply->received);
|
||||
sp->reply = NULL;
|
||||
} else {
|
||||
dev_err(dev, "Ignoring incorrect reply\n");
|
||||
dev_dbg(dev, "Code: expected = 0x%08x received = 0x%08x\n",
|
||||
reply->code, data[0]);
|
||||
dev_dbg(dev, "ACK ID: expected = 0x%08x received = 0x%08x\n",
|
||||
reply->ackid, data[1]);
|
||||
dev_dbg(dev, "Length: expected = %zu received = %zu\n",
|
||||
reply->length, payload_length);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sp->reply_lock);
|
||||
}
|
||||
|
||||
static void rave_sp_receive_frame(struct rave_sp *sp,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
const size_t checksum_length = sp->variant->checksum->length;
|
||||
const size_t payload_length = length - checksum_length;
|
||||
const u8 *crc_reported = &data[payload_length];
|
||||
struct device *dev = &sp->serdev->dev;
|
||||
u8 crc_calculated[checksum_length];
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "rave-sp rx: ", DUMP_PREFIX_NONE,
|
||||
16, 1, data, length, false);
|
||||
|
||||
if (unlikely(length <= checksum_length)) {
|
||||
dev_warn(dev, "Dropping short frame\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sp->variant->checksum->subroutine(data, payload_length,
|
||||
crc_calculated);
|
||||
|
||||
if (memcmp(crc_calculated, crc_reported, checksum_length)) {
|
||||
dev_warn(dev, "Dropping bad frame\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rave_sp_id_is_event(data[0]))
|
||||
rave_sp_receive_event(sp, data, length);
|
||||
else
|
||||
rave_sp_receive_reply(sp, data, length);
|
||||
}
|
||||
|
||||
static int rave_sp_receive_buf(struct serdev_device *serdev,
|
||||
const unsigned char *buf, size_t size)
|
||||
{
|
||||
struct device *dev = &serdev->dev;
|
||||
struct rave_sp *sp = dev_get_drvdata(dev);
|
||||
struct rave_sp_deframer *deframer = &sp->deframer;
|
||||
const unsigned char *src = buf;
|
||||
const unsigned char *end = buf + size;
|
||||
|
||||
while (src < end) {
|
||||
const unsigned char byte = *src++;
|
||||
|
||||
switch (deframer->state) {
|
||||
case RAVE_SP_EXPECT_SOF:
|
||||
if (byte == RAVE_SP_STX)
|
||||
deframer->state = RAVE_SP_EXPECT_DATA;
|
||||
break;
|
||||
|
||||
case RAVE_SP_EXPECT_DATA:
|
||||
/*
|
||||
* Treat special byte values first
|
||||
*/
|
||||
switch (byte) {
|
||||
case RAVE_SP_ETX:
|
||||
rave_sp_receive_frame(sp,
|
||||
deframer->data,
|
||||
deframer->length);
|
||||
/*
|
||||
* Once we extracted a complete frame
|
||||
* out of a stream, we call it done
|
||||
* and proceed to bailing out while
|
||||
* resetting the framer to initial
|
||||
* state, regardless if we've consumed
|
||||
* all of the stream or not.
|
||||
*/
|
||||
goto reset_framer;
|
||||
case RAVE_SP_STX:
|
||||
dev_warn(dev, "Bad frame: STX before ETX\n");
|
||||
/*
|
||||
* If we encounter second "start of
|
||||
* the frame" marker before seeing
|
||||
* corresponding "end of frame", we
|
||||
* reset the framer and ignore both:
|
||||
* frame started by first SOF and
|
||||
* frame started by current SOF.
|
||||
*
|
||||
* NOTE: The above means that only the
|
||||
* frame started by third SOF, sent
|
||||
* after this one will have a chance
|
||||
* to get throught.
|
||||
*/
|
||||
goto reset_framer;
|
||||
case RAVE_SP_DLE:
|
||||
deframer->state = RAVE_SP_EXPECT_ESCAPED_DATA;
|
||||
/*
|
||||
* If we encounter escape sequence we
|
||||
* need to skip it and collect the
|
||||
* byte that follows. We do it by
|
||||
* forcing the next iteration of the
|
||||
* encompassing while loop.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* For the rest of the bytes, that are not
|
||||
* speical snoflakes, we do the same thing
|
||||
* that we do to escaped data - collect it in
|
||||
* deframer buffer
|
||||
*/
|
||||
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case RAVE_SP_EXPECT_ESCAPED_DATA:
|
||||
deframer->data[deframer->length++] = byte;
|
||||
|
||||
if (deframer->length == sizeof(deframer->data)) {
|
||||
dev_warn(dev, "Bad frame: Too long\n");
|
||||
/*
|
||||
* If the amount of data we've
|
||||
* accumulated for current frame so
|
||||
* far starts to exceed the capacity
|
||||
* of deframer's buffer, there's
|
||||
* nothing else we can do but to
|
||||
* discard that data and start
|
||||
* assemblying a new frame again
|
||||
*/
|
||||
goto reset_framer;
|
||||
}
|
||||
|
||||
/*
|
||||
* We've extracted out special byte, now we
|
||||
* can go back to regular data collecting
|
||||
*/
|
||||
deframer->state = RAVE_SP_EXPECT_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The only way to get out of the above loop and end up here
|
||||
* is throught consuming all of the supplied data, so here we
|
||||
* report that we processed it all.
|
||||
*/
|
||||
return size;
|
||||
|
||||
reset_framer:
|
||||
/*
|
||||
* NOTE: A number of codepaths that will drop us here will do
|
||||
* so before consuming all 'size' bytes of the data passed by
|
||||
* serdev layer. We rely on the fact that serdev layer will
|
||||
* re-execute this handler with the remainder of the Rx bytes
|
||||
* once we report actual number of bytes that we processed.
|
||||
*/
|
||||
deframer->state = RAVE_SP_EXPECT_SOF;
|
||||
deframer->length = 0;
|
||||
|
||||
return src - buf;
|
||||
}
|
||||
|
||||
static int rave_sp_rdu1_cmd_translate(enum rave_sp_command command)
|
||||
{
|
||||
if (command >= RAVE_SP_CMD_STATUS &&
|
||||
command <= RAVE_SP_CMD_CONTROL_EVENTS)
|
||||
return command;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rave_sp_rdu2_cmd_translate(enum rave_sp_command command)
|
||||
{
|
||||
if (command >= RAVE_SP_CMD_GET_FIRMWARE_VERSION &&
|
||||
command <= RAVE_SP_CMD_GET_GPIO_STATE)
|
||||
return command;
|
||||
|
||||
if (command == RAVE_SP_CMD_REQ_COPPER_REV) {
|
||||
/*
|
||||
* As per RDU2 ICD 3.4.47 CMD_GET_COPPER_REV code is
|
||||
* different from that for RDU1 and it is set to 0x28.
|
||||
*/
|
||||
return 0x28;
|
||||
}
|
||||
|
||||
return rave_sp_rdu1_cmd_translate(command);
|
||||
}
|
||||
|
||||
static int rave_sp_default_cmd_translate(enum rave_sp_command command)
|
||||
{
|
||||
/*
|
||||
* All of the following command codes were taken from "Table :
|
||||
* Communications Protocol Message Types" in section 3.3
|
||||
* "MESSAGE TYPES" of Rave PIC24 ICD.
|
||||
*/
|
||||
switch (command) {
|
||||
case RAVE_SP_CMD_GET_FIRMWARE_VERSION:
|
||||
return 0x11;
|
||||
case RAVE_SP_CMD_GET_BOOTLOADER_VERSION:
|
||||
return 0x12;
|
||||
case RAVE_SP_CMD_BOOT_SOURCE:
|
||||
return 0x14;
|
||||
case RAVE_SP_CMD_SW_WDT:
|
||||
return 0x1C;
|
||||
case RAVE_SP_CMD_RESET:
|
||||
return 0x1E;
|
||||
case RAVE_SP_CMD_RESET_REASON:
|
||||
return 0x1F;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rave_sp_checksum rave_sp_checksum_8b2c = {
|
||||
.length = 1,
|
||||
.subroutine = csum_8b2c,
|
||||
};
|
||||
|
||||
static const struct rave_sp_checksum rave_sp_checksum_ccitt = {
|
||||
.length = 2,
|
||||
.subroutine = csum_ccitt,
|
||||
};
|
||||
|
||||
static const struct rave_sp_variant rave_sp_legacy = {
|
||||
.checksum = &rave_sp_checksum_8b2c,
|
||||
.cmd = {
|
||||
.translate = rave_sp_default_cmd_translate,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rave_sp_variant rave_sp_rdu1 = {
|
||||
.checksum = &rave_sp_checksum_8b2c,
|
||||
.cmd = {
|
||||
.translate = rave_sp_rdu1_cmd_translate,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rave_sp_variant rave_sp_rdu2 = {
|
||||
.checksum = &rave_sp_checksum_ccitt,
|
||||
.cmd = {
|
||||
.translate = rave_sp_rdu2_cmd_translate,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id rave_sp_dt_ids[] = {
|
||||
{ .compatible = "zii,rave-sp-niu", .data = &rave_sp_legacy },
|
||||
{ .compatible = "zii,rave-sp-mezz", .data = &rave_sp_legacy },
|
||||
{ .compatible = "zii,rave-sp-esb", .data = &rave_sp_legacy },
|
||||
{ .compatible = "zii,rave-sp-rdu1", .data = &rave_sp_rdu1 },
|
||||
{ .compatible = "zii,rave-sp-rdu2", .data = &rave_sp_rdu2 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct serdev_device_ops rave_sp_serdev_device_ops = {
|
||||
.receive_buf = rave_sp_receive_buf,
|
||||
.write_wakeup = serdev_device_write_wakeup,
|
||||
};
|
||||
|
||||
static int rave_sp_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct device *dev = &serdev->dev;
|
||||
struct rave_sp *sp;
|
||||
u32 baud;
|
||||
int ret;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "current-speed", &baud)) {
|
||||
dev_err(dev,
|
||||
"'current-speed' is not specified in device node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL);
|
||||
if (!sp)
|
||||
return -ENOMEM;
|
||||
|
||||
sp->serdev = serdev;
|
||||
dev_set_drvdata(dev, sp);
|
||||
|
||||
sp->variant = of_device_get_match_data(dev);
|
||||
if (!sp->variant)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_init(&sp->bus_lock);
|
||||
mutex_init(&sp->reply_lock);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&sp->event_notifier_list);
|
||||
|
||||
serdev_device_set_client_ops(serdev, &rave_sp_serdev_device_ops);
|
||||
ret = devm_serdev_device_open(dev, serdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
serdev_device_set_baudrate(serdev, baud);
|
||||
|
||||
return devm_of_platform_populate(dev);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, rave_sp_dt_ids);
|
||||
|
||||
static struct serdev_device_driver rave_sp_drv = {
|
||||
.probe = rave_sp_probe,
|
||||
.driver = {
|
||||
.name = "rave-sp",
|
||||
.of_match_table = rave_sp_dt_ids,
|
||||
},
|
||||
};
|
||||
module_serdev_device_driver(rave_sp_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
|
||||
MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
|
||||
MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||
MODULE_DESCRIPTION("RAVE SP core driver");
|
|
@ -496,6 +496,10 @@ config PCI_ENDPOINT_TEST
|
|||
Enable this configuration option to enable the host side test driver
|
||||
for PCI Endpoint.
|
||||
|
||||
config MISC_RTSX
|
||||
tristate
|
||||
default MISC_RTSX_PCI || MISC_RTSX_USB
|
||||
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
|
@ -508,4 +512,5 @@ source "drivers/misc/mic/Kconfig"
|
|||
source "drivers/misc/genwqe/Kconfig"
|
||||
source "drivers/misc/echo/Kconfig"
|
||||
source "drivers/misc/cxl/Kconfig"
|
||||
source "drivers/misc/cardreader/Kconfig"
|
||||
endmenu
|
||||
|
|
|
@ -55,6 +55,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/
|
|||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||
obj-$(CONFIG_MISC_RTSX) += cardreader/
|
||||
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
|
||||
|
|
20
drivers/misc/cardreader/Kconfig
Normal file
20
drivers/misc/cardreader/Kconfig
Normal file
|
@ -0,0 +1,20 @@
|
|||
config MISC_RTSX_PCI
|
||||
tristate "Realtek PCI-E card reader"
|
||||
depends on PCI
|
||||
select MFD_CORE
|
||||
help
|
||||
This supports for Realtek PCI-Express card reader including rts5209,
|
||||
rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, rts5260.
|
||||
Realtek card readers support access to many types of memory cards,
|
||||
such as Memory Stick, Memory Stick Pro, Secure Digital and
|
||||
MultiMediaCard.
|
||||
|
||||
config MISC_RTSX_USB
|
||||
tristate "Realtek USB card reader"
|
||||
depends on USB
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this option to get support for Realtek USB 2.0 card readers
|
||||
including RTS5129, RTS5139, RTS5179 and RTS5170.
|
||||
Realtek card reader supports access to many types of memory cards,
|
||||
such as Memory Stick Pro, Secure Digital and MultiMediaCard.
|
4
drivers/misc/cardreader/Makefile
Normal file
4
drivers/misc/cardreader/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o
|
||||
|
||||
obj-$(CONFIG_MISC_RTSX_PCI) += rtsx_pci.o
|
||||
obj-$(CONFIG_MISC_RTSX_USB) += rtsx_usb.o
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
||||
|
@ -738,4 +738,3 @@ void rts525a_init_params(struct rtsx_pcr *pcr)
|
|||
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
||||
pcr->ops = &rts525a_pcr_ops;
|
||||
}
|
||||
|
748
drivers/misc/cardreader/rts5260.c
Normal file
748
drivers/misc/cardreader/rts5260.c
Normal file
|
@ -0,0 +1,748 @@
|
|||
/* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2016-2017 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Steven FENG <steven_feng@realsil.com.cn>
|
||||
* Rui FENG <rui_feng@realsil.com.cn>
|
||||
* Wei WANG <wei_wang@realsil.com.cn>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rts5260.h"
|
||||
#include "rtsx_pcr.h"
|
||||
|
||||
static u8 rts5260_get_ic_version(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
|
||||
return val & IC_VERSION_MASK;
|
||||
}
|
||||
|
||||
static void rts5260_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
u8 driving_3v3[6][3] = {
|
||||
{0x94, 0x94, 0x94},
|
||||
{0x11, 0x11, 0x18},
|
||||
{0x55, 0x55, 0x5C},
|
||||
{0x94, 0x94, 0x94},
|
||||
{0x94, 0x94, 0x94},
|
||||
{0xFF, 0xFF, 0xFF},
|
||||
};
|
||||
u8 driving_1v8[6][3] = {
|
||||
{0x9A, 0x89, 0x89},
|
||||
{0xC4, 0xC4, 0xC4},
|
||||
{0x3C, 0x3C, 0x3C},
|
||||
{0x9B, 0x99, 0x99},
|
||||
{0x9A, 0x89, 0x89},
|
||||
{0xFE, 0xFE, 0xFE},
|
||||
};
|
||||
u8 (*driving)[3], drive_sel;
|
||||
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
driving = driving_3v3;
|
||||
drive_sel = pcr->sd30_drive_sel_3v3;
|
||||
} else {
|
||||
driving = driving_1v8;
|
||||
drive_sel = pcr->sd30_drive_sel_1v8;
|
||||
}
|
||||
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][0]);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][1]);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][2]);
|
||||
}
|
||||
|
||||
static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg)) {
|
||||
pcr_dbg(pcr, "skip fetch vendor setting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcr->aspm_en = rtsx_reg_to_aspm(reg);
|
||||
pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
|
||||
if (rtsx_reg_check_reverse_socket(reg))
|
||||
pcr->flags |= PCR_REVERSE_SOCKET;
|
||||
}
|
||||
|
||||
static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
{
|
||||
/* Set relink_time to 0 */
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
|
||||
RELINK_TIME_MASK, 0);
|
||||
|
||||
if (pm_state == HOST_ENTER_S3)
|
||||
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
|
||||
D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
|
||||
|
||||
rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
|
||||
}
|
||||
|
||||
static int rtsx_base_enable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
|
||||
LED_SHINE_MASK, LED_SHINE_EN);
|
||||
}
|
||||
|
||||
static int rtsx_base_disable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
|
||||
LED_SHINE_MASK, LED_SHINE_DISABLE);
|
||||
}
|
||||
|
||||
static int rts5260_turn_on_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, RTS5260_REG_GPIO_CTL0,
|
||||
RTS5260_REG_GPIO_MASK, RTS5260_REG_GPIO_ON);
|
||||
}
|
||||
|
||||
static int rts5260_turn_off_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, RTS5260_REG_GPIO_CTL0,
|
||||
RTS5260_REG_GPIO_MASK, RTS5260_REG_GPIO_OFF);
|
||||
}
|
||||
|
||||
/* SD Pull Control Enable:
|
||||
* SD_DAT[3:0] ==> pull up
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull up
|
||||
* SD_CMD ==> pull up
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5260_sd_pull_ctl_enable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA),
|
||||
0,
|
||||
};
|
||||
|
||||
/* SD Pull Control Disable:
|
||||
* SD_DAT[3:0] ==> pull down
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull down
|
||||
* SD_CMD ==> pull down
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5260_sd_pull_ctl_disable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
|
||||
0,
|
||||
};
|
||||
|
||||
/* MS Pull Control Enable:
|
||||
* MS CD ==> pull up
|
||||
* others ==> pull down
|
||||
*/
|
||||
static const u32 rts5260_ms_pull_ctl_enable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
|
||||
0,
|
||||
};
|
||||
|
||||
/* MS Pull Control Disable:
|
||||
* MS CD ==> pull up
|
||||
* others ==> pull down
|
||||
*/
|
||||
static const u32 rts5260_ms_pull_ctl_disable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
|
||||
0,
|
||||
};
|
||||
|
||||
static int sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
|
||||
| SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
|
||||
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
|
||||
rtsx_pci_write_register(pcr, CARD_CLK_SOURCE, 0xFF,
|
||||
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
|
||||
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rts5260_card_power_on(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
int err = 0;
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
if (option->ocp_en)
|
||||
rtsx_pci_enable_ocp(pcr);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
|
||||
DV331812_VDD1, DV331812_VDD1);
|
||||
err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG0,
|
||||
RTS5260_DVCC_TUNE_MASK, RTS5260_DVCC_33);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG1,
|
||||
LDO_POW_SDVDD1_MASK, LDO_POW_SDVDD1_ON);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
|
||||
DV331812_POWERON, DV331812_POWERON);
|
||||
err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
||||
|
||||
msleep(20);
|
||||
|
||||
if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50 ||
|
||||
pcr->extra_caps & EXTRA_CAPS_SD_SDR104)
|
||||
sd_set_sample_push_timing_sd30(pcr);
|
||||
|
||||
/* Initialize SD_CFG1 register */
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, 0xFF,
|
||||
SD_CLK_DIVIDE_128 | SD_20_MODE);
|
||||
|
||||
rtsx_pci_write_register(pcr, SD_SAMPLE_POINT_CTL,
|
||||
0xFF, SD20_RX_POS_EDGE);
|
||||
rtsx_pci_write_register(pcr, SD_PUSH_POINT_CTL, 0xFF, 0);
|
||||
rtsx_pci_write_register(pcr, CARD_STOP, SD_STOP | SD_CLR_ERR,
|
||||
SD_STOP | SD_CLR_ERR);
|
||||
|
||||
/* Reset SD_CFG3 register */
|
||||
rtsx_pci_write_register(pcr, SD_CFG3, SD30_CLK_END_EN, 0);
|
||||
rtsx_pci_write_register(pcr, REG_SD_STOP_SDCLK_CFG,
|
||||
SD30_CLK_STOP_CFG_EN | SD30_CLK_STOP_CFG1 |
|
||||
SD30_CLK_STOP_CFG0, 0);
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_PRE_RW_MODE, EN_INFINITE_MODE, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rts5260_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
switch (voltage) {
|
||||
case OUTPUT_3V3:
|
||||
rtsx_pci_write_register(pcr, LDO_CONFIG2,
|
||||
DV331812_VDD1, DV331812_VDD1);
|
||||
rtsx_pci_write_register(pcr, LDO_DV18_CFG,
|
||||
DV331812_MASK, DV331812_33);
|
||||
rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, 0);
|
||||
break;
|
||||
case OUTPUT_1V8:
|
||||
rtsx_pci_write_register(pcr, LDO_CONFIG2,
|
||||
DV331812_VDD1, DV331812_VDD1);
|
||||
rtsx_pci_write_register(pcr, LDO_DV18_CFG,
|
||||
DV331812_MASK, DV331812_17);
|
||||
rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8,
|
||||
SD_IO_USING_1V8);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set pad drive */
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rts5260_fill_driving(pcr, voltage);
|
||||
return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
||||
}
|
||||
|
||||
static void rts5260_stop_cmd(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
|
||||
rtsx_pci_write_register(pcr, RTS5260_DMA_RST_CTL_0,
|
||||
RTS5260_DMA_RST | RTS5260_ADMA3_RST,
|
||||
RTS5260_DMA_RST | RTS5260_ADMA3_RST);
|
||||
rtsx_pci_write_register(pcr, RBCTL, RB_FLUSH, RB_FLUSH);
|
||||
}
|
||||
|
||||
static void rts5260_card_before_power_off(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
rts5260_stop_cmd(pcr);
|
||||
rts5260_switch_output_voltage(pcr, OUTPUT_3V3);
|
||||
|
||||
if (option->ocp_en)
|
||||
rtsx_pci_disable_ocp(pcr);
|
||||
}
|
||||
|
||||
static int rts5260_card_power_off(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
rts5260_card_before_power_off(pcr);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG1,
|
||||
LDO_POW_SDVDD1_MASK, LDO_POW_SDVDD1_OFF);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
|
||||
DV331812_POWERON, DV331812_POWEROFF);
|
||||
err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rts5260_init_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
if (option->ocp_en) {
|
||||
u8 mask, val;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
|
||||
RTS5260_DVCC_OCP_EN |
|
||||
RTS5260_DVCC_OCP_CL_EN,
|
||||
RTS5260_DVCC_OCP_EN |
|
||||
RTS5260_DVCC_OCP_CL_EN);
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
|
||||
RTS5260_DVIO_OCP_EN |
|
||||
RTS5260_DVIO_OCP_CL_EN,
|
||||
RTS5260_DVIO_OCP_EN |
|
||||
RTS5260_DVIO_OCP_CL_EN);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
|
||||
RTS5260_DVCC_OCP_THD_MASK,
|
||||
option->sd_400mA_ocp_thd);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
|
||||
RTS5260_DVIO_OCP_THD_MASK,
|
||||
RTS5260_DVIO_OCP_THD_350);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5260_DV331812_CFG,
|
||||
RTS5260_DV331812_OCP_THD_MASK,
|
||||
RTS5260_DV331812_OCP_THD_210);
|
||||
|
||||
mask = SD_OCP_GLITCH_MASK | SDVIO_OCP_GLITCH_MASK;
|
||||
val = pcr->hw_param.ocp_glitch;
|
||||
rtsx_pci_write_register(pcr, REG_OCPGLITCH, mask, val);
|
||||
|
||||
rtsx_pci_enable_ocp(pcr);
|
||||
} else {
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
|
||||
RTS5260_DVCC_OCP_EN |
|
||||
RTS5260_DVCC_OCP_CL_EN, 0);
|
||||
rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
|
||||
RTS5260_DVIO_OCP_EN |
|
||||
RTS5260_DVIO_OCP_CL_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void rts5260_enable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, 0);
|
||||
|
||||
val = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
val |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
|
||||
rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
|
||||
DV3318_DETECT_EN | DV3318_OCP_INT_EN,
|
||||
DV3318_DETECT_EN | DV3318_OCP_INT_EN);
|
||||
}
|
||||
|
||||
static void rts5260_disable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 mask = 0;
|
||||
|
||||
mask = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
mask |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
|
||||
DV3318_DETECT_EN | DV3318_OCP_INT_EN, 0);
|
||||
|
||||
rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
|
||||
OC_POWER_DOWN);
|
||||
}
|
||||
|
||||
int rts5260_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
|
||||
{
|
||||
return rtsx_pci_read_register(pcr, REG_OCPSTAT, val);
|
||||
}
|
||||
|
||||
int rts5260_get_ocpstat2(struct rtsx_pcr *pcr, u8 *val)
|
||||
{
|
||||
return rtsx_pci_read_register(pcr, REG_DV3318_OCPSTAT, val);
|
||||
}
|
||||
|
||||
void rts5260_clear_ocpstat(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 mask = 0;
|
||||
u8 val = 0;
|
||||
|
||||
mask = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
mask |= SDVIO_OCP_INT_CLR | SDVIO_OC_CLR;
|
||||
val = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
val |= SDVIO_OCP_INT_CLR | SDVIO_OC_CLR;
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
|
||||
rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
|
||||
DV3318_OCP_INT_CLR | DV3318_OCP_CLR,
|
||||
DV3318_OCP_INT_CLR | DV3318_OCP_CLR);
|
||||
udelay(10);
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
|
||||
DV3318_OCP_INT_CLR | DV3318_OCP_CLR, 0);
|
||||
}
|
||||
|
||||
void rts5260_process_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (!pcr->option.ocp_en)
|
||||
return;
|
||||
|
||||
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
|
||||
rts5260_get_ocpstat2(pcr, &pcr->ocp_stat2);
|
||||
if (pcr->card_exist & SD_EXIST)
|
||||
rtsx_sd_power_off_card3v3(pcr);
|
||||
else if (pcr->card_exist & MS_EXIST)
|
||||
rtsx_ms_power_off_card3v3(pcr);
|
||||
|
||||
if (!(pcr->card_exist & MS_EXIST) && !(pcr->card_exist & SD_EXIST)) {
|
||||
if ((pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER |
|
||||
SDVIO_OC_NOW | SDVIO_OC_EVER)) ||
|
||||
(pcr->ocp_stat2 & (DV3318_OCP_NOW | DV3318_OCP_EVER)))
|
||||
rtsx_pci_clear_ocpstat(pcr);
|
||||
pcr->ocp_stat = 0;
|
||||
pcr->ocp_stat2 = 0;
|
||||
}
|
||||
|
||||
if ((pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER |
|
||||
SDVIO_OC_NOW | SDVIO_OC_EVER)) ||
|
||||
(pcr->ocp_stat2 & (DV3318_OCP_NOW | DV3318_OCP_EVER))) {
|
||||
if (pcr->card_exist & SD_EXIST)
|
||||
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
|
||||
else if (pcr->card_exist & MS_EXIST)
|
||||
rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int rts5260_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtsx_pci_init_ocp(pcr);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG1,
|
||||
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
|
||||
/* Rest L1SUB Config */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG3, 0xFF, 0x00);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CLK_FORCE_CTL,
|
||||
CLK_PM_EN, CLK_PM_EN);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWD_SUSPEND_EN, 0xFF, 0xFF);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
|
||||
PWR_GATE_EN, PWR_GATE_EN);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, REG_VREF,
|
||||
PWD_SUSPND_EN, PWD_SUSPND_EN);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RBCTL,
|
||||
U_AUTO_DMA_EN_MASK, U_AUTO_DMA_DISABLE);
|
||||
|
||||
if (pcr->flags & PCR_REVERSE_SOCKET)
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0xB0);
|
||||
else
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
|
||||
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG,
|
||||
OBFF_EN_MASK, OBFF_DISABLE);
|
||||
|
||||
err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int lss_l1_1, lss_l1_2;
|
||||
|
||||
lss_l1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN)
|
||||
| rtsx_check_dev_flag(pcr, PM_L1_1_EN);
|
||||
lss_l1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN)
|
||||
| rtsx_check_dev_flag(pcr, PM_L1_2_EN);
|
||||
|
||||
if (lss_l1_2) {
|
||||
pcr_dbg(pcr, "Set parameters for L1.2.");
|
||||
rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
|
||||
0xFF, PCIE_L1_2_EN);
|
||||
rtsx_pci_write_register(pcr, PWR_FE_CTL,
|
||||
0xFF, PCIE_L1_2_PD_FE_EN);
|
||||
} else if (lss_l1_1) {
|
||||
pcr_dbg(pcr, "Set parameters for L1.1.");
|
||||
rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
|
||||
0xFF, PCIE_L1_1_EN);
|
||||
rtsx_pci_write_register(pcr, PWR_FE_CTL,
|
||||
0xFF, PCIE_L1_1_PD_FE_EN);
|
||||
} else {
|
||||
pcr_dbg(pcr, "Set parameters for L1.");
|
||||
rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
|
||||
0xFF, PCIE_L1_0_EN);
|
||||
rtsx_pci_write_register(pcr, PWR_FE_CTL,
|
||||
0xFF, PCIE_L1_0_PD_FE_EN);
|
||||
}
|
||||
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_PCIE_DPHY_RET_VALUE,
|
||||
0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_PCIE_MAC_RET_VALUE,
|
||||
0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_CRC_SD30_RET_VALUE,
|
||||
0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_CRC_SD40_RET_VALUE,
|
||||
0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_SYS_RET_VALUE,
|
||||
0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
|
||||
/*Option cut APHY*/
|
||||
rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_0,
|
||||
0xFF, CFG_PCIE_APHY_OFF_0_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_1,
|
||||
0xFF, CFG_PCIE_APHY_OFF_1_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_2,
|
||||
0xFF, CFG_PCIE_APHY_OFF_2_DEFAULT);
|
||||
rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_3,
|
||||
0xFF, CFG_PCIE_APHY_OFF_3_DEFAULT);
|
||||
/*CDR DEC*/
|
||||
rtsx_pci_write_register(pcr, PWC_CDR, 0xFF, PWC_CDR_DEFAULT);
|
||||
/*PWMPFM*/
|
||||
rtsx_pci_write_register(pcr, CFG_LP_FPWM_VALUE,
|
||||
0xFF, CFG_LP_FPWM_VALUE_DEFAULT);
|
||||
/*No Power Saving WA*/
|
||||
rtsx_pci_write_register(pcr, CFG_L1_0_CRC_MISC_RET_VALUE,
|
||||
0xFF, CFG_L1_0_CRC_MISC_RET_VALUE_DEFAULT);
|
||||
}
|
||||
|
||||
static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
u32 lval;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_5260, &lval);
|
||||
|
||||
if (lval & ASPM_L1_1_EN_MASK)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
|
||||
if (lval & ASPM_L1_2_EN_MASK)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (lval & PM_L1_1_EN_MASK)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
||||
|
||||
if (lval & PM_L1_2_EN_MASK)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
||||
|
||||
rts5260_pwr_saving_setting(pcr);
|
||||
|
||||
if (option->ltr_en) {
|
||||
u16 val;
|
||||
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
||||
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
option->ltr_enabled = true;
|
||||
option->ltr_active = true;
|
||||
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
|
||||
} else {
|
||||
option->ltr_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
|
||||
| PM_L1_1_EN | PM_L1_2_EN))
|
||||
option->force_clkreq_0 = false;
|
||||
else
|
||||
option->force_clkreq_0 = true;
|
||||
}
|
||||
|
||||
static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
/* Set mcu_cnt to 7 to ensure data can be sampled properly */
|
||||
rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07);
|
||||
rtsx_pci_write_register(pcr, SSC_DIV_N_0, 0xFF, 0x5D);
|
||||
|
||||
rts5260_init_from_cfg(pcr);
|
||||
|
||||
/* force no MDIO*/
|
||||
rtsx_pci_write_register(pcr, RTS5260_AUTOLOAD_CFG4,
|
||||
0xFF, RTS5260_MIMO_DISABLE);
|
||||
/*Modify SDVCC Tune Default Parameters!*/
|
||||
rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
|
||||
RTS5260_DVCC_TUNE_MASK, RTS5260_DVCC_33);
|
||||
|
||||
rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
|
||||
|
||||
rts5260_init_hw(pcr);
|
||||
|
||||
/*
|
||||
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
|
||||
* to drive low, and we forcibly request clock.
|
||||
*/
|
||||
if (option->force_clkreq_0)
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
|
||||
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
|
||||
else
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
|
||||
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rts5260_set_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
u8 val = 0;
|
||||
|
||||
if (pcr->aspm_enabled == enable)
|
||||
return;
|
||||
|
||||
if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
|
||||
if (enable)
|
||||
val = pcr->aspm_en;
|
||||
rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL,
|
||||
ASPM_MASK_NEG, val);
|
||||
} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
|
||||
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0;
|
||||
|
||||
if (!enable)
|
||||
val = FORCE_ASPM_CTL0;
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||
}
|
||||
|
||||
pcr->aspm_enabled = enable;
|
||||
}
|
||||
|
||||
static void rts5260_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
|
||||
int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST);
|
||||
int aspm_L1_1, aspm_L1_2;
|
||||
u8 val = 0;
|
||||
|
||||
aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (active) {
|
||||
/* run, latency: 60us */
|
||||
if (aspm_L1_1)
|
||||
val = option->ltr_l1off_snooze_sspwrgate;
|
||||
} else {
|
||||
/* l1off, latency: 300us */
|
||||
if (aspm_L1_2)
|
||||
val = option->ltr_l1off_sspwrgate;
|
||||
}
|
||||
|
||||
if (aspm_L1_1 || aspm_L1_2) {
|
||||
if (rtsx_check_dev_flag(pcr,
|
||||
LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
|
||||
if (card_exist)
|
||||
val &= ~L1OFF_MBIAS2_EN_5250;
|
||||
else
|
||||
val |= L1OFF_MBIAS2_EN_5250;
|
||||
}
|
||||
}
|
||||
rtsx_set_l1off_sub(pcr, val);
|
||||
}
|
||||
|
||||
static const struct pcr_ops rts5260_pcr_ops = {
|
||||
.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
|
||||
.turn_on_led = rts5260_turn_on_led,
|
||||
.turn_off_led = rts5260_turn_off_led,
|
||||
.extra_init_hw = rts5260_extra_init_hw,
|
||||
.enable_auto_blink = rtsx_base_enable_auto_blink,
|
||||
.disable_auto_blink = rtsx_base_disable_auto_blink,
|
||||
.card_power_on = rts5260_card_power_on,
|
||||
.card_power_off = rts5260_card_power_off,
|
||||
.switch_output_voltage = rts5260_switch_output_voltage,
|
||||
.force_power_down = rtsx_base_force_power_down,
|
||||
.stop_cmd = rts5260_stop_cmd,
|
||||
.set_aspm = rts5260_set_aspm,
|
||||
.set_l1off_cfg_sub_d0 = rts5260_set_l1off_cfg_sub_d0,
|
||||
.enable_ocp = rts5260_enable_ocp,
|
||||
.disable_ocp = rts5260_disable_ocp,
|
||||
.init_ocp = rts5260_init_ocp,
|
||||
.process_ocp = rts5260_process_ocp,
|
||||
.get_ocpstat = rts5260_get_ocpstat,
|
||||
.clear_ocpstat = rts5260_clear_ocpstat,
|
||||
};
|
||||
|
||||
void rts5260_init_params(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
struct rtsx_hw_param *hw_param = &pcr->hw_param;
|
||||
|
||||
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
||||
pcr->num_slots = 2;
|
||||
|
||||
pcr->flags = 0;
|
||||
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
|
||||
pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
|
||||
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
|
||||
pcr->aspm_en = ASPM_L1_EN;
|
||||
pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
|
||||
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
|
||||
|
||||
pcr->ic_version = rts5260_get_ic_version(pcr);
|
||||
pcr->sd_pull_ctl_enable_tbl = rts5260_sd_pull_ctl_enable_tbl;
|
||||
pcr->sd_pull_ctl_disable_tbl = rts5260_sd_pull_ctl_disable_tbl;
|
||||
pcr->ms_pull_ctl_enable_tbl = rts5260_ms_pull_ctl_enable_tbl;
|
||||
pcr->ms_pull_ctl_disable_tbl = rts5260_ms_pull_ctl_disable_tbl;
|
||||
|
||||
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
||||
|
||||
pcr->ops = &rts5260_pcr_ops;
|
||||
|
||||
option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
|
||||
| LTR_L1SS_PWR_GATE_EN);
|
||||
option->ltr_en = true;
|
||||
|
||||
/* init latency of active, idle, L1OFF to 60us, 300us, 3ms */
|
||||
option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
|
||||
option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
|
||||
option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
|
||||
option->dev_aspm_mode = DEV_ASPM_DYNAMIC;
|
||||
option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
|
||||
option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
|
||||
option->ltr_l1off_snooze_sspwrgate =
|
||||
LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
|
||||
|
||||
option->ocp_en = 1;
|
||||
if (option->ocp_en)
|
||||
hw_param->interrupt_en |= SD_OC_INT_EN;
|
||||
hw_param->ocp_glitch = SD_OCP_GLITCH_10M | SDVIO_OCP_GLITCH_800U;
|
||||
option->sd_400mA_ocp_thd = RTS5260_DVCC_OCP_THD_550;
|
||||
option->sd_800mA_ocp_thd = RTS5260_DVCC_OCP_THD_970;
|
||||
}
|
45
drivers/misc/cardreader/rts5260.h
Normal file
45
drivers/misc/cardreader/rts5260.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef __RTS5260_H__
|
||||
#define __RTS5260_H__
|
||||
|
||||
#define RTS5260_DVCC_CTRL 0xFF73
|
||||
#define RTS5260_DVCC_OCP_EN (0x01 << 7)
|
||||
#define RTS5260_DVCC_OCP_THD_MASK (0x07 << 4)
|
||||
#define RTS5260_DVCC_POWERON (0x01 << 3)
|
||||
#define RTS5260_DVCC_OCP_CL_EN (0x01 << 2)
|
||||
|
||||
#define RTS5260_DVIO_CTRL 0xFF75
|
||||
#define RTS5260_DVIO_OCP_EN (0x01 << 7)
|
||||
#define RTS5260_DVIO_OCP_THD_MASK (0x07 << 4)
|
||||
#define RTS5260_DVIO_POWERON (0x01 << 3)
|
||||
#define RTS5260_DVIO_OCP_CL_EN (0x01 << 2)
|
||||
|
||||
#define RTS5260_DV331812_CFG 0xFF71
|
||||
#define RTS5260_DV331812_OCP_EN (0x01 << 7)
|
||||
#define RTS5260_DV331812_OCP_THD_MASK (0x07 << 4)
|
||||
#define RTS5260_DV331812_POWERON (0x01 << 3)
|
||||
#define RTS5260_DV331812_SEL (0x01 << 2)
|
||||
#define RTS5260_DV331812_VDD1 (0x01 << 2)
|
||||
#define RTS5260_DV331812_VDD2 (0x00 << 2)
|
||||
|
||||
#define RTS5260_DV331812_OCP_THD_120 (0x00 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_140 (0x01 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_160 (0x02 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_180 (0x03 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_210 (0x04 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_240 (0x05 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_270 (0x06 << 4)
|
||||
#define RTS5260_DV331812_OCP_THD_300 (0x07 << 4)
|
||||
|
||||
#define RTS5260_DVIO_OCP_THD_250 (0x00 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_300 (0x01 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_350 (0x02 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_400 (0x03 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_450 (0x04 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_500 (0x05 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_550 (0x06 << 4)
|
||||
#define RTS5260_DVIO_OCP_THD_600 (0x07 << 4)
|
||||
|
||||
#define RTS5260_DVCC_OCP_THD_550 (0x00 << 4)
|
||||
#define RTS5260_DVCC_OCP_THD_970 (0x05 << 4)
|
||||
|
||||
#endif
|
|
@ -29,7 +29,7 @@
|
|||
#include <linux/idr.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -62,6 +62,7 @@ static const struct pci_device_id rtsx_pci_ids[] = {
|
|||
{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x524A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
@ -334,6 +335,9 @@ EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register);
|
|||
|
||||
void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (pcr->ops->stop_cmd)
|
||||
return pcr->ops->stop_cmd(pcr);
|
||||
|
||||
rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
|
||||
|
||||
|
@ -826,7 +830,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
|||
return err;
|
||||
|
||||
/* Wait SSC clock stable */
|
||||
udelay(10);
|
||||
udelay(SSC_CLOCK_STABLE_WAIT);
|
||||
err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -963,6 +967,20 @@ static void rtsx_pci_card_detect(struct work_struct *work)
|
|||
pcr->slots[RTSX_MS_CARD].p_dev);
|
||||
}
|
||||
|
||||
void rtsx_pci_process_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (pcr->ops->process_ocp)
|
||||
pcr->ops->process_ocp(pcr);
|
||||
}
|
||||
|
||||
int rtsx_pci_process_ocp_interrupt(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (pcr->option.ocp_en)
|
||||
rtsx_pci_process_ocp(pcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rtsx_pcr *pcr = dev_id;
|
||||
|
@ -987,6 +1005,9 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
|||
|
||||
int_reg &= (pcr->bier | 0x7FFFFF);
|
||||
|
||||
if (int_reg & SD_OC_INT)
|
||||
rtsx_pci_process_ocp_interrupt(pcr);
|
||||
|
||||
if (int_reg & SD_INT) {
|
||||
if (int_reg & SD_EXIST) {
|
||||
pcr->card_inserted |= SD_EXIST;
|
||||
|
@ -1119,6 +1140,102 @@ static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
|
|||
}
|
||||
#endif
|
||||
|
||||
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 val = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
|
||||
if (pcr->ops->enable_ocp)
|
||||
pcr->ops->enable_ocp(pcr);
|
||||
else
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
|
||||
|
||||
}
|
||||
|
||||
void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 mask = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
|
||||
if (pcr->ops->disable_ocp)
|
||||
pcr->ops->disable_ocp(pcr);
|
||||
else
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
}
|
||||
|
||||
void rtsx_pci_init_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (pcr->ops->init_ocp) {
|
||||
pcr->ops->init_ocp(pcr);
|
||||
} else {
|
||||
struct rtsx_cr_option *option = &(pcr->option);
|
||||
|
||||
if (option->ocp_en) {
|
||||
u8 val = option->sd_400mA_ocp_thd;
|
||||
|
||||
rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, 0);
|
||||
rtsx_pci_write_register(pcr, REG_OCPPARA1,
|
||||
SD_OCP_TIME_MASK, SD_OCP_TIME_800);
|
||||
rtsx_pci_write_register(pcr, REG_OCPPARA2,
|
||||
SD_OCP_THD_MASK, val);
|
||||
rtsx_pci_write_register(pcr, REG_OCPGLITCH,
|
||||
SD_OCP_GLITCH_MASK, pcr->hw_param.ocp_glitch);
|
||||
rtsx_pci_enable_ocp(pcr);
|
||||
} else {
|
||||
/* OC power down */
|
||||
rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
|
||||
OC_POWER_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
|
||||
{
|
||||
if (pcr->ops->get_ocpstat)
|
||||
return pcr->ops->get_ocpstat(pcr, val);
|
||||
else
|
||||
return rtsx_pci_read_register(pcr, REG_OCPSTAT, val);
|
||||
}
|
||||
|
||||
void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (pcr->ops->clear_ocpstat) {
|
||||
pcr->ops->clear_ocpstat(pcr);
|
||||
} else {
|
||||
u8 mask = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
u8 val = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
|
||||
MS_CLK_EN | SD40_CLK_EN, 0);
|
||||
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
|
||||
|
||||
rtsx_pci_card_power_off(pcr, RTSX_SD_CARD);
|
||||
|
||||
msleep(50);
|
||||
|
||||
rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
|
||||
MS_CLK_EN | SD40_CLK_EN, 0);
|
||||
|
||||
rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD);
|
||||
|
||||
rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0);
|
||||
rtsx_pci_card_power_off(pcr, RTSX_MS_CARD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int err;
|
||||
|
@ -1189,6 +1306,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
|||
case PID_5250:
|
||||
case PID_524A:
|
||||
case PID_525A:
|
||||
case PID_5260:
|
||||
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
|
||||
break;
|
||||
default:
|
||||
|
@ -1265,6 +1383,9 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
|
|||
case 0x5286:
|
||||
rtl8402_init_params(pcr);
|
||||
break;
|
||||
case 0x5260:
|
||||
rts5260_init_params(pcr);
|
||||
break;
|
||||
}
|
||||
|
||||
pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef __RTSX_PCR_H
|
||||
#define __RTSX_PCR_H
|
||||
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#define MIN_DIV_N_PCR 80
|
||||
#define MAX_DIV_N_PCR 208
|
||||
|
@ -44,6 +44,8 @@
|
|||
#define ASPM_MASK_NEG 0xFC
|
||||
#define MASK_8_BIT_DEF 0xFF
|
||||
|
||||
#define SSC_CLOCK_STABLE_WAIT 130
|
||||
|
||||
int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
|
||||
int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
|
||||
|
||||
|
@ -57,6 +59,7 @@ void rts5249_init_params(struct rtsx_pcr *pcr);
|
|||
void rts524a_init_params(struct rtsx_pcr *pcr);
|
||||
void rts525a_init_params(struct rtsx_pcr *pcr);
|
||||
void rtl8411b_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5260_init_params(struct rtsx_pcr *pcr);
|
||||
|
||||
static inline u8 map_sd_drive(int idx)
|
||||
{
|
||||
|
@ -99,5 +102,12 @@ do { \
|
|||
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
|
||||
int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency);
|
||||
int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val);
|
||||
void rtsx_pci_init_ocp(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr);
|
||||
int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val);
|
||||
void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr);
|
||||
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr);
|
||||
int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr);
|
||||
|
||||
#endif
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/usb.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rtsx_usb.h>
|
||||
#include <linux/rtsx_usb.h>
|
||||
|
||||
static int polling_pipe = 1;
|
||||
module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
|
|
@ -838,14 +838,14 @@ config MMC_USDHI6ROL0
|
|||
|
||||
config MMC_REALTEK_PCI
|
||||
tristate "Realtek PCI-E SD/MMC Card Interface Driver"
|
||||
depends on MFD_RTSX_PCI
|
||||
depends on MISC_RTSX_PCI
|
||||
help
|
||||
Say Y here to include driver code to support SD/MMC card interface
|
||||
of Realtek PCI-E card reader
|
||||
|
||||
config MMC_REALTEK_USB
|
||||
tristate "Realtek USB SD/MMC Card Interface Driver"
|
||||
depends on MFD_RTSX_USB
|
||||
depends on MISC_RTSX_USB
|
||||
help
|
||||
Say Y here to include driver code to support SD/MMC card interface
|
||||
of Realtek RTS5129/39 series card reader
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <linux/mmc/sd.h>
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
struct realtek_pci_sdmmc {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/scatterlist.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/mfd/rtsx_usb.h>
|
||||
#include <linux/rtsx_usb.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
|
||||
|
|
|
@ -38,14 +38,8 @@ config CHROMEOS_PSTORE
|
|||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called chromeos_pstore.
|
||||
|
||||
config CROS_EC_CHARDEV
|
||||
tristate "Chrome OS Embedded Controller userspace device interface"
|
||||
depends on MFD_CROS_EC
|
||||
---help---
|
||||
This driver adds support to talk with the ChromeOS EC from userspace.
|
||||
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called cros_ec_dev.
|
||||
config CROS_EC_CTL
|
||||
tristate
|
||||
|
||||
config CROS_EC_LPC
|
||||
tristate "ChromeOS Embedded Controller (LPC)"
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
|
||||
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
|
||||
cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \
|
||||
cros_ec_lightbar.o cros_ec_vbc.o \
|
||||
cros_ec_debugfs.o
|
||||
obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
|
||||
cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \
|
||||
cros_ec_vbc.o cros_ec_debugfs.o
|
||||
obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o
|
||||
cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o
|
||||
cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
|
||||
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "cros_ec_dev.h"
|
||||
#include "cros_ec_debugfs.h"
|
||||
|
||||
#define LOG_SHIFT 14
|
||||
#define LOG_SIZE (1 << LOG_SHIFT)
|
||||
#define LOG_POLL_SEC 10
|
||||
|
@ -390,6 +387,7 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
|
|||
debugfs_remove_recursive(debug_info->dir);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_debugfs_init);
|
||||
|
||||
void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
|
||||
{
|
||||
|
@ -399,3 +397,4 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
|
|||
debugfs_remove_recursive(ec->debug_info->dir);
|
||||
cros_ec_cleanup_console_log(ec->debug_info);
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_debugfs_remove);
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Google, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DRV_CROS_EC_DEBUGFS_H_
|
||||
#define _DRV_CROS_EC_DEBUGFS_H_
|
||||
|
||||
#include "cros_ec_dev.h"
|
||||
|
||||
/* debugfs stuff */
|
||||
int cros_ec_debugfs_init(struct cros_ec_dev *ec);
|
||||
void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
|
||||
|
||||
#endif /* _DRV_CROS_EC_DEBUGFS_H_ */
|
|
@ -33,8 +33,6 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "cros_ec_dev.h"
|
||||
|
||||
/* Rate-limit the lightbar interface to prevent DoS. */
|
||||
static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
|
||||
|
||||
|
@ -414,6 +412,7 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(lb_manual_suspend_ctrl);
|
||||
|
||||
int lb_suspend(struct cros_ec_dev *ec)
|
||||
{
|
||||
|
@ -422,6 +421,7 @@ int lb_suspend(struct cros_ec_dev *ec)
|
|||
|
||||
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
|
||||
}
|
||||
EXPORT_SYMBOL(lb_suspend);
|
||||
|
||||
int lb_resume(struct cros_ec_dev *ec)
|
||||
{
|
||||
|
@ -430,6 +430,7 @@ int lb_resume(struct cros_ec_dev *ec)
|
|||
|
||||
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
|
||||
}
|
||||
EXPORT_SYMBOL(lb_resume);
|
||||
|
||||
static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
@ -622,3 +623,4 @@ struct attribute_group cros_ec_lightbar_attr_group = {
|
|||
.attrs = __lb_cmds_attrs,
|
||||
.is_visible = cros_ec_lightbar_attrs_are_visible,
|
||||
};
|
||||
EXPORT_SYMBOL(cros_ec_lightbar_attr_group);
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "cros_ec_dev.h"
|
||||
|
||||
/* Accessor functions */
|
||||
|
||||
static ssize_t show_ec_reboot(struct device *dev,
|
||||
|
@ -294,4 +292,7 @@ static struct attribute *__ec_attrs[] = {
|
|||
struct attribute_group cros_ec_attr_group = {
|
||||
.attrs = __ec_attrs,
|
||||
};
|
||||
EXPORT_SYMBOL(cros_ec_attr_group);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ChromeOS EC control driver");
|
||||
|
|
|
@ -135,3 +135,4 @@ struct attribute_group cros_ec_vbc_attr_group = {
|
|||
.bin_attrs = cros_ec_vbc_bin_attrs,
|
||||
.is_bin_visible = cros_ec_vbc_is_visible,
|
||||
};
|
||||
EXPORT_SYMBOL(cros_ec_vbc_attr_group);
|
||||
|
|
|
@ -132,6 +132,33 @@ void serdev_device_close(struct serdev_device *serdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_close);
|
||||
|
||||
static void devm_serdev_device_release(struct device *dev, void *dr)
|
||||
{
|
||||
serdev_device_close(*(struct serdev_device **)dr);
|
||||
}
|
||||
|
||||
int devm_serdev_device_open(struct device *dev, struct serdev_device *serdev)
|
||||
{
|
||||
struct serdev_device **dr;
|
||||
int ret;
|
||||
|
||||
dr = devres_alloc(devm_serdev_device_release, sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = serdev_device_open(serdev);
|
||||
if (ret) {
|
||||
devres_free(dr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dr = serdev;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_serdev_device_open);
|
||||
|
||||
void serdev_device_write_wakeup(struct serdev_device *serdev)
|
||||
{
|
||||
complete(&serdev->write_comp);
|
||||
|
@ -268,8 +295,8 @@ static int serdev_drv_probe(struct device *dev)
|
|||
static int serdev_drv_remove(struct device *dev)
|
||||
{
|
||||
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
|
||||
|
||||
sdrv->remove(to_serdev_device(dev));
|
||||
if (sdrv->remove)
|
||||
sdrv->remove(to_serdev_device(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,6 +223,13 @@ config ZIIRAVE_WATCHDOG
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ziirave_wdt.
|
||||
|
||||
config RAVE_SP_WATCHDOG
|
||||
tristate "RAVE SP Watchdog timer"
|
||||
depends on RAVE_SP_CORE
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Support for the watchdog on RAVE SP device.
|
||||
|
||||
# ALPHA Architecture
|
||||
|
||||
# ARM Architecture
|
||||
|
|
|
@ -224,3 +224,4 @@ obj-$(CONFIG_MAX77620_WATCHDOG) += max77620_wdt.o
|
|||
obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o
|
||||
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
|
||||
obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
|
||||
obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
|
||||
|
|
337
drivers/watchdog/rave-sp-wdt.c
Normal file
337
drivers/watchdog/rave-sp-wdt.c
Normal file
|
@ -0,0 +1,337 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/*
|
||||
* Driver for watchdog aspect of for Zodiac Inflight Innovations RAVE
|
||||
* Supervisory Processor(SP) MCU
|
||||
*
|
||||
* Copyright (C) 2017 Zodiac Inflight Innovation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/rave-sp.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
enum {
|
||||
RAVE_SP_RESET_BYTE = 1,
|
||||
RAVE_SP_RESET_REASON_NORMAL = 0,
|
||||
RAVE_SP_RESET_DELAY_MS = 500,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_wdt_variant - RAVE SP watchdog variant
|
||||
*
|
||||
* @max_timeout: Largest possible watchdog timeout setting
|
||||
* @min_timeout: Smallest possible watchdog timeout setting
|
||||
*
|
||||
* @configure: Function to send configuration command
|
||||
* @restart: Function to send "restart" command
|
||||
*/
|
||||
struct rave_sp_wdt_variant {
|
||||
unsigned int max_timeout;
|
||||
unsigned int min_timeout;
|
||||
|
||||
int (*configure)(struct watchdog_device *, bool);
|
||||
int (*restart)(struct watchdog_device *);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rave_sp_wdt - RAVE SP watchdog
|
||||
*
|
||||
* @wdd: Underlying watchdog device
|
||||
* @sp: Pointer to parent RAVE SP device
|
||||
* @variant: Device specific variant information
|
||||
* @reboot_notifier: Reboot notifier implementing machine reset
|
||||
*/
|
||||
struct rave_sp_wdt {
|
||||
struct watchdog_device wdd;
|
||||
struct rave_sp *sp;
|
||||
const struct rave_sp_wdt_variant *variant;
|
||||
struct notifier_block reboot_notifier;
|
||||
};
|
||||
|
||||
static struct rave_sp_wdt *to_rave_sp_wdt(struct watchdog_device *wdd)
|
||||
{
|
||||
return container_of(wdd, struct rave_sp_wdt, wdd);
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_exec(struct watchdog_device *wdd, void *data,
|
||||
size_t data_size)
|
||||
{
|
||||
return rave_sp_exec(to_rave_sp_wdt(wdd)->sp,
|
||||
data, data_size, NULL, 0);
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_legacy_configure(struct watchdog_device *wdd, bool on)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = RAVE_SP_CMD_SW_WDT,
|
||||
[1] = 0,
|
||||
[2] = 0,
|
||||
[3] = on,
|
||||
[4] = on ? wdd->timeout : 0,
|
||||
};
|
||||
|
||||
return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_rdu_configure(struct watchdog_device *wdd, bool on)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = RAVE_SP_CMD_SW_WDT,
|
||||
[1] = 0,
|
||||
[2] = on,
|
||||
[3] = (u8)wdd->timeout,
|
||||
[4] = (u8)(wdd->timeout >> 8),
|
||||
};
|
||||
|
||||
return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
/**
|
||||
* rave_sp_wdt_configure - Configure watchdog device
|
||||
*
|
||||
* @wdd: Device to configure
|
||||
* @on: Desired state of the watchdog timer (ON/OFF)
|
||||
*
|
||||
* This function configures two aspects of the watchdog timer:
|
||||
*
|
||||
* - Wheither it is ON or OFF
|
||||
* - Its timeout duration
|
||||
*
|
||||
* with first aspect specified via function argument and second via
|
||||
* the value of 'wdd->timeout'.
|
||||
*/
|
||||
static int rave_sp_wdt_configure(struct watchdog_device *wdd, bool on)
|
||||
{
|
||||
return to_rave_sp_wdt(wdd)->variant->configure(wdd, on);
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_legacy_restart(struct watchdog_device *wdd)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = RAVE_SP_CMD_RESET,
|
||||
[1] = 0,
|
||||
[2] = RAVE_SP_RESET_BYTE
|
||||
};
|
||||
|
||||
return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_rdu_restart(struct watchdog_device *wdd)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = RAVE_SP_CMD_RESET,
|
||||
[1] = 0,
|
||||
[2] = RAVE_SP_RESET_BYTE,
|
||||
[3] = RAVE_SP_RESET_REASON_NORMAL
|
||||
};
|
||||
|
||||
return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_reboot_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
/*
|
||||
* Restart handler is called in atomic context which means we
|
||||
* can't communicate to SP via UART. Luckily for use SP will
|
||||
* wait 500ms before actually resetting us, so we ask it to do
|
||||
* so here and let the rest of the system go on wrapping
|
||||
* things up.
|
||||
*/
|
||||
if (action == SYS_DOWN || action == SYS_HALT) {
|
||||
struct rave_sp_wdt *sp_wd =
|
||||
container_of(nb, struct rave_sp_wdt, reboot_notifier);
|
||||
|
||||
const int ret = sp_wd->variant->restart(&sp_wd->wdd);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(sp_wd->wdd.parent,
|
||||
"Failed to issue restart command (%d)", ret);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_restart(struct watchdog_device *wdd,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
/*
|
||||
* The actual work was done by reboot notifier above. SP
|
||||
* firmware waits 500 ms before issuing reset, so let's hang
|
||||
* here for twice that delay and hopefuly we'd never reach
|
||||
* the return statement.
|
||||
*/
|
||||
mdelay(2 * RAVE_SP_RESET_DELAY_MS);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rave_sp_wdt_configure(wdd, true);
|
||||
if (!ret)
|
||||
set_bit(WDOG_HW_RUNNING, &wdd->status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
return rave_sp_wdt_configure(wdd, false);
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_set_timeout(struct watchdog_device *wdd,
|
||||
unsigned int timeout)
|
||||
{
|
||||
wdd->timeout = timeout;
|
||||
|
||||
return rave_sp_wdt_configure(wdd, watchdog_active(wdd));
|
||||
}
|
||||
|
||||
static int rave_sp_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
u8 cmd[] = {
|
||||
[0] = RAVE_SP_CMD_PET_WDT,
|
||||
[1] = 0,
|
||||
};
|
||||
|
||||
return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static const struct watchdog_info rave_sp_wdt_info = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
|
||||
.identity = "RAVE SP Watchdog",
|
||||
};
|
||||
|
||||
static const struct watchdog_ops rave_sp_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = rave_sp_wdt_start,
|
||||
.stop = rave_sp_wdt_stop,
|
||||
.ping = rave_sp_wdt_ping,
|
||||
.set_timeout = rave_sp_wdt_set_timeout,
|
||||
.restart = rave_sp_wdt_restart,
|
||||
};
|
||||
|
||||
static const struct rave_sp_wdt_variant rave_sp_wdt_legacy = {
|
||||
.max_timeout = 255,
|
||||
.min_timeout = 1,
|
||||
.configure = rave_sp_wdt_legacy_configure,
|
||||
.restart = rave_sp_wdt_legacy_restart,
|
||||
};
|
||||
|
||||
static const struct rave_sp_wdt_variant rave_sp_wdt_rdu = {
|
||||
.max_timeout = 180,
|
||||
.min_timeout = 60,
|
||||
.configure = rave_sp_wdt_rdu_configure,
|
||||
.restart = rave_sp_wdt_rdu_restart,
|
||||
};
|
||||
|
||||
static const struct of_device_id rave_sp_wdt_of_match[] = {
|
||||
{
|
||||
.compatible = "zii,rave-sp-watchdog-legacy",
|
||||
.data = &rave_sp_wdt_legacy,
|
||||
},
|
||||
{
|
||||
.compatible = "zii,rave-sp-watchdog",
|
||||
.data = &rave_sp_wdt_rdu,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int rave_sp_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct watchdog_device *wdd;
|
||||
struct rave_sp_wdt *sp_wd;
|
||||
struct nvmem_cell *cell;
|
||||
__le16 timeout = 0;
|
||||
int ret;
|
||||
|
||||
sp_wd = devm_kzalloc(dev, sizeof(*sp_wd), GFP_KERNEL);
|
||||
if (!sp_wd)
|
||||
return -ENOMEM;
|
||||
|
||||
sp_wd->variant = of_device_get_match_data(dev);
|
||||
sp_wd->sp = dev_get_drvdata(dev->parent);
|
||||
|
||||
wdd = &sp_wd->wdd;
|
||||
wdd->parent = dev;
|
||||
wdd->info = &rave_sp_wdt_info;
|
||||
wdd->ops = &rave_sp_wdt_ops;
|
||||
wdd->min_timeout = sp_wd->variant->min_timeout;
|
||||
wdd->max_timeout = sp_wd->variant->max_timeout;
|
||||
wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS;
|
||||
wdd->timeout = 60;
|
||||
|
||||
cell = nvmem_cell_get(dev, "wdt-timeout");
|
||||
if (!IS_ERR(cell)) {
|
||||
size_t len;
|
||||
void *value = nvmem_cell_read(cell, &len);
|
||||
|
||||
if (!IS_ERR(value)) {
|
||||
memcpy(&timeout, value, min(len, sizeof(timeout)));
|
||||
kfree(value);
|
||||
}
|
||||
nvmem_cell_put(cell);
|
||||
}
|
||||
watchdog_init_timeout(wdd, le16_to_cpu(timeout), dev);
|
||||
watchdog_set_restart_priority(wdd, 255);
|
||||
watchdog_stop_on_unregister(wdd);
|
||||
|
||||
sp_wd->reboot_notifier.notifier_call = rave_sp_wdt_reboot_notifier;
|
||||
ret = devm_register_reboot_notifier(dev, &sp_wd->reboot_notifier);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register reboot notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't know if watchdog is running now. To be sure, let's
|
||||
* start it and depend on watchdog core to ping it
|
||||
*/
|
||||
wdd->max_hw_heartbeat_ms = wdd->max_timeout * 1000;
|
||||
ret = rave_sp_wdt_start(wdd);
|
||||
if (ret) {
|
||||
dev_err(dev, "Watchdog didn't start\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_watchdog_register_device(dev, wdd);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register watchdog device\n");
|
||||
rave_sp_wdt_stop(wdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rave_sp_wdt_driver = {
|
||||
.probe = rave_sp_wdt_probe,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = rave_sp_wdt_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rave_sp_wdt_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(of, rave_sp_wdt_of_match);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
|
||||
MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
|
||||
MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||
MODULE_DESCRIPTION("RAVE SP Watchdog driver");
|
||||
MODULE_ALIAS("platform:rave-sp-watchdog");
|
|
@ -5,12 +5,19 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
extern u16 const crc_ccitt_table[256];
|
||||
extern u16 const crc_ccitt_false_table[256];
|
||||
|
||||
extern u16 crc_ccitt(u16 crc, const u8 *buffer, size_t len);
|
||||
extern u16 crc_ccitt_false(u16 crc, const u8 *buffer, size_t len);
|
||||
|
||||
static inline u16 crc_ccitt_byte(u16 crc, const u8 c)
|
||||
{
|
||||
return (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff];
|
||||
}
|
||||
|
||||
static inline u16 crc_ccitt_false_byte(u16 crc, const u8 c)
|
||||
{
|
||||
return (crc << 8) ^ crc_ccitt_false_table[(crc >> 8) ^ c];
|
||||
}
|
||||
|
||||
#endif /* _LINUX_CRC_CCITT_H */
|
||||
|
|
|
@ -645,11 +645,6 @@ struct axp20x_dev {
|
|||
const struct regmap_irq_chip *regmap_irq_chip;
|
||||
};
|
||||
|
||||
struct axp288_extcon_pdata {
|
||||
/* GPIO pin control to switch D+/D- lines b/w PMIC and SOC */
|
||||
struct gpio_desc *gpio_mux_cntl;
|
||||
};
|
||||
|
||||
/* generic helper function for reading 9-16 bit wide regs */
|
||||
static inline int axp20x_read_variable_width(struct regmap *regmap,
|
||||
unsigned int reg, unsigned int width)
|
||||
|
|
|
@ -322,6 +322,10 @@ extern struct attribute_group cros_ec_attr_group;
|
|||
extern struct attribute_group cros_ec_lightbar_attr_group;
|
||||
extern struct attribute_group cros_ec_vbc_attr_group;
|
||||
|
||||
/* debugfs stuff */
|
||||
int cros_ec_debugfs_init(struct cros_ec_dev *ec);
|
||||
void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
|
||||
|
||||
/* ACPI GPE handler */
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
|
|
|
@ -2904,16 +2904,33 @@ enum usb_pd_control_mux {
|
|||
USB_PD_CTRL_MUX_AUTO = 5,
|
||||
};
|
||||
|
||||
enum usb_pd_control_swap {
|
||||
USB_PD_CTRL_SWAP_NONE = 0,
|
||||
USB_PD_CTRL_SWAP_DATA = 1,
|
||||
USB_PD_CTRL_SWAP_POWER = 2,
|
||||
USB_PD_CTRL_SWAP_VCONN = 3,
|
||||
USB_PD_CTRL_SWAP_COUNT
|
||||
};
|
||||
|
||||
struct ec_params_usb_pd_control {
|
||||
uint8_t port;
|
||||
uint8_t role;
|
||||
uint8_t mux;
|
||||
uint8_t swap;
|
||||
} __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 */
|
||||
|
||||
#define PD_CTRL_RESP_ROLE_POWER BIT(0) /* 0=SNK/1=SRC */
|
||||
#define PD_CTRL_RESP_ROLE_DATA BIT(1) /* 0=UFP/1=DFP */
|
||||
#define PD_CTRL_RESP_ROLE_VCONN BIT(2) /* Vconn status */
|
||||
#define PD_CTRL_RESP_ROLE_DR_POWER BIT(3) /* Partner is dualrole power */
|
||||
#define PD_CTRL_RESP_ROLE_DR_DATA BIT(4) /* Partner is dualrole data */
|
||||
#define PD_CTRL_RESP_ROLE_USB_COMM BIT(5) /* Partner USB comm capable */
|
||||
#define PD_CTRL_RESP_ROLE_EXT_POWERED BIT(6) /* Partner externally powerd */
|
||||
|
||||
struct ec_response_usb_pd_control_v1 {
|
||||
uint8_t enabled;
|
||||
uint8_t role;
|
||||
|
|
60
include/linux/mfd/rave-sp.h
Normal file
60
include/linux/mfd/rave-sp.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
/*
|
||||
* Core definitions for RAVE SP MFD driver.
|
||||
*
|
||||
* Copyright (C) 2017 Zodiac Inflight Innovations
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_RAVE_SP_H_
|
||||
#define _LINUX_RAVE_SP_H_
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
||||
enum rave_sp_command {
|
||||
RAVE_SP_CMD_GET_FIRMWARE_VERSION = 0x20,
|
||||
RAVE_SP_CMD_GET_BOOTLOADER_VERSION = 0x21,
|
||||
RAVE_SP_CMD_BOOT_SOURCE = 0x26,
|
||||
RAVE_SP_CMD_GET_BOARD_COPPER_REV = 0x2B,
|
||||
RAVE_SP_CMD_GET_GPIO_STATE = 0x2F,
|
||||
|
||||
RAVE_SP_CMD_STATUS = 0xA0,
|
||||
RAVE_SP_CMD_SW_WDT = 0xA1,
|
||||
RAVE_SP_CMD_PET_WDT = 0xA2,
|
||||
RAVE_SP_CMD_RESET = 0xA7,
|
||||
RAVE_SP_CMD_RESET_REASON = 0xA8,
|
||||
|
||||
RAVE_SP_CMD_REQ_COPPER_REV = 0xB6,
|
||||
RAVE_SP_CMD_GET_I2C_DEVICE_STATUS = 0xBA,
|
||||
RAVE_SP_CMD_GET_SP_SILICON_REV = 0xB9,
|
||||
RAVE_SP_CMD_CONTROL_EVENTS = 0xBB,
|
||||
|
||||
RAVE_SP_EVNT_BASE = 0xE0,
|
||||
};
|
||||
|
||||
struct rave_sp;
|
||||
|
||||
static inline unsigned long rave_sp_action_pack(u8 event, u8 value)
|
||||
{
|
||||
return ((unsigned long)value << 8) | event;
|
||||
}
|
||||
|
||||
static inline u8 rave_sp_action_unpack_event(unsigned long action)
|
||||
{
|
||||
return action;
|
||||
}
|
||||
|
||||
static inline u8 rave_sp_action_unpack_value(unsigned long action)
|
||||
{
|
||||
return action >> 8;
|
||||
}
|
||||
|
||||
int rave_sp_exec(struct rave_sp *sp,
|
||||
void *__data, size_t data_size,
|
||||
void *reply_data, size_t reply_data_size);
|
||||
|
||||
struct device;
|
||||
int devm_rave_sp_register_event_notifier(struct device *dev,
|
||||
struct notifier_block *nb);
|
||||
|
||||
#endif /* _LINUX_RAVE_SP_H_ */
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mfd/rtsx_common.h>
|
||||
#include <linux/rtsx_common.h>
|
||||
|
||||
#define MAX_RW_REG_CNT 1024
|
||||
|
||||
|
@ -203,6 +203,7 @@
|
|||
#define SD_DDR_MODE 0x04
|
||||
#define SD_30_MODE 0x08
|
||||
#define SD_CLK_DIVIDE_MASK 0xC0
|
||||
#define SD_MODE_SELECT_MASK 0x0C
|
||||
#define SD_CFG2 0xFDA1
|
||||
#define SD_CALCULATE_CRC7 0x00
|
||||
#define SD_NO_CALCULATE_CRC7 0x80
|
||||
|
@ -226,6 +227,7 @@
|
|||
#define SD_RSP_TYPE_R6 0x01
|
||||
#define SD_RSP_TYPE_R7 0x01
|
||||
#define SD_CFG3 0xFDA2
|
||||
#define SD30_CLK_END_EN 0x10
|
||||
#define SD_RSP_80CLK_TIMEOUT_EN 0x01
|
||||
|
||||
#define SD_STAT1 0xFDA3
|
||||
|
@ -309,6 +311,12 @@
|
|||
|
||||
#define SD_DATA_STATE 0xFDB6
|
||||
#define SD_DATA_IDLE 0x80
|
||||
#define REG_SD_STOP_SDCLK_CFG 0xFDB8
|
||||
#define SD30_CLK_STOP_CFG_EN 0x04
|
||||
#define SD30_CLK_STOP_CFG1 0x02
|
||||
#define SD30_CLK_STOP_CFG0 0x01
|
||||
#define REG_PRE_RW_MODE 0xFD70
|
||||
#define EN_INFINITE_MODE 0x01
|
||||
|
||||
#define SRCTL 0xFC13
|
||||
|
||||
|
@ -434,6 +442,7 @@
|
|||
#define CARD_CLK_EN 0xFD69
|
||||
#define SD_CLK_EN 0x04
|
||||
#define MS_CLK_EN 0x08
|
||||
#define SD40_CLK_EN 0x10
|
||||
#define SDIO_CTRL 0xFD6B
|
||||
#define CD_PAD_CTL 0xFD73
|
||||
#define CD_DISABLE_MASK 0x07
|
||||
|
@ -453,8 +462,8 @@
|
|||
#define FPDCTL 0xFC00
|
||||
#define SSC_POWER_DOWN 0x01
|
||||
#define SD_OC_POWER_DOWN 0x02
|
||||
#define ALL_POWER_DOWN 0x07
|
||||
#define OC_POWER_DOWN 0x06
|
||||
#define ALL_POWER_DOWN 0x03
|
||||
#define OC_POWER_DOWN 0x02
|
||||
#define PDINFO 0xFC01
|
||||
|
||||
#define CLK_CTL 0xFC02
|
||||
|
@ -490,6 +499,9 @@
|
|||
|
||||
#define FPGA_PULL_CTL 0xFC1D
|
||||
#define OLT_LED_CTL 0xFC1E
|
||||
#define LED_SHINE_MASK 0x08
|
||||
#define LED_SHINE_EN 0x08
|
||||
#define LED_SHINE_DISABLE 0x00
|
||||
#define GPIO_CTL 0xFC1F
|
||||
|
||||
#define LDO_CTL 0xFC1E
|
||||
|
@ -511,7 +523,11 @@
|
|||
#define BPP_LDO_ON 0x00
|
||||
#define BPP_LDO_SUSPEND 0x02
|
||||
#define BPP_LDO_OFF 0x03
|
||||
#define EFUSE_CTL 0xFC30
|
||||
#define EFUSE_ADD 0xFC31
|
||||
#define SYS_VER 0xFC32
|
||||
#define EFUSE_DATAL 0xFC34
|
||||
#define EFUSE_DATAH 0xFC35
|
||||
|
||||
#define CARD_PULL_CTL1 0xFD60
|
||||
#define CARD_PULL_CTL2 0xFD61
|
||||
|
@ -553,6 +569,9 @@
|
|||
#define RBBC1 0xFE2F
|
||||
#define RBDAT 0xFE30
|
||||
#define RBCTL 0xFE34
|
||||
#define U_AUTO_DMA_EN_MASK 0x20
|
||||
#define U_AUTO_DMA_DISABLE 0x00
|
||||
#define RB_FLUSH 0x80
|
||||
#define CFGADDR0 0xFE35
|
||||
#define CFGADDR1 0xFE36
|
||||
#define CFGDATA0 0xFE37
|
||||
|
@ -581,6 +600,8 @@
|
|||
#define LTR_LATENCY_MODE_HW 0
|
||||
#define LTR_LATENCY_MODE_SW BIT(6)
|
||||
#define OBFF_CFG 0xFE4C
|
||||
#define OBFF_EN_MASK 0x03
|
||||
#define OBFF_DISABLE 0x00
|
||||
|
||||
#define CDRESUMECTL 0xFE52
|
||||
#define WAKE_SEL_CTL 0xFE54
|
||||
|
@ -595,6 +616,7 @@
|
|||
#define FORCE_ASPM_L0_EN 0x01
|
||||
#define FORCE_ASPM_NO_ASPM 0x00
|
||||
#define PM_CLK_FORCE_CTL 0xFE58
|
||||
#define CLK_PM_EN 0x01
|
||||
#define FUNC_FORCE_CTL 0xFE59
|
||||
#define FUNC_FORCE_UPME_XMT_DBG 0x02
|
||||
#define PERST_GLITCH_WIDTH 0xFE5C
|
||||
|
@ -620,14 +642,23 @@
|
|||
#define LDO_PWR_SEL 0xFE78
|
||||
|
||||
#define L1SUB_CONFIG1 0xFE8D
|
||||
#define AUX_CLK_ACTIVE_SEL_MASK 0x01
|
||||
#define MAC_CKSW_DONE 0x00
|
||||
#define L1SUB_CONFIG2 0xFE8E
|
||||
#define L1SUB_AUTO_CFG 0x02
|
||||
#define L1SUB_CONFIG3 0xFE8F
|
||||
#define L1OFF_MBIAS2_EN_5250 BIT(7)
|
||||
|
||||
#define DUMMY_REG_RESET_0 0xFE90
|
||||
#define IC_VERSION_MASK 0x0F
|
||||
|
||||
#define REG_VREF 0xFE97
|
||||
#define PWD_SUSPND_EN 0x10
|
||||
#define RTS5260_DMA_RST_CTL_0 0xFEBF
|
||||
#define RTS5260_DMA_RST 0x80
|
||||
#define RTS5260_ADMA3_RST 0x40
|
||||
#define AUTOLOAD_CFG_BASE 0xFF00
|
||||
#define RELINK_TIME_MASK 0x01
|
||||
#define PETXCFG 0xFF03
|
||||
#define FORCE_CLKREQ_DELINK_MASK BIT(7)
|
||||
#define FORCE_CLKREQ_LOW 0x80
|
||||
|
@ -667,15 +698,24 @@
|
|||
#define LDO_DV18_CFG 0xFF70
|
||||
#define LDO_DV18_SR_MASK 0xC0
|
||||
#define LDO_DV18_SR_DF 0x40
|
||||
#define DV331812_MASK 0x70
|
||||
#define DV331812_33 0x70
|
||||
#define DV331812_17 0x30
|
||||
|
||||
#define LDO_CONFIG2 0xFF71
|
||||
#define LDO_D3318_MASK 0x07
|
||||
#define LDO_D3318_33V 0x07
|
||||
#define LDO_D3318_18V 0x02
|
||||
#define DV331812_VDD1 0x04
|
||||
#define DV331812_POWERON 0x08
|
||||
#define DV331812_POWEROFF 0x00
|
||||
|
||||
#define LDO_VCC_CFG0 0xFF72
|
||||
#define LDO_VCC_LMTVTH_MASK 0x30
|
||||
#define LDO_VCC_LMTVTH_2A 0x10
|
||||
/*RTS5260*/
|
||||
#define RTS5260_DVCC_TUNE_MASK 0x70
|
||||
#define RTS5260_DVCC_33 0x70
|
||||
|
||||
#define LDO_VCC_CFG1 0xFF73
|
||||
#define LDO_VCC_REF_TUNE_MASK 0x30
|
||||
|
@ -684,6 +724,10 @@
|
|||
#define LDO_VCC_1V8 0x04
|
||||
#define LDO_VCC_3V3 0x07
|
||||
#define LDO_VCC_LMT_EN 0x08
|
||||
/*RTS5260*/
|
||||
#define LDO_POW_SDVDD1_MASK 0x08
|
||||
#define LDO_POW_SDVDD1_ON 0x08
|
||||
#define LDO_POW_SDVDD1_OFF 0x00
|
||||
|
||||
#define LDO_VIO_CFG 0xFF75
|
||||
#define LDO_VIO_SR_MASK 0xC0
|
||||
|
@ -711,6 +755,160 @@
|
|||
#define SD_VIO_LDO_1V8 0x40
|
||||
#define SD_VIO_LDO_3V3 0x70
|
||||
|
||||
#define RTS5260_AUTOLOAD_CFG4 0xFF7F
|
||||
#define RTS5260_MIMO_DISABLE 0x8A
|
||||
|
||||
#define RTS5260_REG_GPIO_CTL0 0xFC1A
|
||||
#define RTS5260_REG_GPIO_MASK 0x01
|
||||
#define RTS5260_REG_GPIO_ON 0x01
|
||||
#define RTS5260_REG_GPIO_OFF 0x00
|
||||
|
||||
#define PWR_GLOBAL_CTRL 0xF200
|
||||
#define PCIE_L1_2_EN 0x0C
|
||||
#define PCIE_L1_1_EN 0x0A
|
||||
#define PCIE_L1_0_EN 0x09
|
||||
#define PWR_FE_CTL 0xF201
|
||||
#define PCIE_L1_2_PD_FE_EN 0x0C
|
||||
#define PCIE_L1_1_PD_FE_EN 0x0A
|
||||
#define PCIE_L1_0_PD_FE_EN 0x09
|
||||
#define CFG_PCIE_APHY_OFF_0 0xF204
|
||||
#define CFG_PCIE_APHY_OFF_0_DEFAULT 0xBF
|
||||
#define CFG_PCIE_APHY_OFF_1 0xF205
|
||||
#define CFG_PCIE_APHY_OFF_1_DEFAULT 0xFF
|
||||
#define CFG_PCIE_APHY_OFF_2 0xF206
|
||||
#define CFG_PCIE_APHY_OFF_2_DEFAULT 0x01
|
||||
#define CFG_PCIE_APHY_OFF_3 0xF207
|
||||
#define CFG_PCIE_APHY_OFF_3_DEFAULT 0x00
|
||||
#define CFG_L1_0_PCIE_MAC_RET_VALUE 0xF20C
|
||||
#define CFG_L1_0_PCIE_DPHY_RET_VALUE 0xF20E
|
||||
#define CFG_L1_0_SYS_RET_VALUE 0xF210
|
||||
#define CFG_L1_0_CRC_MISC_RET_VALUE 0xF212
|
||||
#define CFG_L1_0_CRC_SD30_RET_VALUE 0xF214
|
||||
#define CFG_L1_0_CRC_SD40_RET_VALUE 0xF216
|
||||
#define CFG_LP_FPWM_VALUE 0xF219
|
||||
#define CFG_LP_FPWM_VALUE_DEFAULT 0x18
|
||||
#define PWC_CDR 0xF253
|
||||
#define PWC_CDR_DEFAULT 0x03
|
||||
#define CFG_L1_0_RET_VALUE_DEFAULT 0x1B
|
||||
#define CFG_L1_0_CRC_MISC_RET_VALUE_DEFAULT 0x0C
|
||||
|
||||
/* OCPCTL */
|
||||
#define SD_DETECT_EN 0x08
|
||||
#define SD_OCP_INT_EN 0x04
|
||||
#define SD_OCP_INT_CLR 0x02
|
||||
#define SD_OC_CLR 0x01
|
||||
|
||||
#define SDVIO_DETECT_EN (1 << 7)
|
||||
#define SDVIO_OCP_INT_EN (1 << 6)
|
||||
#define SDVIO_OCP_INT_CLR (1 << 5)
|
||||
#define SDVIO_OC_CLR (1 << 4)
|
||||
|
||||
/* OCPSTAT */
|
||||
#define SD_OCP_DETECT 0x08
|
||||
#define SD_OC_NOW 0x04
|
||||
#define SD_OC_EVER 0x02
|
||||
|
||||
#define SDVIO_OC_NOW (1 << 6)
|
||||
#define SDVIO_OC_EVER (1 << 5)
|
||||
|
||||
#define REG_OCPCTL 0xFD6A
|
||||
#define REG_OCPSTAT 0xFD6E
|
||||
#define REG_OCPGLITCH 0xFD6C
|
||||
#define REG_OCPPARA1 0xFD6B
|
||||
#define REG_OCPPARA2 0xFD6D
|
||||
|
||||
/* rts5260 DV3318 OCP-related registers */
|
||||
#define REG_DV3318_OCPCTL 0xFD89
|
||||
#define DV3318_OCP_TIME_MASK 0xF0
|
||||
#define DV3318_DETECT_EN 0x08
|
||||
#define DV3318_OCP_INT_EN 0x04
|
||||
#define DV3318_OCP_INT_CLR 0x02
|
||||
#define DV3318_OCP_CLR 0x01
|
||||
|
||||
#define REG_DV3318_OCPSTAT 0xFD8A
|
||||
#define DV3318_OCP_GlITCH_TIME_MASK 0xF0
|
||||
#define DV3318_OCP_DETECT 0x08
|
||||
#define DV3318_OCP_NOW 0x04
|
||||
#define DV3318_OCP_EVER 0x02
|
||||
|
||||
#define SD_OCP_GLITCH_MASK 0x0F
|
||||
|
||||
/* OCPPARA1 */
|
||||
#define SDVIO_OCP_TIME_60 0x00
|
||||
#define SDVIO_OCP_TIME_100 0x10
|
||||
#define SDVIO_OCP_TIME_200 0x20
|
||||
#define SDVIO_OCP_TIME_400 0x30
|
||||
#define SDVIO_OCP_TIME_600 0x40
|
||||
#define SDVIO_OCP_TIME_800 0x50
|
||||
#define SDVIO_OCP_TIME_1100 0x60
|
||||
#define SDVIO_OCP_TIME_MASK 0x70
|
||||
|
||||
#define SD_OCP_TIME_60 0x00
|
||||
#define SD_OCP_TIME_100 0x01
|
||||
#define SD_OCP_TIME_200 0x02
|
||||
#define SD_OCP_TIME_400 0x03
|
||||
#define SD_OCP_TIME_600 0x04
|
||||
#define SD_OCP_TIME_800 0x05
|
||||
#define SD_OCP_TIME_1100 0x06
|
||||
#define SD_OCP_TIME_MASK 0x07
|
||||
|
||||
/* OCPPARA2 */
|
||||
#define SDVIO_OCP_THD_190 0x00
|
||||
#define SDVIO_OCP_THD_250 0x10
|
||||
#define SDVIO_OCP_THD_320 0x20
|
||||
#define SDVIO_OCP_THD_380 0x30
|
||||
#define SDVIO_OCP_THD_440 0x40
|
||||
#define SDVIO_OCP_THD_500 0x50
|
||||
#define SDVIO_OCP_THD_570 0x60
|
||||
#define SDVIO_OCP_THD_630 0x70
|
||||
#define SDVIO_OCP_THD_MASK 0x70
|
||||
|
||||
#define SD_OCP_THD_450 0x00
|
||||
#define SD_OCP_THD_550 0x01
|
||||
#define SD_OCP_THD_650 0x02
|
||||
#define SD_OCP_THD_750 0x03
|
||||
#define SD_OCP_THD_850 0x04
|
||||
#define SD_OCP_THD_950 0x05
|
||||
#define SD_OCP_THD_1050 0x06
|
||||
#define SD_OCP_THD_1150 0x07
|
||||
#define SD_OCP_THD_MASK 0x07
|
||||
|
||||
#define SDVIO_OCP_GLITCH_MASK 0xF0
|
||||
#define SDVIO_OCP_GLITCH_NONE 0x00
|
||||
#define SDVIO_OCP_GLITCH_50U 0x10
|
||||
#define SDVIO_OCP_GLITCH_100U 0x20
|
||||
#define SDVIO_OCP_GLITCH_200U 0x30
|
||||
#define SDVIO_OCP_GLITCH_600U 0x40
|
||||
#define SDVIO_OCP_GLITCH_800U 0x50
|
||||
#define SDVIO_OCP_GLITCH_1M 0x60
|
||||
#define SDVIO_OCP_GLITCH_2M 0x70
|
||||
#define SDVIO_OCP_GLITCH_3M 0x80
|
||||
#define SDVIO_OCP_GLITCH_4M 0x90
|
||||
#define SDVIO_OCP_GLIVCH_5M 0xA0
|
||||
#define SDVIO_OCP_GLITCH_6M 0xB0
|
||||
#define SDVIO_OCP_GLITCH_7M 0xC0
|
||||
#define SDVIO_OCP_GLITCH_8M 0xD0
|
||||
#define SDVIO_OCP_GLITCH_9M 0xE0
|
||||
#define SDVIO_OCP_GLITCH_10M 0xF0
|
||||
|
||||
#define SD_OCP_GLITCH_MASK 0x0F
|
||||
#define SD_OCP_GLITCH_NONE 0x00
|
||||
#define SD_OCP_GLITCH_50U 0x01
|
||||
#define SD_OCP_GLITCH_100U 0x02
|
||||
#define SD_OCP_GLITCH_200U 0x03
|
||||
#define SD_OCP_GLITCH_600U 0x04
|
||||
#define SD_OCP_GLITCH_800U 0x05
|
||||
#define SD_OCP_GLITCH_1M 0x06
|
||||
#define SD_OCP_GLITCH_2M 0x07
|
||||
#define SD_OCP_GLITCH_3M 0x08
|
||||
#define SD_OCP_GLITCH_4M 0x09
|
||||
#define SD_OCP_GLIVCH_5M 0x0A
|
||||
#define SD_OCP_GLITCH_6M 0x0B
|
||||
#define SD_OCP_GLITCH_7M 0x0C
|
||||
#define SD_OCP_GLITCH_8M 0x0D
|
||||
#define SD_OCP_GLITCH_9M 0x0E
|
||||
#define SD_OCP_GLITCH_10M 0x0F
|
||||
|
||||
/* Phy register */
|
||||
#define PHY_PCR 0x00
|
||||
#define PHY_PCR_FORCE_CODE 0xB000
|
||||
|
@ -857,6 +1055,7 @@
|
|||
|
||||
#define PCR_ASPM_SETTING_REG1 0x160
|
||||
#define PCR_ASPM_SETTING_REG2 0x168
|
||||
#define PCR_ASPM_SETTING_5260 0x178
|
||||
|
||||
#define PCR_SETTING_REG1 0x724
|
||||
#define PCR_SETTING_REG2 0x814
|
||||
|
@ -890,6 +1089,7 @@ struct pcr_ops {
|
|||
int (*conv_clk_and_div_n)(int clk, int dir);
|
||||
void (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
|
||||
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
|
||||
void (*stop_cmd)(struct rtsx_pcr *pcr);
|
||||
|
||||
void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
|
||||
int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
|
||||
|
@ -897,6 +1097,12 @@ struct pcr_ops {
|
|||
void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active);
|
||||
void (*full_on)(struct rtsx_pcr *pcr);
|
||||
void (*power_saving)(struct rtsx_pcr *pcr);
|
||||
void (*enable_ocp)(struct rtsx_pcr *pcr);
|
||||
void (*disable_ocp)(struct rtsx_pcr *pcr);
|
||||
void (*init_ocp)(struct rtsx_pcr *pcr);
|
||||
void (*process_ocp)(struct rtsx_pcr *pcr);
|
||||
int (*get_ocpstat)(struct rtsx_pcr *pcr, u8 *val);
|
||||
void (*clear_ocpstat)(struct rtsx_pcr *pcr);
|
||||
};
|
||||
|
||||
enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN};
|
||||
|
@ -935,6 +1141,9 @@ enum dev_aspm_mode {
|
|||
* @l1_snooze_delay: l1 snooze delay
|
||||
* @ltr_l1off_sspwrgate: ltr l1off sspwrgate
|
||||
* @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
|
||||
* @ocp_en: enable ocp flag
|
||||
* @sd_400mA_ocp_thd: 400mA ocp thd
|
||||
* @sd_800mA_ocp_thd: 800mA ocp thd
|
||||
*/
|
||||
struct rtsx_cr_option {
|
||||
u32 dev_flags;
|
||||
|
@ -949,6 +1158,19 @@ struct rtsx_cr_option {
|
|||
u32 l1_snooze_delay;
|
||||
u8 ltr_l1off_sspwrgate;
|
||||
u8 ltr_l1off_snooze_sspwrgate;
|
||||
bool ocp_en;
|
||||
u8 sd_400mA_ocp_thd;
|
||||
u8 sd_800mA_ocp_thd;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rtsx_hw_param - card reader hardware param
|
||||
* @interrupt_en: indicate which interrutp enable
|
||||
* @ocp_glitch: ocp glitch time
|
||||
*/
|
||||
struct rtsx_hw_param {
|
||||
u32 interrupt_en;
|
||||
u8 ocp_glitch;
|
||||
};
|
||||
|
||||
#define rtsx_set_dev_flag(cr, flag) \
|
||||
|
@ -963,6 +1185,7 @@ struct rtsx_pcr {
|
|||
unsigned int id;
|
||||
int pcie_cap;
|
||||
struct rtsx_cr_option option;
|
||||
struct rtsx_hw_param hw_param;
|
||||
|
||||
/* pci resources */
|
||||
unsigned long addr;
|
||||
|
@ -1042,12 +1265,15 @@ struct rtsx_pcr {
|
|||
struct rtsx_slot *slots;
|
||||
|
||||
u8 dma_error_count;
|
||||
u8 ocp_stat;
|
||||
u8 ocp_stat2;
|
||||
};
|
||||
|
||||
#define PID_524A 0x524A
|
||||
#define PID_5249 0x5249
|
||||
#define PID_5250 0x5250
|
||||
#define PID_5249 0x5249
|
||||
#define PID_5250 0x5250
|
||||
#define PID_525A 0x525A
|
||||
#define PID_5260 0x5260
|
||||
|
||||
#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid))
|
||||
#define PCI_VID(pcr) ((pcr)->pci->vendor)
|
|
@ -193,6 +193,7 @@ static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl,
|
|||
|
||||
int serdev_device_open(struct serdev_device *);
|
||||
void serdev_device_close(struct serdev_device *);
|
||||
int devm_serdev_device_open(struct device *, struct serdev_device *);
|
||||
unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
|
||||
void serdev_device_set_flow_control(struct serdev_device *, bool);
|
||||
int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
|
||||
|
|
|
@ -51,8 +51,49 @@ u16 const crc_ccitt_table[256] = {
|
|||
};
|
||||
EXPORT_SYMBOL(crc_ccitt_table);
|
||||
|
||||
/*
|
||||
* Similar table to calculate CRC16 variant known as CRC-CCITT-FALSE
|
||||
* Reflected bits order, does not augment final value.
|
||||
*/
|
||||
u16 const crc_ccitt_false_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
EXPORT_SYMBOL(crc_ccitt_false_table);
|
||||
|
||||
/**
|
||||
* crc_ccitt - recompute the CRC for the data buffer
|
||||
* crc_ccitt - recompute the CRC (CRC-CCITT variant) for the data
|
||||
* buffer
|
||||
* @crc: previous CRC value
|
||||
* @buffer: data pointer
|
||||
* @len: number of bytes in the buffer
|
||||
|
@ -65,5 +106,20 @@ u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
|
|||
}
|
||||
EXPORT_SYMBOL(crc_ccitt);
|
||||
|
||||
/**
|
||||
* crc_ccitt_false - recompute the CRC (CRC-CCITT-FALSE variant)
|
||||
* for the data buffer
|
||||
* @crc: previous CRC value
|
||||
* @buffer: data pointer
|
||||
* @len: number of bytes in the buffer
|
||||
*/
|
||||
u16 crc_ccitt_false(u16 crc, u8 const *buffer, size_t len)
|
||||
{
|
||||
while (len--)
|
||||
crc = crc_ccitt_false_byte(crc, *buffer++);
|
||||
return crc;
|
||||
}
|
||||
EXPORT_SYMBOL(crc_ccitt_false);
|
||||
|
||||
MODULE_DESCRIPTION("CRC-CCITT calculations");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
Loading…
Reference in a new issue