ARM: dts: npcm8xx: add npcm845 function node
[platform/kernel/u-boot.git] / drivers / gpio / zynqmp_gpio_modepin.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ZynqMP GPIO modepin driver
4  *
5  * Copyright (C) 2021 Xilinx, Inc.
6  */
7
8 #include <common.h>
9 #include <errno.h>
10 #include <asm/io.h>
11 #include <asm/gpio.h>
12 #include <dm.h>
13 #include <asm/arch/hardware.h>
14 #include <zynqmp_firmware.h>
15
16 #define OUTEN(pin)              (BIT(0) << (pin))
17 #define INVAL(pin)              (BIT(4) << (pin))
18 #define OUTVAL(pin)             (BIT(8) << (pin))
19
20 #define ZYNQMP_CRL_APB_BOOTPIN_CTRL_MASK        0xF0F
21 #define ZYNQMP_CRL_APB_BOOT_PIN_CTRL            (ZYNQMP_CRL_APB_BASEADDR + \
22                                                 (0x250U))
23
24 static int get_gpio_modepin(u32 *ret_payload)
25 {
26         return xilinx_pm_request(PM_MMIO_READ, ZYNQMP_CRL_APB_BOOT_PIN_CTRL,
27                                  0, 0, 0, ret_payload);
28 }
29
30 static int set_gpio_modepin(int val)
31 {
32         return xilinx_pm_request(PM_MMIO_WRITE, ZYNQMP_CRL_APB_BOOT_PIN_CTRL,
33                                  ZYNQMP_CRL_APB_BOOTPIN_CTRL_MASK,
34                                  val, 0, NULL);
35 }
36
37 static int modepin_gpio_direction_input(struct udevice *dev,
38                                         unsigned int offset)
39 {
40         return 0;
41 }
42
43 static int modepin_gpio_set_value(struct udevice *dev, unsigned int offset,
44                                   int value)
45 {
46         u32 ret_payload[PAYLOAD_ARG_CNT];
47         u32 out_val = 0;
48         int ret;
49
50         ret = get_gpio_modepin(ret_payload);
51         if (value)
52                 out_val = OUTVAL(offset) | ret_payload[1];
53         else
54                 out_val = ~OUTVAL(offset) & ret_payload[1];
55
56         return set_gpio_modepin(out_val);
57 }
58
59 static int modepin_gpio_direction_output(struct udevice *dev,
60                                          unsigned int offset, int value)
61 {
62         u32 ret_payload[PAYLOAD_ARG_CNT];
63         u32 out_en = 0;
64         int ret;
65
66         ret = get_gpio_modepin(ret_payload);
67         if (ret)
68                 return ret;
69
70         if (value)
71                 out_en = OUTEN(offset) | ret_payload[1];
72         else
73                 out_en = ~OUTEN(offset) & ret_payload[1];
74
75         ret = set_gpio_modepin(out_en);
76         if (ret)
77                 return ret;
78
79         return modepin_gpio_set_value(dev, offset, value);
80 }
81
82 static int modepin_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
83                               struct ofnode_phandle_args *args)
84 {
85         desc->offset = args->args[0];
86
87         return 0;
88 }
89
90 static int modepin_gpio_get_value(struct udevice *dev, unsigned int offset)
91 {
92         u32 ret_payload[PAYLOAD_ARG_CNT];
93         int ret;
94
95         ret = get_gpio_modepin(ret_payload);
96         if (ret)
97                 return ret;
98
99         return (INVAL(offset) & ret_payload[1]) ? 1 : 0;
100 }
101
102 static int modepin_gpio_get_function(struct udevice *dev, unsigned int offset)
103 {
104         u32 ret_payload[PAYLOAD_ARG_CNT];
105         int ret;
106
107         ret = get_gpio_modepin(ret_payload);
108         if (ret)
109                 return ret;
110
111         return (OUTEN(offset) & ret_payload[1]) ? GPIOF_OUTPUT : GPIOF_INPUT;
112 }
113
114 static const struct dm_gpio_ops modepin_gpio_ops = {
115         .direction_input = modepin_gpio_direction_input,
116         .direction_output = modepin_gpio_direction_output,
117         .get_value = modepin_gpio_get_value,
118         .set_value = modepin_gpio_set_value,
119         .get_function = modepin_gpio_get_function,
120         .xlate = modepin_gpio_xlate,
121 };
122
123 static int modepin_gpio_probe(struct udevice *dev)
124 {
125         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
126         const void *label_ptr;
127
128         label_ptr = dev_read_prop(dev, "label", NULL);
129         if (label_ptr) {
130                 uc_priv->bank_name = strdup(label_ptr);
131                 if (!uc_priv->bank_name)
132                         return -ENOMEM;
133         } else {
134                 uc_priv->bank_name = dev->name;
135         }
136
137         uc_priv->gpio_count = 4;
138
139         return 0;
140 }
141
142 static const struct udevice_id modepin_gpio_ids[] = {
143         { .compatible = "xlnx,zynqmp-gpio-modepin",},
144         { }
145 };
146
147 U_BOOT_DRIVER(modepin_gpio) = {
148         .name = "modepin_gpio",
149         .id = UCLASS_GPIO,
150         .ops = &modepin_gpio_ops,
151         .of_match = modepin_gpio_ids,
152         .probe = modepin_gpio_probe,
153 };