]>
Commit | Line | Data |
---|---|---|
81a87e18 MK |
1 | /* |
2 | * Qualcomm GPIO driver | |
3 | * | |
4 | * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> | |
5 | * | |
6 | * SPDX-License-Identifier: GPL-2.0+ | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <dm.h> | |
11 | #include <errno.h> | |
12 | #include <asm/gpio.h> | |
13 | #include <asm/io.h> | |
14 | ||
15 | DECLARE_GLOBAL_DATA_PTR; | |
16 | ||
17 | /* Register offsets */ | |
18 | #define GPIO_CONFIG_OFF(no) ((no) * 0x1000) | |
19 | #define GPIO_IN_OUT_OFF(no) ((no) * 0x1000 + 0x4) | |
20 | ||
21 | /* OE */ | |
22 | #define GPIO_OE_DISABLE (0x0 << 9) | |
23 | #define GPIO_OE_ENABLE (0x1 << 9) | |
24 | #define GPIO_OE_MASK (0x1 << 9) | |
25 | ||
26 | /* GPIO_IN_OUT register shifts. */ | |
27 | #define GPIO_IN 0 | |
28 | #define GPIO_OUT 1 | |
29 | ||
30 | struct msm_gpio_bank { | |
31 | phys_addr_t base; | |
32 | }; | |
33 | ||
34 | static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) | |
35 | { | |
36 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
37 | phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio); | |
38 | ||
39 | /* Disable OE bit */ | |
40 | clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE); | |
41 | ||
42 | return 0; | |
43 | } | |
44 | ||
45 | static int msm_gpio_set_value(struct udevice *dev, unsigned gpio, int value) | |
46 | { | |
47 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
48 | ||
49 | value = !!value; | |
50 | /* set value */ | |
51 | writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio)); | |
52 | ||
53 | return 0; | |
54 | } | |
55 | ||
56 | static int msm_gpio_direction_output(struct udevice *dev, unsigned gpio, | |
57 | int value) | |
58 | { | |
59 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
60 | phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio); | |
61 | ||
62 | value = !!value; | |
63 | /* set value */ | |
64 | writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio)); | |
65 | /* switch direction */ | |
66 | clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_ENABLE); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
71 | static int msm_gpio_get_value(struct udevice *dev, unsigned gpio) | |
72 | { | |
73 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
74 | ||
75 | return !!(readl(priv->base + GPIO_IN_OUT_OFF(gpio)) >> GPIO_IN); | |
76 | } | |
77 | ||
78 | static int msm_gpio_get_function(struct udevice *dev, unsigned offset) | |
79 | { | |
80 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
81 | ||
82 | if (readl(priv->base + GPIO_CONFIG_OFF(offset)) & GPIO_OE_ENABLE) | |
83 | return GPIOF_OUTPUT; | |
84 | ||
85 | return GPIOF_INPUT; | |
86 | } | |
87 | ||
88 | static const struct dm_gpio_ops gpio_msm_ops = { | |
89 | .direction_input = msm_gpio_direction_input, | |
90 | .direction_output = msm_gpio_direction_output, | |
91 | .get_value = msm_gpio_get_value, | |
92 | .set_value = msm_gpio_set_value, | |
93 | .get_function = msm_gpio_get_function, | |
94 | }; | |
95 | ||
96 | static int msm_gpio_probe(struct udevice *dev) | |
97 | { | |
98 | struct msm_gpio_bank *priv = dev_get_priv(dev); | |
99 | ||
a821c4af | 100 | priv->base = devfdt_get_addr(dev); |
81a87e18 MK |
101 | |
102 | return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0; | |
103 | } | |
104 | ||
105 | static int msm_gpio_ofdata_to_platdata(struct udevice *dev) | |
106 | { | |
107 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
108 | ||
e160f7d4 | 109 | uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
81a87e18 | 110 | "gpio-count", 0); |
e160f7d4 | 111 | uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), |
81a87e18 MK |
112 | "gpio-bank-name", NULL); |
113 | if (uc_priv->bank_name == NULL) | |
114 | uc_priv->bank_name = "soc"; | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | static const struct udevice_id msm_gpio_ids[] = { | |
120 | { .compatible = "qcom,msm8916-pinctrl" }, | |
121 | { .compatible = "qcom,apq8016-pinctrl" }, | |
122 | { } | |
123 | }; | |
124 | ||
125 | U_BOOT_DRIVER(gpio_msm) = { | |
126 | .name = "gpio_msm", | |
127 | .id = UCLASS_GPIO, | |
128 | .of_match = msm_gpio_ids, | |
129 | .ofdata_to_platdata = msm_gpio_ofdata_to_platdata, | |
130 | .probe = msm_gpio_probe, | |
131 | .ops = &gpio_msm_ops, | |
132 | .priv_auto_alloc_size = sizeof(struct msm_gpio_bank), | |
133 | }; |