12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ed5f07b3SAdam Thomson /* 3ed5f07b3SAdam Thomson * DA9150 GPADC Driver 4ed5f07b3SAdam Thomson * 5ed5f07b3SAdam Thomson * Copyright (c) 2014 Dialog Semiconductor 6ed5f07b3SAdam Thomson * 7ed5f07b3SAdam Thomson * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> 8ed5f07b3SAdam Thomson */ 9ed5f07b3SAdam Thomson 10ed5f07b3SAdam Thomson #include <linux/kernel.h> 11ed5f07b3SAdam Thomson #include <linux/slab.h> 12ed5f07b3SAdam Thomson #include <linux/module.h> 13ed5f07b3SAdam Thomson #include <linux/platform_device.h> 14ed5f07b3SAdam Thomson #include <linux/interrupt.h> 15ed5f07b3SAdam Thomson #include <linux/mutex.h> 16ed5f07b3SAdam Thomson #include <linux/completion.h> 17ed5f07b3SAdam Thomson #include <linux/iio/iio.h> 18ed5f07b3SAdam Thomson #include <linux/iio/machine.h> 19ed5f07b3SAdam Thomson #include <linux/iio/driver.h> 20ed5f07b3SAdam Thomson #include <linux/mfd/da9150/core.h> 21ed5f07b3SAdam Thomson #include <linux/mfd/da9150/registers.h> 22ed5f07b3SAdam Thomson 23ed5f07b3SAdam Thomson /* Channels */ 24ed5f07b3SAdam Thomson enum da9150_gpadc_hw_channel { 25ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOA_2V = 0, 26ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOA_2V_, 27ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOB_2V, 28ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOB_2V_, 29ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOC_2V, 30ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOC_2V_, 31ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOD_2V, 32ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOD_2V_, 33ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_IBUS_SENSE, 34ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_IBUS_SENSE_, 35ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VBUS_DIV, 36ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VBUS_DIV_, 37ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_ID, 38ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_ID_, 39ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VSYS, 40ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VSYS_, 41ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOA_6V, 42ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOA_6V_, 43ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOB_6V, 44ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOB_6V_, 45ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOC_6V, 46ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOC_6V_, 47ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOD_6V, 48ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_GPIOD_6V_, 49ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VBAT, 50ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_VBAT_, 51ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TBAT, 52ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TBAT_, 53ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TJUNC_CORE, 54ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TJUNC_CORE_, 55ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TJUNC_OVP, 56ed5f07b3SAdam Thomson DA9150_GPADC_HW_CHAN_TJUNC_OVP_, 57ed5f07b3SAdam Thomson }; 58ed5f07b3SAdam Thomson 59ed5f07b3SAdam Thomson enum da9150_gpadc_channel { 60ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_GPIOA = 0, 61ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_GPIOB, 62ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_GPIOC, 63ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_GPIOD, 64ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_IBUS, 65ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_VBUS, 66ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_VSYS, 67ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_VBAT, 68ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_TBAT, 69ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_TJUNC_CORE, 70ed5f07b3SAdam Thomson DA9150_GPADC_CHAN_TJUNC_OVP, 71ed5f07b3SAdam Thomson }; 72ed5f07b3SAdam Thomson 73ed5f07b3SAdam Thomson /* Private data */ 74ed5f07b3SAdam Thomson struct da9150_gpadc { 75ed5f07b3SAdam Thomson struct da9150 *da9150; 76ed5f07b3SAdam Thomson struct device *dev; 77ed5f07b3SAdam Thomson 78ed5f07b3SAdam Thomson struct mutex lock; 79ed5f07b3SAdam Thomson struct completion complete; 80ed5f07b3SAdam Thomson }; 81ed5f07b3SAdam Thomson 82ed5f07b3SAdam Thomson 83ed5f07b3SAdam Thomson static irqreturn_t da9150_gpadc_irq(int irq, void *data) 84ed5f07b3SAdam Thomson { 85ed5f07b3SAdam Thomson 86ed5f07b3SAdam Thomson struct da9150_gpadc *gpadc = data; 87ed5f07b3SAdam Thomson 88ed5f07b3SAdam Thomson complete(&gpadc->complete); 89ed5f07b3SAdam Thomson 90ed5f07b3SAdam Thomson return IRQ_HANDLED; 91ed5f07b3SAdam Thomson } 92ed5f07b3SAdam Thomson 93ed5f07b3SAdam Thomson static int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan) 94ed5f07b3SAdam Thomson { 95ed5f07b3SAdam Thomson u8 result_regs[2]; 96ed5f07b3SAdam Thomson int result; 97ed5f07b3SAdam Thomson 98ed5f07b3SAdam Thomson mutex_lock(&gpadc->lock); 99ed5f07b3SAdam Thomson 100ed5f07b3SAdam Thomson /* Set channel & enable measurement */ 101ed5f07b3SAdam Thomson da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN, 102ed5f07b3SAdam Thomson (DA9150_GPADC_EN_MASK | 103ed5f07b3SAdam Thomson hw_chan << DA9150_GPADC_MUX_SHIFT)); 104ed5f07b3SAdam Thomson 105ed5f07b3SAdam Thomson /* Consume left-over completion from a previous timeout */ 106ed5f07b3SAdam Thomson try_wait_for_completion(&gpadc->complete); 107ed5f07b3SAdam Thomson 108ed5f07b3SAdam Thomson /* Check for actual completion */ 109ed5f07b3SAdam Thomson wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5)); 110ed5f07b3SAdam Thomson 111ed5f07b3SAdam Thomson /* Read result and status from device */ 112ed5f07b3SAdam Thomson da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs); 113ed5f07b3SAdam Thomson 114ed5f07b3SAdam Thomson mutex_unlock(&gpadc->lock); 115ed5f07b3SAdam Thomson 116ed5f07b3SAdam Thomson /* Check to make sure device really has completed reading */ 117ed5f07b3SAdam Thomson if (result_regs[1] & DA9150_GPADC_RUN_MASK) { 118ed5f07b3SAdam Thomson dev_err(gpadc->dev, "Timeout on channel %d of GPADC\n", 119ed5f07b3SAdam Thomson hw_chan); 120ed5f07b3SAdam Thomson return -ETIMEDOUT; 121ed5f07b3SAdam Thomson } 122ed5f07b3SAdam Thomson 123ed5f07b3SAdam Thomson /* LSBs - 2 bits */ 124ed5f07b3SAdam Thomson result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >> 125ed5f07b3SAdam Thomson DA9150_GPADC_RES_L_SHIFT; 126ed5f07b3SAdam Thomson /* MSBs - 8 bits */ 127ed5f07b3SAdam Thomson result |= result_regs[0] << DA9150_GPADC_RES_L_BITS; 128ed5f07b3SAdam Thomson 129ed5f07b3SAdam Thomson return result; 130ed5f07b3SAdam Thomson } 131ed5f07b3SAdam Thomson 132ed5f07b3SAdam Thomson static inline int da9150_gpadc_gpio_6v_voltage_now(int raw_val) 133ed5f07b3SAdam Thomson { 134ed5f07b3SAdam Thomson /* Convert to mV */ 135ed5f07b3SAdam Thomson return (6 * ((raw_val * 1000) + 500)) / 1024; 136ed5f07b3SAdam Thomson } 137ed5f07b3SAdam Thomson 138ed5f07b3SAdam Thomson static inline int da9150_gpadc_ibus_current_avg(int raw_val) 139ed5f07b3SAdam Thomson { 140ed5f07b3SAdam Thomson /* Convert to mA */ 141ed5f07b3SAdam Thomson return (4 * ((raw_val * 1000) + 500)) / 2048; 142ed5f07b3SAdam Thomson } 143ed5f07b3SAdam Thomson 144ed5f07b3SAdam Thomson static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val) 145ed5f07b3SAdam Thomson { 146ed5f07b3SAdam Thomson /* Convert to mV */ 147ed5f07b3SAdam Thomson return (21 * ((raw_val * 1000) + 500)) / 1024; 148ed5f07b3SAdam Thomson } 149ed5f07b3SAdam Thomson 150ed5f07b3SAdam Thomson static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val) 151ed5f07b3SAdam Thomson { 152ed5f07b3SAdam Thomson /* Convert to mV */ 153ed5f07b3SAdam Thomson return (3 * ((raw_val * 1000) + 500)) / 512; 154ed5f07b3SAdam Thomson } 155ed5f07b3SAdam Thomson 156ed5f07b3SAdam Thomson static int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel, 157ed5f07b3SAdam Thomson int hw_chan, int *val) 158ed5f07b3SAdam Thomson { 159ed5f07b3SAdam Thomson int raw_val; 160ed5f07b3SAdam Thomson 161ed5f07b3SAdam Thomson raw_val = da9150_gpadc_read_adc(gpadc, hw_chan); 162ed5f07b3SAdam Thomson if (raw_val < 0) 163ed5f07b3SAdam Thomson return raw_val; 164ed5f07b3SAdam Thomson 165ed5f07b3SAdam Thomson switch (channel) { 166ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_GPIOA: 167ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_GPIOB: 168ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_GPIOC: 169ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_GPIOD: 170ed5f07b3SAdam Thomson *val = da9150_gpadc_gpio_6v_voltage_now(raw_val); 171ed5f07b3SAdam Thomson break; 172ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_IBUS: 173ed5f07b3SAdam Thomson *val = da9150_gpadc_ibus_current_avg(raw_val); 174ed5f07b3SAdam Thomson break; 175ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_VBUS: 176ed5f07b3SAdam Thomson *val = da9150_gpadc_vbus_21v_voltage_now(raw_val); 177ed5f07b3SAdam Thomson break; 178ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_VSYS: 179ed5f07b3SAdam Thomson *val = da9150_gpadc_vsys_6v_voltage_now(raw_val); 180ed5f07b3SAdam Thomson break; 181ed5f07b3SAdam Thomson default: 182ed5f07b3SAdam Thomson /* No processing for other channels so return raw value */ 183ed5f07b3SAdam Thomson *val = raw_val; 184ed5f07b3SAdam Thomson break; 185ed5f07b3SAdam Thomson } 186ed5f07b3SAdam Thomson 187ed5f07b3SAdam Thomson return IIO_VAL_INT; 188ed5f07b3SAdam Thomson } 189ed5f07b3SAdam Thomson 190ed5f07b3SAdam Thomson static int da9150_gpadc_read_scale(int channel, int *val, int *val2) 191ed5f07b3SAdam Thomson { 192ed5f07b3SAdam Thomson switch (channel) { 193ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_VBAT: 194ed5f07b3SAdam Thomson *val = 2932; 195ed5f07b3SAdam Thomson *val2 = 1000; 196ed5f07b3SAdam Thomson return IIO_VAL_FRACTIONAL; 197ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_TJUNC_CORE: 198ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_TJUNC_OVP: 199ed5f07b3SAdam Thomson *val = 1000000; 200ed5f07b3SAdam Thomson *val2 = 4420; 201ed5f07b3SAdam Thomson return IIO_VAL_FRACTIONAL; 202ed5f07b3SAdam Thomson default: 203ed5f07b3SAdam Thomson return -EINVAL; 204ed5f07b3SAdam Thomson } 205ed5f07b3SAdam Thomson } 206ed5f07b3SAdam Thomson 207ed5f07b3SAdam Thomson static int da9150_gpadc_read_offset(int channel, int *val) 208ed5f07b3SAdam Thomson { 209ed5f07b3SAdam Thomson switch (channel) { 210ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_VBAT: 211ed5f07b3SAdam Thomson *val = 1500000 / 2932; 212ed5f07b3SAdam Thomson return IIO_VAL_INT; 213ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_TJUNC_CORE: 214ed5f07b3SAdam Thomson case DA9150_GPADC_CHAN_TJUNC_OVP: 215ed5f07b3SAdam Thomson *val = -144; 216ed5f07b3SAdam Thomson return IIO_VAL_INT; 217ed5f07b3SAdam Thomson default: 218ed5f07b3SAdam Thomson return -EINVAL; 219ed5f07b3SAdam Thomson } 220ed5f07b3SAdam Thomson } 221ed5f07b3SAdam Thomson 222ed5f07b3SAdam Thomson static int da9150_gpadc_read_raw(struct iio_dev *indio_dev, 223ed5f07b3SAdam Thomson struct iio_chan_spec const *chan, 224ed5f07b3SAdam Thomson int *val, int *val2, long mask) 225ed5f07b3SAdam Thomson { 226ed5f07b3SAdam Thomson struct da9150_gpadc *gpadc = iio_priv(indio_dev); 227ed5f07b3SAdam Thomson 228ed5f07b3SAdam Thomson if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) || 229ed5f07b3SAdam Thomson (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP)) 230ed5f07b3SAdam Thomson return -EINVAL; 231ed5f07b3SAdam Thomson 232ed5f07b3SAdam Thomson switch (mask) { 233ed5f07b3SAdam Thomson case IIO_CHAN_INFO_RAW: 234ed5f07b3SAdam Thomson case IIO_CHAN_INFO_PROCESSED: 235ed5f07b3SAdam Thomson return da9150_gpadc_read_processed(gpadc, chan->channel, 236ed5f07b3SAdam Thomson chan->address, val); 237ed5f07b3SAdam Thomson case IIO_CHAN_INFO_SCALE: 238ed5f07b3SAdam Thomson return da9150_gpadc_read_scale(chan->channel, val, val2); 239ed5f07b3SAdam Thomson case IIO_CHAN_INFO_OFFSET: 240ed5f07b3SAdam Thomson return da9150_gpadc_read_offset(chan->channel, val); 241ed5f07b3SAdam Thomson default: 242ed5f07b3SAdam Thomson return -EINVAL; 243ed5f07b3SAdam Thomson } 244ed5f07b3SAdam Thomson } 245ed5f07b3SAdam Thomson 246ed5f07b3SAdam Thomson static const struct iio_info da9150_gpadc_info = { 247ed5f07b3SAdam Thomson .read_raw = &da9150_gpadc_read_raw, 248ed5f07b3SAdam Thomson }; 249ed5f07b3SAdam Thomson 250ed5f07b3SAdam Thomson #define DA9150_GPADC_CHANNEL(_id, _hw_id, _type, chan_info, \ 251ed5f07b3SAdam Thomson _ext_name) { \ 252ed5f07b3SAdam Thomson .type = _type, \ 253ed5f07b3SAdam Thomson .indexed = 1, \ 254ed5f07b3SAdam Thomson .channel = DA9150_GPADC_CHAN_##_id, \ 255ed5f07b3SAdam Thomson .address = DA9150_GPADC_HW_CHAN_##_hw_id, \ 256ed5f07b3SAdam Thomson .info_mask_separate = chan_info, \ 257ed5f07b3SAdam Thomson .extend_name = _ext_name, \ 258ed5f07b3SAdam Thomson .datasheet_name = #_id, \ 259ed5f07b3SAdam Thomson } 260ed5f07b3SAdam Thomson 261ed5f07b3SAdam Thomson #define DA9150_GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name) \ 262ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ 263ed5f07b3SAdam Thomson BIT(IIO_CHAN_INFO_RAW), _ext_name) 264ed5f07b3SAdam Thomson 265ed5f07b3SAdam Thomson #define DA9150_GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name) \ 266ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ 267ed5f07b3SAdam Thomson BIT(IIO_CHAN_INFO_RAW) | \ 268ed5f07b3SAdam Thomson BIT(IIO_CHAN_INFO_SCALE) | \ 269ed5f07b3SAdam Thomson BIT(IIO_CHAN_INFO_OFFSET), \ 270ed5f07b3SAdam Thomson _ext_name) 271ed5f07b3SAdam Thomson 272ed5f07b3SAdam Thomson #define DA9150_GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name) \ 273ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ 274ed5f07b3SAdam Thomson BIT(IIO_CHAN_INFO_PROCESSED), _ext_name) 275ed5f07b3SAdam Thomson 276ed5f07b3SAdam Thomson /* Supported channels */ 277ed5f07b3SAdam Thomson static const struct iio_chan_spec da9150_gpadc_channels[] = { 278ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_6V, IIO_VOLTAGE, NULL), 279ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_6V, IIO_VOLTAGE, NULL), 280ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_6V, IIO_VOLTAGE, NULL), 281ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_6V, IIO_VOLTAGE, NULL), 282ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "ibus"), 283ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "vbus"), 284ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "vsys"), 285ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "vbat"), 286ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "tbat"), 287ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_SCALED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, 288ed5f07b3SAdam Thomson "tjunc_core"), 289ed5f07b3SAdam Thomson DA9150_GPADC_CHANNEL_SCALED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, 290ed5f07b3SAdam Thomson "tjunc_ovp"), 291ed5f07b3SAdam Thomson }; 292ed5f07b3SAdam Thomson 293ed5f07b3SAdam Thomson /* Default maps used by da9150-charger */ 294ed5f07b3SAdam Thomson static struct iio_map da9150_gpadc_default_maps[] = { 295ed5f07b3SAdam Thomson { 296ed5f07b3SAdam Thomson .consumer_dev_name = "da9150-charger", 297ed5f07b3SAdam Thomson .consumer_channel = "CHAN_IBUS", 298ed5f07b3SAdam Thomson .adc_channel_label = "IBUS", 299ed5f07b3SAdam Thomson }, 300ed5f07b3SAdam Thomson { 301ed5f07b3SAdam Thomson .consumer_dev_name = "da9150-charger", 302ed5f07b3SAdam Thomson .consumer_channel = "CHAN_VBUS", 303ed5f07b3SAdam Thomson .adc_channel_label = "VBUS", 304ed5f07b3SAdam Thomson }, 305ed5f07b3SAdam Thomson { 306ed5f07b3SAdam Thomson .consumer_dev_name = "da9150-charger", 307ed5f07b3SAdam Thomson .consumer_channel = "CHAN_TJUNC", 308ed5f07b3SAdam Thomson .adc_channel_label = "TJUNC_CORE", 309ed5f07b3SAdam Thomson }, 310ed5f07b3SAdam Thomson { 311ed5f07b3SAdam Thomson .consumer_dev_name = "da9150-charger", 312ed5f07b3SAdam Thomson .consumer_channel = "CHAN_VBAT", 313ed5f07b3SAdam Thomson .adc_channel_label = "VBAT", 314ed5f07b3SAdam Thomson }, 315ed5f07b3SAdam Thomson {}, 316ed5f07b3SAdam Thomson }; 317ed5f07b3SAdam Thomson 318ed5f07b3SAdam Thomson static int da9150_gpadc_probe(struct platform_device *pdev) 319ed5f07b3SAdam Thomson { 320ed5f07b3SAdam Thomson struct device *dev = &pdev->dev; 321ed5f07b3SAdam Thomson struct da9150 *da9150 = dev_get_drvdata(dev->parent); 322ed5f07b3SAdam Thomson struct da9150_gpadc *gpadc; 323ed5f07b3SAdam Thomson struct iio_dev *indio_dev; 324ed5f07b3SAdam Thomson int irq, ret; 325ed5f07b3SAdam Thomson 326ed5f07b3SAdam Thomson indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); 327ed5f07b3SAdam Thomson if (!indio_dev) { 328ed5f07b3SAdam Thomson dev_err(&pdev->dev, "Failed to allocate IIO device\n"); 329ed5f07b3SAdam Thomson return -ENOMEM; 330ed5f07b3SAdam Thomson } 331ed5f07b3SAdam Thomson gpadc = iio_priv(indio_dev); 332ed5f07b3SAdam Thomson 333ed5f07b3SAdam Thomson platform_set_drvdata(pdev, indio_dev); 334ed5f07b3SAdam Thomson gpadc->da9150 = da9150; 335ed5f07b3SAdam Thomson gpadc->dev = dev; 336ed5f07b3SAdam Thomson mutex_init(&gpadc->lock); 337ed5f07b3SAdam Thomson init_completion(&gpadc->complete); 338ed5f07b3SAdam Thomson 339ed5f07b3SAdam Thomson irq = platform_get_irq_byname(pdev, "GPADC"); 340*7c279229SStephen Boyd if (irq < 0) 341ed5f07b3SAdam Thomson return irq; 342ed5f07b3SAdam Thomson 343ed5f07b3SAdam Thomson ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq, 344ed5f07b3SAdam Thomson IRQF_ONESHOT, "GPADC", gpadc); 345ed5f07b3SAdam Thomson if (ret) { 346ed5f07b3SAdam Thomson dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret); 347ed5f07b3SAdam Thomson return ret; 348ed5f07b3SAdam Thomson } 349ed5f07b3SAdam Thomson 350ed5f07b3SAdam Thomson ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps); 351ed5f07b3SAdam Thomson if (ret) { 352ed5f07b3SAdam Thomson dev_err(dev, "Failed to register IIO maps: %d\n", ret); 353ed5f07b3SAdam Thomson return ret; 354ed5f07b3SAdam Thomson } 355ed5f07b3SAdam Thomson 356ed5f07b3SAdam Thomson indio_dev->name = dev_name(dev); 357ed5f07b3SAdam Thomson indio_dev->dev.parent = dev; 358ed5f07b3SAdam Thomson indio_dev->dev.of_node = pdev->dev.of_node; 359ed5f07b3SAdam Thomson indio_dev->info = &da9150_gpadc_info; 360ed5f07b3SAdam Thomson indio_dev->modes = INDIO_DIRECT_MODE; 361ed5f07b3SAdam Thomson indio_dev->channels = da9150_gpadc_channels; 362ed5f07b3SAdam Thomson indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels); 363ed5f07b3SAdam Thomson 364ed5f07b3SAdam Thomson ret = iio_device_register(indio_dev); 365ed5f07b3SAdam Thomson if (ret) { 366ed5f07b3SAdam Thomson dev_err(dev, "Failed to register IIO device: %d\n", ret); 367ed5f07b3SAdam Thomson goto iio_map_unreg; 368ed5f07b3SAdam Thomson } 369ed5f07b3SAdam Thomson 370ed5f07b3SAdam Thomson return 0; 371ed5f07b3SAdam Thomson 372ed5f07b3SAdam Thomson iio_map_unreg: 373ed5f07b3SAdam Thomson iio_map_array_unregister(indio_dev); 374ed5f07b3SAdam Thomson 375ed5f07b3SAdam Thomson return ret; 376ed5f07b3SAdam Thomson } 377ed5f07b3SAdam Thomson 378ed5f07b3SAdam Thomson static int da9150_gpadc_remove(struct platform_device *pdev) 379ed5f07b3SAdam Thomson { 380ed5f07b3SAdam Thomson struct iio_dev *indio_dev = platform_get_drvdata(pdev); 381ed5f07b3SAdam Thomson 382ed5f07b3SAdam Thomson iio_device_unregister(indio_dev); 383ed5f07b3SAdam Thomson iio_map_array_unregister(indio_dev); 384ed5f07b3SAdam Thomson 385ed5f07b3SAdam Thomson return 0; 386ed5f07b3SAdam Thomson } 387ed5f07b3SAdam Thomson 388ed5f07b3SAdam Thomson static struct platform_driver da9150_gpadc_driver = { 389ed5f07b3SAdam Thomson .driver = { 390ed5f07b3SAdam Thomson .name = "da9150-gpadc", 391ed5f07b3SAdam Thomson }, 392ed5f07b3SAdam Thomson .probe = da9150_gpadc_probe, 393ed5f07b3SAdam Thomson .remove = da9150_gpadc_remove, 394ed5f07b3SAdam Thomson }; 395ed5f07b3SAdam Thomson 396ed5f07b3SAdam Thomson module_platform_driver(da9150_gpadc_driver); 397ed5f07b3SAdam Thomson 398ed5f07b3SAdam Thomson MODULE_DESCRIPTION("GPADC Driver for DA9150"); 399ed5f07b3SAdam Thomson MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 400ed5f07b3SAdam Thomson MODULE_LICENSE("GPL"); 401