]>
Commit | Line | Data |
---|---|---|
efad6cf8 SW |
1 | /* |
2 | * Copyright (C) 2012 Vikram Narayananan | |
3 | * <vikram186@gmail.com> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
efad6cf8 SW |
6 | */ |
7 | ||
8 | #include <common.h> | |
41e98e01 SG |
9 | #include <dm.h> |
10 | #include <errno.h> | |
efad6cf8 SW |
11 | #include <asm/gpio.h> |
12 | #include <asm/io.h> | |
4faf5f93 | 13 | #include <fdtdec.h> |
efad6cf8 | 14 | |
41e98e01 | 15 | struct bcm2835_gpios { |
41e98e01 SG |
16 | struct bcm2835_gpio_regs *reg; |
17 | }; | |
18 | ||
41e98e01 SG |
19 | static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio) |
20 | { | |
21 | struct bcm2835_gpios *gpios = dev_get_priv(dev); | |
efad6cf8 SW |
22 | unsigned val; |
23 | ||
41e98e01 | 24 | val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); |
efad6cf8 SW |
25 | val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio)); |
26 | val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio)); | |
41e98e01 | 27 | writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); |
efad6cf8 SW |
28 | |
29 | return 0; | |
30 | } | |
31 | ||
41e98e01 SG |
32 | static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned gpio, |
33 | int value) | |
efad6cf8 | 34 | { |
41e98e01 | 35 | struct bcm2835_gpios *gpios = dev_get_priv(dev); |
efad6cf8 SW |
36 | unsigned val; |
37 | ||
38 | gpio_set_value(gpio, value); | |
39 | ||
41e98e01 | 40 | val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); |
efad6cf8 SW |
41 | val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio)); |
42 | val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio)); | |
41e98e01 | 43 | writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); |
efad6cf8 SW |
44 | |
45 | return 0; | |
46 | } | |
47 | ||
41e98e01 | 48 | static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio) |
efad6cf8 | 49 | { |
efad6cf8 SW |
50 | unsigned val; |
51 | ||
41e98e01 | 52 | val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]); |
efad6cf8 SW |
53 | |
54 | return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1; | |
55 | } | |
56 | ||
41e98e01 | 57 | static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio) |
efad6cf8 | 58 | { |
41e98e01 SG |
59 | const struct bcm2835_gpios *gpios = dev_get_priv(dev); |
60 | ||
61 | return bcm2835_get_value(gpios, gpio); | |
62 | } | |
63 | ||
64 | static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio, | |
65 | int value) | |
66 | { | |
67 | struct bcm2835_gpios *gpios = dev_get_priv(dev); | |
68 | u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr; | |
efad6cf8 SW |
69 | |
70 | writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio), | |
71 | &output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]); | |
72 | ||
73 | return 0; | |
74 | } | |
41e98e01 | 75 | |
04a993fe | 76 | int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned gpio) |
41e98e01 SG |
77 | { |
78 | struct bcm2835_gpios *gpios = dev_get_priv(dev); | |
04a993fe AG |
79 | u32 val; |
80 | ||
81 | val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); | |
82 | ||
83 | return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK); | |
84 | } | |
85 | ||
86 | static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset) | |
87 | { | |
88 | int funcid = bcm2835_gpio_get_func_id(dev, offset); | |
41e98e01 | 89 | |
04a993fe AG |
90 | switch (funcid) { |
91 | case BCM2835_GPIO_OUTPUT: | |
41e98e01 | 92 | return GPIOF_OUTPUT; |
04a993fe | 93 | case BCM2835_GPIO_INPUT: |
41e98e01 | 94 | return GPIOF_INPUT; |
04a993fe AG |
95 | default: |
96 | return GPIOF_FUNC; | |
97 | } | |
41e98e01 SG |
98 | } |
99 | ||
41e98e01 SG |
100 | |
101 | static const struct dm_gpio_ops gpio_bcm2835_ops = { | |
41e98e01 SG |
102 | .direction_input = bcm2835_gpio_direction_input, |
103 | .direction_output = bcm2835_gpio_direction_output, | |
104 | .get_value = bcm2835_gpio_get_value, | |
105 | .set_value = bcm2835_gpio_set_value, | |
106 | .get_function = bcm2835_gpio_get_function, | |
41e98e01 SG |
107 | }; |
108 | ||
109 | static int bcm2835_gpio_probe(struct udevice *dev) | |
110 | { | |
111 | struct bcm2835_gpios *gpios = dev_get_priv(dev); | |
112 | struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev); | |
e564f054 | 113 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); |
41e98e01 SG |
114 | |
115 | uc_priv->bank_name = "GPIO"; | |
116 | uc_priv->gpio_count = BCM2835_GPIO_COUNT; | |
117 | gpios->reg = (struct bcm2835_gpio_regs *)plat->base; | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
4faf5f93 FV |
122 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
123 | static const struct udevice_id bcm2835_gpio_id[] = { | |
124 | {.compatible = "brcm,bcm2835-gpio"}, | |
125 | {} | |
126 | }; | |
127 | ||
128 | static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev) | |
129 | { | |
130 | struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev); | |
131 | fdt_addr_t addr; | |
132 | ||
133 | addr = dev_get_addr(dev); | |
134 | if (addr == FDT_ADDR_T_NONE) | |
135 | return -EINVAL; | |
136 | ||
137 | plat->base = addr; | |
138 | return 0; | |
139 | } | |
140 | #endif | |
141 | ||
41e98e01 SG |
142 | U_BOOT_DRIVER(gpio_bcm2835) = { |
143 | .name = "gpio_bcm2835", | |
144 | .id = UCLASS_GPIO, | |
4faf5f93 FV |
145 | .of_match = of_match_ptr(bcm2835_gpio_id), |
146 | .ofdata_to_platdata = of_match_ptr(bcm2835_gpio_ofdata_to_platdata), | |
147 | .platdata_auto_alloc_size = sizeof(struct bcm2835_gpio_platdata), | |
41e98e01 SG |
148 | .ops = &gpio_bcm2835_ops, |
149 | .probe = bcm2835_gpio_probe, | |
601147b0 | 150 | .flags = DM_FLAG_PRE_RELOC, |
41e98e01 SG |
151 | .priv_auto_alloc_size = sizeof(struct bcm2835_gpios), |
152 | }; |