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