diff options
Diffstat (limited to 'drivers/iio/dac')
-rw-r--r-- | drivers/iio/dac/Kconfig | 9 | ||||
-rw-r--r-- | drivers/iio/dac/ad5421.c | 6 | ||||
-rw-r--r-- | drivers/iio/dac/ad5504.c | 2 | ||||
-rw-r--r-- | drivers/iio/dac/ad5755.c | 188 | ||||
-rw-r--r-- | drivers/iio/dac/stx104.c | 125 |
5 files changed, 319 insertions, 11 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index f7c71da42f15..ca814479fadf 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -248,11 +248,12 @@ config MCP4922 config STX104 tristate "Apex Embedded Systems STX104 DAC driver" depends on X86 && ISA_BUS_API + select GPIOLIB help - Say yes here to build support for the 2-channel DAC on the Apex - Embedded Systems STX104 integrated analog PC/104 card. The base port - addresses for the devices may be configured via the "base" module - parameter array. + Say yes here to build support for the 2-channel DAC and GPIO on the + Apex Embedded Systems STX104 integrated analog PC/104 card. The base + port addresses for the devices may be configured via the base array + module parameter. config VF610_DAC tristate "Vybrid vf610 DAC driver" diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 968712be967f..559061ab1982 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -242,7 +242,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_UNDER_CURRENT) { @@ -251,7 +251,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_TEMP_OVER_140) { @@ -260,7 +260,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } old_fault = fault; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 4e4c20d6d8b5..788b3d6fd1cc 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; } diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index bfb350a85a16..0fde593ec0d9 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/delay.h> +#include <linux/of.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/platform_data/ad5755.h> @@ -109,6 +110,51 @@ enum ad5755_type { ID_AD5737, }; +#ifdef CONFIG_OF +static const int ad5755_dcdc_freq_table[][2] = { + { 250000, AD5755_DC_DC_FREQ_250kHZ }, + { 410000, AD5755_DC_DC_FREQ_410kHZ }, + { 650000, AD5755_DC_DC_FREQ_650kHZ } +}; + +static const int ad5755_dcdc_maxv_table[][2] = { + { 23000000, AD5755_DC_DC_MAXV_23V }, + { 24500000, AD5755_DC_DC_MAXV_24V5 }, + { 27000000, AD5755_DC_DC_MAXV_27V }, + { 29500000, AD5755_DC_DC_MAXV_29V5 }, +}; + +static const int ad5755_slew_rate_table[][2] = { + { 64000, AD5755_SLEW_RATE_64k }, + { 32000, AD5755_SLEW_RATE_32k }, + { 16000, AD5755_SLEW_RATE_16k }, + { 8000, AD5755_SLEW_RATE_8k }, + { 4000, AD5755_SLEW_RATE_4k }, + { 2000, AD5755_SLEW_RATE_2k }, + { 1000, AD5755_SLEW_RATE_1k }, + { 500, AD5755_SLEW_RATE_500 }, + { 250, AD5755_SLEW_RATE_250 }, + { 125, AD5755_SLEW_RATE_125 }, + { 64, AD5755_SLEW_RATE_64 }, + { 32, AD5755_SLEW_RATE_32 }, + { 16, AD5755_SLEW_RATE_16 }, + { 8, AD5755_SLEW_RATE_8 }, + { 4, AD5755_SLEW_RATE_4 }, + { 0, AD5755_SLEW_RATE_0_5 }, +}; + +static const int ad5755_slew_step_table[][2] = { + { 256, AD5755_SLEW_STEP_SIZE_256 }, + { 128, AD5755_SLEW_STEP_SIZE_128 }, + { 64, AD5755_SLEW_STEP_SIZE_64 }, + { 32, AD5755_SLEW_STEP_SIZE_32 }, + { 16, AD5755_SLEW_STEP_SIZE_16 }, + { 4, AD5755_SLEW_STEP_SIZE_4 }, + { 2, AD5755_SLEW_STEP_SIZE_2 }, + { 1, AD5755_SLEW_STEP_SIZE_1 }, +}; +#endif + static int ad5755_write_unlocked(struct iio_dev *indio_dev, unsigned int reg, unsigned int val) { @@ -556,6 +602,129 @@ static const struct ad5755_platform_data ad5755_default_pdata = { }, }; +#ifdef CONFIG_OF +static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *pp; + struct ad5755_platform_data *pdata; + unsigned int tmp; + unsigned int tmparray[3]; + int devnr, i; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->ext_dc_dc_compenstation_resistor = + of_property_read_bool(np, "adi,ext-dc-dc-compenstation-resistor"); + + if (!of_property_read_u32(np, "adi,dc-dc-phase", &tmp)) + pdata->dc_dc_phase = tmp; + else + pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE; + + pdata->dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ; + if (!of_property_read_u32(np, "adi,dc-dc-freq-hz", &tmp)) { + for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_freq_table); i++) { + if (tmp == ad5755_dcdc_freq_table[i][0]) { + pdata->dc_dc_freq = ad5755_dcdc_freq_table[i][1]; + break; + } + } + + if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) { + dev_err(dev, + "adi,dc-dc-freq out of range selecting 410kHz"); + } + } + + pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V; + if (!of_property_read_u32(np, "adi,dc-dc-max-microvolt", &tmp)) { + for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_maxv_table); i++) { + if (tmp == ad5755_dcdc_maxv_table[i][0]) { + pdata->dc_dc_maxv = ad5755_dcdc_maxv_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) { + dev_err(dev, + "adi,dc-dc-maxv out of range selecting 23V"); + } + } + + devnr = 0; + for_each_child_of_node(np, pp) { + if (devnr > AD5755_NUM_CHANNELS) { + dev_err(dev, + "There is to many channels defined in DT\n"); + goto error_out; + } + + if (!of_property_read_u32(pp, "adi,mode", &tmp)) + pdata->dac[devnr].mode = tmp; + else + pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA; + + pdata->dac[devnr].ext_current_sense_resistor = + of_property_read_bool(pp, "adi,ext-current-sense-resistor"); + + pdata->dac[devnr].enable_voltage_overrange = + of_property_read_bool(pp, "adi,enable-voltage-overrange"); + + if (!of_property_read_u32_array(pp, "adi,slew", tmparray, 3)) { + pdata->dac[devnr].slew.enable = tmparray[0]; + + pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; + for (i = 0; i < ARRAY_SIZE(ad5755_slew_rate_table); i++) { + if (tmparray[1] == ad5755_slew_rate_table[i][0]) { + pdata->dac[devnr].slew.rate = + ad5755_slew_rate_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_slew_rate_table)) { + dev_err(dev, + "channel %d slew rate out of range selecting 64kHz", + devnr); + } + + pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1; + for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) { + if (tmparray[2] == ad5755_slew_step_table[i][0]) { + pdata->dac[devnr].slew.step_size = + ad5755_slew_step_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_slew_step_table)) { + dev_err(dev, + "channel %d slew step size out of range selecting 1 LSB", + devnr); + } + } else { + pdata->dac[devnr].slew.enable = false; + pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; + pdata->dac[devnr].slew.step_size = + AD5755_SLEW_STEP_SIZE_1; + } + devnr++; + } + + return pdata; + + error_out: + devm_kfree(dev, pdata); + return NULL; +} +#else +static +struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int ad5755_probe(struct spi_device *spi) { enum ad5755_type type = spi_get_device_id(spi)->driver_data; @@ -583,8 +752,15 @@ static int ad5755_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->num_channels = AD5755_NUM_CHANNELS; - if (!pdata) + if (spi->dev.of_node) + pdata = ad5755_parse_dt(&spi->dev); + else + pdata = spi->dev.platform_data; + + if (!pdata) { + dev_warn(&spi->dev, "no platform data? using default\n"); pdata = &ad5755_default_pdata; + } ret = ad5755_init_channels(indio_dev, pdata); if (ret) @@ -607,6 +783,16 @@ static const struct spi_device_id ad5755_id[] = { }; MODULE_DEVICE_TABLE(spi, ad5755_id); +static const struct of_device_id ad5755_of_match[] = { + { .compatible = "adi,ad5755" }, + { .compatible = "adi,ad5755-1" }, + { .compatible = "adi,ad5757" }, + { .compatible = "adi,ad5735" }, + { .compatible = "adi,ad5737" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5755_of_match); + static struct spi_driver ad5755_driver = { .driver = { .name = "ad5755", diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/dac/stx104.c index 27941220872f..792a97164cb2 100644 --- a/drivers/iio/dac/stx104.c +++ b/drivers/iio/dac/stx104.c @@ -14,6 +14,7 @@ #include <linux/bitops.h> #include <linux/device.h> #include <linux/errno.h> +#include <linux/gpio/driver.h> #include <linux/iio/iio.h> #include <linux/iio/types.h> #include <linux/io.h> @@ -21,6 +22,7 @@ #include <linux/isa.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/spinlock.h> #define STX104_NUM_CHAN 2 @@ -49,6 +51,20 @@ struct stx104_iio { unsigned base; }; +/** + * struct stx104_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @base: base port address of the GPIO device + * @out_state: output bits state + */ +struct stx104_gpio { + struct gpio_chip chip; + spinlock_t lock; + unsigned int base; + unsigned int out_state; +}; + static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -88,15 +104,81 @@ static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = { STX104_CHAN(1) }; +static int stx104_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset < 4) + return 1; + + return 0; +} + +static int stx104_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset >= 4) + return -EINVAL; + + return 0; +} + +static int stx104_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + if (offset < 4) + return -EINVAL; + + chip->set(chip, offset, value); + return 0; +} + +static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + + if (offset >= 4) + return -EINVAL; + + return !!(inb(stx104gpio->base) & BIT(offset)); +} + +static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + const unsigned int mask = BIT(offset) >> 4; + unsigned long flags; + + if (offset < 4) + return; + + spin_lock_irqsave(&stx104gpio->lock, flags); + + if (value) + stx104gpio->out_state |= mask; + else + stx104gpio->out_state &= ~mask; + + outb(stx104gpio->out_state, stx104gpio->base); + + spin_unlock_irqrestore(&stx104gpio->lock, flags); +} + static int stx104_probe(struct device *dev, unsigned int id) { struct iio_dev *indio_dev; struct stx104_iio *priv; + struct stx104_gpio *stx104gpio; + int err; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; + stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL); + if (!stx104gpio) + return -ENOMEM; + if (!devm_request_region(dev, base[id], STX104_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -117,14 +199,53 @@ static int stx104_probe(struct device *dev, unsigned int id) outw(0, base[id] + 4); outw(0, base[id] + 6); - return devm_iio_device_register(dev, indio_dev); + err = devm_iio_device_register(dev, indio_dev); + if (err) { + dev_err(dev, "IIO device registering failed (%d)\n", err); + return err; + } + + stx104gpio->chip.label = dev_name(dev); + stx104gpio->chip.parent = dev; + stx104gpio->chip.owner = THIS_MODULE; + stx104gpio->chip.base = -1; + stx104gpio->chip.ngpio = 8; + stx104gpio->chip.get_direction = stx104_gpio_get_direction; + stx104gpio->chip.direction_input = stx104_gpio_direction_input; + stx104gpio->chip.direction_output = stx104_gpio_direction_output; + stx104gpio->chip.get = stx104_gpio_get; + stx104gpio->chip.set = stx104_gpio_set; + stx104gpio->base = base[id] + 3; + stx104gpio->out_state = 0x0; + + spin_lock_init(&stx104gpio->lock); + + dev_set_drvdata(dev, stx104gpio); + + err = gpiochip_add_data(&stx104gpio->chip, stx104gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static int stx104_remove(struct device *dev, unsigned int id) +{ + struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev); + + gpiochip_remove(&stx104gpio->chip); + + return 0; } static struct isa_driver stx104_driver = { .probe = stx104_probe, .driver = { .name = "stx104" - } + }, + .remove = stx104_remove }; module_isa_driver(stx104_driver, num_stx104); |