From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/mmc/card/sdio_channel.c | 248 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 drivers/mmc/card/sdio_channel.c (limited to 'drivers/mmc/card/sdio_channel.c') diff --git a/drivers/mmc/card/sdio_channel.c b/drivers/mmc/card/sdio_channel.c new file mode 100644 index 00000000..5d6f9b79 --- /dev/null +++ b/drivers/mmc/card/sdio_channel.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../core/sdio_ops.h" +#include +#include +#include +#include + +#define SDIO_VENDOR_ID_SPRD 0 +#define SDIO_DEVICE_ID_SPRD_SLAVE 0x2260 +#define SDIO_DEVICE_ID_SPRD_SLAVE_9620 0x9620 + +#define DRV_NAME "sprd-sdio-channel" +#define SPRD_SDIO_SLAVE_BLOCK_SIZE 512 + +struct sdio_channel { + unsigned int open_count; + struct sdio_func *func; + struct mutex func_lock; +}; + +static struct sdio_channel sprd_sdio_channel_body; +static struct sdio_channel *sprd_sdio_channel = &sprd_sdio_channel_body; + +static const struct sdio_device_id sprd_sdio_channel_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_SPRD, SDIO_DEVICE_ID_SPRD_SLAVE) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_SPRD, SDIO_DEVICE_ID_SPRD_SLAVE_9620) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(sdio, sprd_sdio_channel_ids); + +int sdio_abort(struct mmc_host *host) +{ + int ret; + u8 abort; + u8 buffer[10]; + + /* SDIO Simplified Specification V2.0, 4.4 Abort for SDIO */ + + //ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort); + //if (ret) + abort = 0x01; + //else + // abort |= 0x01; + + ret = mmc_io_rw_direct(host->card, 1, 0, SDIO_CCCR_ABORT, abort, NULL); + + if (ret) + printk("SDIO: sdio_abort mmc_io_rw_direct_host WRITE FAIL\n"); + + //abort = 0; + + //ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, NULL, &abort); + //if (ret) + // printk("SDIO: sdio_abort mmc_io_rw_direct_host READ FAIL\n"); + + //printk("SDIO: sdio_abort READ abort = %d\n", abort); + + //ret = mmc_io_rw_extended(host->card, 1, 1, 0, 1, buffer, 0, 1); + //if (ret) + //printk("SDIO: sdio_abort EXTENDED_READ FAIL\n"); + + + return ret; +} + +unsigned char s_dbg_addr = 0; + +unsigned int s_dbg_tx_sdio_abort_sent_cnt = 0; +unsigned int s_dbg_rx_sdio_abort_sent_cnt = 0; + +static int sprd_sdio_channel_do_tx(const char *buf, unsigned int len, unsigned int addr) { + int retval; + struct sdio_func *func; + + if(buf == NULL) + return -EINVAL; + if( len == 0) + return 0; + + func = sprd_sdio_channel->func; + sdio_claim_host(func); + retval = sdio_memcpy_toio(func, addr, buf, len); + //retval = sdio_memcpy_toio(func, s_dbg_addr++, buf, len); + if(retval) { + printk("%s retval: %d\n", __func__, retval); + printk("sprd_sdio_channel_do_tx fail, call sdio_abort()\n"); + sdio_abort(func->card->host); + s_dbg_tx_sdio_abort_sent_cnt++; + } + + sdio_release_host(func); + + return retval; +} + +static int sprd_sdio_channel_do_rx(char *buf, unsigned int len, unsigned int addr) { + int retval; + struct sdio_func *func; + if(buf == NULL) + return -EINVAL; + if( len == 0) + return 0; + func = sprd_sdio_channel->func; + sdio_claim_host(func); + retval = sdio_memcpy_fromio(func, buf, addr, len); + if(retval) { + printk("%s retval: %d\n", __func__, retval); + printk("sprd_sdio_channel_do_rx fail, call sdio_abort()\n"); + sdio_abort(func->card->host); + s_dbg_rx_sdio_abort_sent_cnt++; + } + sdio_release_host(func); + + return retval; +} + +int sprd_sdio_channel_open(void) { + int retry = 100; + while(!sprd_sdio_channel->func && retry--) { + msleep (100); + } + if (retry <= 0) { + printk(KERN_ERR "failed to %s()\n", __func__); + return -ENODEV; + } + pr_debug("%s done\n", __func__); + return 0; +} +EXPORT_SYMBOL(sprd_sdio_channel_open); + +void sprd_sdio_channel_close(void) { +} +EXPORT_SYMBOL(sprd_sdio_channel_close); + +int sprd_sdio_channel_tx(const char *buf, unsigned int len, unsigned int addr) { + int retval = -ENODEV; + if(sprd_sdio_channel->func) { + mutex_lock(&sprd_sdio_channel->func_lock); + if(sprd_sdio_channel->func) { + retval = sprd_sdio_channel_do_tx(buf, len, addr); + } + mutex_unlock(&sprd_sdio_channel->func_lock); + } + return retval; +} +EXPORT_SYMBOL(sprd_sdio_channel_tx); + +int sprd_sdio_channel_rx(char *buf, unsigned int len, unsigned int addr) { + int retval = -ENODEV; + if(sprd_sdio_channel->func) { + mutex_lock(&sprd_sdio_channel->func_lock); + if(sprd_sdio_channel->func) { + retval = sprd_sdio_channel_do_rx(buf, len, addr); + } + mutex_unlock(&sprd_sdio_channel->func_lock); + } + return retval; +} +EXPORT_SYMBOL(sprd_sdio_channel_rx); + +static int sprd_sdio_channel_probe(struct sdio_func *func, const struct sdio_device_id *id) { + int retval; + struct sdio_channel *channel; + printk(KERN_INFO "%s enter\n", __func__); + channel = sprd_sdio_channel; + mutex_init(&channel->func_lock); + sdio_claim_host(func); + if((retval = sdio_set_block_size(func, SPRD_SDIO_SLAVE_BLOCK_SIZE))) { + goto ERR_HOST; + } + if((retval = sdio_enable_func(func))) { + goto ERR_HOST; + } + channel->func = func; + printk(KERN_INFO "%s done\n", __func__); +ERR_HOST: + sdio_release_host(func); + return retval; +} + +static void sprd_sdio_channel_remove(struct sdio_func *func) { + printk(KERN_INFO "%s enter\n", __func__); + mutex_lock(&sprd_sdio_channel->func_lock); + sprd_sdio_channel->func = 0; + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + mutex_unlock(&sprd_sdio_channel->func_lock); + printk(KERN_INFO "%s done\n", __func__); +} + +static int sprd_sdio_channel_suspend(struct device *dev) { + mutex_lock(&sprd_sdio_channel->func_lock); + return 0; +} + +static int sprd_sdio_channel_resume(struct device *dev) { + mutex_unlock(&sprd_sdio_channel->func_lock); + return 0; +} + +static const struct dev_pm_ops sprd_sdio_channel_dev_pm_ops = { + .suspend = sprd_sdio_channel_suspend, + .resume = sprd_sdio_channel_resume, +}; + +static struct sdio_driver sprd_sdio_channel_driver = { + .name = DRV_NAME, + .probe = sprd_sdio_channel_probe, + .remove = sprd_sdio_channel_remove, + .id_table = sprd_sdio_channel_ids, + .drv = { + .pm = &sprd_sdio_channel_dev_pm_ops, + }, +}; + +static int __init sprd_sdio_channel_init(void) { + return sdio_register_driver(&sprd_sdio_channel_driver); +} + +static void __exit sprd_sdio_channel_exit(void) { + sdio_unregister_driver(&sprd_sdio_channel_driver); +} + +module_init(sprd_sdio_channel_init); +module_exit(sprd_sdio_channel_exit); + +MODULE_DESCRIPTION("Spredtrum SDHCI Function Slave"); +MODULE_LICENSE("GPL"); -- cgit v1.3.1