1 /* 2 * Copyright (C) 2014 Linaro Ltd 3 * 4 * Author: Ulf Hansson <[email protected]> 5 * 6 * License terms: GNU General Public License (GPL) version 2 7 * 8 * Simple MMC power sequence management 9 */ 10 #include <linux/kernel.h> 11 #include <linux/slab.h> 12 #include <linux/device.h> 13 #include <linux/err.h> 14 #include <linux/of_gpio.h> 15 #include <linux/gpio/consumer.h> 16 17 #include <linux/mmc/host.h> 18 19 #include "pwrseq.h" 20 21 struct mmc_pwrseq_simple { 22 struct mmc_pwrseq pwrseq; 23 int nr_gpios; 24 struct gpio_desc *reset_gpios[0]; 25 }; 26 27 static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, 28 int value) 29 { 30 int i; 31 32 for (i = 0; i < pwrseq->nr_gpios; i++) 33 if (!IS_ERR(pwrseq->reset_gpios[i])) 34 gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value); 35 } 36 37 static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) 38 { 39 struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, 40 struct mmc_pwrseq_simple, pwrseq); 41 42 mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); 43 } 44 45 static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) 46 { 47 struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, 48 struct mmc_pwrseq_simple, pwrseq); 49 50 mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); 51 } 52 53 static void mmc_pwrseq_simple_free(struct mmc_host *host) 54 { 55 struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, 56 struct mmc_pwrseq_simple, pwrseq); 57 int i; 58 59 for (i = 0; i < pwrseq->nr_gpios; i++) 60 if (!IS_ERR(pwrseq->reset_gpios[i])) 61 gpiod_put(pwrseq->reset_gpios[i]); 62 63 kfree(pwrseq); 64 host->pwrseq = NULL; 65 } 66 67 static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { 68 .pre_power_on = mmc_pwrseq_simple_pre_power_on, 69 .post_power_on = mmc_pwrseq_simple_post_power_on, 70 .power_off = mmc_pwrseq_simple_pre_power_on, 71 .free = mmc_pwrseq_simple_free, 72 }; 73 74 int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) 75 { 76 struct mmc_pwrseq_simple *pwrseq; 77 int i, nr_gpios, ret = 0; 78 79 nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios"); 80 if (nr_gpios < 0) 81 nr_gpios = 0; 82 83 pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios * 84 sizeof(struct gpio_desc *), GFP_KERNEL); 85 if (!pwrseq) 86 return -ENOMEM; 87 88 for (i = 0; i < nr_gpios; i++) { 89 pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, 90 GPIOD_OUT_HIGH); 91 if (IS_ERR(pwrseq->reset_gpios[i]) && 92 PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT && 93 PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) { 94 ret = PTR_ERR(pwrseq->reset_gpios[i]); 95 96 while (--i) 97 gpiod_put(pwrseq->reset_gpios[i]); 98 99 goto free; 100 } 101 } 102 103 pwrseq->nr_gpios = nr_gpios; 104 pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; 105 host->pwrseq = &pwrseq->pwrseq; 106 107 return 0; 108 free: 109 kfree(pwrseq); 110 return ret; 111 } 112