Merge tag 'afs-next-20190507' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowel...
[linux-2.6-microblaze.git] / drivers / iio / adc / ti-ads7950.c
index 0ad6359..2e66e4d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
  */
 #define TI_ADS7950_VA_MV_ACPI_DEFAULT  5000
 
+#define TI_ADS7950_CR_GPIO     BIT(14)
 #define TI_ADS7950_CR_MANUAL   BIT(12)
 #define TI_ADS7950_CR_WRITE    BIT(11)
 #define TI_ADS7950_CR_CHAN(ch) ((ch) << 7)
 #define TI_ADS7950_CR_RANGE_5V BIT(6)
+#define TI_ADS7950_CR_GPIO_DATA        BIT(4)
 
 #define TI_ADS7950_MAX_CHAN    16
+#define TI_ADS7950_NUM_GPIOS   4
 
 #define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
 
 #define TI_ADS7950_EXTRACT(val, dec, bits) \
        (((val) >> (dec)) & ((1 << (bits)) - 1))
 
+#define TI_ADS7950_MAN_CMD(cmd)         (TI_ADS7950_CR_MANUAL | (cmd))
+#define TI_ADS7950_GPIO_CMD(cmd)        (TI_ADS7950_CR_GPIO | (cmd))
+
+/* Manual mode configuration */
+#define TI_ADS7950_MAN_CMD_SETTINGS(st) \
+       (TI_ADS7950_MAN_CMD(TI_ADS7950_CR_WRITE | st->cmd_settings_bitmask))
+/* GPIO mode configuration */
+#define TI_ADS7950_GPIO_CMD_SETTINGS(st) \
+       (TI_ADS7950_GPIO_CMD(st->gpio_cmd_settings_bitmask))
+
 struct ti_ads7950_state {
        struct spi_device       *spi;
        struct spi_transfer     ring_xfer;
@@ -56,10 +70,36 @@ struct ti_ads7950_state {
        struct spi_message      ring_msg;
        struct spi_message      scan_single_msg;
 
+       /* Lock to protect the spi xfer buffers */
+       struct mutex            slock;
+       struct gpio_chip        chip;
+
        struct regulator        *reg;
        unsigned int            vref_mv;
 
-       unsigned int            settings;
+       /*
+        * Bitmask of lower 7 bits used for configuration
+        * These bits only can be written when TI_ADS7950_CR_WRITE
+        * is set, otherwise it retains its original state.
+        * [0-3] GPIO signal
+        * [4]   Set following frame to return GPIO signal values
+        * [5]   Powers down device
+        * [6]   Sets Vref range1(2.5v) or range2(5v)
+        *
+        * Bits present on Manual/Auto1/Auto2 commands
+        */
+       unsigned int            cmd_settings_bitmask;
+
+       /*
+        * Bitmask of GPIO command
+        * [0-3] GPIO direction
+        * [4-6] Different GPIO alarm mode configurations
+        * [7]   GPIO 2 as device range input
+        * [8]   GPIO 3 as device power down input
+        * [9]   Reset all registers
+        * [10-11] N/A
+        */
+       unsigned int            gpio_cmd_settings_bitmask;
 
        /*
         * DMA (thus cache coherency maintenance) requires the
@@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
 
        len = 0;
        for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
-               cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings;
+               cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i));
                st->tx_buf[len++] = cmd;
        }
 
@@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
        struct ti_ads7950_state *st = iio_priv(indio_dev);
        int ret;
 
+       mutex_lock(&st->slock);
        ret = spi_sync(st->spi, &st->ring_msg);
        if (ret < 0)
                goto out;
@@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
                                           iio_get_time_ns(indio_dev));
 
 out:
+       mutex_unlock(&st->slock);
        iio_trigger_notify_done(indio_dev->trig);
 
        return IRQ_HANDLED;
@@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
        struct ti_ads7950_state *st = iio_priv(indio_dev);
        int ret, cmd;
 
-       mutex_lock(&indio_dev->mlock);
-
-       cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
+       mutex_lock(&st->slock);
+       cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch));
        st->single_tx = cmd;
 
        ret = spi_sync(st->spi, &st->scan_single_msg);
@@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
        ret = st->single_rx;
 
 out:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->slock);
 
        return ret;
 }
@@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st)
                vref /= 1000;
        }
 
-       if (st->settings & TI_ADS7950_CR_RANGE_5V)
+       if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V)
                vref *= 2;
 
        return vref;
@@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = {
        .update_scan_mode       = ti_ads7950_update_scan_mode,
 };
 
+static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
+                          int value)
+{
+       struct ti_ads7950_state *st = gpiochip_get_data(chip);
+
+       mutex_lock(&st->slock);
+
+       if (value)
+               st->cmd_settings_bitmask |= BIT(offset);
+       else
+               st->cmd_settings_bitmask &= ~BIT(offset);
+
+       st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
+       spi_sync(st->spi, &st->scan_single_msg);
+
+       mutex_unlock(&st->slock);
+}
+
+static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct ti_ads7950_state *st = gpiochip_get_data(chip);
+       int ret;
+
+       mutex_lock(&st->slock);
+
+       /* If set as output, return the output */
+       if (st->gpio_cmd_settings_bitmask & BIT(offset)) {
+               ret = st->cmd_settings_bitmask & BIT(offset);
+               goto out;
+       }
+
+       /* GPIO data bit sets SDO bits 12-15 to GPIO input */
+       st->cmd_settings_bitmask |= TI_ADS7950_CR_GPIO_DATA;
+       st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+       if (ret)
+               goto out;
+
+       ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0;
+
+       /* Revert back to original settings */
+       st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA;
+       st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+       if (ret)
+               goto out;
+
+out:
+       mutex_unlock(&st->slock);
+
+       return ret;
+}
+
+static int ti_ads7950_get_direction(struct gpio_chip *chip,
+                                   unsigned int offset)
+{
+       struct ti_ads7950_state *st = gpiochip_get_data(chip);
+
+       /* Bitmask is inverted from GPIO framework 0=input/1=output */
+       return !(st->gpio_cmd_settings_bitmask & BIT(offset));
+}
+
+static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset,
+                                    int input)
+{
+       struct ti_ads7950_state *st = gpiochip_get_data(chip);
+       int ret = 0;
+
+       mutex_lock(&st->slock);
+
+       /* Only change direction if needed */
+       if (input && (st->gpio_cmd_settings_bitmask & BIT(offset)))
+               st->gpio_cmd_settings_bitmask &= ~BIT(offset);
+       else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset)))
+               st->gpio_cmd_settings_bitmask |= BIT(offset);
+       else
+               goto out;
+
+       st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+
+out:
+       mutex_unlock(&st->slock);
+
+       return ret;
+}
+
+static int ti_ads7950_direction_input(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       return _ti_ads7950_set_direction(chip, offset, 1);
+}
+
+static int ti_ads7950_direction_output(struct gpio_chip *chip,
+                                      unsigned int offset, int value)
+{
+       ti_ads7950_set(chip, offset, value);
+
+       return _ti_ads7950_set_direction(chip, offset, 0);
+}
+
+static int ti_ads7950_init_hw(struct ti_ads7950_state *st)
+{
+       int ret = 0;
+
+       mutex_lock(&st->slock);
+
+       /* Settings for Manual/Auto1/Auto2 commands */
+       /* Default to 5v ref */
+       st->cmd_settings_bitmask = TI_ADS7950_CR_RANGE_5V;
+       st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+       if (ret)
+               goto out;
+
+       /* Settings for GPIO command */
+       st->gpio_cmd_settings_bitmask = 0x0;
+       st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+
+out:
+       mutex_unlock(&st->slock);
+
+       return ret;
+}
+
 static int ti_ads7950_probe(struct spi_device *spi)
 {
        struct ti_ads7950_state *st;
@@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi)
        spi_set_drvdata(spi, indio_dev);
 
        st->spi = spi;
