xref: /linux-6.15/drivers/mmc/core/pwrseq_simple.c (revision 934f1f48)
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