1e4a70e3eSLorenzo Bianconi /* 2e4a70e3eSLorenzo Bianconi * STMicroelectronics hts221 spi driver 3e4a70e3eSLorenzo Bianconi * 4e4a70e3eSLorenzo Bianconi * Copyright 2016 STMicroelectronics Inc. 5e4a70e3eSLorenzo Bianconi * 6e4a70e3eSLorenzo Bianconi * Lorenzo Bianconi <lorenzo.bianconi@st.com> 7e4a70e3eSLorenzo Bianconi * 8e4a70e3eSLorenzo Bianconi * Licensed under the GPL-2. 9e4a70e3eSLorenzo Bianconi */ 10e4a70e3eSLorenzo Bianconi 11e4a70e3eSLorenzo Bianconi #include <linux/kernel.h> 12e4a70e3eSLorenzo Bianconi #include <linux/module.h> 13e4a70e3eSLorenzo Bianconi #include <linux/spi/spi.h> 14e4a70e3eSLorenzo Bianconi #include <linux/slab.h> 15e4a70e3eSLorenzo Bianconi #include "hts221.h" 16e4a70e3eSLorenzo Bianconi 17e4a70e3eSLorenzo Bianconi #define SENSORS_SPI_READ 0x80 18e4a70e3eSLorenzo Bianconi #define SPI_AUTO_INCREMENT 0x40 19e4a70e3eSLorenzo Bianconi 20e4a70e3eSLorenzo Bianconi static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data) 21e4a70e3eSLorenzo Bianconi { 22e4a70e3eSLorenzo Bianconi int err; 23e4a70e3eSLorenzo Bianconi struct spi_device *spi = to_spi_device(dev); 24e4a70e3eSLorenzo Bianconi struct iio_dev *iio_dev = spi_get_drvdata(spi); 25e4a70e3eSLorenzo Bianconi struct hts221_hw *hw = iio_priv(iio_dev); 26e4a70e3eSLorenzo Bianconi 27e4a70e3eSLorenzo Bianconi struct spi_transfer xfers[] = { 28e4a70e3eSLorenzo Bianconi { 29e4a70e3eSLorenzo Bianconi .tx_buf = hw->tb.tx_buf, 30e4a70e3eSLorenzo Bianconi .bits_per_word = 8, 31e4a70e3eSLorenzo Bianconi .len = 1, 32e4a70e3eSLorenzo Bianconi }, 33e4a70e3eSLorenzo Bianconi { 34e4a70e3eSLorenzo Bianconi .rx_buf = hw->tb.rx_buf, 35e4a70e3eSLorenzo Bianconi .bits_per_word = 8, 36e4a70e3eSLorenzo Bianconi .len = len, 37e4a70e3eSLorenzo Bianconi } 38e4a70e3eSLorenzo Bianconi }; 39e4a70e3eSLorenzo Bianconi 40e4a70e3eSLorenzo Bianconi if (len > 1) 41e4a70e3eSLorenzo Bianconi addr |= SPI_AUTO_INCREMENT; 42e4a70e3eSLorenzo Bianconi hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ; 43e4a70e3eSLorenzo Bianconi 44e4a70e3eSLorenzo Bianconi err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); 45e4a70e3eSLorenzo Bianconi if (err < 0) 46e4a70e3eSLorenzo Bianconi return err; 47e4a70e3eSLorenzo Bianconi 48e4a70e3eSLorenzo Bianconi memcpy(data, hw->tb.rx_buf, len * sizeof(u8)); 49e4a70e3eSLorenzo Bianconi 50e4a70e3eSLorenzo Bianconi return len; 51e4a70e3eSLorenzo Bianconi } 52e4a70e3eSLorenzo Bianconi 53e4a70e3eSLorenzo Bianconi static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data) 54e4a70e3eSLorenzo Bianconi { 55e4a70e3eSLorenzo Bianconi struct spi_device *spi = to_spi_device(dev); 56e4a70e3eSLorenzo Bianconi struct iio_dev *iio_dev = spi_get_drvdata(spi); 57e4a70e3eSLorenzo Bianconi struct hts221_hw *hw = iio_priv(iio_dev); 58e4a70e3eSLorenzo Bianconi 59e4a70e3eSLorenzo Bianconi struct spi_transfer xfers = { 60e4a70e3eSLorenzo Bianconi .tx_buf = hw->tb.tx_buf, 61e4a70e3eSLorenzo Bianconi .bits_per_word = 8, 62e4a70e3eSLorenzo Bianconi .len = len + 1, 63e4a70e3eSLorenzo Bianconi }; 64e4a70e3eSLorenzo Bianconi 65e4a70e3eSLorenzo Bianconi if (len >= HTS221_TX_MAX_LENGTH) 66e4a70e3eSLorenzo Bianconi return -ENOMEM; 67e4a70e3eSLorenzo Bianconi 68e4a70e3eSLorenzo Bianconi if (len > 1) 69e4a70e3eSLorenzo Bianconi addr |= SPI_AUTO_INCREMENT; 70e4a70e3eSLorenzo Bianconi hw->tb.tx_buf[0] = addr; 71e4a70e3eSLorenzo Bianconi memcpy(&hw->tb.tx_buf[1], data, len); 72e4a70e3eSLorenzo Bianconi 73e4a70e3eSLorenzo Bianconi return spi_sync_transfer(spi, &xfers, 1); 74e4a70e3eSLorenzo Bianconi } 75e4a70e3eSLorenzo Bianconi 76e4a70e3eSLorenzo Bianconi static const struct hts221_transfer_function hts221_transfer_fn = { 77e4a70e3eSLorenzo Bianconi .read = hts221_spi_read, 78e4a70e3eSLorenzo Bianconi .write = hts221_spi_write, 79e4a70e3eSLorenzo Bianconi }; 80e4a70e3eSLorenzo Bianconi 81e4a70e3eSLorenzo Bianconi static int hts221_spi_probe(struct spi_device *spi) 82e4a70e3eSLorenzo Bianconi { 83e4a70e3eSLorenzo Bianconi struct hts221_hw *hw; 84e4a70e3eSLorenzo Bianconi struct iio_dev *iio_dev; 85e4a70e3eSLorenzo Bianconi 86e4a70e3eSLorenzo Bianconi iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*hw)); 87e4a70e3eSLorenzo Bianconi if (!iio_dev) 88e4a70e3eSLorenzo Bianconi return -ENOMEM; 89e4a70e3eSLorenzo Bianconi 90e4a70e3eSLorenzo Bianconi spi_set_drvdata(spi, iio_dev); 91e4a70e3eSLorenzo Bianconi 92e4a70e3eSLorenzo Bianconi hw = iio_priv(iio_dev); 93e4a70e3eSLorenzo Bianconi hw->name = spi->modalias; 94e4a70e3eSLorenzo Bianconi hw->dev = &spi->dev; 95e4a70e3eSLorenzo Bianconi hw->irq = spi->irq; 96e4a70e3eSLorenzo Bianconi hw->tf = &hts221_transfer_fn; 97e4a70e3eSLorenzo Bianconi 98e4a70e3eSLorenzo Bianconi return hts221_probe(iio_dev); 99e4a70e3eSLorenzo Bianconi } 100e4a70e3eSLorenzo Bianconi 101e4a70e3eSLorenzo Bianconi static const struct of_device_id hts221_spi_of_match[] = { 102e4a70e3eSLorenzo Bianconi { .compatible = "st,hts221", }, 103e4a70e3eSLorenzo Bianconi {}, 104e4a70e3eSLorenzo Bianconi }; 105e4a70e3eSLorenzo Bianconi MODULE_DEVICE_TABLE(of, hts221_spi_of_match); 106e4a70e3eSLorenzo Bianconi 107e4a70e3eSLorenzo Bianconi static const struct spi_device_id hts221_spi_id_table[] = { 108e4a70e3eSLorenzo Bianconi { HTS221_DEV_NAME }, 109e4a70e3eSLorenzo Bianconi {}, 110e4a70e3eSLorenzo Bianconi }; 111e4a70e3eSLorenzo Bianconi MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); 112e4a70e3eSLorenzo Bianconi 113e4a70e3eSLorenzo Bianconi static struct spi_driver hts221_driver = { 114e4a70e3eSLorenzo Bianconi .driver = { 115e4a70e3eSLorenzo Bianconi .name = "hts221_spi", 116*b7079eeaSLorenzo Bianconi .pm = &hts221_pm_ops, 117e4a70e3eSLorenzo Bianconi .of_match_table = of_match_ptr(hts221_spi_of_match), 118e4a70e3eSLorenzo Bianconi }, 119e4a70e3eSLorenzo Bianconi .probe = hts221_spi_probe, 120e4a70e3eSLorenzo Bianconi .id_table = hts221_spi_id_table, 121e4a70e3eSLorenzo Bianconi }; 122e4a70e3eSLorenzo Bianconi module_spi_driver(hts221_driver); 123e4a70e3eSLorenzo Bianconi 124e4a70e3eSLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 125e4a70e3eSLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver"); 126e4a70e3eSLorenzo Bianconi MODULE_LICENSE("GPL v2"); 127