mmc: pwrseq_simple: Extend to support more pins
[deliverable/linux.git] / drivers / mmc / core / pwrseq_simple.c
1 /*
2 * Copyright (C) 2014 Linaro Ltd
3 *
4 * Author: Ulf Hansson <ulf.hansson@linaro.org>
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 }
This page took 0.055554 seconds and 5 git commands to generate.