2019-09-16 21:15:44 +05:30
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Actions Semi Owl SoCs SD / MMC driver
*
* Copyright ( c ) 2014 Actions Semi Inc .
* Copyright ( c ) 2019 Manivannan Sadhasivam < manivannan . sadhasivam @ linaro . org >
*
* TODO : SDIO support
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/dmaengine.h>
# include <linux/dma-direction.h>
# include <linux/dma-mapping.h>
# include <linux/interrupt.h>
# include <linux/mmc/host.h>
# include <linux/mmc/slot-gpio.h>
# include <linux/module.h>
# include <linux/of_platform.h>
# include <linux/reset.h>
# include <linux/spinlock.h>
/*
* SDC registers
*/
# define OWL_REG_SD_EN 0x0000
# define OWL_REG_SD_CTL 0x0004
# define OWL_REG_SD_STATE 0x0008
# define OWL_REG_SD_CMD 0x000c
# define OWL_REG_SD_ARG 0x0010
# define OWL_REG_SD_RSPBUF0 0x0014
# define OWL_REG_SD_RSPBUF1 0x0018
# define OWL_REG_SD_RSPBUF2 0x001c
# define OWL_REG_SD_RSPBUF3 0x0020
# define OWL_REG_SD_RSPBUF4 0x0024
# define OWL_REG_SD_DAT 0x0028
# define OWL_REG_SD_BLK_SIZE 0x002c
# define OWL_REG_SD_BLK_NUM 0x0030
# define OWL_REG_SD_BUF_SIZE 0x0034
/* SD_EN Bits */
# define OWL_SD_EN_RANE BIT(31)
# define OWL_SD_EN_RAN_SEED(x) (((x) & 0x3f) << 24)
# define OWL_SD_EN_S18EN BIT(12)
# define OWL_SD_EN_RESE BIT(10)
# define OWL_SD_EN_DAT1_S BIT(9)
# define OWL_SD_EN_CLK_S BIT(8)
# define OWL_SD_ENABLE BIT(7)
# define OWL_SD_EN_BSEL BIT(6)
# define OWL_SD_EN_SDIOEN BIT(3)
# define OWL_SD_EN_DDREN BIT(2)
# define OWL_SD_EN_DATAWID(x) (((x) & 0x3) << 0)
/* SD_CTL Bits */
# define OWL_SD_CTL_TOUTEN BIT(31)
# define OWL_SD_CTL_TOUTCNT(x) (((x) & 0x7f) << 24)
# define OWL_SD_CTL_DELAY_MSK GENMASK(23, 16)
# define OWL_SD_CTL_RDELAY(x) (((x) & 0xf) << 20)
# define OWL_SD_CTL_WDELAY(x) (((x) & 0xf) << 16)
# define OWL_SD_CTL_CMDLEN BIT(13)
# define OWL_SD_CTL_SCC BIT(12)
# define OWL_SD_CTL_TCN(x) (((x) & 0xf) << 8)
# define OWL_SD_CTL_TS BIT(7)
# define OWL_SD_CTL_LBE BIT(6)
# define OWL_SD_CTL_C7EN BIT(5)
# define OWL_SD_CTL_TM(x) (((x) & 0xf) << 0)
# define OWL_SD_DELAY_LOW_CLK 0x0f
# define OWL_SD_DELAY_MID_CLK 0x0a
# define OWL_SD_DELAY_HIGH_CLK 0x09
# define OWL_SD_RDELAY_DDR50 0x0a
# define OWL_SD_WDELAY_DDR50 0x08
/* SD_STATE Bits */
# define OWL_SD_STATE_DAT1BS BIT(18)
# define OWL_SD_STATE_SDIOB_P BIT(17)
# define OWL_SD_STATE_SDIOB_EN BIT(16)
# define OWL_SD_STATE_TOUTE BIT(15)
# define OWL_SD_STATE_BAEP BIT(14)
# define OWL_SD_STATE_MEMRDY BIT(12)
# define OWL_SD_STATE_CMDS BIT(11)
# define OWL_SD_STATE_DAT1AS BIT(10)
# define OWL_SD_STATE_SDIOA_P BIT(9)
# define OWL_SD_STATE_SDIOA_EN BIT(8)
# define OWL_SD_STATE_DAT0S BIT(7)
# define OWL_SD_STATE_TEIE BIT(6)
# define OWL_SD_STATE_TEI BIT(5)
# define OWL_SD_STATE_CLNR BIT(4)
# define OWL_SD_STATE_CLC BIT(3)
# define OWL_SD_STATE_WC16ER BIT(2)
# define OWL_SD_STATE_RC16ER BIT(1)
# define OWL_SD_STATE_CRC7ER BIT(0)
2020-04-14 18:14:01 +02:00
# define OWL_CMD_TIMEOUT_MS 30000
2019-09-16 21:15:44 +05:30
struct owl_mmc_host {
struct device * dev ;
struct reset_control * reset ;
void __iomem * base ;
struct clk * clk ;
struct completion sdc_complete ;
spinlock_t lock ;
int irq ;
u32 clock ;
bool ddr_50 ;
enum dma_data_direction dma_dir ;
struct dma_chan * dma ;
struct dma_async_tx_descriptor * desc ;
struct dma_slave_config dma_cfg ;
struct completion dma_complete ;
struct mmc_host * mmc ;
struct mmc_request * mrq ;
struct mmc_command * cmd ;
struct mmc_data * data ;
} ;
static void owl_mmc_update_reg ( void __iomem * reg , unsigned int val , bool state )
{
unsigned int regval ;
regval = readl ( reg ) ;
if ( state )
regval | = val ;
else
regval & = ~ val ;
writel ( regval , reg ) ;
}
static irqreturn_t owl_irq_handler ( int irq , void * devid )
{
struct owl_mmc_host * owl_host = devid ;
u32 state ;
2020-11-02 08:52:17 +08:00
spin_lock ( & owl_host - > lock ) ;
2019-09-16 21:15:44 +05:30
state = readl ( owl_host - > base + OWL_REG_SD_STATE ) ;
if ( state & OWL_SD_STATE_TEI ) {
state = readl ( owl_host - > base + OWL_REG_SD_STATE ) ;
state | = OWL_SD_STATE_TEI ;
writel ( state , owl_host - > base + OWL_REG_SD_STATE ) ;
complete ( & owl_host - > sdc_complete ) ;
}
2020-11-02 08:52:17 +08:00
spin_unlock ( & owl_host - > lock ) ;
2019-09-16 21:15:44 +05:30
return IRQ_HANDLED ;
}
static void owl_mmc_finish_request ( struct owl_mmc_host * owl_host )
{
struct mmc_request * mrq = owl_host - > mrq ;
struct mmc_data * data = mrq - > data ;
/* Should never be NULL */
WARN_ON ( ! mrq ) ;
owl_host - > mrq = NULL ;
if ( data )
dma_unmap_sg ( owl_host - > dma - > device - > dev , data - > sg , data - > sg_len ,
owl_host - > dma_dir ) ;
/* Finally finish request */
mmc_request_done ( owl_host - > mmc , mrq ) ;
}
static void owl_mmc_send_cmd ( struct owl_mmc_host * owl_host ,
struct mmc_command * cmd ,
struct mmc_data * data )
{
2020-04-14 18:14:01 +02:00
unsigned long timeout ;
2019-09-16 21:15:44 +05:30
u32 mode , state , resp [ 2 ] ;
u32 cmd_rsp_mask = 0 ;
init_completion ( & owl_host - > sdc_complete ) ;
switch ( mmc_resp_type ( cmd ) ) {
case MMC_RSP_NONE :
mode = OWL_SD_CTL_TM ( 0 ) ;
break ;
case MMC_RSP_R1 :
if ( data ) {
if ( data - > flags & MMC_DATA_READ )
mode = OWL_SD_CTL_TM ( 4 ) ;
else
mode = OWL_SD_CTL_TM ( 5 ) ;
} else {
mode = OWL_SD_CTL_TM ( 1 ) ;
}
cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER ;
break ;
case MMC_RSP_R1B :
mode = OWL_SD_CTL_TM ( 3 ) ;
cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER ;
break ;
case MMC_RSP_R2 :
mode = OWL_SD_CTL_TM ( 2 ) ;
cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER ;
break ;
case MMC_RSP_R3 :
mode = OWL_SD_CTL_TM ( 1 ) ;
cmd_rsp_mask = OWL_SD_STATE_CLNR ;
break ;
default :
dev_warn ( owl_host - > dev , " Unknown MMC command \n " ) ;
cmd - > error = - EINVAL ;
return ;
}
/* Keep current WDELAY and RDELAY */
mode | = ( readl ( owl_host - > base + OWL_REG_SD_CTL ) & ( 0xff < < 16 ) ) ;
/* Start to send corresponding command type */
writel ( cmd - > arg , owl_host - > base + OWL_REG_SD_ARG ) ;
writel ( cmd - > opcode , owl_host - > base + OWL_REG_SD_CMD ) ;
/* Set LBE to send clk at the end of last read block */
if ( data ) {
mode | = ( OWL_SD_CTL_TS | OWL_SD_CTL_LBE | 0x64000000 ) ;
} else {
mode & = ~ ( OWL_SD_CTL_TOUTEN | OWL_SD_CTL_LBE ) ;
mode | = OWL_SD_CTL_TS ;
}
owl_host - > cmd = cmd ;
/* Start transfer */
writel ( mode , owl_host - > base + OWL_REG_SD_CTL ) ;
if ( data )
return ;
2020-04-14 18:14:01 +02:00
timeout = msecs_to_jiffies ( cmd - > busy_timeout ? cmd - > busy_timeout :
OWL_CMD_TIMEOUT_MS ) ;
if ( ! wait_for_completion_timeout ( & owl_host - > sdc_complete , timeout ) ) {
2019-09-16 21:15:44 +05:30
dev_err ( owl_host - > dev , " CMD interrupt timeout \n " ) ;
cmd - > error = - ETIMEDOUT ;
return ;
}
state = readl ( owl_host - > base + OWL_REG_SD_STATE ) ;
if ( mmc_resp_type ( cmd ) & MMC_RSP_PRESENT ) {
if ( cmd_rsp_mask & state ) {
if ( state & OWL_SD_STATE_CLNR ) {
dev_err ( owl_host - > dev , " Error CMD_NO_RSP \n " ) ;
cmd - > error = - EILSEQ ;
return ;
}
if ( state & OWL_SD_STATE_CRC7ER ) {
dev_err ( owl_host - > dev , " Error CMD_RSP_CRC \n " ) ;
cmd - > error = - EILSEQ ;
return ;
}
}
if ( mmc_resp_type ( cmd ) & MMC_RSP_136 ) {
cmd - > resp [ 3 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF0 ) ;
cmd - > resp [ 2 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF1 ) ;
cmd - > resp [ 1 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF2 ) ;
cmd - > resp [ 0 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF3 ) ;
} else {
resp [ 0 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF0 ) ;
resp [ 1 ] = readl ( owl_host - > base + OWL_REG_SD_RSPBUF1 ) ;
cmd - > resp [ 0 ] = resp [ 1 ] < < 24 | resp [ 0 ] > > 8 ;
cmd - > resp [ 1 ] = resp [ 1 ] > > 8 ;
}
}
}
static void owl_mmc_dma_complete ( void * param )
{
struct owl_mmc_host * owl_host = param ;
struct mmc_data * data = owl_host - > data ;
if ( data )
complete ( & owl_host - > dma_complete ) ;
}
static int owl_mmc_prepare_data ( struct owl_mmc_host * owl_host ,
struct mmc_data * data )
{
u32 total ;
owl_mmc_update_reg ( owl_host - > base + OWL_REG_SD_EN , OWL_SD_EN_BSEL ,
true ) ;
writel ( data - > blocks , owl_host - > base + OWL_REG_SD_BLK_NUM ) ;
writel ( data - > blksz , owl_host - > base + OWL_REG_SD_BLK_SIZE ) ;
total = data - > blksz * data - > blocks ;
if ( total < 512 )
writel ( total , owl_host - > base + OWL_REG_SD_BUF_SIZE ) ;
else
writel ( 512 , owl_host - > base + OWL_REG_SD_BUF_SIZE ) ;
if ( data - > flags & MMC_DATA_WRITE ) {
owl_host - > dma_dir = DMA_TO_DEVICE ;
owl_host - > dma_cfg . direction = DMA_MEM_TO_DEV ;
} else {
owl_host - > dma_dir = DMA_FROM_DEVICE ;
owl_host - > dma_cfg . direction = DMA_DEV_TO_MEM ;
}
dma_map_sg ( owl_host - > dma - > device - > dev , data - > sg ,
data - > sg_len , owl_host - > dma_dir ) ;
dmaengine_slave_config ( owl_host - > dma , & owl_host - > dma_cfg ) ;
owl_host - > desc = dmaengine_prep_slave_sg ( owl_host - > dma , data - > sg ,
data - > sg_len ,
owl_host - > dma_cfg . direction ,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK ) ;
if ( ! owl_host - > desc ) {
dev_err ( owl_host - > dev , " Can't prepare slave sg \n " ) ;
return - EBUSY ;
}
owl_host - > data = data ;
owl_host - > desc - > callback = owl_mmc_dma_complete ;
owl_host - > desc - > callback_param = ( void * ) owl_host ;
data - > error = 0 ;
return 0 ;
}
static void owl_mmc_request ( struct mmc_host * mmc , struct mmc_request * mrq )
{
struct owl_mmc_host * owl_host = mmc_priv ( mmc ) ;
struct mmc_data * data = mrq - > data ;
int ret ;
owl_host - > mrq = mrq ;
if ( mrq - > data ) {
ret = owl_mmc_prepare_data ( owl_host , data ) ;
if ( ret < 0 ) {
data - > error = ret ;
goto err_out ;
}
init_completion ( & owl_host - > dma_complete ) ;
dmaengine_submit ( owl_host - > desc ) ;
dma_async_issue_pending ( owl_host - > dma ) ;
}
owl_mmc_send_cmd ( owl_host , mrq - > cmd , data ) ;
if ( data ) {
if ( ! wait_for_completion_timeout ( & owl_host - > sdc_complete ,
10 * HZ ) ) {
dev_err ( owl_host - > dev , " CMD interrupt timeout \n " ) ;
mrq - > cmd - > error = - ETIMEDOUT ;
dmaengine_terminate_all ( owl_host - > dma ) ;
goto err_out ;
}
if ( ! wait_for_completion_timeout ( & owl_host - > dma_complete ,
5 * HZ ) ) {
dev_err ( owl_host - > dev , " DMA interrupt timeout \n " ) ;
mrq - > cmd - > error = - ETIMEDOUT ;
dmaengine_terminate_all ( owl_host - > dma ) ;
goto err_out ;
}
if ( data - > stop )
owl_mmc_send_cmd ( owl_host , data - > stop , NULL ) ;
data - > bytes_xfered = data - > blocks * data - > blksz ;
}
err_out :
owl_mmc_finish_request ( owl_host ) ;
}
static int owl_mmc_set_clk_rate ( struct owl_mmc_host * owl_host ,
unsigned int rate )
{
unsigned long clk_rate ;
int ret ;
u32 reg ;
reg = readl ( owl_host - > base + OWL_REG_SD_CTL ) ;
reg & = ~ OWL_SD_CTL_DELAY_MSK ;
/* Set RDELAY and WDELAY based on the clock */
if ( rate < = 1000000 ) {
writel ( reg | OWL_SD_CTL_RDELAY ( OWL_SD_DELAY_LOW_CLK ) |
OWL_SD_CTL_WDELAY ( OWL_SD_DELAY_LOW_CLK ) ,
owl_host - > base + OWL_REG_SD_CTL ) ;
} else if ( ( rate > 1000000 ) & & ( rate < = 26000000 ) ) {
writel ( reg | OWL_SD_CTL_RDELAY ( OWL_SD_DELAY_MID_CLK ) |
OWL_SD_CTL_WDELAY ( OWL_SD_DELAY_MID_CLK ) ,
owl_host - > base + OWL_REG_SD_CTL ) ;
} else if ( ( rate > 26000000 ) & & ( rate < = 52000000 ) & & ! owl_host - > ddr_50 ) {
writel ( reg | OWL_SD_CTL_RDELAY ( OWL_SD_DELAY_HIGH_CLK ) |
OWL_SD_CTL_WDELAY ( OWL_SD_DELAY_HIGH_CLK ) ,
owl_host - > base + OWL_REG_SD_CTL ) ;
/* DDR50 mode has special delay chain */
} else if ( ( rate > 26000000 ) & & ( rate < = 52000000 ) & & owl_host - > ddr_50 ) {
writel ( reg | OWL_SD_CTL_RDELAY ( OWL_SD_RDELAY_DDR50 ) |
OWL_SD_CTL_WDELAY ( OWL_SD_WDELAY_DDR50 ) ,
owl_host - > base + OWL_REG_SD_CTL ) ;
} else {
dev_err ( owl_host - > dev , " SD clock rate not supported \n " ) ;
return - EINVAL ;
}
clk_rate = clk_round_rate ( owl_host - > clk , rate < < 1 ) ;
ret = clk_set_rate ( owl_host - > clk , clk_rate ) ;
return ret ;
}
static void owl_mmc_set_clk ( struct owl_mmc_host * owl_host , struct mmc_ios * ios )
{
if ( ! ios - > clock )
return ;
owl_host - > clock = ios - > clock ;
owl_mmc_set_clk_rate ( owl_host , ios - > clock ) ;
}
static void owl_mmc_set_bus_width ( struct owl_mmc_host * owl_host ,
struct mmc_ios * ios )
{
u32 reg ;
reg = readl ( owl_host - > base + OWL_REG_SD_EN ) ;
reg & = ~ 0x03 ;
switch ( ios - > bus_width ) {
case MMC_BUS_WIDTH_1 :
break ;
case MMC_BUS_WIDTH_4 :
reg | = OWL_SD_EN_DATAWID ( 1 ) ;
break ;
case MMC_BUS_WIDTH_8 :
reg | = OWL_SD_EN_DATAWID ( 2 ) ;
break ;
}
writel ( reg , owl_host - > base + OWL_REG_SD_EN ) ;
}
static void owl_mmc_ctr_reset ( struct owl_mmc_host * owl_host )
{
reset_control_assert ( owl_host - > reset ) ;
udelay ( 20 ) ;
reset_control_deassert ( owl_host - > reset ) ;
}
static void owl_mmc_power_on ( struct owl_mmc_host * owl_host )
{
u32 mode ;
init_completion ( & owl_host - > sdc_complete ) ;
/* Enable transfer end IRQ */
owl_mmc_update_reg ( owl_host - > base + OWL_REG_SD_STATE ,
OWL_SD_STATE_TEIE , true ) ;
/* Send init clk */
mode = ( readl ( owl_host - > base + OWL_REG_SD_CTL ) & ( 0xff < < 16 ) ) ;
mode | = OWL_SD_CTL_TS | OWL_SD_CTL_TCN ( 5 ) | OWL_SD_CTL_TM ( 8 ) ;
writel ( mode , owl_host - > base + OWL_REG_SD_CTL ) ;
if ( ! wait_for_completion_timeout ( & owl_host - > sdc_complete , HZ ) ) {
dev_err ( owl_host - > dev , " CMD interrupt timeout \n " ) ;
return ;
}
}
static void owl_mmc_set_ios ( struct mmc_host * mmc , struct mmc_ios * ios )
{
struct owl_mmc_host * owl_host = mmc_priv ( mmc ) ;
switch ( ios - > power_mode ) {
case MMC_POWER_UP :
dev_dbg ( owl_host - > dev , " Powering card up \n " ) ;
/* Reset the SDC controller to clear all previous states */
owl_mmc_ctr_reset ( owl_host ) ;
clk_prepare_enable ( owl_host - > clk ) ;
writel ( OWL_SD_ENABLE | OWL_SD_EN_RESE ,
owl_host - > base + OWL_REG_SD_EN ) ;
break ;
case MMC_POWER_ON :
dev_dbg ( owl_host - > dev , " Powering card on \n " ) ;
owl_mmc_power_on ( owl_host ) ;
break ;
case MMC_POWER_OFF :
dev_dbg ( owl_host - > dev , " Powering card off \n " ) ;
clk_disable_unprepare ( owl_host - > clk ) ;
return ;
default :
dev_dbg ( owl_host - > dev , " Ignoring unknown card power state \n " ) ;
break ;
}
if ( ios - > clock ! = owl_host - > clock )
owl_mmc_set_clk ( owl_host , ios ) ;
owl_mmc_set_bus_width ( owl_host , ios ) ;
/* Enable DDR mode if requested */
if ( ios - > timing = = MMC_TIMING_UHS_DDR50 ) {
2020-11-09 10:25:06 +08:00
owl_host - > ddr_50 = true ;
2019-09-16 21:15:44 +05:30
owl_mmc_update_reg ( owl_host - > base + OWL_REG_SD_EN ,
OWL_SD_EN_DDREN , true ) ;
} else {
2020-11-09 10:25:06 +08:00
owl_host - > ddr_50 = false ;
2019-09-16 21:15:44 +05:30
}
}
static int owl_mmc_start_signal_voltage_switch ( struct mmc_host * mmc ,
struct mmc_ios * ios )
{
struct owl_mmc_host * owl_host = mmc_priv ( mmc ) ;
/* It is enough to change the pad ctrl bit for voltage switch */
switch ( ios - > signal_voltage ) {
case MMC_SIGNAL_VOLTAGE_330 :
owl_mmc_update_reg ( owl_host - > base + OWL_REG_SD_EN ,
OWL_SD_EN_S18EN , false ) ;
break ;
case MMC_SIGNAL_VOLTAGE_180 :
owl_mmc_update_reg ( owl_host - > base + OWL_REG_SD_EN ,
OWL_SD_EN_S18EN , true ) ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static const struct mmc_host_ops owl_mmc_ops = {
. request = owl_mmc_request ,
. set_ios = owl_mmc_set_ios ,
. get_ro = mmc_gpio_get_ro ,
. get_cd = mmc_gpio_get_cd ,
. start_signal_voltage_switch = owl_mmc_start_signal_voltage_switch ,
} ;
static int owl_mmc_probe ( struct platform_device * pdev )
{
struct owl_mmc_host * owl_host ;
struct mmc_host * mmc ;
struct resource * res ;
int ret ;
mmc = mmc_alloc_host ( sizeof ( struct owl_mmc_host ) , & pdev - > dev ) ;
if ( ! mmc ) {
dev_err ( & pdev - > dev , " mmc alloc host failed \n " ) ;
return - ENOMEM ;
}
platform_set_drvdata ( pdev , mmc ) ;
owl_host = mmc_priv ( mmc ) ;
owl_host - > dev = & pdev - > dev ;
owl_host - > mmc = mmc ;
spin_lock_init ( & owl_host - > lock ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
owl_host - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( owl_host - > base ) ) {
ret = PTR_ERR ( owl_host - > base ) ;
goto err_free_host ;
}
owl_host - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( owl_host - > clk ) ) {
dev_err ( & pdev - > dev , " No clock defined \n " ) ;
ret = PTR_ERR ( owl_host - > clk ) ;
goto err_free_host ;
}
owl_host - > reset = devm_reset_control_get_exclusive ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( owl_host - > reset ) ) {
dev_err ( & pdev - > dev , " Could not get reset control \n " ) ;
ret = PTR_ERR ( owl_host - > reset ) ;
goto err_free_host ;
}
mmc - > ops = & owl_mmc_ops ;
mmc - > max_blk_count = 512 ;
mmc - > max_blk_size = 512 ;
mmc - > max_segs = 256 ;
mmc - > max_seg_size = 262144 ;
mmc - > max_req_size = 262144 ;
/* 100kHz ~ 52MHz */
mmc - > f_min = 100000 ;
mmc - > f_max = 52000000 ;
mmc - > caps | = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_4_BIT_DATA ;
mmc - > caps2 = ( MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_NO_SDIO ) ;
mmc - > ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 |
MMC_VDD_165_195 ;
ret = mmc_of_parse ( mmc ) ;
if ( ret )
goto err_free_host ;
pdev - > dev . coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
pdev - > dev . dma_mask = & pdev - > dev . coherent_dma_mask ;
2019-12-17 13:29:34 +02:00
owl_host - > dma = dma_request_chan ( & pdev - > dev , " mmc " ) ;
if ( IS_ERR ( owl_host - > dma ) ) {
2019-09-16 21:15:44 +05:30
dev_err ( owl_host - > dev , " Failed to get external DMA channel. \n " ) ;
2019-12-17 13:29:34 +02:00
ret = PTR_ERR ( owl_host - > dma ) ;
2019-09-16 21:15:44 +05:30
goto err_free_host ;
}
dev_info ( & pdev - > dev , " Using %s for DMA transfers \n " ,
dma_chan_name ( owl_host - > dma ) ) ;
owl_host - > dma_cfg . src_addr = res - > start + OWL_REG_SD_DAT ;
owl_host - > dma_cfg . dst_addr = res - > start + OWL_REG_SD_DAT ;
owl_host - > dma_cfg . src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
owl_host - > dma_cfg . dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
owl_host - > dma_cfg . device_fc = false ;
owl_host - > irq = platform_get_irq ( pdev , 0 ) ;
if ( owl_host - > irq < 0 ) {
ret = - EINVAL ;
2020-12-09 20:42:02 +01:00
goto err_release_channel ;
2019-09-16 21:15:44 +05:30
}
ret = devm_request_irq ( & pdev - > dev , owl_host - > irq , owl_irq_handler ,
0 , dev_name ( & pdev - > dev ) , owl_host ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to request irq %d \n " ,
owl_host - > irq ) ;
2020-12-09 20:42:02 +01:00
goto err_release_channel ;
2019-09-16 21:15:44 +05:30
}
ret = mmc_add_host ( mmc ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to add host \n " ) ;
2020-12-09 20:42:02 +01:00
goto err_release_channel ;
2019-09-16 21:15:44 +05:30
}
dev_dbg ( & pdev - > dev , " Owl MMC Controller Initialized \n " ) ;
return 0 ;
2020-12-09 20:42:02 +01:00
err_release_channel :
dma_release_channel ( owl_host - > dma ) ;
2019-09-16 21:15:44 +05:30
err_free_host :
mmc_free_host ( mmc ) ;
return ret ;
}
static int owl_mmc_remove ( struct platform_device * pdev )
{
struct mmc_host * mmc = platform_get_drvdata ( pdev ) ;
struct owl_mmc_host * owl_host = mmc_priv ( mmc ) ;
mmc_remove_host ( mmc ) ;
disable_irq ( owl_host - > irq ) ;
2020-12-09 20:42:02 +01:00
dma_release_channel ( owl_host - > dma ) ;
2019-09-16 21:15:44 +05:30
mmc_free_host ( mmc ) ;
return 0 ;
}
static const struct of_device_id owl_mmc_of_match [ ] = {
{ . compatible = " actions,owl-mmc " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , owl_mmc_of_match ) ;
static struct platform_driver owl_mmc_driver = {
. driver = {
. name = " owl_mmc " ,
2020-09-03 16:24:41 -07:00
. probe_type = PROBE_PREFER_ASYNCHRONOUS ,
2020-06-21 08:23:30 +05:30
. of_match_table = owl_mmc_of_match ,
2019-09-16 21:15:44 +05:30
} ,
. probe = owl_mmc_probe ,
. remove = owl_mmc_remove ,
} ;
module_platform_driver ( owl_mmc_driver ) ;
MODULE_DESCRIPTION ( " Actions Semi Owl SoCs SD/MMC Driver " ) ;
MODULE_AUTHOR ( " Actions Semi " ) ;
MODULE_AUTHOR ( " Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;