/**
 * \file
 *
 * \brief SD/MMC probe engine
 *
 * SD/MMC probe engine identifies card in slot and notifies and listening
 * instance about change in card presence.
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All devices
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 * Atmel AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include <bitops.h>
#include <byteorder.h>
#include <debug.h>
#include <delay.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <util.h>
#include <workqueue.h>
#include <delayed_work.h>
#include <malloc.h>
#include <sdmmc/sdmmc.h>
#include <buffer.h>
#include "protocol.h"
#include <app/timer.h>
#include <app/workqueue.h>
#include <board/sdmmc.h>

#ifdef BOARD_SDMMC_POWER_RAMP_UP_US
# define POWER_RAMP_UP_US	BOARD_SDMMC_POWER_RAMP_UP_US
#else
# define POWER_RAMP_UP_US	0
#endif

struct sdmmc_probe_data {
	bool			running;
	int			state;
	struct sdmmc_slot	*slot;
	struct workqueue_item	work;
	struct delayed_work	dwork;
	struct sdmmc_request	req;
	int			i;
	struct buffer		*buf;
	/** \brief Callback for events regarding slot state */
	void			(*event)(struct sdmmc_slot *slot, void *context);
	void			*context;
};

enum {
	SDMMC_PROBE_STATE_INIT,
	SDMMC_PROBE_STATE_INITSEQ,
	SDMMC_PROBE_STATE_GO_IDLE,
	SDMMC_PROBE_STATE_WAIT_SWITCH,
	SDMMC_PROBE_STATE_SEND_IF_COND,
	SDMMC_PROBE_STATE_DETECT_SD_ACMD,
	SDMMC_PROBE_STATE_DETECT_SD_CMD,
	SDMMC_PROBE_STATE_DETECT_SD_DONE,
	SDMMC_PROBE_STATE_SD_APP_COND_LOOP,
	SDMMC_PROBE_STATE_SD_APP_COND_CMD,
	SDMMC_PROBE_STATE_SD_SEND_CID,
	SDMMC_PROBE_STATE_SD_SET_RELADDR,
	SDMMC_PROBE_STATE_SD_SEND_CSD,
	SDMMC_PROBE_STATE_SD_SELECT_CARD,
	SDMMC_PROBE_STATE_SD_SEND_SCR_ACMD,
	SDMMC_PROBE_STATE_SD_SEND_SCR_CMD,
	SDMMC_PROBE_STATE_SD_FUNC_CHECK,
	SDMMC_PROBE_STATE_SD_FUNC_SWITCH,
	SDMMC_PROBE_STATE_SD_FUNC_DONE,
	SDMMC_PROBE_STATE_SD_DESELECT_CARD,
	SDMMC_PROBE_STATE_SD_RESEND_CSD,
	SDMMC_PROBE_STATE_SD_RESELECT_CARD,
	SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_ACMD,
	SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_CMD,
	SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_DONE,
	SDMMC_PROBE_STATE_SD_SET_CLK,
	SDMMC_PROBE_STATE_SD_SET_BLOCK_LEN,
	SDMMC_PROBE_STATE_SD_FINAL,
	SDMMC_PROBE_STATE_DETECT_MMC,
	SDMMC_PROBE_STATE_SEND_STATUS,
	SDMMC_PROBE_STATE_CHECK_STATUS,
};

static void sdmmc_probe_callback(struct sdmmc_request *req)
{
	struct sdmmc_probe_data *pdata = req->context;

	workqueue_add_item(&sdmmc_workqueue, &pdata->work);
}

