Lines Matching full:host
3 * meson-mx-sdio.c - Meson6, Meson8 and Meson8b SDIO/MMC Host Controller
25 #include <linux/mmc/host.h>
128 struct meson_mx_mmc_host *host = mmc_priv(mmc); in meson_mx_mmc_mask_bits() local
131 regval = readl(host->base + reg); in meson_mx_mmc_mask_bits()
135 writel(regval, host->base + reg); in meson_mx_mmc_mask_bits()
138 static void meson_mx_mmc_soft_reset(struct meson_mx_mmc_host *host) in meson_mx_mmc_soft_reset() argument
140 writel(MESON_MX_SDIO_IRQC_SOFT_RESET, host->base + MESON_MX_SDIO_IRQC); in meson_mx_mmc_soft_reset()
158 struct meson_mx_mmc_host *host = mmc_priv(mmc); in meson_mx_mmc_start_cmd() local
163 host->cmd = cmd; in meson_mx_mmc_start_cmd()
216 spin_lock_irqsave(&host->irq_lock, irqflags); in meson_mx_mmc_start_cmd()
218 mult = readl(host->base + MESON_MX_SDIO_MULT); in meson_mx_mmc_start_cmd()
220 mult |= FIELD_PREP(MESON_MX_SDIO_MULT_PORT_SEL_MASK, host->slot_id); in meson_mx_mmc_start_cmd()
222 writel(mult, host->base + MESON_MX_SDIO_MULT); in meson_mx_mmc_start_cmd()
234 writel(cmd->arg, host->base + MESON_MX_SDIO_ARGU); in meson_mx_mmc_start_cmd()
235 writel(ext, host->base + MESON_MX_SDIO_EXT); in meson_mx_mmc_start_cmd()
236 writel(send, host->base + MESON_MX_SDIO_SEND); in meson_mx_mmc_start_cmd()
238 spin_unlock_irqrestore(&host->irq_lock, irqflags); in meson_mx_mmc_start_cmd()
240 mod_timer(&host->cmd_timeout, jiffies + timeout); in meson_mx_mmc_start_cmd()
243 static void meson_mx_mmc_request_done(struct meson_mx_mmc_host *host) in meson_mx_mmc_request_done() argument
247 mrq = host->mrq; in meson_mx_mmc_request_done()
249 if (host->cmd->error) in meson_mx_mmc_request_done()
250 meson_mx_mmc_soft_reset(host); in meson_mx_mmc_request_done()
252 host->mrq = NULL; in meson_mx_mmc_request_done()
253 host->cmd = NULL; in meson_mx_mmc_request_done()
255 mmc_request_done(host->mmc, mrq); in meson_mx_mmc_request_done()
260 struct meson_mx_mmc_host *host = mmc_priv(mmc); in meson_mx_mmc_set_ios() local
280 host->error = -EINVAL; in meson_mx_mmc_set_ios()
284 host->error = clk_set_rate(host->cfg_div_clk, ios->clock); in meson_mx_mmc_set_ios()
285 if (host->error) { in meson_mx_mmc_set_ios()
288 clk_rate, host->error); in meson_mx_mmc_set_ios()
292 mmc->actual_clock = clk_get_rate(host->cfg_div_clk); in meson_mx_mmc_set_ios()
300 host->error = mmc_regulator_set_ocr(mmc, in meson_mx_mmc_set_ios()
303 if (host->error) in meson_mx_mmc_set_ios()
339 struct meson_mx_mmc_host *host = mmc_priv(mmc); in meson_mx_mmc_request() local
342 if (!host->error) in meson_mx_mmc_request()
343 host->error = meson_mx_mmc_map_dma(mmc, mrq); in meson_mx_mmc_request()
345 if (host->error) { in meson_mx_mmc_request()
346 cmd->error = host->error; in meson_mx_mmc_request()
351 host->mrq = mrq; in meson_mx_mmc_request()
355 host->base + MESON_MX_SDIO_ADDR); in meson_mx_mmc_request()
366 struct meson_mx_mmc_host *host = mmc_priv(mmc); in meson_mx_mmc_read_response() local
370 mult = readl(host->base + MESON_MX_SDIO_MULT); in meson_mx_mmc_read_response()
374 writel(mult, host->base + MESON_MX_SDIO_MULT); in meson_mx_mmc_read_response()
378 resp[3 - i] = readl(host->base + MESON_MX_SDIO_ARGU); in meson_mx_mmc_read_response()
384 cmd->resp[0] = readl(host->base + MESON_MX_SDIO_ARGU); in meson_mx_mmc_read_response()
388 static irqreturn_t meson_mx_mmc_process_cmd_irq(struct meson_mx_mmc_host *host, in meson_mx_mmc_process_cmd_irq() argument
391 struct mmc_command *cmd = host->cmd; in meson_mx_mmc_process_cmd_irq()
402 meson_mx_mmc_read_response(host->mmc, cmd); in meson_mx_mmc_process_cmd_irq()
419 struct meson_mx_mmc_host *host = (void *) data; in meson_mx_mmc_irq() local
423 spin_lock(&host->irq_lock); in meson_mx_mmc_irq()
425 irqs = readl(host->base + MESON_MX_SDIO_IRQS); in meson_mx_mmc_irq()
426 send = readl(host->base + MESON_MX_SDIO_SEND); in meson_mx_mmc_irq()
429 ret = meson_mx_mmc_process_cmd_irq(host, irqs, send); in meson_mx_mmc_irq()
434 writel(irqs, host->base + MESON_MX_SDIO_IRQS); in meson_mx_mmc_irq()
436 spin_unlock(&host->irq_lock); in meson_mx_mmc_irq()
443 struct meson_mx_mmc_host *host = (void *) irq_data; in meson_mx_mmc_irq_thread() local
444 struct mmc_command *cmd = host->cmd, *next_cmd; in meson_mx_mmc_irq_thread()
449 timer_delete_sync(&host->cmd_timeout); in meson_mx_mmc_irq_thread()
452 dma_unmap_sg(mmc_dev(host->mmc), cmd->data->sg, in meson_mx_mmc_irq_thread()
461 meson_mx_mmc_start_cmd(host->mmc, next_cmd); in meson_mx_mmc_irq_thread()
463 meson_mx_mmc_request_done(host); in meson_mx_mmc_irq_thread()
470 struct meson_mx_mmc_host *host = timer_container_of(host, t, in meson_mx_mmc_timeout() local
475 spin_lock_irqsave(&host->irq_lock, irqflags); in meson_mx_mmc_timeout()
478 irqc = readl(host->base + MESON_MX_SDIO_IRQC); in meson_mx_mmc_timeout()
480 writel(irqc, host->base + MESON_MX_SDIO_IRQC); in meson_mx_mmc_timeout()
482 spin_unlock_irqrestore(&host->irq_lock, irqflags); in meson_mx_mmc_timeout()
488 if (!host->cmd) in meson_mx_mmc_timeout()
491 dev_dbg(mmc_dev(host->mmc), in meson_mx_mmc_timeout()
493 host->cmd->opcode, readl(host->base + MESON_MX_SDIO_IRQS), in meson_mx_mmc_timeout()
494 readl(host->base + MESON_MX_SDIO_ARGU)); in meson_mx_mmc_timeout()
496 host->cmd->error = -ETIMEDOUT; in meson_mx_mmc_timeout()
498 meson_mx_mmc_request_done(host); in meson_mx_mmc_timeout()
530 static int meson_mx_mmc_add_host(struct meson_mx_mmc_host *host) in meson_mx_mmc_add_host() argument
532 struct mmc_host *mmc = host->mmc; in meson_mx_mmc_add_host()
536 if (of_property_read_u32(slot_dev->of_node, "reg", &host->slot_id)) { in meson_mx_mmc_add_host()
541 if (host->slot_id >= MESON_MX_SDIO_MAX_SLOTS) { in meson_mx_mmc_add_host()
543 host->slot_id); in meson_mx_mmc_add_host()
563 mmc->f_min = clk_round_rate(host->cfg_div_clk, 1); in meson_mx_mmc_add_host()
564 mmc->f_max = clk_round_rate(host->cfg_div_clk, in meson_mx_mmc_add_host()
565 clk_get_rate(host->parent_clk)); in meson_mx_mmc_add_host()
581 static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host) in meson_mx_mmc_register_clks() argument
586 clk_fixed_factor_parent = __clk_get_name(host->parent_clk); in meson_mx_mmc_register_clks()
587 init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL, in meson_mx_mmc_register_clks()
589 dev_name(host->controller_dev)); in meson_mx_mmc_register_clks()
597 host->fixed_factor.div = 2; in meson_mx_mmc_register_clks()
598 host->fixed_factor.mult = 1; in meson_mx_mmc_register_clks()
599 host->fixed_factor.hw.init = &init; in meson_mx_mmc_register_clks()
601 host->fixed_factor_clk = devm_clk_register(host->controller_dev, in meson_mx_mmc_register_clks()
602 &host->fixed_factor.hw); in meson_mx_mmc_register_clks()
603 if (WARN_ON(IS_ERR(host->fixed_factor_clk))) in meson_mx_mmc_register_clks()
604 return PTR_ERR(host->fixed_factor_clk); in meson_mx_mmc_register_clks()
606 clk_div_parent = __clk_get_name(host->fixed_factor_clk); in meson_mx_mmc_register_clks()
607 init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL, in meson_mx_mmc_register_clks()
608 "%s#div", dev_name(host->controller_dev)); in meson_mx_mmc_register_clks()
616 host->cfg_div.reg = host->base + MESON_MX_SDIO_CONF; in meson_mx_mmc_register_clks()
617 host->cfg_div.shift = MESON_MX_SDIO_CONF_CMD_CLK_DIV_SHIFT; in meson_mx_mmc_register_clks()
618 host->cfg_div.width = MESON_MX_SDIO_CONF_CMD_CLK_DIV_WIDTH; in meson_mx_mmc_register_clks()
619 host->cfg_div.hw.init = &init; in meson_mx_mmc_register_clks()
620 host->cfg_div.flags = CLK_DIVIDER_ALLOW_ZERO; in meson_mx_mmc_register_clks()
622 host->cfg_div_clk = devm_clk_register(host->controller_dev, in meson_mx_mmc_register_clks()
623 &host->cfg_div.hw); in meson_mx_mmc_register_clks()
624 if (WARN_ON(IS_ERR(host->cfg_div_clk))) in meson_mx_mmc_register_clks()
625 return PTR_ERR(host->cfg_div_clk); in meson_mx_mmc_register_clks()
634 struct meson_mx_mmc_host *host; in meson_mx_mmc_probe() local
644 mmc = mmc_alloc_host(sizeof(*host), &slot_pdev->dev); in meson_mx_mmc_probe()
650 host = mmc_priv(mmc); in meson_mx_mmc_probe()
651 host->mmc = mmc; in meson_mx_mmc_probe()
652 host->controller_dev = &pdev->dev; in meson_mx_mmc_probe()
654 spin_lock_init(&host->irq_lock); in meson_mx_mmc_probe()
655 timer_setup(&host->cmd_timeout, meson_mx_mmc_timeout, 0); in meson_mx_mmc_probe()
657 platform_set_drvdata(pdev, host); in meson_mx_mmc_probe()
659 host->base = devm_platform_ioremap_resource(pdev, 0); in meson_mx_mmc_probe()
660 if (IS_ERR(host->base)) { in meson_mx_mmc_probe()
661 ret = PTR_ERR(host->base); in meson_mx_mmc_probe()
671 ret = devm_request_threaded_irq(host->controller_dev, irq, in meson_mx_mmc_probe()
674 NULL, host); in meson_mx_mmc_probe()
678 host->core_clk = devm_clk_get(host->controller_dev, "core"); in meson_mx_mmc_probe()
679 if (IS_ERR(host->core_clk)) { in meson_mx_mmc_probe()
680 ret = PTR_ERR(host->core_clk); in meson_mx_mmc_probe()
684 host->parent_clk = devm_clk_get(host->controller_dev, "clkin"); in meson_mx_mmc_probe()
685 if (IS_ERR(host->parent_clk)) { in meson_mx_mmc_probe()
686 ret = PTR_ERR(host->parent_clk); in meson_mx_mmc_probe()
690 ret = meson_mx_mmc_register_clks(host); in meson_mx_mmc_probe()
694 ret = clk_prepare_enable(host->core_clk); in meson_mx_mmc_probe()
696 dev_err(host->controller_dev, "Failed to enable core clock\n"); in meson_mx_mmc_probe()
700 ret = clk_prepare_enable(host->cfg_div_clk); in meson_mx_mmc_probe()
702 dev_err(host->controller_dev, "Failed to enable MMC clock\n"); in meson_mx_mmc_probe()
711 writel(conf, host->base + MESON_MX_SDIO_CONF); in meson_mx_mmc_probe()
713 meson_mx_mmc_soft_reset(host); in meson_mx_mmc_probe()
715 ret = meson_mx_mmc_add_host(host); in meson_mx_mmc_probe()
722 clk_disable_unprepare(host->cfg_div_clk); in meson_mx_mmc_probe()
724 clk_disable_unprepare(host->core_clk); in meson_mx_mmc_probe()
734 struct meson_mx_mmc_host *host = platform_get_drvdata(pdev); in meson_mx_mmc_remove() local
735 struct device *slot_dev = mmc_dev(host->mmc); in meson_mx_mmc_remove()
737 timer_delete_sync(&host->cmd_timeout); in meson_mx_mmc_remove()
739 mmc_remove_host(host->mmc); in meson_mx_mmc_remove()
743 clk_disable_unprepare(host->cfg_div_clk); in meson_mx_mmc_remove()
744 clk_disable_unprepare(host->core_clk); in meson_mx_mmc_remove()
746 mmc_free_host(host->mmc); in meson_mx_mmc_remove()
768 MODULE_DESCRIPTION("Meson6, Meson8 and Meson8b SDIO/MMC Host Driver");