diff options
Diffstat (limited to 'drivers/spi/spi-xcomm.c')
| -rw-r--r-- | drivers/spi/spi-xcomm.c | 75 | 
1 files changed, 57 insertions, 18 deletions
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 63354dd3110f..846f00e23b71 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -10,6 +10,7 @@  #include <linux/module.h>  #include <linux/delay.h>  #include <linux/i2c.h> +#include <linux/gpio/driver.h>  #include <linux/spi/spi.h>  #include <asm/unaligned.h> @@ -26,24 +27,63 @@  #define SPI_XCOMM_CMD_UPDATE_CONFIG	0x03  #define SPI_XCOMM_CMD_WRITE		0x04 +#define SPI_XCOMM_CMD_GPIO_SET		0x05  #define SPI_XCOMM_CLOCK 48000000  struct spi_xcomm {  	struct i2c_client *i2c; -	uint16_t settings; -	uint16_t chipselect; +	struct gpio_chip gc; + +	u16 settings; +	u16 chipselect;  	unsigned int current_speed; -	uint8_t buf[63]; +	u8 buf[63];  }; +static void spi_xcomm_gpio_set_value(struct gpio_chip *chip, +				     unsigned int offset, int val) +{ +	struct spi_xcomm *spi_xcomm = gpiochip_get_data(chip); +	unsigned char buf[2]; + +	buf[0] = SPI_XCOMM_CMD_GPIO_SET; +	buf[1] = !!val; + +	i2c_master_send(spi_xcomm->i2c, buf, 2); +} + +static int spi_xcomm_gpio_get_direction(struct gpio_chip *chip, +					unsigned int offset) +{ +	return GPIO_LINE_DIRECTION_OUT; +} + +static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm) +{ +	struct device *dev = &spi_xcomm->i2c->dev; + +	if (!IS_ENABLED(CONFIG_GPIOLIB)) +		return 0; + +	spi_xcomm->gc.get_direction = spi_xcomm_gpio_get_direction; +	spi_xcomm->gc.set = spi_xcomm_gpio_set_value; +	spi_xcomm->gc.can_sleep = 1; +	spi_xcomm->gc.base = -1; +	spi_xcomm->gc.ngpio = 1; +	spi_xcomm->gc.label = spi_xcomm->i2c->name; +	spi_xcomm->gc.owner = THIS_MODULE; + +	return devm_gpiochip_add_data(dev, &spi_xcomm->gc, spi_xcomm); +} +  static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)  { -	uint16_t settings; -	uint8_t *buf = spi_xcomm->buf; +	u16 settings; +	u8 *buf = spi_xcomm->buf;  	settings = spi_xcomm->settings;  	settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET; @@ -56,10 +96,10 @@ static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)  }  static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, -	struct spi_device *spi, int is_active) +				 struct spi_device *spi, int is_active)  {  	unsigned long cs = spi_get_chipselect(spi, 0); -	uint16_t chipselect = spi_xcomm->chipselect; +	u16 chipselect = spi_xcomm->chipselect;  	if (is_active)  		chipselect |= BIT(cs); @@ -70,7 +110,8 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,  }  static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, -	struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) +				    struct spi_device *spi, struct spi_transfer *t, +				    unsigned int *settings)  {  	if (t->len > 62)  		return -EINVAL; @@ -108,7 +149,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,  }  static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, -	struct spi_device *spi, struct spi_transfer *t) +			       struct spi_device *spi, struct spi_transfer *t)  {  	int ret; @@ -119,13 +160,13 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,  		ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1);  		if (ret < 0)  			return ret; -		else if (ret != t->len + 1) +		if (ret != t->len + 1)  			return -EIO;  	} else if (t->rx_buf) {  		ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len);  		if (ret < 0)  			return ret; -		else if (ret != t->len) +		if (ret != t->len)  			return -EIO;  	} @@ -133,12 +174,12 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,  }  static int spi_xcomm_transfer_one(struct spi_controller *host, -	struct spi_message *msg) +				  struct spi_message *msg)  {  	struct spi_xcomm *spi_xcomm = spi_controller_get_devdata(host);  	unsigned int settings = spi_xcomm->settings;  	struct spi_device *spi = msg->spi; -	unsigned cs_change = 0; +	unsigned int cs_change = 0;  	struct spi_transfer *t;  	bool is_first = true;  	int status = 0; @@ -147,7 +188,6 @@ static int spi_xcomm_transfer_one(struct spi_controller *host,  	spi_xcomm_chipselect(spi_xcomm, spi, true);  	list_for_each_entry(t, &msg->transfers, transfer_list) { -  		if (!t->tx_buf && !t->rx_buf && t->len) {  			status = -EINVAL;  			break; @@ -208,7 +248,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c)  	struct spi_controller *host;  	int ret; -	host = spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); +	host = devm_spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm));  	if (!host)  		return -ENOMEM; @@ -221,13 +261,12 @@ static int spi_xcomm_probe(struct i2c_client *i2c)  	host->flags = SPI_CONTROLLER_HALF_DUPLEX;  	host->transfer_one_message = spi_xcomm_transfer_one;  	host->dev.of_node = i2c->dev.of_node; -	i2c_set_clientdata(i2c, host);  	ret = devm_spi_register_controller(&i2c->dev, host);  	if (ret < 0) -		spi_controller_put(host); +		return ret; -	return ret; +	return spi_xcomm_gpio_add(spi_xcomm);  }  static const struct i2c_device_id spi_xcomm_ids[] = {  |