]>
Commit | Line | Data |
---|---|---|
7d9ec6a0 VP |
1 | /* |
2 | * (C) Copyright 2013 | |
3 | * Viktar Palstsiuk, Promwad, viktar.palstsiuk@promwad.com | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Driver for Semtech SX151x SPI GPIO Expanders | |
10 | */ | |
11 | ||
12 | #include <common.h> | |
13 | #include <spi.h> | |
14 | #include <sx151x.h> | |
15 | ||
16 | #ifndef CONFIG_SX151X_SPI_BUS | |
17 | #define CONFIG_SX151X_SPI_BUS 0 | |
18 | #endif | |
19 | ||
20 | /* | |
21 | * The SX151x registers | |
22 | */ | |
23 | ||
24 | #ifdef CONFIG_SX151X_GPIO_COUNT_8 | |
25 | /* 8bit: SX1511 */ | |
26 | #define SX151X_REG_DIR 0x07 | |
27 | #define SX151X_REG_DATA 0x08 | |
28 | #else | |
29 | /* 16bit: SX1512 */ | |
30 | #define SX151X_REG_DIR 0x0F | |
31 | #define SX151X_REG_DATA 0x11 | |
32 | #endif | |
33 | #define SX151X_REG_RESET 0x7D | |
34 | ||
35 | static int sx151x_spi_write(int chip, unsigned char reg, unsigned char val) | |
36 | { | |
37 | struct spi_slave *slave; | |
38 | unsigned char buf[2]; | |
39 | int ret; | |
40 | ||
41 | slave = spi_setup_slave(CONFIG_SX151X_SPI_BUS, chip, 1000000, | |
42 | SPI_MODE_0); | |
43 | if (!slave) | |
44 | return 0; | |
45 | ||
46 | spi_claim_bus(slave); | |
47 | ||
48 | buf[0] = reg; | |
49 | buf[1] = val; | |
50 | ||
51 | ret = spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); | |
52 | if (ret < 0) | |
53 | printf("spi%d.%d write fail: can't write %02x to %02x: %d\n", | |
54 | CONFIG_SX151X_SPI_BUS, chip, val, reg, ret); | |
55 | else | |
56 | printf("spi%d.%d write 0x%02x to register 0x%02x\n", | |
57 | CONFIG_SX151X_SPI_BUS, chip, val, reg); | |
58 | spi_release_bus(slave); | |
59 | spi_free_slave(slave); | |
60 | ||
61 | return ret; | |
62 | } | |
63 | ||
64 | static int sx151x_spi_read(int chip, unsigned char reg) | |
65 | { | |
66 | struct spi_slave *slave; | |
67 | int ret; | |
68 | ||
69 | slave = spi_setup_slave(CONFIG_SX151X_SPI_BUS, chip, 1000000, | |
70 | SPI_MODE_0); | |
71 | if (!slave) | |
72 | return 0; | |
73 | ||
74 | spi_claim_bus(slave); | |
75 | ||
76 | ret = spi_w8r8(slave, reg | 0x80); | |
77 | if (ret < 0) | |
78 | printf("spi%d.%d read fail: can't read %02x: %d\n", | |
79 | CONFIG_SX151X_SPI_BUS, chip, reg, ret); | |
80 | else | |
81 | printf("spi%d.%d read register 0x%02x: 0x%02x\n", | |
82 | CONFIG_SX151X_SPI_BUS, chip, reg, ret); | |
83 | ||
84 | spi_release_bus(slave); | |
85 | spi_free_slave(slave); | |
86 | ||
87 | return ret; | |
88 | } | |
89 | ||
90 | static inline void sx151x_find_cfg(int gpio, unsigned char *reg, unsigned char *mask) | |
91 | { | |
92 | *reg -= gpio / 8; | |
93 | *mask = 1 << (gpio % 8); | |
94 | } | |
95 | ||
96 | static int sx151x_write_cfg(int chip, unsigned char gpio, unsigned char reg, int val) | |
97 | { | |
98 | unsigned char mask; | |
99 | unsigned char data; | |
100 | int ret; | |
101 | ||
102 | sx151x_find_cfg(gpio, ®, &mask); | |
103 | ret = sx151x_spi_read(chip, reg); | |
104 | if (ret < 0) | |
105 | return ret; | |
106 | else | |
107 | data = ret; | |
108 | data &= ~mask; | |
109 | data |= (val << (gpio % 8)) & mask; | |
110 | return sx151x_spi_write(chip, reg, data); | |
111 | } | |
112 | ||
113 | int sx151x_get_value(int chip, int gpio) | |
114 | { | |
115 | unsigned char reg = SX151X_REG_DATA; | |
116 | unsigned char mask; | |
117 | int ret; | |
118 | ||
119 | sx151x_find_cfg(gpio, ®, &mask); | |
120 | ret = sx151x_spi_read(chip, reg); | |
121 | if (ret >= 0) | |
122 | ret = (ret & mask) != 0 ? 1 : 0; | |
123 | ||
124 | return ret; | |
125 | } | |
126 | ||
127 | int sx151x_set_value(int chip, int gpio, int val) | |
128 | { | |
129 | return sx151x_write_cfg(chip, gpio, SX151X_REG_DATA, (val ? 1 : 0)); | |
130 | } | |
131 | ||
132 | int sx151x_direction_input(int chip, int gpio) | |
133 | { | |
134 | return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 1); | |
135 | } | |
136 | ||
137 | int sx151x_direction_output(int chip, int gpio) | |
138 | { | |
139 | return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 0); | |
140 | } | |
141 | ||
142 | int sx151x_reset(int chip) | |
143 | { | |
144 | int err; | |
145 | ||
146 | err = sx151x_spi_write(chip, SX151X_REG_RESET, 0x12); | |
147 | if (err < 0) | |
148 | return err; | |
149 | ||
150 | err = sx151x_spi_write(chip, SX151X_REG_RESET, 0x34); | |
151 | return err; | |
152 | } | |
153 | ||
154 | #ifdef CONFIG_CMD_SX151X | |
155 | ||
156 | int do_sx151x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
157 | { | |
158 | int ret = CMD_RET_USAGE, chip = 0, gpio = 0, val = 0; | |
159 | ||
160 | if (argc < 3) | |
161 | return CMD_RET_USAGE; | |
162 | ||
163 | /* arg2 used as chip number */ | |
164 | chip = simple_strtoul(argv[2], NULL, 10); | |
165 | ||
166 | if (strcmp(argv[1], "reset") == 0) { | |
167 | ret = sx151x_reset(chip); | |
168 | if (!ret) { | |
169 | printf("Device at spi%d.%d was reset\n", | |
170 | CONFIG_SX151X_SPI_BUS, chip); | |
171 | } | |
172 | return ret; | |
173 | } | |
174 | ||
175 | if (argc < 4) | |
176 | return CMD_RET_USAGE; | |
177 | ||
178 | /* arg3 used as gpio number */ | |
179 | gpio = simple_strtoul(argv[3], NULL, 10); | |
180 | ||
181 | if (strcmp(argv[1], "get") == 0) { | |
182 | ret = sx151x_get_value(chip, gpio); | |
183 | if (ret < 0) | |
184 | printf("Failed to get value at spi%d.%d gpio %d\n", | |
185 | CONFIG_SX151X_SPI_BUS, chip, gpio); | |
186 | else { | |
187 | printf("Value at spi%d.%d gpio %d is %d\n", | |
188 | CONFIG_SX151X_SPI_BUS, chip, gpio, ret); | |
189 | ret = 0; | |
190 | } | |
191 | return ret; | |
192 | } | |
193 | ||
194 | if (argc < 5) | |
195 | return CMD_RET_USAGE; | |
196 | ||
197 | /* arg4 used as value or direction */ | |
198 | val = simple_strtoul(argv[4], NULL, 10); | |
199 | ||
200 | if (strcmp(argv[1], "set") == 0) { | |
201 | ret = sx151x_set_value(chip, gpio, val); | |
202 | if (ret < 0) | |
203 | printf("Failed to set value at spi%d.%d gpio %d\n", | |
204 | CONFIG_SX151X_SPI_BUS, chip, gpio); | |
205 | else | |
206 | printf("New value at spi%d.%d gpio %d is %d\n", | |
207 | CONFIG_SX151X_SPI_BUS, chip, gpio, val); | |
208 | return ret; | |
209 | } else if (strcmp(argv[1], "dir") == 0) { | |
210 | if (val == 0) | |
211 | ret = sx151x_direction_output(chip, gpio); | |
212 | else | |
213 | ret = sx151x_direction_input(chip, gpio); | |
214 | ||
215 | if (ret < 0) | |
216 | printf("Failed to set direction of spi%d.%d gpio %d\n", | |
217 | CONFIG_SX151X_SPI_BUS, chip, gpio); | |
218 | else | |
219 | printf("New direction of spi%d.%d gpio %d is %d\n", | |
220 | CONFIG_SX151X_SPI_BUS, chip, gpio, val); | |
221 | return ret; | |
222 | } | |
223 | ||
224 | printf("Please see usage\n"); | |
225 | ||
226 | return ret; | |
227 | } | |
228 | ||
229 | U_BOOT_CMD( | |
230 | sx151x, 5, 1, do_sx151x, | |
231 | "sx151x gpio access", | |
232 | "dir chip gpio 0|1\n" | |
233 | " - set gpio direction (0 for output, 1 for input)\n" | |
234 | "sx151x get chip gpio\n" | |
235 | " - get gpio value\n" | |
236 | "sx151x set chip gpio 0|1\n" | |
237 | " - set gpio value\n" | |
238 | "sx151x reset chip\n" | |
239 | " - reset chip" | |
240 | ); | |
241 | ||
242 | #endif /* CONFIG_CMD_SX151X */ |