1/* 2 * Copyright (C) 2015, Samsung Electronics Co., Ltd. 3 * 4 * Author: Marek Szyprowski <m.szyprowski@samsung.com> 5 * 6 * License terms: GNU General Public License (GPL) version 2 7 * 8 * Simple eMMC hardware reset provider 9 */ 10#include <linux/delay.h> 11#include <linux/kernel.h> 12#include <linux/slab.h> 13#include <linux/device.h> 14#include <linux/err.h> 15#include <linux/gpio/consumer.h> 16#include <linux/reboot.h> 17 18#include <linux/mmc/host.h> 19 20#include "pwrseq.h" 21 22struct mmc_pwrseq_emmc { 23 struct mmc_pwrseq pwrseq; 24 struct notifier_block reset_nb; 25 struct gpio_desc *reset_gpio; 26}; 27 28static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) 29{ 30 gpiod_set_value(pwrseq->reset_gpio, 1); 31 udelay(1); 32 gpiod_set_value(pwrseq->reset_gpio, 0); 33 udelay(200); 34} 35 36static void mmc_pwrseq_emmc_reset(struct mmc_host *host) 37{ 38 struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, 39 struct mmc_pwrseq_emmc, pwrseq); 40 41 __mmc_pwrseq_emmc_reset(pwrseq); 42} 43 44static void mmc_pwrseq_emmc_free(struct mmc_host *host) 45{ 46 struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, 47 struct mmc_pwrseq_emmc, pwrseq); 48 49 unregister_restart_handler(&pwrseq->reset_nb); 50 gpiod_put(pwrseq->reset_gpio); 51 kfree(pwrseq); 52} 53 54static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { 55 .post_power_on = mmc_pwrseq_emmc_reset, 56 .free = mmc_pwrseq_emmc_free, 57}; 58 59static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, 60 unsigned long mode, void *cmd) 61{ 62 struct mmc_pwrseq_emmc *pwrseq = container_of(this, 63 struct mmc_pwrseq_emmc, reset_nb); 64 65 __mmc_pwrseq_emmc_reset(pwrseq); 66 return NOTIFY_DONE; 67} 68 69struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, 70 struct device *dev) 71{ 72 struct mmc_pwrseq_emmc *pwrseq; 73 int ret = 0; 74 75 pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); 76 if (!pwrseq) 77 return ERR_PTR(-ENOMEM); 78 79 pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); 80 if (IS_ERR(pwrseq->reset_gpio)) { 81 ret = PTR_ERR(pwrseq->reset_gpio); 82 goto free; 83 } 84 85 /* 86 * register reset handler to ensure emmc reset also from 87 * emergency_reboot(), priority 129 schedules it just before 88 * system reboot 89 */ 90 pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; 91 pwrseq->reset_nb.priority = 129; 92 register_restart_handler(&pwrseq->reset_nb); 93 94 pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; 95 96 return &pwrseq->pwrseq; 97free: 98 kfree(pwrseq); 99 return ERR_PTR(ret); 100} 101