9
0
Fork 0

mci s3c: pass around the right pointer

The s3c driver passes around a struct device_d * internally in which
it is never interested in. Instead pass around a struct s3c_mci_host
and get rid of all this ugly void * derefs.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2012-02-09 12:34:41 +01:00
parent 7c1e1e3ddf
commit 4f2cf36acb
1 changed files with 45 additions and 58 deletions

View File

@ -160,13 +160,15 @@ struct s3c_mci_host {
unsigned data_size; /* data transfer in bytes */
};
#define to_s3c_host(h) container_of(h, struct s3c_mci_host, host)
/**
* Finish a request
* @param hw_dev Host interface instance
*
* Just a little bit paranoia.
*/
static void s3c_finish_request(struct device_d *hw_dev)
static void s3c_finish_request(struct s3c_mci_host *host_data)
{
/* TODO ensure the engines are stopped */
}
@ -177,11 +179,10 @@ static void s3c_finish_request(struct device_d *hw_dev)
* @param nc New clock value in Hz (can be 0)
* @return New clock value (may differ from 'nc')
*/
static unsigned s3c_setup_clock_speed(struct device_d *hw_dev, unsigned nc)
static unsigned s3c_setup_clock_speed(struct s3c_mci_host *host_data, unsigned nc)
{
unsigned clock;
uint32_t mci_psc;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
if (nc == 0)
return 0;
@ -206,10 +207,8 @@ static unsigned s3c_setup_clock_speed(struct device_d *hw_dev, unsigned nc)
*
* This will reset everything in all registers of this unit!
*/
static void s3c_mci_reset(struct device_d *hw_dev)
static void s3c_mci_reset(struct s3c_mci_host *host_data)
{
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
/* reset the hardware */
writel(SDICON_SDRESET, host_data->base + SDICON);
/* wait until reset it finished */
@ -222,14 +221,12 @@ static void s3c_mci_reset(struct device_d *hw_dev)
* @param hw_dev Host interface instance
* @param mci_dev MCI device instance (might be NULL)
*/
static int s3c_mci_initialize(struct device_d *hw_dev, struct device_d *mci_dev)
static int s3c_mci_initialize(struct s3c_mci_host *host_data, struct device_d *mci_dev)
{
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
s3c_mci_reset(hw_dev);
s3c_mci_reset(host_data);
/* restore last settings */
host_data->clock = s3c_setup_clock_speed(hw_dev, host_data->clock);
host_data->clock = s3c_setup_clock_speed(host_data, host_data->clock);
writel(0x007FFFFF, host_data->base + SDITIMER);
writel(SDICON_MMCCLOCK, host_data->base + SDICON);
writel(512, host_data->base + SDIBSIZE);
@ -276,9 +273,8 @@ static uint32_t s3c_prepare_command_setup(unsigned cmd_flags, unsigned data_flag
* @param data_flags MCI's data flags
* @return Register bits for this transfer
*/
static uint32_t s3c_prepare_data_setup(struct device_d *hw_dev, unsigned data_flags)
static uint32_t s3c_prepare_data_setup(struct s3c_mci_host *host_data, unsigned data_flags)
{
struct s3c_mci_host *host_data = (struct s3c_mci_host*)GET_HOST_DATA(hw_dev);
uint32_t reg = SDIDCON_BLOCKMODE; /* block mode only is supported */
if (host_data->bus_width == 1)
@ -305,16 +301,15 @@ static uint32_t s3c_prepare_data_setup(struct device_d *hw_dev, unsigned data_fl
* Note: Try to stop a running transfer. This should not happen, as all
* transfers must complete in this driver. But who knows... ;-)
*/
static int s3c_terminate_transfer(struct device_d *hw_dev)
static int s3c_terminate_transfer(struct s3c_mci_host *host_data)
{
unsigned stoptries = 3;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
while (readl(host_data->base + SDIDSTA) & (SDIDSTA_TXDATAON | SDIDSTA_RXDATAON)) {
pr_debug("Transfer still in progress.\n");
writel(SDIDCON_STOP, host_data->base + SDIDCON);
s3c_mci_initialize(hw_dev, NULL);
s3c_mci_initialize(host_data, NULL);
if ((stoptries--) == 0) {
pr_warning("Cannot stop the engine!\n");
@ -331,13 +326,12 @@ static int s3c_terminate_transfer(struct device_d *hw_dev)
* @param data The data information (buffer, direction aso.)
* @return 0 on success
*/
static int s3c_prepare_data_transfer(struct device_d *hw_dev, struct mci_data *data)
static int s3c_prepare_data_transfer(struct s3c_mci_host *host_data, struct mci_data *data)
{
uint32_t reg;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
writel(data->blocksize, host_data->base + SDIBSIZE);
reg = s3c_prepare_data_setup(hw_dev, data->flags);
reg = s3c_prepare_data_setup(host_data, data->flags);
reg |= data->blocks & SDIDCON_BLKNUM;
writel(reg, host_data->base + SDIDCON);
writel(0x007FFFFF, host_data->base + SDITIMER);
@ -352,12 +346,11 @@ static int s3c_prepare_data_transfer(struct device_d *hw_dev, struct mci_data *d
* @param data The data information (buffer, direction aso.)
* @return 0 on success
*/
static int s3c_send_command(struct device_d *hw_dev, struct mci_cmd *cmd,
static int s3c_send_command(struct s3c_mci_host *host_data, struct mci_cmd *cmd,
struct mci_data *data)
{
uint32_t reg, t1;
int rc;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
writel(0x007FFFFF, host_data->base + SDITIMER);
@ -416,12 +409,11 @@ static int s3c_send_command(struct device_d *hw_dev, struct mci_cmd *cmd,
*
* FIFO clear is only necessary on 2440, but doesn't hurt on 2410
*/
static int s3c_prepare_engine(struct device_d *hw_dev)
static int s3c_prepare_engine(struct s3c_mci_host *host_data)
{
int rc;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
rc = s3c_terminate_transfer(hw_dev);
rc = s3c_terminate_transfer(host_data);
if (rc != 0)
return rc;
@ -443,15 +435,15 @@ static int s3c_prepare_engine(struct device_d *hw_dev)
* - "broadcast commands with response (BCR)"
* - "addressed command (AC)" with response, but without data
*/
static int s3c_mci_std_cmds(struct device_d *hw_dev, struct mci_cmd *cmd)
static int s3c_mci_std_cmds(struct s3c_mci_host *host_data, struct mci_cmd *cmd)
{
int rc;
rc = s3c_prepare_engine(hw_dev);
rc = s3c_prepare_engine(host_data);
if (rc != 0)
return 0;
return s3c_send_command(hw_dev, cmd, NULL);
return s3c_send_command(host_data, cmd, NULL);
}
/**
@ -460,11 +452,10 @@ static int s3c_mci_std_cmds(struct device_d *hw_dev, struct mci_cmd *cmd)
* @param data The data information (buffer, direction aso.)
* @return 0 on success
*/
static int s3c_mci_read_block(struct device_d *hw_dev, struct mci_data *data)
static int s3c_mci_read_block(struct s3c_mci_host *host_data, struct mci_data *data)
{
uint32_t *p;
unsigned cnt, data_size;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
#define READ_REASON_TO_FAIL (SDIDSTA_CRCFAIL | SDIDSTA_RXCRCFAIL | SDIDSTA_DATATIMEOUT)
@ -514,13 +505,12 @@ static int s3c_mci_read_block(struct device_d *hw_dev, struct mci_data *data)
* We must ensure data in the FIFO when the command phase changes into the
* data phase. To ensure this, the FIFO gets filled first, then the command.
*/
static int s3c_mci_write_block(struct device_d *hw_dev, struct mci_cmd *cmd,
static int s3c_mci_write_block(struct s3c_mci_host *host_data, struct mci_cmd *cmd,
struct mci_data *data)
{
const uint32_t *p = (const uint32_t*)data->src;
unsigned cnt, data_size;
uint32_t reg;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
#define WRITE_REASON_TO_FAIL (SDIDSTA_CRCFAIL | SDIDSTA_DATATIMEOUT)
@ -543,7 +533,7 @@ static int s3c_mci_write_block(struct device_d *hw_dev, struct mci_cmd *cmd,
}
/* data is now in place and waits for transmitt. Start the command right now */
s3c_send_command(hw_dev, cmd, data);
s3c_send_command(host_data, cmd, data);
if ((reg = readl(host_data->base + SDIFSTA)) & SDIFSTA_FIFOFAIL) {
pr_err("Command fails immediatly due to FIFO underrun when writing %08X\n",
@ -591,37 +581,36 @@ static int s3c_mci_write_block(struct device_d *hw_dev, struct mci_cmd *cmd,
* @param data The data information (buffer, direction aso.)
* @return 0 on success
*/
static int s3c_mci_adtc(struct device_d *hw_dev, struct mci_cmd *cmd,
static int s3c_mci_adtc(struct s3c_mci_host *host_data, struct mci_cmd *cmd,
struct mci_data *data)
{
int rc;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
rc = s3c_prepare_engine(hw_dev);
rc = s3c_prepare_engine(host_data);
if (rc != 0)
return rc;
rc = s3c_prepare_data_transfer(hw_dev, data);
rc = s3c_prepare_data_transfer(host_data, data);
if (rc != 0)
return rc;
if (data->flags & MMC_DATA_READ) {
s3c_send_command(hw_dev, cmd, data);
rc = s3c_mci_read_block(hw_dev, data);
s3c_send_command(host_data, cmd, data);
rc = s3c_mci_read_block(host_data, data);
if (rc == 0) {
while (!(readl(host_data->base + SDIDSTA) & SDIDSTA_XFERFINISH))
;
} else
s3c_terminate_transfer(hw_dev);
s3c_terminate_transfer(host_data);
}
if (data->flags & MMC_DATA_WRITE) {
rc = s3c_mci_write_block(hw_dev, cmd, data);
rc = s3c_mci_write_block(host_data, cmd, data);
if (rc == 0) {
while (!(readl(host_data->base + SDIDSTA) & SDIDSTA_XFERFINISH))
;
} else
s3c_terminate_transfer(hw_dev);
s3c_terminate_transfer(host_data);
}
writel(0, host_data->base + SDIDCON);
@ -632,29 +621,28 @@ static int s3c_mci_adtc(struct device_d *hw_dev, struct mci_cmd *cmd,
/**
* Keep the attached MMC/SD unit in a well know state
* @param mci_pdata MCI platform data
* @param host MCI host
* @param mci_dev MCI device instance
* @return 0 on success, negative value else
*/
static int mci_reset(struct mci_host *mci_pdata, struct device_d *mci_dev)
static int mci_reset(struct mci_host *host, struct device_d *mci_dev)
{
struct device_d *hw_dev = mci_pdata->hw_dev;
struct s3c_mci_host *host_data = to_s3c_host(host);
return s3c_mci_initialize(hw_dev, mci_dev);
return s3c_mci_initialize(host_data, mci_dev);
}
/**
* Process one command to the MCI card
* @param mci_pdata MCI platform data
* @param host MCI host
* @param cmd The command to process
* @param data The data to handle in the command (can be NULL)
* @return 0 on success, negative value else
*/
static int mci_request(struct mci_host *mci_pdata, struct mci_cmd *cmd,
static int mci_request(struct mci_host *host, struct mci_cmd *cmd,
struct mci_data *data)
{
struct device_d *hw_dev = mci_pdata->hw_dev;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
struct s3c_mci_host *host_data = to_s3c_host(host);
int rc;
/* enable clock */
@ -662,11 +650,11 @@ static int mci_request(struct mci_host *mci_pdata, struct mci_cmd *cmd,
host_data->base + SDICON);
if ((cmd->resp_type == 0) || (data == NULL))
rc = s3c_mci_std_cmds(hw_dev, cmd);
rc = s3c_mci_std_cmds(host_data, cmd);
else
rc = s3c_mci_adtc(hw_dev, cmd, data); /* with response and data */
rc = s3c_mci_adtc(host_data, cmd, data); /* with response and data */
s3c_finish_request(hw_dev);
s3c_finish_request(host_data);
/* disable clock */
writel(readl(host_data->base + SDICON) & ~SDICON_CLKEN,
@ -676,16 +664,15 @@ static int mci_request(struct mci_host *mci_pdata, struct mci_cmd *cmd,
/**
* Setup the bus width and IO speed
* @param mci_pdata MCI platform data
* @param host MCI host
* @param mci_dev MCI device instance
* @param bus_width New bus width value (1, 4 or 8)
* @param clock New clock in Hz (can be '0' to disable the clock)
*/
static void mci_set_ios(struct mci_host *mci_pdata, struct device_d *mci_dev,
static void mci_set_ios(struct mci_host *host, struct device_d *mci_dev,
struct mci_ios *ios)
{
struct device_d *hw_dev = mci_pdata->hw_dev;
struct s3c_mci_host *host_data = GET_HOST_DATA(hw_dev);
struct s3c_mci_host *host_data = to_s3c_host(host);
uint32_t reg;
switch (ios->bus_width) {
@ -702,7 +689,7 @@ static void mci_set_ios(struct mci_host *mci_pdata, struct device_d *mci_dev,
reg = readl(host_data->base + SDICON);
if (ios->clock) {
/* setup the IO clock frequency and enable it */
host_data->clock = s3c_setup_clock_speed(hw_dev, ios->clock);
host_data->clock = s3c_setup_clock_speed(host_data, ios->clock);
reg |= SDICON_CLKEN; /* enable the clock */
} else {
reg &= ~SDICON_CLKEN; /* disable the clock */
@ -770,7 +757,7 @@ static int s3c_mci_probe(struct device_d *hw_dev)
/*
* Start the clock to let the engine and the card finishes its startup
*/
s3c_host->clock = s3c_setup_clock_speed(hw_dev, pd->f_min);
s3c_host->clock = s3c_setup_clock_speed(s3c_host, pd->f_min);
writel(SDICON_FIFORESET | SDICON_MMCCLOCK, s3c_host->base + SDICON);
return mci_register(&s3c_host->host);