162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ST SPEAr ADC driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2012 Stefan Roese <sr@denx.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/clk.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/completion.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/of_address.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/iio/iio.h> 2262306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* SPEAR registers definitions */ 2562306a36Sopenharmony_ci#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) 2662306a36Sopenharmony_ci#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) 2762306a36Sopenharmony_ci#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0) 2862306a36Sopenharmony_ci#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Bit definitions for SPEAR_ADC_STATUS */ 3162306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_START_CONVERSION BIT(0) 3262306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) 3362306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4) 3462306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) 3562306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define SPEAR_ADC_DATA_MASK 0x03ff 3862306a36Sopenharmony_ci#define SPEAR_ADC_DATA_BITS 10 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define SPEAR_ADC_MOD_NAME "spear-adc" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define SPEAR_ADC_CHANNEL_NUM 8 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SPEAR_ADC_CLK_MIN 2500000 4562306a36Sopenharmony_ci#define SPEAR_ADC_CLK_MAX 20000000 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct adc_regs_spear3xx { 4862306a36Sopenharmony_ci u32 status; 4962306a36Sopenharmony_ci u32 average; 5062306a36Sopenharmony_ci u32 scan_rate; 5162306a36Sopenharmony_ci u32 clk; /* Not avail for 1340 & 1310 */ 5262306a36Sopenharmony_ci u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; 5362306a36Sopenharmony_ci u32 ch_data[SPEAR_ADC_CHANNEL_NUM]; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct chan_data { 5762306a36Sopenharmony_ci u32 lsb; 5862306a36Sopenharmony_ci u32 msb; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct adc_regs_spear6xx { 6262306a36Sopenharmony_ci u32 status; 6362306a36Sopenharmony_ci u32 pad[2]; 6462306a36Sopenharmony_ci u32 clk; 6562306a36Sopenharmony_ci u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; 6662306a36Sopenharmony_ci struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM]; 6762306a36Sopenharmony_ci u32 scan_rate_lo; 6862306a36Sopenharmony_ci u32 scan_rate_hi; 6962306a36Sopenharmony_ci struct chan_data average; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct spear_adc_state { 7362306a36Sopenharmony_ci struct device_node *np; 7462306a36Sopenharmony_ci struct adc_regs_spear3xx __iomem *adc_base_spear3xx; 7562306a36Sopenharmony_ci struct adc_regs_spear6xx __iomem *adc_base_spear6xx; 7662306a36Sopenharmony_ci struct clk *clk; 7762306a36Sopenharmony_ci struct completion completion; 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * Lock to protect the device state during a potential concurrent 8062306a36Sopenharmony_ci * read access from userspace. Reading a raw value requires a sequence 8162306a36Sopenharmony_ci * of register writes, then a wait for a completion callback, 8262306a36Sopenharmony_ci * and finally a register read, during which userspace could issue 8362306a36Sopenharmony_ci * another read request. This lock protects a read access from 8462306a36Sopenharmony_ci * ocurring before another one has finished. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci struct mutex lock; 8762306a36Sopenharmony_ci u32 current_clk; 8862306a36Sopenharmony_ci u32 sampling_freq; 8962306a36Sopenharmony_ci u32 avg_samples; 9062306a36Sopenharmony_ci u32 vref_external; 9162306a36Sopenharmony_ci u32 value; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * Functions to access some SPEAr ADC register. Abstracted into 9662306a36Sopenharmony_ci * static inline functions, because of different register offsets 9762306a36Sopenharmony_ci * on different SoC variants (SPEAr300 vs SPEAr600 etc). 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistatic void spear_adc_set_status(struct spear_adc_state *st, u32 val) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci __raw_writel(val, &st->adc_base_spear6xx->status); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void spear_adc_set_clk(struct spear_adc_state *st, u32 val) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci u32 clk_high, clk_low, count; 10762306a36Sopenharmony_ci u32 apb_clk = clk_get_rate(st->clk); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci count = DIV_ROUND_UP(apb_clk, val); 11062306a36Sopenharmony_ci clk_low = count / 2; 11162306a36Sopenharmony_ci clk_high = count - clk_low; 11262306a36Sopenharmony_ci st->current_clk = apb_clk / count; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), 11562306a36Sopenharmony_ci &st->adc_base_spear6xx->clk); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void spear_adc_set_ctrl(struct spear_adc_state *st, int n, 11962306a36Sopenharmony_ci u32 val) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci __raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic u32 spear_adc_get_average(struct spear_adc_state *st) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci if (of_device_is_compatible(st->np, "st,spear600-adc")) { 12762306a36Sopenharmony_ci return __raw_readl(&st->adc_base_spear6xx->average.msb) & 12862306a36Sopenharmony_ci SPEAR_ADC_DATA_MASK; 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci return __raw_readl(&st->adc_base_spear3xx->average) & 13162306a36Sopenharmony_ci SPEAR_ADC_DATA_MASK; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci if (of_device_is_compatible(st->np, "st,spear600-adc")) { 13862306a36Sopenharmony_ci __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), 13962306a36Sopenharmony_ci &st->adc_base_spear6xx->scan_rate_lo); 14062306a36Sopenharmony_ci __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), 14162306a36Sopenharmony_ci &st->adc_base_spear6xx->scan_rate_hi); 14262306a36Sopenharmony_ci } else { 14362306a36Sopenharmony_ci __raw_writel(rate, &st->adc_base_spear3xx->scan_rate); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int spear_adc_read_raw(struct iio_dev *indio_dev, 14862306a36Sopenharmony_ci struct iio_chan_spec const *chan, 14962306a36Sopenharmony_ci int *val, 15062306a36Sopenharmony_ci int *val2, 15162306a36Sopenharmony_ci long mask) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct spear_adc_state *st = iio_priv(indio_dev); 15462306a36Sopenharmony_ci u32 status; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci switch (mask) { 15762306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 15862306a36Sopenharmony_ci mutex_lock(&st->lock); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | 16162306a36Sopenharmony_ci SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | 16262306a36Sopenharmony_ci SPEAR_ADC_STATUS_START_CONVERSION | 16362306a36Sopenharmony_ci SPEAR_ADC_STATUS_ADC_ENABLE; 16462306a36Sopenharmony_ci if (st->vref_external == 0) 16562306a36Sopenharmony_ci status |= SPEAR_ADC_STATUS_VREF_INTERNAL; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci spear_adc_set_status(st, status); 16862306a36Sopenharmony_ci wait_for_completion(&st->completion); /* set by ISR */ 16962306a36Sopenharmony_ci *val = st->value; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci mutex_unlock(&st->lock); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return IIO_VAL_INT; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 17662306a36Sopenharmony_ci *val = st->vref_external; 17762306a36Sopenharmony_ci *val2 = SPEAR_ADC_DATA_BITS; 17862306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 17962306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 18062306a36Sopenharmony_ci *val = st->current_clk; 18162306a36Sopenharmony_ci return IIO_VAL_INT; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int spear_adc_write_raw(struct iio_dev *indio_dev, 18862306a36Sopenharmony_ci struct iio_chan_spec const *chan, 18962306a36Sopenharmony_ci int val, 19062306a36Sopenharmony_ci int val2, 19162306a36Sopenharmony_ci long mask) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct spear_adc_state *st = iio_priv(indio_dev); 19462306a36Sopenharmony_ci int ret = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (mask != IIO_CHAN_INFO_SAMP_FREQ) 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci mutex_lock(&st->lock); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if ((val < SPEAR_ADC_CLK_MIN) || 20262306a36Sopenharmony_ci (val > SPEAR_ADC_CLK_MAX) || 20362306a36Sopenharmony_ci (val2 != 0)) { 20462306a36Sopenharmony_ci ret = -EINVAL; 20562306a36Sopenharmony_ci goto out; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spear_adc_set_clk(st, val); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciout: 21162306a36Sopenharmony_ci mutex_unlock(&st->lock); 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#define SPEAR_ADC_CHAN(idx) { \ 21662306a36Sopenharmony_ci .type = IIO_VOLTAGE, \ 21762306a36Sopenharmony_ci .indexed = 1, \ 21862306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 21962306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 22062306a36Sopenharmony_ci .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ 22162306a36Sopenharmony_ci .channel = idx, \ 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic const struct iio_chan_spec spear_adc_iio_channels[] = { 22562306a36Sopenharmony_ci SPEAR_ADC_CHAN(0), 22662306a36Sopenharmony_ci SPEAR_ADC_CHAN(1), 22762306a36Sopenharmony_ci SPEAR_ADC_CHAN(2), 22862306a36Sopenharmony_ci SPEAR_ADC_CHAN(3), 22962306a36Sopenharmony_ci SPEAR_ADC_CHAN(4), 23062306a36Sopenharmony_ci SPEAR_ADC_CHAN(5), 23162306a36Sopenharmony_ci SPEAR_ADC_CHAN(6), 23262306a36Sopenharmony_ci SPEAR_ADC_CHAN(7), 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic irqreturn_t spear_adc_isr(int irq, void *dev_id) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct spear_adc_state *st = dev_id; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Read value to clear IRQ */ 24062306a36Sopenharmony_ci st->value = spear_adc_get_average(st); 24162306a36Sopenharmony_ci complete(&st->completion); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return IRQ_HANDLED; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int spear_adc_configure(struct spear_adc_state *st) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci int i; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Reset ADC core */ 25162306a36Sopenharmony_ci spear_adc_set_status(st, 0); 25262306a36Sopenharmony_ci __raw_writel(0, &st->adc_base_spear6xx->clk); 25362306a36Sopenharmony_ci for (i = 0; i < 8; i++) 25462306a36Sopenharmony_ci spear_adc_set_ctrl(st, i, 0); 25562306a36Sopenharmony_ci spear_adc_set_scanrate(st, 0); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spear_adc_set_clk(st, st->sampling_freq); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct iio_info spear_adc_info = { 26362306a36Sopenharmony_ci .read_raw = &spear_adc_read_raw, 26462306a36Sopenharmony_ci .write_raw = &spear_adc_write_raw, 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int spear_adc_probe(struct platform_device *pdev) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 27062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 27162306a36Sopenharmony_ci struct spear_adc_state *st; 27262306a36Sopenharmony_ci struct iio_dev *indio_dev = NULL; 27362306a36Sopenharmony_ci int ret = -ENODEV; 27462306a36Sopenharmony_ci int irq; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); 27762306a36Sopenharmony_ci if (!indio_dev) { 27862306a36Sopenharmony_ci dev_err(dev, "failed allocating iio device\n"); 27962306a36Sopenharmony_ci return -ENOMEM; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci st = iio_priv(indio_dev); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci mutex_init(&st->lock); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci st->np = np; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * SPEAr600 has a different register layout than other SPEAr SoC's 29062306a36Sopenharmony_ci * (e.g. SPEAr3xx). Let's provide two register base addresses 29162306a36Sopenharmony_ci * to support multi-arch kernels. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci st->adc_base_spear6xx = devm_platform_ioremap_resource(pdev, 0); 29462306a36Sopenharmony_ci if (IS_ERR(st->adc_base_spear6xx)) 29562306a36Sopenharmony_ci return PTR_ERR(st->adc_base_spear6xx); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci st->adc_base_spear3xx = 29862306a36Sopenharmony_ci (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci st->clk = devm_clk_get(dev, NULL); 30162306a36Sopenharmony_ci if (IS_ERR(st->clk)) { 30262306a36Sopenharmony_ci dev_err(dev, "failed getting clock\n"); 30362306a36Sopenharmony_ci return PTR_ERR(st->clk); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci ret = clk_prepare_enable(st->clk); 30762306a36Sopenharmony_ci if (ret) { 30862306a36Sopenharmony_ci dev_err(dev, "failed enabling clock\n"); 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 31362306a36Sopenharmony_ci if (irq < 0) { 31462306a36Sopenharmony_ci ret = irq; 31562306a36Sopenharmony_ci goto errout2; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, 31962306a36Sopenharmony_ci st); 32062306a36Sopenharmony_ci if (ret < 0) { 32162306a36Sopenharmony_ci dev_err(dev, "failed requesting interrupt\n"); 32262306a36Sopenharmony_ci goto errout2; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (of_property_read_u32(np, "sampling-frequency", 32662306a36Sopenharmony_ci &st->sampling_freq)) { 32762306a36Sopenharmony_ci dev_err(dev, "sampling-frequency missing in DT\n"); 32862306a36Sopenharmony_ci ret = -EINVAL; 32962306a36Sopenharmony_ci goto errout2; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * Optional avg_samples defaults to 0, resulting in single data 33462306a36Sopenharmony_ci * conversion 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci of_property_read_u32(np, "average-samples", &st->avg_samples); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * Optional vref_external defaults to 0, resulting in internal vref 34062306a36Sopenharmony_ci * selection 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci of_property_read_u32(np, "vref-external", &st->vref_external); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci spear_adc_configure(st); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci init_completion(&st->completion); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci indio_dev->name = SPEAR_ADC_MOD_NAME; 35162306a36Sopenharmony_ci indio_dev->info = &spear_adc_info; 35262306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 35362306a36Sopenharmony_ci indio_dev->channels = spear_adc_iio_channels; 35462306a36Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 35762306a36Sopenharmony_ci if (ret) 35862306a36Sopenharmony_ci goto errout2; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cierrout2: 36562306a36Sopenharmony_ci clk_disable_unprepare(st->clk); 36662306a36Sopenharmony_ci return ret; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int spear_adc_remove(struct platform_device *pdev) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 37262306a36Sopenharmony_ci struct spear_adc_state *st = iio_priv(indio_dev); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci iio_device_unregister(indio_dev); 37562306a36Sopenharmony_ci clk_disable_unprepare(st->clk); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci#ifdef CONFIG_OF 38162306a36Sopenharmony_cistatic const struct of_device_id spear_adc_dt_ids[] = { 38262306a36Sopenharmony_ci { .compatible = "st,spear600-adc", }, 38362306a36Sopenharmony_ci { /* sentinel */ } 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spear_adc_dt_ids); 38662306a36Sopenharmony_ci#endif 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic struct platform_driver spear_adc_driver = { 38962306a36Sopenharmony_ci .probe = spear_adc_probe, 39062306a36Sopenharmony_ci .remove = spear_adc_remove, 39162306a36Sopenharmony_ci .driver = { 39262306a36Sopenharmony_ci .name = SPEAR_ADC_MOD_NAME, 39362306a36Sopenharmony_ci .of_match_table = of_match_ptr(spear_adc_dt_ids), 39462306a36Sopenharmony_ci }, 39562306a36Sopenharmony_ci}; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cimodule_platform_driver(spear_adc_driver); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Roese <sr@denx.de>"); 40062306a36Sopenharmony_ciMODULE_DESCRIPTION("SPEAr ADC driver"); 40162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 402