static void sdmmc_probe_engine(void *data)
{
	struct sdmmc_probe_data *pdata = data;
	struct sdmmc_slot	*slot = pdata->slot;
	struct sdmmc_request	*req = &pdata->req;
	uint32_t		*tmp;
	int			ret;

	dbg_verbose("probe slot%u state=%d\n", slot->id, pdata->state);

	/* Always init request to make sure data reference is removed */
	sdmmc_req_init(req);

	switch (pdata->state) {
	case SDMMC_PROBE_STATE_INIT:
		if (!test_bit(SDMMC_SLOT_CARD_DETECT, &slot->flags)) {
			pdata->running = false;
			clear_bit(SDMMC_SLOT_CARD_PRESENT, &slot->flags);
			if (pdata->event)
				pdata->event(slot, pdata->context);
			return;
		}
		sdmmc_slot_power_up(slot);
		sdmmc_req_prep_callback(req, sdmmc_probe_callback, pdata);
		if (POWER_RAMP_UP_US > 0) {
			/* Delay to give power the chance to ramp up */
			delayed_work_run_us(&pdata->dwork, &pdata->work,
					POWER_RAMP_UP_US);
			pdata->state = SDMMC_PROBE_STATE_INITSEQ;
			return;
		}
		/* fall through */
	case SDMMC_PROBE_STATE_INITSEQ:
		/* Run the 74 cycle initialization sequence */
		sdmmc_slot_set_f_max(slot, SDMMC_F_OD);
		sdmmc_req_prep_cmd(req, 0, 0, 0);
		set_bit(SDMMC_REQ_INITSEQ, &req->flags);
		pdata->state = SDMMC_PROBE_STATE_GO_IDLE;
		break;
	case SDMMC_PROBE_STATE_GO_IDLE:
		sdmmc_req_prep_cmd(req, SDMMC_GO_IDLE_STATE, 0,
				SDMMC_RSP_NONE | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_WAIT_SWITCH;
		break;
	case SDMMC_PROBE_STATE_WAIT_SWITCH:
		if (req->status)
			goto failure;
		/* The card might have got a switch function and in such a
		 * case we need to apply a delay for it to switch back.
		 * Same as for switch function (8 cycles).
		 */
		delayed_work_run_us(&pdata->dwork, &pdata->work, 80);
		pdata->state = SDMMC_PROBE_STATE_SEND_IF_COND;
		return;
	case SDMMC_PROBE_STATE_SEND_IF_COND:
		/* Indicate to card that host is SDHC capable and
		 * detect if card support HC
		 */
		sdmmc_req_prep_cmd(req, SD_SEND_IF_COND,
				SD_IF_COND_V_27_33 | SD_IF_COND_CHECK_PATTERN,
				SDMMC_RSP_R7 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_DETECT_SD_ACMD;
		break;
	case SDMMC_PROBE_STATE_DETECT_SD_ACMD:
		if (req->status) {
			clear_bit(SDMMC_SLOT_HCS, &slot->flags);
			slot->bcr = 0;
		} else {
			set_bit(SDMMC_SLOT_HCS, &slot->flags);
			slot->bcr = SDMMC_OCR_CCS;
		}
		sdmmc_req_prep_cmd(req, SDMMC_APP_CMD, 0,
				SDMMC_RSP_R1 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_DETECT_SD_CMD;
		break;
	case SDMMC_PROBE_STATE_DETECT_SD_CMD:
		if (req->status || !(req->cmd.resp[0] &
					SDMMC_CARD_STATUS_APP_CMD)) {
			pdata->state = SDMMC_PROBE_STATE_DETECT_MMC;
			goto rerun;
		}
		sdmmc_req_prep_cmd(req, SD_SEND_OP_COND, slot->bcr,
				SDMMC_RSP_R3 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_DETECT_SD_DONE;
		break;
	case SDMMC_PROBE_STATE_DETECT_SD_DONE:
		if (req->status) {
			pdata->state = SDMMC_PROBE_STATE_DETECT_MMC;
			goto rerun;
		}
		sdmmc_card_set_type(&slot->card, SDMMC_CARD_TYPE_SD);
		slot->ocr = req->cmd.resp[0];
		slot->ocr = sdmmc_slot_set_voltage(slot, slot->ocr);
		if (test_bit(SDMMC_SLOT_HCS, &slot->flags))
			slot->ocr |= SDMMC_OCR_CCS;
		pdata->i = 0;
		/* intentionally no break */
	case SDMMC_PROBE_STATE_SD_APP_COND_LOOP:
		/* Send app op cond again and loop 100 times with a 10ms
		 * pause
		 */
		sdmmc_req_prep_cmd(req, SDMMC_APP_CMD, 0,
				SDMMC_RSP_R1 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_SD_APP_COND_CMD;
		break;
	case SDMMC_PROBE_STATE_SD_APP_COND_CMD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SD_SEND_OP_COND, slot->ocr,
				SDMMC_RSP_R3 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_SD_SEND_CID;
		break;
	case SDMMC_PROBE_STATE_SD_SEND_CID:
		if (req->status)
			goto failure;
		if (!(req->cmd.resp[0] & SDMMC_OCR_POWER_UP_DONE)) {
			if (pdata->i >= 100)
				goto failure;
			pdata->i++;
			pdata->state = SDMMC_PROBE_STATE_SD_APP_COND_LOOP;
			delayed_work_run_us(&pdata->dwork, &pdata->work,
					10000);
			return;
		}
		if (req->cmd.resp[0] & SDMMC_OCR_CCS)
			sdmmc_card_set_type(&slot->card,
					SDMMC_CARD_TYPE_SDHC);
		sdmmc_req_prep_cmd(req, SDMMC_ALL_SEND_CID, 0,
				SDMMC_RSP_R2 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_SD_SET_RELADDR;
		break;
	case SDMMC_PROBE_STATE_SD_SET_RELADDR:
		if (req->status)
			goto failure;
		sdmmc_decode_sd_cid(&slot->card, req->cmd.resp);
		sdmmc_req_prep_cmd(req, SDMMC_SET_RELATIVE_ADDR, 0,
				SDMMC_RSP_R6 | SDMMC_CMD_OPD);
		pdata->state = SDMMC_PROBE_STATE_SD_SEND_CSD;
		break;
	case SDMMC_PROBE_STATE_SD_SEND_CSD:
		if (req->status)
			goto failure;
		slot->card.rca = req->cmd.resp[0] & SDMMC_RCA_MASK;
		sdmmc_req_prep_cmd(req, SDMMC_SEND_CSD, slot->card.rca,
				SDMMC_RSP_R2);
		pdata->state = SDMMC_PROBE_STATE_SD_SELECT_CARD;
		break;
	case SDMMC_PROBE_STATE_SD_SELECT_CARD:
		if (req->status)
			goto failure;
		ret = sdmmc_decode_sd_csd(&slot->card, req->cmd.resp);
		if (ret) {
			dbg_error("sdmmc probe: Failed to decode CSD!\n");
			goto failure;
		}

		sdmmc_req_prep_cmd(req, SDMMC_SELECT_DESELECT_CARD,
				slot->card.rca, SDMMC_RSP_R1B);
		pdata->state = SDMMC_PROBE_STATE_SD_SEND_SCR_ACMD;
		break;
	case SDMMC_PROBE_STATE_SD_SEND_SCR_ACMD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SDMMC_APP_CMD, slot->card.rca,
				SDMMC_RSP_R1);
		pdata->state = SDMMC_PROBE_STATE_SD_SEND_SCR_CMD;
		break;
	case SDMMC_PROBE_STATE_SD_SEND_SCR_CMD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SD_SEND_SCR, 0, SDMMC_RSP_R1);
		pdata->buf = buffer_dma_alloc(8);
		if (pdata->buf == NULL) {
			dbg_error("sdmmc probe: Failed to allocate buffer "
					"w/dma!\n");
			goto failure;
		}
		sdmmc_req_prep_data(req, pdata->buf);
		pdata->state = SDMMC_PROBE_STATE_SD_FUNC_CHECK;
		break;
	case SDMMC_PROBE_STATE_SD_FUNC_CHECK:
		if (req->status) {
			buffer_dma_free(pdata->buf, pdata->buf->len);
			goto failure;
		}
		dma_sync_for_cpu(pdata->buf->addr.ptr, 8, DMA_FROM_DEVICE);
		tmp = pdata->buf->addr.ptr;
		dbg_verbose("sdmmc probe: SCR: %08x %08x\n", tmp[0], tmp[1]);
		if (!(tmp[0] & SD_SCR0_BUS_WIDTH_4BIT_MASK)) {
			pdata->state = SDMMC_PROBE_STATE_SD_SET_CLK;
			buffer_dma_free(pdata->buf, pdata->buf->len);
			goto rerun;
		}
		/* If card is version 1.0 or 1.01, it doesn't support switch
		 * function.
		 */
		if ((tmp[0] & SD_SCR0_SPEC_VERSION_MASK) ==
				SD_SCR0_SPEC_VERSION_10_101) {
			pdata->state = SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_ACMD;
			buffer_dma_free(pdata->buf, pdata->buf->len);
			goto rerun;
		}
		buffer_dma_free(pdata->buf, pdata->buf->len);
		sdmmc_req_prep_cmd(req, SDMMC_SWITCH_FUNC,
				SDMMC_SWITCH_FUNC_MODE_CHECK |
				SDMMC_SWITCH_FUNC_HIGH_SPEED, SDMMC_RSP_R1);
		pdata->buf = buffer_dma_alloc(64);
		if (pdata->buf == NULL) {
			dbg_error("sdmmc probe: Failed to allocate buffer "
					"w/dma!\n");
			goto failure;
		}
		sdmmc_req_prep_data(req, pdata->buf);
		pdata->state = SDMMC_PROBE_STATE_SD_FUNC_SWITCH;
		break;
	case SDMMC_PROBE_STATE_SD_FUNC_SWITCH:
		if ((((uint8_t *)pdata->buf->addr.ptr)[16] & 0xf) != 1 ||
				req->status) {
			pdata->state = SDMMC_PROBE_STATE_SD_DESELECT_CARD;
			buffer_dma_free(pdata->buf, pdata->buf->len);
			goto rerun;
		}
		dbg_verbose("sdmmc probe: Card supports high speed\n");
		sdmmc_req_prep_cmd(req, SDMMC_SWITCH_FUNC,
				SDMMC_SWITCH_FUNC_MODE_SWITCH |
				SDMMC_SWITCH_FUNC_G6_KEEP |
				SDMMC_SWITCH_FUNC_G5_KEEP |
				SDMMC_SWITCH_FUNC_G4_KEEP |
				SDMMC_SWITCH_FUNC_G3_KEEP |
				SDMMC_SWITCH_FUNC_G2_KEEP |
				SDMMC_SWITCH_FUNC_HIGH_SPEED, SDMMC_RSP_R1);
		sdmmc_req_prep_data(req, pdata->buf);
		pdata->state = SDMMC_PROBE_STATE_SD_FUNC_DONE;
		break;
	case SDMMC_PROBE_STATE_SD_FUNC_DONE:
		if (req->status) {
			buffer_dma_free(pdata->buf, pdata->buf->len);
			goto failure;
		}
		set_bit(SDMMC_SLOT_HIGH_SPEED, &slot->flags);
		buffer_dma_free(pdata->buf, pdata->buf->len);
		/* A 8 cycle delay is required after switch command
		 * @ 200KHz clock this should be 40 uS, but we use
		 * 80 to handle unprecise clock setting.
		 */
		delayed_work_run_us(&pdata->dwork, &pdata->work, 80);
		pdata->state = SDMMC_PROBE_STATE_SD_DESELECT_CARD;
		return;
	case SDMMC_PROBE_STATE_SD_DESELECT_CARD:
		sdmmc_req_prep_cmd(req, SDMMC_SELECT_DESELECT_CARD,
				0, SDMMC_RSP_NONE);
		pdata->state = SDMMC_PROBE_STATE_SD_RESEND_CSD;
		break;
	case SDMMC_PROBE_STATE_SD_RESEND_CSD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SDMMC_SEND_CSD, slot->card.rca,
				SDMMC_RSP_R2);
		pdata->state = SDMMC_PROBE_STATE_SD_RESELECT_CARD;
		break;
	case SDMMC_PROBE_STATE_SD_RESELECT_CARD:
		if (req->status)
			goto failure;
		ret = sdmmc_decode_sd_csd(&slot->card, req->cmd.resp);
		if (ret) {
			dbg_error("sdmmc probe: Failed to decode CSD!\n");
			goto failure;
		}
		sdmmc_req_prep_cmd(req, SDMMC_SELECT_DESELECT_CARD,
				slot->card.rca, SDMMC_RSP_R1B);
		pdata->state = SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_ACMD;
		break;
	case SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_ACMD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SDMMC_APP_CMD, slot->card.rca,
				SDMMC_RSP_R1);
		pdata->state = SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_CMD;
		break;
	case SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_CMD:
		if (req->status)
			goto failure;
		sdmmc_req_prep_cmd(req, SD_SET_BUS_WIDTH,
				SD_ARG_SET_BUS_WIDTH_4BIT, SDMMC_RSP_R1);
		pdata->state = SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_DONE;
		break;
	case SDMMC_PROBE_STATE_SD_SET_BUS_WIDTH_DONE:
		if (req->status)
			goto failure;
		sdmmc_slot_set_bus_width(slot, 4);
		/* intentionally no break */
	case SDMMC_PROBE_STATE_SD_SET_CLK:
		dbg_info("sdmmc: card%u max transfer rate: %d MHz\n",
				slot->id,
				slot->card.csd.max_transfer_rate / 1000000);
		sdmmc_slot_set_f_max(slot, slot->card.csd.max_transfer_rate);
		/* intentionally no break */
	case SDMMC_PROBE_STATE_SD_SET_BLOCK_LEN:
		sdmmc_req_prep_cmd(req, SDMMC_SET_BLOCKLEN,
				512, SDMMC_RSP_R1);
		slot->card.block_size = 512;
		pdata->state = SDMMC_PROBE_STATE_SD_FINAL;
		break;
	case SDMMC_PROBE_STATE_SD_FINAL:
		if (req->status)
			goto failure;
		pdata->state = SDMMC_PROBE_STATE_SEND_STATUS;
		goto rerun;

	case SDMMC_PROBE_STATE_DETECT_MMC:
		/* TODO: MMC detection */
		goto failure;
	/* send_op_cond */
	/* if ok attach mmc */

	/* State to stay in as long as the card is available.
	 * Will stop the state machine after verifying that the card
	 * responds to SEND_STATUS, but might be restarted by
	 * card detection. And in case of card removal it will
	 * continue with card removal procedure.
	 *
	 * Always requesting the card status upon a card event allows us
	 * to synchronize the with request queue and avoid nasty race
	 * conditions elsewhere.
	 */
	case SDMMC_PROBE_STATE_SEND_STATUS:
		if (!test_bit(SDMMC_SLOT_CARD_DETECT, &slot->flags))
			clear_bit(SDMMC_SLOT_CARD_PRESENT, &slot->flags);
		else
			set_bit(SDMMC_SLOT_CARD_PRESENT, &slot->flags);

		sdmmc_req_prep_cmd(req, SDMMC_SEND_STATUS, slot->card.rca,
				SDMMC_RSP_R1);
		pdata->state = SDMMC_PROBE_STATE_CHECK_STATUS;
		break;

	case SDMMC_PROBE_STATE_CHECK_STATUS:
		/* Normally, we go back to the SEND_STATUS state */
		pdata->state = SDMMC_PROBE_STATE_SEND_STATUS;

		if (req->status == 0) {
			uint32_t card_status;

			if (!test_bit(SDMMC_SLOT_CARD_DETECT, &slot->flags)
					&& sdmmc_slot_is_card_present(slot))
				/* Missed an event; retry */
				goto rerun;

			if (pdata->event)
				pdata->event(slot, pdata->context);

			card_status = req->cmd.resp[0];
			dbg_info("sdmmc: slot%u card status: %08x\n",
					slot->id, card_status);
			if ((card_status & SDMMC_CURRENT_STATE_MASK)
					== SDMMC_CURRENT_STATE_TRAN) {
				pdata->running = false;
				return;
			} else {
				/*
				 * Card may have been disconnected
				 * briefly. Re-run probe sequence.
				 */
				pdata->state = SDMMC_PROBE_STATE_INIT;
				goto rerun;
			}
		}

		/* No response to SEND_STATUS, so it must be gone. */
		if (test_bit(SDMMC_SLOT_CARD_DETECT, &slot->flags)
				&& !sdmmc_slot_is_card_present(slot))
			/* Missed an event; retry */
			goto rerun;

		clear_bit(SDMMC_SLOT_CARD_PRESENT, &slot->flags);

		if (pdata->event)
			pdata->event(slot, pdata->context);

		sdmmc_slot_power_down(slot);
		pdata->state = SDMMC_PROBE_STATE_INIT;
		pdata->running = false;
		return;
	}

	pdata->slot->host->submit_req(pdata->slot->host, req);
	return;

rerun:
	workqueue_add_item(&sdmmc_workqueue, &pdata->work);
	return;

failure:
	dbg_error("sdmmc: probe failure in state %d\n", pdata->state);
	sdmmc_slot_power_down(slot);
	pdata->state = SDMMC_PROBE_STATE_INIT;
	pdata->running = false;
	clear_bit(SDMMC_SLOT_CARD_PRESENT, &slot->flags);
	if (pdata->event)
		pdata->event(slot, pdata->context);
	/* TODO: Retry timer? */
}

/* This must be run in sdmmc_workqueue context */
void sdmmc_probe_notify_card_detect(void *context)
{
	struct sdmmc_probe_data *pdata = context;

	if (!pdata->running) {
		pdata->running = true;
		workqueue_add_item(&sdmmc_workqueue, &pdata->work);
	}
}

void *sdmmc_probe_init(struct sdmmc_slot *slot,
		void (*event)(struct sdmmc_slot *slot, void *context),
		void *context)
{
	struct sdmmc_probe_data *pdata;

	pdata = malloc(sizeof(struct sdmmc_probe_data));
	if (pdata == NULL)
		return NULL;
	memset(pdata, 0, sizeof(struct sdmmc_probe_data));

	slot->notify_card_detect = sdmmc_probe_notify_card_detect;
	slot->context = pdata;

	pdata->req.slot = slot;
	pdata->slot = slot;
	pdata->event = event;
	pdata->context = context;
	workqueue_init_item(&pdata->work, sdmmc_probe_engine, pdata);
	delayed_work_init(&pdata->dwork, &sdmmc_timer, &sdmmc_workqueue);

	return pdata;
}

