diff options
| author | Viktar Palstsiuk <viktar.palstsiuk@promwad.com> | 2013-10-31 11:16:59 +0300 | 
|---|---|---|
| committer | Tom Rini <trini@ti.com> | 2013-11-08 09:39:13 -0500 | 
| commit | 7d9ec6a0aff88b6d7d3b36c04ff1ae490324ebf1 (patch) | |
| tree | d679e1e4414795d8a81788a3bd5f248b10f24ebd | |
| parent | 3314204b665e42aac360a0f709561d2686ea2862 (diff) | |
| download | olio-uboot-2014.01-7d9ec6a0aff88b6d7d3b36c04ff1ae490324ebf1.tar.xz olio-uboot-2014.01-7d9ec6a0aff88b6d7d3b36c04ff1ae490324ebf1.zip | |
Add support for SX151x SPI GPIO Expanders
Signed-off-by: Viktar Palstsiuk <viktar.palstsiuk@promwad.com>
| -rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpio/sx151x.c | 242 | ||||
| -rw-r--r-- | include/sx151x.h | 17 | 
3 files changed, 260 insertions, 0 deletions
| diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1165793b5..b903c45c5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_S3C2440_GPIO)	+= s3c2440_gpio.o  obj-$(CONFIG_XILINX_GPIO)	+= xilinx_gpio.o  obj-$(CONFIG_ADI_GPIO2)	+= adi_gpio2.o  obj-$(CONFIG_TCA642X)		+= tca642x.o +oby-$(CONFIG_SX151X)		+= sx151x.o diff --git a/drivers/gpio/sx151x.c b/drivers/gpio/sx151x.c new file mode 100644 index 000000000..167cf40c7 --- /dev/null +++ b/drivers/gpio/sx151x.c @@ -0,0 +1,242 @@ +/* + * (C) Copyright 2013 + * Viktar Palstsiuk, Promwad, viktar.palstsiuk@promwad.com + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* + * Driver for Semtech SX151x SPI GPIO Expanders + */ + +#include <common.h> +#include <spi.h> +#include <sx151x.h> + +#ifndef CONFIG_SX151X_SPI_BUS +#define CONFIG_SX151X_SPI_BUS 0 +#endif + +/* + * The SX151x registers + */ + +#ifdef CONFIG_SX151X_GPIO_COUNT_8 +/* 8bit: SX1511 */ +#define SX151X_REG_DIR		0x07 +#define SX151X_REG_DATA		0x08 +#else +/* 16bit: SX1512 */ +#define SX151X_REG_DIR		0x0F +#define SX151X_REG_DATA		0x11 +#endif +#define SX151X_REG_RESET	0x7D + +static int sx151x_spi_write(int chip, unsigned char reg, unsigned char val) +{ +	struct spi_slave *slave; +	unsigned char buf[2]; +	int ret; + +	slave = spi_setup_slave(CONFIG_SX151X_SPI_BUS, chip, 1000000, +				SPI_MODE_0); +	if (!slave) +		return 0; + +	spi_claim_bus(slave); + +	buf[0] = reg; +	buf[1] = val; + +	ret = spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); +	if (ret < 0) +		printf("spi%d.%d write fail: can't write %02x to %02x: %d\n", +			CONFIG_SX151X_SPI_BUS, chip, val, reg, ret); +	else +		printf("spi%d.%d write 0x%02x to register 0x%02x\n", +		       CONFIG_SX151X_SPI_BUS, chip, val, reg); +	spi_release_bus(slave); +	spi_free_slave(slave); + +	return ret; +} + +static int sx151x_spi_read(int chip, unsigned char reg) +{ +	struct spi_slave *slave; +	int ret; + +	slave = spi_setup_slave(CONFIG_SX151X_SPI_BUS, chip, 1000000, +				SPI_MODE_0); +	if (!slave) +		return 0; + +	spi_claim_bus(slave); + +	ret = spi_w8r8(slave, reg | 0x80); +	if (ret < 0) +		printf("spi%d.%d read fail: can't read %02x: %d\n", +			CONFIG_SX151X_SPI_BUS, chip, reg, ret); +	else +		printf("spi%d.%d read register 0x%02x: 0x%02x\n", +		       CONFIG_SX151X_SPI_BUS, chip, reg, ret); + +	spi_release_bus(slave); +	spi_free_slave(slave); + +	return ret; +} + +static inline void sx151x_find_cfg(int gpio, unsigned char *reg, unsigned char *mask) +{ +	*reg   -= gpio / 8; +	*mask   = 1 << (gpio % 8); +} + +static int sx151x_write_cfg(int chip, unsigned char gpio, unsigned char reg, int val) +{ +	unsigned char  mask; +	unsigned char  data; +	int ret; + +	sx151x_find_cfg(gpio, ®, &mask); +	ret = sx151x_spi_read(chip, reg); +	if (ret < 0) +		return ret; +	else +		data = ret; +	data &= ~mask; +	data |= (val << (gpio % 8)) & mask; +	return sx151x_spi_write(chip, reg, data); +} + +int sx151x_get_value(int chip, int gpio) +{ +	unsigned char  reg = SX151X_REG_DATA; +	unsigned char  mask; +	int ret; + +	sx151x_find_cfg(gpio, ®, &mask); +	ret = sx151x_spi_read(chip, reg); +	if (ret >= 0) +		ret = (ret & mask) != 0 ? 1 : 0; + +	return ret; +} + +int sx151x_set_value(int chip, int gpio, int val) +{ +	return sx151x_write_cfg(chip, gpio, SX151X_REG_DATA, (val ? 1 : 0)); +} + +int sx151x_direction_input(int chip, int gpio) +{ +	return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 1); +} + +int sx151x_direction_output(int chip, int gpio) +{ +	return sx151x_write_cfg(chip, gpio, SX151X_REG_DIR, 0); +} + +int sx151x_reset(int chip) +{ +	int err; + +	err = sx151x_spi_write(chip, SX151X_REG_RESET, 0x12); +	if (err < 0) +		return err; + +	err = sx151x_spi_write(chip, SX151X_REG_RESET, 0x34); +	return err; +} + +#ifdef CONFIG_CMD_SX151X + +int do_sx151x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	int ret = CMD_RET_USAGE, chip = 0, gpio = 0, val = 0; + +	if (argc < 3) +		return CMD_RET_USAGE; + +	/* arg2 used as chip number */ +	chip = simple_strtoul(argv[2], NULL, 10); + +	if (strcmp(argv[1], "reset") == 0) { +		ret = sx151x_reset(chip); +		if (!ret) { +			printf("Device at spi%d.%d was reset\n", +			       CONFIG_SX151X_SPI_BUS, chip); +		} +		return ret; +	} + +	if (argc < 4) +		return CMD_RET_USAGE; + +	/* arg3 used as gpio number */ +	gpio = simple_strtoul(argv[3], NULL, 10); + +	if (strcmp(argv[1], "get") == 0) { +		ret = sx151x_get_value(chip, gpio); +		if (ret < 0) +			printf("Failed to get value at spi%d.%d gpio %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio); +		else { +			printf("Value at spi%d.%d gpio %d is %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio, ret); +			ret = 0; +		} +		return ret; +	} + +	if (argc < 5) +		return CMD_RET_USAGE; + +	/* arg4 used as value or direction */ +	val = simple_strtoul(argv[4], NULL, 10); + +	if (strcmp(argv[1], "set") == 0) { +		ret = sx151x_set_value(chip, gpio, val); +		if (ret < 0) +			printf("Failed to set value at spi%d.%d gpio %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio); +		else +			printf("New value at spi%d.%d gpio %d is %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio, val); +		return ret; +	} else if (strcmp(argv[1], "dir") == 0) { +		if (val == 0) +			ret = sx151x_direction_output(chip, gpio); +		else +			ret = sx151x_direction_input(chip, gpio); + +		if (ret < 0) +			printf("Failed to set direction of spi%d.%d gpio %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio); +		else +			printf("New direction of spi%d.%d gpio %d is %d\n", +			       CONFIG_SX151X_SPI_BUS, chip, gpio, val); +		return ret; +	} + +	printf("Please see usage\n"); + +	return ret; +} + +U_BOOT_CMD( +	sx151x,	5,	1,	do_sx151x, +	"sx151x gpio access", +	"dir chip gpio 0|1\n" +	"	- set gpio direction (0 for output, 1 for input)\n" +	"sx151x get chip gpio\n" +	"	- get gpio value\n" +	"sx151x set chip gpio 0|1\n" +	"	- set gpio value\n" +	"sx151x reset chip\n" +	"	- reset chip" +); + +#endif /* CONFIG_CMD_SX151X */ diff --git a/include/sx151x.h b/include/sx151x.h new file mode 100644 index 000000000..be42b0681 --- /dev/null +++ b/include/sx151x.h @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2013 + * Viktar Palstsiuk, Promwad, viktar.palstsiuk@promwad.com + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#ifndef __SX151X_H_ +#define __SX151X_H_ + +int sx151x_get_value(int chip, int gpio); +int sx151x_set_value(int chip, int gpio, int val); +int sx151x_direction_input(int chip, int gpio); +int sx151x_direction_output(int chip, int gpio); +int sx151x_reset(int chip); + +#endif /* __SX151X_H_ */ |