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:
Lee Jones 2018-01-08 11:02:37 +00:00
52 changed files with 2659 additions and 146 deletions

View file

@ -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";
};
}

View file

@ -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()

View file

@ -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,

View file

@ -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 */

View file

@ -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) {

View file

@ -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

View file

@ -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 {

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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),
};

View file

@ -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
View 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");

View file

@ -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

View file

@ -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

View 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.

View 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

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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;
}

View 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, &reg);
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, &reg);
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;
}

View 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

View file

@ -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",

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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 {

View file

@ -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) && \

View file

@ -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)"

View file

@ -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

View file

@ -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);

View file

@ -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_ */

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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

View 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");

View file

@ -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 */

View file

@ -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)

View file

@ -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

View file

@ -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;

View 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_ */

View file

@ -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)

View file

@ -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);

View file

@ -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");