blob: 167cf40c7123a6549ed70a41a7cd90a68b9f4492 [file] [log] [blame]
Viktar Palstsiuk7d9ec6a2013-10-31 11:16:59 +03001/*
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
35static 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
64static 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
90static 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
96static 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, &reg, &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
113int 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, &reg, &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
127int 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
132int sx151x_direction_input(int chip, int gpio)
133{
134 return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 1);
135}
136
137int sx151x_direction_output(int chip, int gpio)
138{
139 return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 0);
140}
141
142int 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
156int 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
229U_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 */