-       st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V;
 
        info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
 
@@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi)
        if (ACPI_COMPANION(&spi->dev))
                st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT;
 
+       mutex_init(&st->slock);
+
        st->reg = devm_regulator_get(&spi->dev, "vref");
        if (IS_ERR(st->reg)) {
                dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
-               return PTR_ERR(st->reg);
+               ret = PTR_ERR(st->reg);
+               goto error_destroy_mutex;
        }
 
        ret = regulator_enable(st->reg);
        if (ret) {
                dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
-               return ret;
+               goto error_destroy_mutex;
        }
 
        ret = iio_triggered_buffer_setup(indio_dev, NULL,
@@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi)
                goto error_disable_reg;
        }
 
+       ret = ti_ads7950_init_hw(st);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to init adc chip\n");
+               goto error_cleanup_ring;
+       }
+
        ret = iio_device_register(indio_dev);
        if (ret) {
                dev_err(&spi->dev, "Failed to register iio device\n");
                goto error_cleanup_ring;
        }
 
+       /* Add GPIO chip */
+       st->chip.label = dev_name(&st->spi->dev);
+       st->chip.parent = &st->spi->dev;
+       st->chip.owner = THIS_MODULE;
+       st->chip.base = -1;
+       st->chip.ngpio = TI_ADS7950_NUM_GPIOS;
+       st->chip.get_direction = ti_ads7950_get_direction;
+       st->chip.direction_input = ti_ads7950_direction_input;
+       st->chip.direction_output = ti_ads7950_direction_output;
+       st->chip.get = ti_ads7950_get;
+       st->chip.set = ti_ads7950_set;
+
+       ret = gpiochip_add_data(&st->chip, st);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to init GPIOs\n");
+               goto error_iio_device;
+       }
+
        return 0;
 
+error_iio_device:
+       iio_device_unregister(indio_dev);
 error_cleanup_ring:
        iio_triggered_buffer_cleanup(indio_dev);
 error_disable_reg:
        regulator_disable(st->reg);
+error_destroy_mutex:
+       mutex_destroy(&st->slock);
 
        return ret;
 }
@@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi)
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ti_ads7950_state *st = iio_priv(indio_dev);
 
+       gpiochip_remove(&st->chip);
        iio_device_unregister(indio_dev);
        iio_triggered_buffer_cleanup(indio_dev);
        regulator_disable(st->reg);
+       mutex_destroy(&st->slock);
 
        return 0;
 }