From: Wei WANG <wei_wang@xxxxxxxxxxxxxx> Realtek card reader core driver is the bus driver for Realtek driver-based card reader, which supplies adapter layer to be used by lower-level pci/usb card reader and upper-level sdmmc/memstick host driver. Signed-off-by: Wei WANG <wei_wang@xxxxxxxxxxxxxx> --- Documentation/misc-devices/realtek_cr.txt | 27 ++ drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/realtek_cr/Kconfig | 26 ++ drivers/misc/realtek_cr/Makefile | 7 + drivers/misc/realtek_cr/core/Kconfig | 5 + drivers/misc/realtek_cr/core/Makefile | 1 + drivers/misc/realtek_cr/core/rtsx_core.c | 462 +++++++++++++++++++++++++++++ include/linux/rtsx_core.h | 188 ++++++++++++ 9 files changed, 718 insertions(+) create mode 100644 Documentation/misc-devices/realtek_cr.txt create mode 100644 drivers/misc/realtek_cr/Kconfig create mode 100644 drivers/misc/realtek_cr/Makefile create mode 100644 drivers/misc/realtek_cr/core/Kconfig create mode 100644 drivers/misc/realtek_cr/core/Makefile create mode 100644 drivers/misc/realtek_cr/core/rtsx_core.c create mode 100644 include/linux/rtsx_core.h diff --git a/Documentation/misc-devices/realtek_cr.txt b/Documentation/misc-devices/realtek_cr.txt new file mode 100644 index 0000000..b4e6fbe --- /dev/null +++ b/Documentation/misc-devices/realtek_cr.txt @@ -0,0 +1,27 @@ +Realtek Driver-based Card Reader +================================ + +Supported chips: +RTS5209 +RTS5229 + +Contact Email: +pc_sw_linux@xxxxxxxxxxxxxx + + +Description +----------- + +Realtek driver-based card reader supports access to many types of memory cards, +such as Memory Stick, Memory Stick Pro, Secure Digital and MultiMediaCard. + + +udev rules +---------- + +In order to modprobe Realtek SD/MMC interface driver automatically, the following rule +should be added to the udev rules file: + +SUBSYSTEM=="rtsx_cr", ENV{RTSX_CARD_TYPE}=="SD", RUN+="/sbin/modprobe -bv rtsx_sdmmc" + +Typically, we may edit /lib/udev/rules.d/80-drivers.rules and copy the rule into it in Ubuntu. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 154f3ef..d32076e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -516,4 +516,5 @@ source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/carma/Kconfig" source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/mei/Kconfig" +source "drivers/misc/realtek_cr/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b88df7a..0bb17ce 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -50,3 +50,4 @@ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_INTEL_MEI) += mei/ +obj-$(CONFIG_REALTEK_CR_SUPPORT) += realtek_cr/ diff --git a/drivers/misc/realtek_cr/Kconfig b/drivers/misc/realtek_cr/Kconfig new file mode 100644 index 0000000..303d98a --- /dev/null +++ b/drivers/misc/realtek_cr/Kconfig @@ -0,0 +1,26 @@ +# +# Realtek driver-based card reader +# + +menuconfig REALTEK_CR_SUPPORT + tristate "Realtek driver-based card reader" + help + Realtek driver-based card reader supports access to many types of + memory cards, such as Memory Stick, Memory Stick Pro, Secure Digital + and MultiMediaCard. + + If you want to use Realtek driver-based card reader, enable this + option and other options below. + +config REALTEK_CR_DEBUG + bool "Realtek driver-based card reader debugging" + depends on REALTEK_CR_SUPPORT != n + help + This is an option for use by developers; most people should + say N here. This enables Realtek card reader driver debugging. + +if REALTEK_CR_SUPPORT + +source "drivers/misc/realtek_cr/core/Kconfig" + +endif diff --git a/drivers/misc/realtek_cr/Makefile b/drivers/misc/realtek_cr/Makefile new file mode 100644 index 0000000..f4e16ba --- /dev/null +++ b/drivers/misc/realtek_cr/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Realtek driver-based card reader. +# + +subdir-ccflags-$(CONFIG_REALTEK_CR_DEBUG) := -DDEBUG + +obj-$(CONFIG_REALTEK_CR_SUPPORT) += core/ diff --git a/drivers/misc/realtek_cr/core/Kconfig b/drivers/misc/realtek_cr/core/Kconfig new file mode 100644 index 0000000..38fff8a --- /dev/null +++ b/drivers/misc/realtek_cr/core/Kconfig @@ -0,0 +1,5 @@ +config REALTEK_CR_CORE + tristate "RealTek Card Reader Core Driver" + help + Say Y here to include driver code to support the Realtek + driver-based card reader. diff --git a/drivers/misc/realtek_cr/core/Makefile b/drivers/misc/realtek_cr/core/Makefile new file mode 100644 index 0000000..010055e --- /dev/null +++ b/drivers/misc/realtek_cr/core/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_REALTEK_CR_CORE) += rtsx_core.o diff --git a/drivers/misc/realtek_cr/core/rtsx_core.c b/drivers/misc/realtek_cr/core/rtsx_core.c new file mode 100644 index 0000000..9868980 --- /dev/null +++ b/drivers/misc/realtek_cr/core/rtsx_core.c @@ -0,0 +1,462 @@ +/* Realtek card reader core driver + * + * Copyright(c) 2009 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: + * Wei WANG <wei_wang@xxxxxxxxxxxxxx> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/idr.h> +#include <linux/rtsx_core.h> + +static struct workqueue_struct *workqueue; +static DEFINE_IDR(rtsx_adapter_idr); +static DEFINE_SPINLOCK(rtsx_adapter_lock); + +#define DRIVER_NAME "rtsx_core" + +#ifdef CONFIG_PM + +static const char *rtsx_media_type_name(unsigned char type, unsigned char nt) +{ + const char *card_type_name[3][3] = { + { "SmartMedia/xD", "MemoryStick", "MMC/SD" }, + { "XD", "MS", "SD"}, + { "xd", "ms", "sd"} + }; + + if (nt > 2 || type < 1 || type > 3) + return NULL; + return card_type_name[nt][type - 1]; +} + +static int rtsx_dev_match(struct rtsx_dev *sock, struct rtsx_device_id *id) +{ + if (sock->type == id->type) + return 1; + return 0; +} + +static int rtsx_bus_match(struct device *dev, struct device_driver *drv) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + struct rtsx_driver *rtsx_drv = container_of(drv, struct rtsx_driver, + driver); + struct rtsx_device_id *ids = rtsx_drv->id_table; + + if (ids) { + while (ids->type) { + if (rtsx_dev_match(sock, ids)) + return 1; + ++ids; + } + } + return 0; +} + +static int rtsx_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + + if (add_uevent_var(env, "RTSX_CARD_TYPE=%s", + rtsx_media_type_name(sock->type, 1))) + return -ENOMEM; + + return 0; +} + +static int rtsx_device_probe(struct device *dev) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + struct rtsx_driver *drv = container_of(dev->driver, struct rtsx_driver, + driver); + int rc = -ENODEV; + + get_device(dev); + if (dev->driver && drv->probe) { + rc = drv->probe(sock); + if (!rc) + return 0; + } + put_device(dev); + return rc; +} + +static void rtsx_dummy_event(struct rtsx_dev *sock) +{ + return; +} + +static int rtsx_device_remove(struct device *dev) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + struct rtsx_driver *drv = container_of(dev->driver, struct rtsx_driver, + driver); + + if (dev->driver && drv->remove) { + sock->card_event = rtsx_dummy_event; + sock->data_event = rtsx_dummy_event; + drv->remove(sock); + sock->dev.driver = NULL; + } + + put_device(dev); + return 0; +} + +static int rtsx_device_suspend(struct device *dev, pm_message_t state) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + struct rtsx_driver *drv = container_of(dev->driver, struct rtsx_driver, + driver); + + if (dev->driver && drv->suspend) + return drv->suspend(sock, state); + return 0; +} + +static int rtsx_device_resume(struct device *dev) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + struct rtsx_driver *drv = container_of(dev->driver, struct rtsx_driver, + driver); + + if (dev->driver && drv->resume) + return drv->resume(sock); + return 0; +} + +#else + +#define rtsx_device_suspend NULL +#define rtsx_device_resume NULL + +#endif /* CONFIG_PM */ + +static ssize_t type_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + return sprintf(buf, "%x", sock->type); +} + +static struct device_attribute rtsx_dev_attrs[] = { + __ATTR(type, S_IRUGO, type_show, NULL), + __ATTR_NULL +}; + +static struct bus_type rtsx_bus_type = { + .name = "rtsx_cr", + .dev_attrs = rtsx_dev_attrs, + .match = rtsx_bus_match, + .uevent = rtsx_uevent, + .probe = rtsx_device_probe, + .remove = rtsx_device_remove, + .suspend = rtsx_device_suspend, + .resume = rtsx_device_resume +}; + +static void rtsx_free(struct device *dev) +{ + struct rtsx_adapter *adapter; + + adapter = container_of(dev, struct rtsx_adapter, dev); + kfree(adapter); +} + +static struct class rtsx_adapter_class = { + .name = "rtsx_adapter", + .dev_release = rtsx_free +}; + +struct rtsx_adapter *rtsx_alloc_adapter(unsigned int num_sockets, + struct device *dev) +{ + struct rtsx_adapter *adapter; + + adapter = kzalloc(sizeof(*adapter) + + sizeof(struct rtsx_dev *) * num_sockets, GFP_KERNEL); + if (adapter) { + adapter->dev.class = &rtsx_adapter_class; + adapter->dev.parent = dev; + device_initialize(&adapter->dev); + spin_lock_init(&adapter->lock); + adapter->num_sockets = num_sockets; + } + return adapter; +} +EXPORT_SYMBOL(rtsx_alloc_adapter); + +int rtsx_add_adapter(struct rtsx_adapter *adapter) +{ + int rc; + + if (!idr_pre_get(&rtsx_adapter_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&rtsx_adapter_lock); + rc = idr_get_new(&rtsx_adapter_idr, adapter, &adapter->id); + spin_unlock(&rtsx_adapter_lock); + if (rc) + return rc; + + dev_set_name(&adapter->dev, "rtsx%u", adapter->id); + rc = device_add(&adapter->dev); + if (rc) { + spin_lock(&rtsx_adapter_lock); + idr_remove(&rtsx_adapter_idr, adapter->id); + spin_unlock(&rtsx_adapter_lock); + } + + return rc; +} +EXPORT_SYMBOL(rtsx_add_adapter); + +void rtsx_remove_adapter(struct rtsx_adapter *adapter) +{ + unsigned int cnt; + + flush_workqueue(workqueue); + for (cnt = 0; cnt < adapter->num_sockets; ++cnt) { + if (adapter->sockets[cnt]) + device_unregister(&adapter->sockets[cnt]->dev); + } + + spin_lock(&rtsx_adapter_lock); + idr_remove(&rtsx_adapter_idr, adapter->id); + spin_unlock(&rtsx_adapter_lock); + device_del(&adapter->dev); +} +EXPORT_SYMBOL(rtsx_remove_adapter); + +void rtsx_free_adapter(struct rtsx_adapter *adapter) +{ + put_device(&adapter->dev); +} +EXPORT_SYMBOL(rtsx_free_adapter); + +void rtsx_free_device(struct device *dev) +{ + struct rtsx_dev *sock = container_of(dev, struct rtsx_dev, dev); + kfree(sock); +} +EXPORT_SYMBOL(rtsx_free_device); + +struct rtsx_dev *rtsx_alloc_device(struct rtsx_adapter *adapter, + unsigned int id, unsigned char type) +{ + struct rtsx_dev *sock = NULL; + + if (!rtsx_media_type_name(type, 0)) + return sock; + + sock = kzalloc(sizeof(*sock), GFP_KERNEL); + if (sock) { + spin_lock_init(&sock->lock); + sock->type = type; + sock->socket_id = id; + sock->card_event = rtsx_dummy_event; + sock->data_event = rtsx_dummy_event; + + sock->dev.parent = &(adapter->dev); + sock->dev.bus = &rtsx_bus_type; + sock->dev.dma_mask = adapter->dev.parent->dma_mask; + sock->dev.release = rtsx_free_device; + + dev_set_name(&sock->dev, "rtsx_%s%u:%u", + rtsx_media_type_name(type, 2), adapter->id, id); + pr_info(DRIVER_NAME + ": %s card detected in socket %u:%u\n", + rtsx_media_type_name(type, 0), adapter->id, id); + } + return sock; +} +EXPORT_SYMBOL(rtsx_alloc_device); + +void rtsx_queue_work(struct work_struct *work) +{ + queue_work(workqueue, work); +} +EXPORT_SYMBOL(rtsx_queue_work); + +void rtsx_queue_delayed_work(struct delayed_work *dwork, unsigned long delay) +{ + queue_delayed_work(workqueue, dwork, delay); +} +EXPORT_SYMBOL(rtsx_queue_delayed_work); + +int rtsx_register_driver(struct rtsx_driver *drv) +{ + drv->driver.bus = &rtsx_bus_type; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(rtsx_register_driver); + +void rtsx_unregister_driver(struct rtsx_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(rtsx_unregister_driver); + +void rtsx_switch_clock(struct rtsx_dev *sock, unsigned int card_clock, + u8 ssc_depth, int double_clk, int vpclk) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + adapter->common_ops->switch_clock(adapter, + card_clock, ssc_depth, double_clk, vpclk); +} +EXPORT_SYMBOL(rtsx_switch_clock); + +void rtsx_complete_unfinished_transfer(struct rtsx_dev *sock) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + adapter->common_ops->complete_unfinished_transfer(adapter); +} +EXPORT_SYMBOL(rtsx_complete_unfinished_transfer); + +void rtsx_sdmmc_set_bus_width(struct rtsx_dev *sock, unsigned char bus_width) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + adapter->sdmmc_ops->sdmmc_set_bus_width(adapter, bus_width); +} +EXPORT_SYMBOL(rtsx_sdmmc_set_bus_width); + +void rtsx_sdmmc_set_power_mode(struct rtsx_dev *sock, unsigned char power_mode) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + adapter->sdmmc_ops->sdmmc_set_power_mode(adapter, power_mode); +} +EXPORT_SYMBOL(rtsx_sdmmc_set_power_mode); + +void rtsx_sdmmc_set_timing(struct rtsx_dev *sock, unsigned char timing) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + adapter->sdmmc_ops->sdmmc_set_timing(adapter, timing); +} +EXPORT_SYMBOL(rtsx_sdmmc_set_timing); + +int rtsx_sdmmc_switch_voltage(struct rtsx_dev *sock, unsigned char voltage) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_switch_voltage(adapter, voltage); +} +EXPORT_SYMBOL(rtsx_sdmmc_switch_voltage); + +int rtsx_sdmmc_get_ro(struct rtsx_dev *sock) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_get_ro(adapter); +} +EXPORT_SYMBOL(rtsx_sdmmc_get_ro); + +int rtsx_sdmmc_get_cd(struct rtsx_dev *sock) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_get_cd(adapter); +} +EXPORT_SYMBOL(rtsx_sdmmc_get_cd); + +int rtsx_sdmmc_execute_tuning(struct rtsx_dev *sock) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_execute_tuning(adapter); +} +EXPORT_SYMBOL(rtsx_sdmmc_execute_tuning); + +int rtsx_sdmmc_send_cmd_get_rsp(struct rtsx_dev *sock, u8 cmd_idx, + u32 arg, unsigned int resp_type, u32 *resp) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_send_cmd_get_rsp(adapter, + cmd_idx, arg, resp_type, resp); +} +EXPORT_SYMBOL(rtsx_sdmmc_send_cmd_get_rsp); + +int rtsx_sdmmc_read_data(struct rtsx_dev *sock, u8 *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_read_data(adapter, cmd, + byte_cnt, buf, buf_len, timeout); +} +EXPORT_SYMBOL(rtsx_sdmmc_read_data); + +int rtsx_sdmmc_write_data(struct rtsx_dev *sock, u8 *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_write_data(adapter, cmd, + byte_cnt, buf, buf_len, timeout); +} +EXPORT_SYMBOL(rtsx_sdmmc_write_data); + +int rtsx_sdmmc_rw_multi(struct rtsx_dev *sock, void *buf, unsigned int blksz, + unsigned int blocks, unsigned int use_sg, int read, int uhs) +{ + struct rtsx_adapter *adapter = sock_to_adapter(sock); + + return adapter->sdmmc_ops->sdmmc_rw_multi(adapter, buf, blksz, + blocks, use_sg, read, uhs); +} +EXPORT_SYMBOL(rtsx_sdmmc_rw_multi); + +static int __init rtsx_core_init(void) +{ + int rc; + + workqueue = create_freezable_workqueue("rtsx_wq"); + if (!workqueue) + return -ENOMEM; + + rc = bus_register(&rtsx_bus_type); + if (rc) + return rc; + + rc = class_register(&rtsx_adapter_class); + if (rc) + return rc; + + return rc; +} + +static void __exit rtsx_core_exit(void) +{ + class_unregister(&rtsx_adapter_class); + bus_unregister(&rtsx_bus_type); + destroy_workqueue(workqueue); +} + +module_init(rtsx_core_init); +module_exit(rtsx_core_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Realtek Corp."); +MODULE_DESCRIPTION("Realtek Card Reader Core Driver"); diff --git a/include/linux/rtsx_core.h b/include/linux/rtsx_core.h new file mode 100644 index 0000000..564e7b0 --- /dev/null +++ b/include/linux/rtsx_core.h @@ -0,0 +1,188 @@ +/* Realtek card reader core driver + * + * Copyright(c) 2009 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: + * Wei WANG <wei_wang@xxxxxxxxxxxxxx> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#ifndef __RTSX_CORE_H +#define __RTSX_CORE_H + +#include <linux/pci.h> + +#define RTSX_TYPE_XD 1 +#define RTSX_TYPE_MS 2 +#define RTSX_TYPE_SD 3 + +#define RTSX_SSC_DEPTH_4M 0x01 +#define RTSX_SSC_DEPTH_2M 0x02 +#define RTSX_SSC_DEPTH_1M 0x03 +#define RTSX_SSC_DEPTH_500K 0x04 +#define RTSX_SSC_DEPTH_250K 0x05 + +#define wait_timeout_x(task_state, msecs) \ +do { \ + set_current_state((task_state)); \ + schedule_timeout(msecs_to_jiffies(msecs)); \ +} while (0) + +#define wait_timeout(msecs) wait_timeout_x(TASK_INTERRUPTIBLE, (msecs)) + +struct rtsx_device_id { + unsigned char type; +}; + +struct rtsx_dev { + char __iomem *addr; + spinlock_t lock; + unsigned char type; + unsigned int socket_id; + + void (*card_event)(struct rtsx_dev *sock); + void (*data_event)(struct rtsx_dev *sock); + + struct device dev; +}; + +struct rtsx_driver { + struct rtsx_device_id *id_table; + int (*probe)(struct rtsx_dev *dev); + void (*remove)(struct rtsx_dev *dev); + int (*suspend)(struct rtsx_dev *dev, + pm_message_t state); + int (*resume)(struct rtsx_dev *dev); + + struct device_driver driver; +}; + +struct rtsx_adapter; + +struct rtsx_common_ops { + int (*switch_clock)(struct rtsx_adapter *adapter, + unsigned int card_clock, u8 ssc_depth, + int double_clk, int vpclk); + void (*complete_unfinished_transfer)( + struct rtsx_adapter *adapter); +}; + +struct rtsx_sdmmc_ops { + int (*sdmmc_set_bus_width)( + struct rtsx_adapter *adapter, + unsigned char bus_width); + int (*sdmmc_set_power_mode)( + struct rtsx_adapter *adapter, + unsigned char power_mode); + int (*sdmmc_set_timing)(struct rtsx_adapter *adapter, + unsigned char timing); + int (*sdmmc_switch_voltage)( + struct rtsx_adapter *adapter, + unsigned char signal_voltage); + int (*sdmmc_get_ro)(struct rtsx_adapter *adapter); + int (*sdmmc_get_cd)(struct rtsx_adapter *adapter); + int (*sdmmc_execute_tuning)( + struct rtsx_adapter *adapter); + int (*sdmmc_send_cmd_get_rsp)( + struct rtsx_adapter *adapter, u8 cmd_idx, + u32 arg, unsigned int resp_type, u32 *resp); + int (*sdmmc_read_data)(struct rtsx_adapter *adapter, + u8 *cmd, u16 byte_cnt, u8 *buf, + int buf_len, int timeout); + int (*sdmmc_write_data)(struct rtsx_adapter *adapter, + u8 *cmd, u16 byte_cnt, u8 *buf, + int buf_len, int timeout); + int (*sdmmc_rw_multi)(struct rtsx_adapter *adapter, + void *buf, unsigned int blksz, + unsigned int blocks, unsigned int use_sg, + int read, int uhs); +}; + +#define EXTRA_CAPS_SD_SDR50 (1 << 0) +#define EXTRA_CAPS_SD_SDR104 (1 << 1) +#define EXTRA_CAPS_SD_DDR50 (1 << 2) +#define EXTRA_CAPS_MMC_HSDDR (1 << 3) +#define EXTRA_CAPS_MMC_HS200 (1 << 4) +#define EXTRA_CAPS_MMC_8BIT (1 << 5) + +struct rtsx_adapter { + spinlock_t lock; + unsigned int id; + unsigned int num_sockets; + u32 extra_caps; + + struct device dev; + + const struct rtsx_common_ops *common_ops; + const struct rtsx_sdmmc_ops *sdmmc_ops; + + struct rtsx_dev *sockets[0]; +}; + +struct rtsx_reg_pair { + u16 addr; + u8 val; +}; + +static inline struct rtsx_adapter *sock_to_adapter(struct rtsx_dev *sock) +{ + return container_of(sock->dev.parent, struct rtsx_adapter, dev); +} + +struct rtsx_adapter *rtsx_alloc_adapter(unsigned int num_sockets, + struct device *dev); +int rtsx_add_adapter(struct rtsx_adapter *adapter); +void rtsx_remove_adapter(struct rtsx_adapter *adapter); +void rtsx_free_adapter(struct rtsx_adapter *adapter); +void rtsx_free_device(struct device *dev); +struct rtsx_dev *rtsx_alloc_device(struct rtsx_adapter *adapter, + unsigned int id, unsigned char type); +void rtsx_queue_work(struct work_struct *work); +void rtsx_queue_delayed_work(struct delayed_work *dwork, unsigned long delay); +int rtsx_register_driver(struct rtsx_driver *drv); +void rtsx_unregister_driver(struct rtsx_driver *drv); + +void rtsx_switch_clock(struct rtsx_dev *sock, unsigned int card_clock, + u8 ssc_depth, int double_clk, int vpclk); +void rtsx_complete_unfinished_transfer(struct rtsx_dev *sock); + +void rtsx_sdmmc_set_bus_width(struct rtsx_dev *sock, unsigned char bus_width); +void rtsx_sdmmc_set_power_mode(struct rtsx_dev *sock, unsigned char power_mode); +void rtsx_sdmmc_set_timing(struct rtsx_dev *sock, unsigned char timing); +int rtsx_sdmmc_switch_voltage(struct rtsx_dev *sock, unsigned char voltage); +int rtsx_sdmmc_get_ro(struct rtsx_dev *sock); +int rtsx_sdmmc_get_cd(struct rtsx_dev *sock); +int rtsx_sdmmc_execute_tuning(struct rtsx_dev *sock); +int rtsx_sdmmc_send_cmd_get_rsp(struct rtsx_dev *sock, u8 cmd_idx, + u32 arg, unsigned int resp_type, u32 *resp); +int rtsx_sdmmc_read_data(struct rtsx_dev *sock, u8 *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout); +int rtsx_sdmmc_write_data(struct rtsx_dev *sock, u8 *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout); +int rtsx_sdmmc_rw_multi(struct rtsx_dev *sock, void *buf, unsigned int blksz, + unsigned int blocks, unsigned int use_sg, int read, int uhs); + +static inline void *rtsx_get_drvdata(struct rtsx_dev *dev) +{ + return dev_get_drvdata(&dev->dev); +} + +static inline void rtsx_set_drvdata(struct rtsx_dev *dev, void *data) +{ + dev_set_drvdata(&dev->dev, data); +} + +#endif -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html