245b43f5351a9c88bae8dd88f58b8aa2c1a42edd
[platform/kernel/u-boot.git] / drivers / gpio / mpc83xx_spisel_boot.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2019 DEIF A/S
4  *
5  * GPIO driver to set/clear SPISEL_BOOT pin on mpc83xx.
6  */
7
8 #include <common.h>
9 #include <log.h>
10 #include <dm.h>
11 #include <mapmem.h>
12 #include <asm/gpio.h>
13
14 struct mpc83xx_spisel_boot {
15         u32 __iomem *spi_cs;
16         ulong addr;
17         uint gpio_count;
18         ulong type;
19 };
20
21 static u32 gpio_mask(uint gpio)
22 {
23         return (1U << (31 - (gpio)));
24 }
25
26 static int mpc83xx_spisel_boot_direction_input(struct udevice *dev, uint gpio)
27 {
28         return -EINVAL;
29 }
30
31 static int mpc83xx_spisel_boot_set_value(struct udevice *dev, uint gpio, int value)
32 {
33         struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
34
35         debug("%s: gpio=%d, value=%u, gpio_mask=0x%08x\n", __func__,
36               gpio, value, gpio_mask(gpio));
37
38         if (value)
39                 setbits_be32(data->spi_cs, gpio_mask(gpio));
40         else
41                 clrbits_be32(data->spi_cs, gpio_mask(gpio));
42
43         return 0;
44 }
45
46 static int mpc83xx_spisel_boot_direction_output(struct udevice *dev, uint gpio, int value)
47 {
48         return 0;
49 }
50
51 static int mpc83xx_spisel_boot_get_value(struct udevice *dev, uint gpio)
52 {
53         struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
54
55         return !!(in_be32(data->spi_cs) & gpio_mask(gpio));
56 }
57
58 static int mpc83xx_spisel_boot_get_function(struct udevice *dev, uint gpio)
59 {
60         return GPIOF_OUTPUT;
61 }
62
63 #if CONFIG_IS_ENABLED(OF_CONTROL)
64 static int mpc83xx_spisel_boot_ofdata_to_platdata(struct udevice *dev)
65 {
66         struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
67         fdt_addr_t addr;
68         u32 reg[2];
69
70         dev_read_u32_array(dev, "reg", reg, 2);
71         addr = dev_translate_address(dev, reg);
72
73         plat->addr = addr;
74         plat->size = reg[1];
75         plat->ngpios = dev_read_u32_default(dev, "ngpios", 1);
76
77         return 0;
78 }
79 #endif
80
81 static int mpc83xx_spisel_boot_platdata_to_priv(struct udevice *dev)
82 {
83         struct mpc83xx_spisel_boot *priv = dev_get_priv(dev);
84         struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
85         unsigned long size = plat->size;
86         ulong driver_data = dev_get_driver_data(dev);
87
88         if (size == 0)
89                 size = 0x04;
90
91         priv->addr = plat->addr;
92         priv->spi_cs = map_sysmem(plat->addr, size);
93
94         if (!priv->spi_cs)
95                 return -ENOMEM;
96
97         priv->gpio_count = plat->ngpios;
98
99         priv->type = driver_data;
100
101         return 0;
102 }
103
104 static int mpc83xx_spisel_boot_probe(struct udevice *dev)
105 {
106         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
107         struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
108         char name[32], *str;
109
110         mpc83xx_spisel_boot_platdata_to_priv(dev);
111
112         snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
113         str = strdup(name);
114
115         if (!str)
116                 return -ENOMEM;
117
118         uc_priv->bank_name = str;
119         uc_priv->gpio_count = data->gpio_count;
120
121         return 0;
122 }
123
124 static const struct dm_gpio_ops mpc83xx_spisel_boot_ops = {
125         .direction_input        = mpc83xx_spisel_boot_direction_input,
126         .direction_output       = mpc83xx_spisel_boot_direction_output,
127         .get_value              = mpc83xx_spisel_boot_get_value,
128         .set_value              = mpc83xx_spisel_boot_set_value,
129         .get_function           = mpc83xx_spisel_boot_get_function,
130 };
131
132 static const struct udevice_id mpc83xx_spisel_boot_ids[] = {
133         { .compatible = "fsl,mpc8309-spisel-boot" },
134         { .compatible = "fsl,mpc83xx-spisel-boot" },
135         { /* sentinel */ }
136 };
137
138 U_BOOT_DRIVER(spisel_boot_mpc83xx) = {
139         .name   = "spisel_boot_mpc83xx",
140         .id     = UCLASS_GPIO,
141         .ops    = &mpc83xx_spisel_boot_ops,
142 #if CONFIG_IS_ENABLED(OF_CONTROL)
143         .ofdata_to_platdata = mpc83xx_spisel_boot_ofdata_to_platdata,
144         .plat_auto      = sizeof(struct mpc8xxx_gpio_plat),
145         .of_match = mpc83xx_spisel_boot_ids,
146 #endif
147         .probe  = mpc83xx_spisel_boot_probe,
148         .priv_auto      = sizeof(struct mpc83xx_spisel_boot),
149 };