Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc5 119 lines 3.0 kB view raw
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/init.h> 13#include <linux/platform_device.h> 14#include <linux/module.h> 15#include <linux/slab.h> 16#include <linux/device.h> 17#include <linux/err.h> 18#include <linux/gpio/consumer.h> 19#include <linux/reboot.h> 20 21#include <linux/mmc/host.h> 22 23#include "pwrseq.h" 24 25struct mmc_pwrseq_emmc { 26 struct mmc_pwrseq pwrseq; 27 struct notifier_block reset_nb; 28 struct gpio_desc *reset_gpio; 29}; 30 31#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) 32 33static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) 34{ 35 gpiod_set_value(pwrseq->reset_gpio, 1); 36 udelay(1); 37 gpiod_set_value(pwrseq->reset_gpio, 0); 38 udelay(200); 39} 40 41static void mmc_pwrseq_emmc_reset(struct mmc_host *host) 42{ 43 struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); 44 45 __mmc_pwrseq_emmc_reset(pwrseq); 46} 47 48static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, 49 unsigned long mode, void *cmd) 50{ 51 struct mmc_pwrseq_emmc *pwrseq = container_of(this, 52 struct mmc_pwrseq_emmc, reset_nb); 53 54 __mmc_pwrseq_emmc_reset(pwrseq); 55 return NOTIFY_DONE; 56} 57 58static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { 59 .post_power_on = mmc_pwrseq_emmc_reset, 60}; 61 62static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) 63{ 64 struct mmc_pwrseq_emmc *pwrseq; 65 struct device *dev = &pdev->dev; 66 67 pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); 68 if (!pwrseq) 69 return -ENOMEM; 70 71 pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 72 if (IS_ERR(pwrseq->reset_gpio)) 73 return PTR_ERR(pwrseq->reset_gpio); 74 75 /* 76 * register reset handler to ensure emmc reset also from 77 * emergency_reboot(), priority 255 is the highest priority 78 * so it will be executed before any system reboot handler. 79 */ 80 pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; 81 pwrseq->reset_nb.priority = 255; 82 register_restart_handler(&pwrseq->reset_nb); 83 84 pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; 85 pwrseq->pwrseq.dev = dev; 86 pwrseq->pwrseq.owner = THIS_MODULE; 87 platform_set_drvdata(pdev, pwrseq); 88 89 return mmc_pwrseq_register(&pwrseq->pwrseq); 90} 91 92static int mmc_pwrseq_emmc_remove(struct platform_device *pdev) 93{ 94 struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev); 95 96 unregister_restart_handler(&pwrseq->reset_nb); 97 mmc_pwrseq_unregister(&pwrseq->pwrseq); 98 99 return 0; 100} 101 102static const struct of_device_id mmc_pwrseq_emmc_of_match[] = { 103 { .compatible = "mmc-pwrseq-emmc",}, 104 {/* sentinel */}, 105}; 106 107MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match); 108 109static struct platform_driver mmc_pwrseq_emmc_driver = { 110 .probe = mmc_pwrseq_emmc_probe, 111 .remove = mmc_pwrseq_emmc_remove, 112 .driver = { 113 .name = "pwrseq_emmc", 114 .of_match_table = mmc_pwrseq_emmc_of_match, 115 }, 116}; 117 118module_platform_driver(mmc_pwrseq_emmc_driver); 119MODULE_LICENSE("GPL v2");