162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the ADC present in the Atmel AT91 evaluation boards. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011 Free Electrons 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitmap.h> 962306a36Sopenharmony_ci#include <linux/bitops.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/input.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/jiffies.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/sched.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/wait.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/iio/iio.h> 2562306a36Sopenharmony_ci#include <linux/iio/buffer.h> 2662306a36Sopenharmony_ci#include <linux/iio/trigger.h> 2762306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 2862306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2962306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Registers */ 3262306a36Sopenharmony_ci#define AT91_ADC_CR 0x00 /* Control Register */ 3362306a36Sopenharmony_ci#define AT91_ADC_SWRST (1 << 0) /* Software Reset */ 3462306a36Sopenharmony_ci#define AT91_ADC_START (1 << 1) /* Start Conversion */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define AT91_ADC_MR 0x04 /* Mode Register */ 3762306a36Sopenharmony_ci#define AT91_ADC_TSAMOD (3 << 0) /* ADC mode */ 3862306a36Sopenharmony_ci#define AT91_ADC_TSAMOD_ADC_ONLY_MODE (0 << 0) /* ADC Mode */ 3962306a36Sopenharmony_ci#define AT91_ADC_TSAMOD_TS_ONLY_MODE (1 << 0) /* Touch Screen Only Mode */ 4062306a36Sopenharmony_ci#define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */ 4162306a36Sopenharmony_ci#define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */ 4262306a36Sopenharmony_ci#define AT91_ADC_TRGSEL_TC0 (0 << 1) 4362306a36Sopenharmony_ci#define AT91_ADC_TRGSEL_TC1 (1 << 1) 4462306a36Sopenharmony_ci#define AT91_ADC_TRGSEL_TC2 (2 << 1) 4562306a36Sopenharmony_ci#define AT91_ADC_TRGSEL_EXTERNAL (6 << 1) 4662306a36Sopenharmony_ci#define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */ 4762306a36Sopenharmony_ci#define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */ 4862306a36Sopenharmony_ci#define AT91_ADC_PENDET (1 << 6) /* Pen contact detection enable */ 4962306a36Sopenharmony_ci#define AT91_ADC_PRESCAL_9260 (0x3f << 8) /* Prescalar Rate Selection */ 5062306a36Sopenharmony_ci#define AT91_ADC_PRESCAL_9G45 (0xff << 8) 5162306a36Sopenharmony_ci#define AT91_ADC_PRESCAL_(x) ((x) << 8) 5262306a36Sopenharmony_ci#define AT91_ADC_STARTUP_9260 (0x1f << 16) /* Startup Up Time */ 5362306a36Sopenharmony_ci#define AT91_ADC_STARTUP_9G45 (0x7f << 16) 5462306a36Sopenharmony_ci#define AT91_ADC_STARTUP_9X5 (0xf << 16) 5562306a36Sopenharmony_ci#define AT91_ADC_STARTUP_(x) ((x) << 16) 5662306a36Sopenharmony_ci#define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */ 5762306a36Sopenharmony_ci#define AT91_ADC_SHTIM_(x) ((x) << 24) 5862306a36Sopenharmony_ci#define AT91_ADC_PENDBC (0x0f << 28) /* Pen Debounce time */ 5962306a36Sopenharmony_ci#define AT91_ADC_PENDBC_(x) ((x) << 28) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define AT91_ADC_TSR 0x0C 6262306a36Sopenharmony_ci#define AT91_ADC_TSR_SHTIM (0xf << 24) /* Sample & Hold Time */ 6362306a36Sopenharmony_ci#define AT91_ADC_TSR_SHTIM_(x) ((x) << 24) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define AT91_ADC_CHER 0x10 /* Channel Enable Register */ 6662306a36Sopenharmony_ci#define AT91_ADC_CHDR 0x14 /* Channel Disable Register */ 6762306a36Sopenharmony_ci#define AT91_ADC_CHSR 0x18 /* Channel Status Register */ 6862306a36Sopenharmony_ci#define AT91_ADC_CH(n) (1 << (n)) /* Channel Number */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define AT91_ADC_SR 0x1C /* Status Register */ 7162306a36Sopenharmony_ci#define AT91_ADC_EOC(n) (1 << (n)) /* End of Conversion on Channel N */ 7262306a36Sopenharmony_ci#define AT91_ADC_OVRE(n) (1 << ((n) + 8))/* Overrun Error on Channel N */ 7362306a36Sopenharmony_ci#define AT91_ADC_DRDY (1 << 16) /* Data Ready */ 7462306a36Sopenharmony_ci#define AT91_ADC_GOVRE (1 << 17) /* General Overrun Error */ 7562306a36Sopenharmony_ci#define AT91_ADC_ENDRX (1 << 18) /* End of RX Buffer */ 7662306a36Sopenharmony_ci#define AT91_ADC_RXFUFF (1 << 19) /* RX Buffer Full */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define AT91_ADC_SR_9X5 0x30 /* Status Register for 9x5 */ 7962306a36Sopenharmony_ci#define AT91_ADC_SR_DRDY_9X5 (1 << 24) /* Data Ready */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define AT91_ADC_LCDR 0x20 /* Last Converted Data Register */ 8262306a36Sopenharmony_ci#define AT91_ADC_LDATA (0x3ff) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define AT91_ADC_IER 0x24 /* Interrupt Enable Register */ 8562306a36Sopenharmony_ci#define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */ 8662306a36Sopenharmony_ci#define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */ 8762306a36Sopenharmony_ci#define AT91RL_ADC_IER_PEN (1 << 20) 8862306a36Sopenharmony_ci#define AT91RL_ADC_IER_NOPEN (1 << 21) 8962306a36Sopenharmony_ci#define AT91_ADC_IER_PEN (1 << 29) 9062306a36Sopenharmony_ci#define AT91_ADC_IER_NOPEN (1 << 30) 9162306a36Sopenharmony_ci#define AT91_ADC_IER_XRDY (1 << 20) 9262306a36Sopenharmony_ci#define AT91_ADC_IER_YRDY (1 << 21) 9362306a36Sopenharmony_ci#define AT91_ADC_IER_PRDY (1 << 22) 9462306a36Sopenharmony_ci#define AT91_ADC_ISR_PENS (1 << 31) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */ 9762306a36Sopenharmony_ci#define AT91_ADC_DATA (0x3ff) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define AT91_ADC_ACR 0x94 /* Analog Control Register */ 10262306a36Sopenharmony_ci#define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define AT91_ADC_TSMR 0xB0 10562306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */ 10662306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSMODE_NONE (0 << 0) 10762306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0) 10862306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0) 10962306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0) 11062306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */ 11162306a36Sopenharmony_ci#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4) 11262306a36Sopenharmony_ci#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */ 11362306a36Sopenharmony_ci#define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16) 11462306a36Sopenharmony_ci#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */ 11562306a36Sopenharmony_ci#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28) 11662306a36Sopenharmony_ci#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */ 11762306a36Sopenharmony_ci#define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */ 11862306a36Sopenharmony_ci#define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define AT91_ADC_TSXPOSR 0xB4 12162306a36Sopenharmony_ci#define AT91_ADC_TSYPOSR 0xB8 12262306a36Sopenharmony_ci#define AT91_ADC_TSPRESSR 0xBC 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define AT91_ADC_TRGR_9260 AT91_ADC_MR 12562306a36Sopenharmony_ci#define AT91_ADC_TRGR_9G45 0x08 12662306a36Sopenharmony_ci#define AT91_ADC_TRGR_9X5 0xC0 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* Trigger Register bit field */ 12962306a36Sopenharmony_ci#define AT91_ADC_TRGR_TRGPER (0xffff << 16) 13062306a36Sopenharmony_ci#define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16) 13162306a36Sopenharmony_ci#define AT91_ADC_TRGR_TRGMOD (0x7 << 0) 13262306a36Sopenharmony_ci#define AT91_ADC_TRGR_NONE (0 << 0) 13362306a36Sopenharmony_ci#define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define AT91_ADC_CHAN(st, ch) \ 13662306a36Sopenharmony_ci (st->registers->channel_base + (ch * 4)) 13762306a36Sopenharmony_ci#define at91_adc_readl(st, reg) \ 13862306a36Sopenharmony_ci (readl_relaxed(st->reg_base + reg)) 13962306a36Sopenharmony_ci#define at91_adc_writel(st, reg, val) \ 14062306a36Sopenharmony_ci (writel_relaxed(val, st->reg_base + reg)) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define DRIVER_NAME "at91_adc" 14362306a36Sopenharmony_ci#define MAX_POS_BITS 12 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ 14662306a36Sopenharmony_ci#define TOUCH_PEN_DETECT_DEBOUNCE_US 200 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define MAX_RLPOS_BITS 10 14962306a36Sopenharmony_ci#define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */ 15062306a36Sopenharmony_ci#define TOUCH_SHTIM 0xa 15162306a36Sopenharmony_ci#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cienum atmel_adc_ts_type { 15462306a36Sopenharmony_ci ATMEL_ADC_TOUCHSCREEN_NONE = 0, 15562306a36Sopenharmony_ci ATMEL_ADC_TOUCHSCREEN_4WIRE = 4, 15662306a36Sopenharmony_ci ATMEL_ADC_TOUCHSCREEN_5WIRE = 5, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/** 16062306a36Sopenharmony_ci * struct at91_adc_trigger - description of triggers 16162306a36Sopenharmony_ci * @name: name of the trigger advertised to the user 16262306a36Sopenharmony_ci * @value: value to set in the ADC's trigger setup register 16362306a36Sopenharmony_ci * to enable the trigger 16462306a36Sopenharmony_ci * @is_external: Does the trigger rely on an external pin? 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistruct at91_adc_trigger { 16762306a36Sopenharmony_ci const char *name; 16862306a36Sopenharmony_ci u8 value; 16962306a36Sopenharmony_ci bool is_external; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * struct at91_adc_reg_desc - Various informations relative to registers 17462306a36Sopenharmony_ci * @channel_base: Base offset for the channel data registers 17562306a36Sopenharmony_ci * @drdy_mask: Mask of the DRDY field in the relevant registers 17662306a36Sopenharmony_ci * (Interruptions registers mostly) 17762306a36Sopenharmony_ci * @status_register: Offset of the Interrupt Status Register 17862306a36Sopenharmony_ci * @trigger_register: Offset of the Trigger setup register 17962306a36Sopenharmony_ci * @mr_prescal_mask: Mask of the PRESCAL field in the adc MR register 18062306a36Sopenharmony_ci * @mr_startup_mask: Mask of the STARTUP field in the adc MR register 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_cistruct at91_adc_reg_desc { 18362306a36Sopenharmony_ci u8 channel_base; 18462306a36Sopenharmony_ci u32 drdy_mask; 18562306a36Sopenharmony_ci u8 status_register; 18662306a36Sopenharmony_ci u8 trigger_register; 18762306a36Sopenharmony_ci u32 mr_prescal_mask; 18862306a36Sopenharmony_ci u32 mr_startup_mask; 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistruct at91_adc_caps { 19262306a36Sopenharmony_ci bool has_ts; /* Support touch screen */ 19362306a36Sopenharmony_ci bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */ 19462306a36Sopenharmony_ci /* 19562306a36Sopenharmony_ci * Numbers of sampling data will be averaged. Can be 0~3. 19662306a36Sopenharmony_ci * Hardware can average (2 ^ ts_filter_average) sample data. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci u8 ts_filter_average; 19962306a36Sopenharmony_ci /* Pen Detection input pull-up resistor, can be 0~3 */ 20062306a36Sopenharmony_ci u8 ts_pen_detect_sensitivity; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* startup time calculate function */ 20362306a36Sopenharmony_ci u32 (*calc_startup_ticks)(u32 startup_time, u32 adc_clk_khz); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci u8 num_channels; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci u8 low_res_bits; 20862306a36Sopenharmony_ci u8 high_res_bits; 20962306a36Sopenharmony_ci u32 trigger_number; 21062306a36Sopenharmony_ci const struct at91_adc_trigger *triggers; 21162306a36Sopenharmony_ci struct at91_adc_reg_desc registers; 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistruct at91_adc_state { 21562306a36Sopenharmony_ci struct clk *adc_clk; 21662306a36Sopenharmony_ci u16 *buffer; 21762306a36Sopenharmony_ci unsigned long channels_mask; 21862306a36Sopenharmony_ci struct clk *clk; 21962306a36Sopenharmony_ci bool done; 22062306a36Sopenharmony_ci int irq; 22162306a36Sopenharmony_ci u16 last_value; 22262306a36Sopenharmony_ci int chnb; 22362306a36Sopenharmony_ci struct mutex lock; 22462306a36Sopenharmony_ci u8 num_channels; 22562306a36Sopenharmony_ci void __iomem *reg_base; 22662306a36Sopenharmony_ci const struct at91_adc_reg_desc *registers; 22762306a36Sopenharmony_ci u32 startup_time; 22862306a36Sopenharmony_ci u8 sample_hold_time; 22962306a36Sopenharmony_ci bool sleep_mode; 23062306a36Sopenharmony_ci struct iio_trigger **trig; 23162306a36Sopenharmony_ci bool use_external; 23262306a36Sopenharmony_ci u32 vref_mv; 23362306a36Sopenharmony_ci u32 res; /* resolution used for convertions */ 23462306a36Sopenharmony_ci wait_queue_head_t wq_data_avail; 23562306a36Sopenharmony_ci const struct at91_adc_caps *caps; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * Following ADC channels are shared by touchscreen: 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * CH0 -- Touch screen XP/UL 24162306a36Sopenharmony_ci * CH1 -- Touch screen XM/UR 24262306a36Sopenharmony_ci * CH2 -- Touch screen YP/LL 24362306a36Sopenharmony_ci * CH3 -- Touch screen YM/Sense 24462306a36Sopenharmony_ci * CH4 -- Touch screen LR(5-wire only) 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * The bitfields below represents the reserved channel in the 24762306a36Sopenharmony_ci * touchscreen mode. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 0) 25062306a36Sopenharmony_ci#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 0) 25162306a36Sopenharmony_ci enum atmel_adc_ts_type touchscreen_type; 25262306a36Sopenharmony_ci struct input_dev *ts_input; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci u16 ts_sample_period_val; 25562306a36Sopenharmony_ci u32 ts_pressure_threshold; 25662306a36Sopenharmony_ci u16 ts_pendbc; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci bool ts_bufferedmeasure; 25962306a36Sopenharmony_ci u32 ts_prev_absx; 26062306a36Sopenharmony_ci u32 ts_prev_absy; 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic irqreturn_t at91_adc_trigger_handler(int irq, void *p) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct iio_poll_func *pf = p; 26662306a36Sopenharmony_ci struct iio_dev *idev = pf->indio_dev; 26762306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 26862306a36Sopenharmony_ci struct iio_chan_spec const *chan; 26962306a36Sopenharmony_ci int i, j = 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci for (i = 0; i < idev->masklength; i++) { 27262306a36Sopenharmony_ci if (!test_bit(i, idev->active_scan_mask)) 27362306a36Sopenharmony_ci continue; 27462306a36Sopenharmony_ci chan = idev->channels + i; 27562306a36Sopenharmony_ci st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, chan->channel)); 27662306a36Sopenharmony_ci j++; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(idev, st->buffer, pf->timestamp); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci iio_trigger_notify_done(idev->trig); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Needed to ACK the DRDY interruption */ 28462306a36Sopenharmony_ci at91_adc_readl(st, AT91_ADC_LCDR); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci enable_irq(st->irq); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return IRQ_HANDLED; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* Handler for classic adc channel eoc trigger */ 29262306a36Sopenharmony_cistatic void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (iio_buffer_enabled(idev)) { 29762306a36Sopenharmony_ci disable_irq_nosync(irq); 29862306a36Sopenharmony_ci iio_trigger_poll(idev->trig); 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci st->last_value = at91_adc_readl(st, AT91_ADC_CHAN(st, st->chnb)); 30162306a36Sopenharmony_ci /* Needed to ACK the DRDY interruption */ 30262306a36Sopenharmony_ci at91_adc_readl(st, AT91_ADC_LCDR); 30362306a36Sopenharmony_ci st->done = true; 30462306a36Sopenharmony_ci wake_up_interruptible(&st->wq_data_avail); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int at91_ts_sample(struct iio_dev *idev) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 31162306a36Sopenharmony_ci unsigned int xscale, yscale, reg, z1, z2; 31262306a36Sopenharmony_ci unsigned int x, y, pres, xpos, ypos; 31362306a36Sopenharmony_ci unsigned int rxp = 1; 31462306a36Sopenharmony_ci unsigned int factor = 1000; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci unsigned int xyz_mask_bits = st->res; 31762306a36Sopenharmony_ci unsigned int xyz_mask = (1 << xyz_mask_bits) - 1; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* calculate position */ 32062306a36Sopenharmony_ci /* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */ 32162306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_TSXPOSR); 32262306a36Sopenharmony_ci xpos = reg & xyz_mask; 32362306a36Sopenharmony_ci x = (xpos << MAX_POS_BITS) - xpos; 32462306a36Sopenharmony_ci xscale = (reg >> 16) & xyz_mask; 32562306a36Sopenharmony_ci if (xscale == 0) { 32662306a36Sopenharmony_ci dev_err(&idev->dev, "Error: xscale == 0!\n"); 32762306a36Sopenharmony_ci return -1; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci x /= xscale; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */ 33262306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_TSYPOSR); 33362306a36Sopenharmony_ci ypos = reg & xyz_mask; 33462306a36Sopenharmony_ci y = (ypos << MAX_POS_BITS) - ypos; 33562306a36Sopenharmony_ci yscale = (reg >> 16) & xyz_mask; 33662306a36Sopenharmony_ci if (yscale == 0) { 33762306a36Sopenharmony_ci dev_err(&idev->dev, "Error: yscale == 0!\n"); 33862306a36Sopenharmony_ci return -1; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci y /= yscale; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* calculate the pressure */ 34362306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_TSPRESSR); 34462306a36Sopenharmony_ci z1 = reg & xyz_mask; 34562306a36Sopenharmony_ci z2 = (reg >> 16) & xyz_mask; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (z1 != 0) 34862306a36Sopenharmony_ci pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor) 34962306a36Sopenharmony_ci / factor; 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci pres = st->ts_pressure_threshold; /* no pen contacted */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n", 35462306a36Sopenharmony_ci xpos, xscale, ypos, yscale, z1, z2, pres); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (pres < st->ts_pressure_threshold) { 35762306a36Sopenharmony_ci dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n", 35862306a36Sopenharmony_ci x, y, pres / factor); 35962306a36Sopenharmony_ci input_report_abs(st->ts_input, ABS_X, x); 36062306a36Sopenharmony_ci input_report_abs(st->ts_input, ABS_Y, y); 36162306a36Sopenharmony_ci input_report_abs(st->ts_input, ABS_PRESSURE, pres); 36262306a36Sopenharmony_ci input_report_key(st->ts_input, BTN_TOUCH, 1); 36362306a36Sopenharmony_ci input_sync(st->ts_input); 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci dev_dbg(&idev->dev, "pressure too low: not reporting\n"); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic irqreturn_t at91_adc_rl_interrupt(int irq, void *private) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct iio_dev *idev = private; 37462306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 37562306a36Sopenharmony_ci u32 status = at91_adc_readl(st, st->registers->status_register); 37662306a36Sopenharmony_ci unsigned int reg; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci status &= at91_adc_readl(st, AT91_ADC_IMR); 37962306a36Sopenharmony_ci if (status & GENMASK(st->num_channels - 1, 0)) 38062306a36Sopenharmony_ci handle_adc_eoc_trigger(irq, idev); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (status & AT91RL_ADC_IER_PEN) { 38362306a36Sopenharmony_ci /* Disabling pen debounce is required to get a NOPEN irq */ 38462306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_MR); 38562306a36Sopenharmony_ci reg &= ~AT91_ADC_PENDBC; 38662306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_MR, reg); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); 38962306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_NOPEN 39062306a36Sopenharmony_ci | AT91_ADC_EOC(3)); 39162306a36Sopenharmony_ci /* Set up period trigger for sampling */ 39262306a36Sopenharmony_ci at91_adc_writel(st, st->registers->trigger_register, 39362306a36Sopenharmony_ci AT91_ADC_TRGR_MOD_PERIOD_TRIG | 39462306a36Sopenharmony_ci AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); 39562306a36Sopenharmony_ci } else if (status & AT91RL_ADC_IER_NOPEN) { 39662306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_MR); 39762306a36Sopenharmony_ci reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; 39862306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_MR, reg); 39962306a36Sopenharmony_ci at91_adc_writel(st, st->registers->trigger_register, 40062306a36Sopenharmony_ci AT91_ADC_TRGR_NONE); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_NOPEN 40362306a36Sopenharmony_ci | AT91_ADC_EOC(3)); 40462306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); 40562306a36Sopenharmony_ci st->ts_bufferedmeasure = false; 40662306a36Sopenharmony_ci input_report_key(st->ts_input, BTN_TOUCH, 0); 40762306a36Sopenharmony_ci input_sync(st->ts_input); 40862306a36Sopenharmony_ci } else if (status & AT91_ADC_EOC(3) && st->ts_input) { 40962306a36Sopenharmony_ci /* Conversion finished and we've a touchscreen */ 41062306a36Sopenharmony_ci if (st->ts_bufferedmeasure) { 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * Last measurement is always discarded, since it can 41362306a36Sopenharmony_ci * be erroneous. 41462306a36Sopenharmony_ci * Always report previous measurement 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci input_report_abs(st->ts_input, ABS_X, st->ts_prev_absx); 41762306a36Sopenharmony_ci input_report_abs(st->ts_input, ABS_Y, st->ts_prev_absy); 41862306a36Sopenharmony_ci input_report_key(st->ts_input, BTN_TOUCH, 1); 41962306a36Sopenharmony_ci input_sync(st->ts_input); 42062306a36Sopenharmony_ci } else 42162306a36Sopenharmony_ci st->ts_bufferedmeasure = true; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* Now make new measurement */ 42462306a36Sopenharmony_ci st->ts_prev_absx = at91_adc_readl(st, AT91_ADC_CHAN(st, 3)) 42562306a36Sopenharmony_ci << MAX_RLPOS_BITS; 42662306a36Sopenharmony_ci st->ts_prev_absx /= at91_adc_readl(st, AT91_ADC_CHAN(st, 2)); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci st->ts_prev_absy = at91_adc_readl(st, AT91_ADC_CHAN(st, 1)) 42962306a36Sopenharmony_ci << MAX_RLPOS_BITS; 43062306a36Sopenharmony_ci st->ts_prev_absy /= at91_adc_readl(st, AT91_ADC_CHAN(st, 0)); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return IRQ_HANDLED; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct iio_dev *idev = private; 43962306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 44062306a36Sopenharmony_ci u32 status = at91_adc_readl(st, st->registers->status_register); 44162306a36Sopenharmony_ci const uint32_t ts_data_irq_mask = 44262306a36Sopenharmony_ci AT91_ADC_IER_XRDY | 44362306a36Sopenharmony_ci AT91_ADC_IER_YRDY | 44462306a36Sopenharmony_ci AT91_ADC_IER_PRDY; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (status & GENMASK(st->num_channels - 1, 0)) 44762306a36Sopenharmony_ci handle_adc_eoc_trigger(irq, idev); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (status & AT91_ADC_IER_PEN) { 45062306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); 45162306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN | 45262306a36Sopenharmony_ci ts_data_irq_mask); 45362306a36Sopenharmony_ci /* Set up period trigger for sampling */ 45462306a36Sopenharmony_ci at91_adc_writel(st, st->registers->trigger_register, 45562306a36Sopenharmony_ci AT91_ADC_TRGR_MOD_PERIOD_TRIG | 45662306a36Sopenharmony_ci AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); 45762306a36Sopenharmony_ci } else if (status & AT91_ADC_IER_NOPEN) { 45862306a36Sopenharmony_ci at91_adc_writel(st, st->registers->trigger_register, 0); 45962306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN | 46062306a36Sopenharmony_ci ts_data_irq_mask); 46162306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci input_report_key(st->ts_input, BTN_TOUCH, 0); 46462306a36Sopenharmony_ci input_sync(st->ts_input); 46562306a36Sopenharmony_ci } else if ((status & ts_data_irq_mask) == ts_data_irq_mask) { 46662306a36Sopenharmony_ci /* Now all touchscreen data is ready */ 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (status & AT91_ADC_ISR_PENS) { 46962306a36Sopenharmony_ci /* validate data by pen contact */ 47062306a36Sopenharmony_ci at91_ts_sample(idev); 47162306a36Sopenharmony_ci } else { 47262306a36Sopenharmony_ci /* triggered by event that is no pen contact, just read 47362306a36Sopenharmony_ci * them to clean the interrupt and discard all. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci at91_adc_readl(st, AT91_ADC_TSXPOSR); 47662306a36Sopenharmony_ci at91_adc_readl(st, AT91_ADC_TSYPOSR); 47762306a36Sopenharmony_ci at91_adc_readl(st, AT91_ADC_TSPRESSR); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return IRQ_HANDLED; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int at91_adc_channel_init(struct iio_dev *idev) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 48762306a36Sopenharmony_ci struct iio_chan_spec *chan_array, *timestamp; 48862306a36Sopenharmony_ci int bit, idx = 0; 48962306a36Sopenharmony_ci unsigned long rsvd_mask = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* If touchscreen is enable, then reserve the adc channels */ 49262306a36Sopenharmony_ci if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) 49362306a36Sopenharmony_ci rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE; 49462306a36Sopenharmony_ci else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE) 49562306a36Sopenharmony_ci rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* set up the channel mask to reserve touchscreen channels */ 49862306a36Sopenharmony_ci st->channels_mask &= ~rsvd_mask; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci idev->num_channels = bitmap_weight(&st->channels_mask, 50162306a36Sopenharmony_ci st->num_channels) + 1; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci chan_array = devm_kzalloc(&idev->dev, 50462306a36Sopenharmony_ci ((idev->num_channels + 1) * 50562306a36Sopenharmony_ci sizeof(struct iio_chan_spec)), 50662306a36Sopenharmony_ci GFP_KERNEL); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!chan_array) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci for_each_set_bit(bit, &st->channels_mask, st->num_channels) { 51262306a36Sopenharmony_ci struct iio_chan_spec *chan = chan_array + idx; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci chan->type = IIO_VOLTAGE; 51562306a36Sopenharmony_ci chan->indexed = 1; 51662306a36Sopenharmony_ci chan->channel = bit; 51762306a36Sopenharmony_ci chan->scan_index = idx; 51862306a36Sopenharmony_ci chan->scan_type.sign = 'u'; 51962306a36Sopenharmony_ci chan->scan_type.realbits = st->res; 52062306a36Sopenharmony_ci chan->scan_type.storagebits = 16; 52162306a36Sopenharmony_ci chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); 52262306a36Sopenharmony_ci chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); 52362306a36Sopenharmony_ci idx++; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci timestamp = chan_array + idx; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci timestamp->type = IIO_TIMESTAMP; 52862306a36Sopenharmony_ci timestamp->channel = -1; 52962306a36Sopenharmony_ci timestamp->scan_index = idx; 53062306a36Sopenharmony_ci timestamp->scan_type.sign = 's'; 53162306a36Sopenharmony_ci timestamp->scan_type.realbits = 64; 53262306a36Sopenharmony_ci timestamp->scan_type.storagebits = 64; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci idev->channels = chan_array; 53562306a36Sopenharmony_ci return idev->num_channels; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int at91_adc_get_trigger_value_by_name(struct iio_dev *idev, 53962306a36Sopenharmony_ci const struct at91_adc_trigger *triggers, 54062306a36Sopenharmony_ci const char *trigger_name) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 54362306a36Sopenharmony_ci int i; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci for (i = 0; i < st->caps->trigger_number; i++) { 54662306a36Sopenharmony_ci char *name = kasprintf(GFP_KERNEL, 54762306a36Sopenharmony_ci "%s-dev%d-%s", 54862306a36Sopenharmony_ci idev->name, 54962306a36Sopenharmony_ci iio_device_id(idev), 55062306a36Sopenharmony_ci triggers[i].name); 55162306a36Sopenharmony_ci if (!name) 55262306a36Sopenharmony_ci return -ENOMEM; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (strcmp(trigger_name, name) == 0) { 55562306a36Sopenharmony_ci kfree(name); 55662306a36Sopenharmony_ci if (triggers[i].value == 0) 55762306a36Sopenharmony_ci return -EINVAL; 55862306a36Sopenharmony_ci return triggers[i].value; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci kfree(name); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return -EINVAL; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct iio_dev *idev = iio_trigger_get_drvdata(trig); 57062306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 57162306a36Sopenharmony_ci const struct at91_adc_reg_desc *reg = st->registers; 57262306a36Sopenharmony_ci u32 status = at91_adc_readl(st, reg->trigger_register); 57362306a36Sopenharmony_ci int value; 57462306a36Sopenharmony_ci u8 bit; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci value = at91_adc_get_trigger_value_by_name(idev, 57762306a36Sopenharmony_ci st->caps->triggers, 57862306a36Sopenharmony_ci idev->trig->name); 57962306a36Sopenharmony_ci if (value < 0) 58062306a36Sopenharmony_ci return value; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (state) { 58362306a36Sopenharmony_ci st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); 58462306a36Sopenharmony_ci if (st->buffer == NULL) 58562306a36Sopenharmony_ci return -ENOMEM; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci at91_adc_writel(st, reg->trigger_register, 58862306a36Sopenharmony_ci status | value); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci for_each_set_bit(bit, idev->active_scan_mask, 59162306a36Sopenharmony_ci st->num_channels) { 59262306a36Sopenharmony_ci struct iio_chan_spec const *chan = idev->channels + bit; 59362306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CHER, 59462306a36Sopenharmony_ci AT91_ADC_CH(chan->channel)); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci } else { 60062306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci at91_adc_writel(st, reg->trigger_register, 60362306a36Sopenharmony_ci status & ~value); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci for_each_set_bit(bit, idev->active_scan_mask, 60662306a36Sopenharmony_ci st->num_channels) { 60762306a36Sopenharmony_ci struct iio_chan_spec const *chan = idev->channels + bit; 60862306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CHDR, 60962306a36Sopenharmony_ci AT91_ADC_CH(chan->channel)); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci kfree(st->buffer); 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic const struct iio_trigger_ops at91_adc_trigger_ops = { 61862306a36Sopenharmony_ci .set_trigger_state = &at91_adc_configure_trigger, 61962306a36Sopenharmony_ci}; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, 62262306a36Sopenharmony_ci const struct at91_adc_trigger *trigger) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct iio_trigger *trig; 62562306a36Sopenharmony_ci int ret; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name, 62862306a36Sopenharmony_ci iio_device_id(idev), trigger->name); 62962306a36Sopenharmony_ci if (trig == NULL) 63062306a36Sopenharmony_ci return NULL; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci iio_trigger_set_drvdata(trig, idev); 63362306a36Sopenharmony_ci trig->ops = &at91_adc_trigger_ops; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ret = iio_trigger_register(trig); 63662306a36Sopenharmony_ci if (ret) { 63762306a36Sopenharmony_ci iio_trigger_free(trig); 63862306a36Sopenharmony_ci return NULL; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return trig; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int at91_adc_trigger_init(struct iio_dev *idev) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 64762306a36Sopenharmony_ci int i, ret; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci st->trig = devm_kcalloc(&idev->dev, 65062306a36Sopenharmony_ci st->caps->trigger_number, sizeof(*st->trig), 65162306a36Sopenharmony_ci GFP_KERNEL); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (st->trig == NULL) { 65462306a36Sopenharmony_ci ret = -ENOMEM; 65562306a36Sopenharmony_ci goto error_ret; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci for (i = 0; i < st->caps->trigger_number; i++) { 65962306a36Sopenharmony_ci if (st->caps->triggers[i].is_external && !(st->use_external)) 66062306a36Sopenharmony_ci continue; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci st->trig[i] = at91_adc_allocate_trigger(idev, 66362306a36Sopenharmony_ci st->caps->triggers + i); 66462306a36Sopenharmony_ci if (st->trig[i] == NULL) { 66562306a36Sopenharmony_ci dev_err(&idev->dev, 66662306a36Sopenharmony_ci "Could not allocate trigger %d\n", i); 66762306a36Sopenharmony_ci ret = -ENOMEM; 66862306a36Sopenharmony_ci goto error_trigger; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cierror_trigger: 67562306a36Sopenharmony_ci for (i--; i >= 0; i--) { 67662306a36Sopenharmony_ci iio_trigger_unregister(st->trig[i]); 67762306a36Sopenharmony_ci iio_trigger_free(st->trig[i]); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_cierror_ret: 68062306a36Sopenharmony_ci return ret; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void at91_adc_trigger_remove(struct iio_dev *idev) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 68662306a36Sopenharmony_ci int i; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci for (i = 0; i < st->caps->trigger_number; i++) { 68962306a36Sopenharmony_ci iio_trigger_unregister(st->trig[i]); 69062306a36Sopenharmony_ci iio_trigger_free(st->trig[i]); 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int at91_adc_buffer_init(struct iio_dev *idev) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci return iio_triggered_buffer_setup(idev, &iio_pollfunc_store_time, 69762306a36Sopenharmony_ci &at91_adc_trigger_handler, NULL); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic void at91_adc_buffer_remove(struct iio_dev *idev) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci iio_triggered_buffer_cleanup(idev); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic int at91_adc_read_raw(struct iio_dev *idev, 70662306a36Sopenharmony_ci struct iio_chan_spec const *chan, 70762306a36Sopenharmony_ci int *val, int *val2, long mask) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 71062306a36Sopenharmony_ci int ret; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci switch (mask) { 71362306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 71462306a36Sopenharmony_ci mutex_lock(&st->lock); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci st->chnb = chan->channel; 71762306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CHER, 71862306a36Sopenharmony_ci AT91_ADC_CH(chan->channel)); 71962306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, BIT(chan->channel)); 72062306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(st->wq_data_avail, 72362306a36Sopenharmony_ci st->done, 72462306a36Sopenharmony_ci msecs_to_jiffies(1000)); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Disable interrupts, regardless if adc conversion was 72762306a36Sopenharmony_ci * successful or not 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CHDR, 73062306a36Sopenharmony_ci AT91_ADC_CH(chan->channel)); 73162306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel)); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (ret > 0) { 73462306a36Sopenharmony_ci /* a valid conversion took place */ 73562306a36Sopenharmony_ci *val = st->last_value; 73662306a36Sopenharmony_ci st->last_value = 0; 73762306a36Sopenharmony_ci st->done = false; 73862306a36Sopenharmony_ci ret = IIO_VAL_INT; 73962306a36Sopenharmony_ci } else if (ret == 0) { 74062306a36Sopenharmony_ci /* conversion timeout */ 74162306a36Sopenharmony_ci dev_err(&idev->dev, "ADC Channel %d timeout.\n", 74262306a36Sopenharmony_ci chan->channel); 74362306a36Sopenharmony_ci ret = -ETIMEDOUT; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci mutex_unlock(&st->lock); 74762306a36Sopenharmony_ci return ret; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 75062306a36Sopenharmony_ci *val = st->vref_mv; 75162306a36Sopenharmony_ci *val2 = chan->scan_type.realbits; 75262306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 75362306a36Sopenharmony_ci default: 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci return -EINVAL; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic u32 calc_startup_ticks_9260(u32 startup_time, u32 adc_clk_khz) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci /* 76362306a36Sopenharmony_ci * Number of ticks needed to cover the startup time of the ADC 76462306a36Sopenharmony_ci * as defined in the electrical characteristics of the board, 76562306a36Sopenharmony_ci * divided by 8. The formula thus is : 76662306a36Sopenharmony_ci * Startup Time = (ticks + 1) * 8 / ADC Clock 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci /* 77462306a36Sopenharmony_ci * For sama5d3x and at91sam9x5, the formula changes to: 77562306a36Sopenharmony_ci * Startup Time = <lookup_table_value> / ADC Clock 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_ci static const int startup_lookup[] = { 77862306a36Sopenharmony_ci 0, 8, 16, 24, 77962306a36Sopenharmony_ci 64, 80, 96, 112, 78062306a36Sopenharmony_ci 512, 576, 640, 704, 78162306a36Sopenharmony_ci 768, 832, 896, 960 78262306a36Sopenharmony_ci }; 78362306a36Sopenharmony_ci int i, size = ARRAY_SIZE(startup_lookup); 78462306a36Sopenharmony_ci unsigned int ticks; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci ticks = startup_time * adc_clk_khz / 1000; 78762306a36Sopenharmony_ci for (i = 0; i < size; i++) 78862306a36Sopenharmony_ci if (ticks < startup_lookup[i]) 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ticks = i; 79262306a36Sopenharmony_ci if (ticks == size) 79362306a36Sopenharmony_ci /* Reach the end of lookup table */ 79462306a36Sopenharmony_ci ticks = size - 1; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return ticks; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int at91_adc_probe_dt_ts(struct device_node *node, 80062306a36Sopenharmony_ci struct at91_adc_state *st, struct device *dev) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci int ret; 80362306a36Sopenharmony_ci u32 prop; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop); 80662306a36Sopenharmony_ci if (ret) { 80762306a36Sopenharmony_ci dev_info(dev, "ADC Touch screen is disabled.\n"); 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci switch (prop) { 81262306a36Sopenharmony_ci case 4: 81362306a36Sopenharmony_ci case 5: 81462306a36Sopenharmony_ci st->touchscreen_type = prop; 81562306a36Sopenharmony_ci break; 81662306a36Sopenharmony_ci default: 81762306a36Sopenharmony_ci dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop); 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (!st->caps->has_tsmr) 82262306a36Sopenharmony_ci return 0; 82362306a36Sopenharmony_ci prop = 0; 82462306a36Sopenharmony_ci of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); 82562306a36Sopenharmony_ci st->ts_pressure_threshold = prop; 82662306a36Sopenharmony_ci if (st->ts_pressure_threshold) { 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci dev_err(dev, "Invalid pressure threshold for the touchscreen\n"); 83062306a36Sopenharmony_ci return -EINVAL; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic const struct iio_info at91_adc_info = { 83562306a36Sopenharmony_ci .read_raw = &at91_adc_read_raw, 83662306a36Sopenharmony_ci}; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/* Touchscreen related functions */ 83962306a36Sopenharmony_cistatic int atmel_ts_open(struct input_dev *dev) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct at91_adc_state *st = input_get_drvdata(dev); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (st->caps->has_tsmr) 84462306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); 84562306a36Sopenharmony_ci else 84662306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic void atmel_ts_close(struct input_dev *dev) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct at91_adc_state *st = input_get_drvdata(dev); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (st->caps->has_tsmr) 85562306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic int at91_ts_hw_init(struct iio_dev *idev, u32 adc_clk_khz) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 86362306a36Sopenharmony_ci u32 reg = 0; 86462306a36Sopenharmony_ci u32 tssctim = 0; 86562306a36Sopenharmony_ci int i = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid 86862306a36Sopenharmony_ci * pen detect noise. 86962306a36Sopenharmony_ci * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_ci st->ts_pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 87262306a36Sopenharmony_ci 1000, 1); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci while (st->ts_pendbc >> ++i) 87562306a36Sopenharmony_ci ; /* Empty! Find the shift offset */ 87662306a36Sopenharmony_ci if (abs(st->ts_pendbc - (1 << i)) < abs(st->ts_pendbc - (1 << (i - 1)))) 87762306a36Sopenharmony_ci st->ts_pendbc = i; 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci st->ts_pendbc = i - 1; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (!st->caps->has_tsmr) { 88262306a36Sopenharmony_ci reg = at91_adc_readl(st, AT91_ADC_MR); 88362306a36Sopenharmony_ci reg |= AT91_ADC_TSAMOD_TS_ONLY_MODE | AT91_ADC_PENDET; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; 88662306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_MR, reg); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci reg = AT91_ADC_TSR_SHTIM_(TOUCH_SHTIM) & AT91_ADC_TSR_SHTIM; 88962306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_TSR, reg); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US_RL * 89262306a36Sopenharmony_ci adc_clk_khz / 1000) - 1, 1); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Touchscreen Switches Closure time needed for allowing the value to 89862306a36Sopenharmony_ci * stabilize. 89962306a36Sopenharmony_ci * Switch Closure Time = (TSSCTIM * 4) ADCClock periods 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4); 90262306a36Sopenharmony_ci dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n", 90362306a36Sopenharmony_ci adc_clk_khz, tssctim); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) 90662306a36Sopenharmony_ci reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; 90762306a36Sopenharmony_ci else 90862306a36Sopenharmony_ci reg = AT91_ADC_TSMR_TSMODE_5WIRE; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM; 91162306a36Sopenharmony_ci reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) 91262306a36Sopenharmony_ci & AT91_ADC_TSMR_TSAV; 91362306a36Sopenharmony_ci reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC; 91462306a36Sopenharmony_ci reg |= AT91_ADC_TSMR_NOTSDMA; 91562306a36Sopenharmony_ci reg |= AT91_ADC_TSMR_PENDET_ENA; 91662306a36Sopenharmony_ci reg |= 0x03 << 8; /* TSFREQ, needs to be bigger than TSAV */ 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_TSMR, reg); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* Change adc internal resistor value for better pen detection, 92162306a36Sopenharmony_ci * default value is 100 kOhm. 92262306a36Sopenharmony_ci * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm 92362306a36Sopenharmony_ci * option only available on ES2 and higher 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity 92662306a36Sopenharmony_ci & AT91_ADC_ACR_PENDETSENS); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* Sample Period Time = (TRGPER + 1) / ADCClock */ 92962306a36Sopenharmony_ci st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * 93062306a36Sopenharmony_ci adc_clk_khz / 1000) - 1, 1); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci return 0; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic int at91_ts_register(struct iio_dev *idev, 93662306a36Sopenharmony_ci struct platform_device *pdev) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 93962306a36Sopenharmony_ci struct input_dev *input; 94062306a36Sopenharmony_ci int ret; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci input = input_allocate_device(); 94362306a36Sopenharmony_ci if (!input) { 94462306a36Sopenharmony_ci dev_err(&idev->dev, "Failed to allocate TS device!\n"); 94562306a36Sopenharmony_ci return -ENOMEM; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci input->name = DRIVER_NAME; 94962306a36Sopenharmony_ci input->id.bustype = BUS_HOST; 95062306a36Sopenharmony_ci input->dev.parent = &pdev->dev; 95162306a36Sopenharmony_ci input->open = atmel_ts_open; 95262306a36Sopenharmony_ci input->close = atmel_ts_close; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci __set_bit(EV_ABS, input->evbit); 95562306a36Sopenharmony_ci __set_bit(EV_KEY, input->evbit); 95662306a36Sopenharmony_ci __set_bit(BTN_TOUCH, input->keybit); 95762306a36Sopenharmony_ci if (st->caps->has_tsmr) { 95862306a36Sopenharmony_ci input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 95962306a36Sopenharmony_ci 0, 0); 96062306a36Sopenharmony_ci input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 96162306a36Sopenharmony_ci 0, 0); 96262306a36Sopenharmony_ci input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); 96362306a36Sopenharmony_ci } else { 96462306a36Sopenharmony_ci if (st->touchscreen_type != ATMEL_ADC_TOUCHSCREEN_4WIRE) { 96562306a36Sopenharmony_ci dev_err(&pdev->dev, 96662306a36Sopenharmony_ci "This touchscreen controller only support 4 wires\n"); 96762306a36Sopenharmony_ci ret = -EINVAL; 96862306a36Sopenharmony_ci goto err; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci input_set_abs_params(input, ABS_X, 0, (1 << MAX_RLPOS_BITS) - 1, 97262306a36Sopenharmony_ci 0, 0); 97362306a36Sopenharmony_ci input_set_abs_params(input, ABS_Y, 0, (1 << MAX_RLPOS_BITS) - 1, 97462306a36Sopenharmony_ci 0, 0); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci st->ts_input = input; 97862306a36Sopenharmony_ci input_set_drvdata(input, st); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci ret = input_register_device(input); 98162306a36Sopenharmony_ci if (ret) 98262306a36Sopenharmony_ci goto err; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return ret; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cierr: 98762306a36Sopenharmony_ci input_free_device(st->ts_input); 98862306a36Sopenharmony_ci return ret; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void at91_ts_unregister(struct at91_adc_state *st) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci input_unregister_device(st->ts_input); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int at91_adc_probe(struct platform_device *pdev) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim; 99962306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 100062306a36Sopenharmony_ci int ret; 100162306a36Sopenharmony_ci struct iio_dev *idev; 100262306a36Sopenharmony_ci struct at91_adc_state *st; 100362306a36Sopenharmony_ci u32 reg, prop; 100462306a36Sopenharmony_ci char *s; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state)); 100762306a36Sopenharmony_ci if (!idev) 100862306a36Sopenharmony_ci return -ENOMEM; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci st = iio_priv(idev); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci st->caps = of_device_get_match_data(&pdev->dev); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { 101762306a36Sopenharmony_ci dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); 101862306a36Sopenharmony_ci return -EINVAL; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci st->channels_mask = prop; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { 102562306a36Sopenharmony_ci dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); 102662306a36Sopenharmony_ci return -EINVAL; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci st->startup_time = prop; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci prop = 0; 103162306a36Sopenharmony_ci of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); 103262306a36Sopenharmony_ci st->sample_hold_time = prop; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { 103562306a36Sopenharmony_ci dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); 103662306a36Sopenharmony_ci return -EINVAL; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci st->vref_mv = prop; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci st->res = st->caps->high_res_bits; 104162306a36Sopenharmony_ci if (st->caps->low_res_bits && 104262306a36Sopenharmony_ci !of_property_read_string(node, "atmel,adc-use-res", (const char **)&s) 104362306a36Sopenharmony_ci && !strcmp(s, "lowres")) 104462306a36Sopenharmony_ci st->res = st->caps->low_res_bits; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci dev_info(&idev->dev, "Resolution used: %u bits\n", st->res); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci st->registers = &st->caps->registers; 104962306a36Sopenharmony_ci st->num_channels = st->caps->num_channels; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Check if touchscreen is supported. */ 105262306a36Sopenharmony_ci if (st->caps->has_ts) { 105362306a36Sopenharmony_ci ret = at91_adc_probe_dt_ts(node, st, &idev->dev); 105462306a36Sopenharmony_ci if (ret) 105562306a36Sopenharmony_ci return ret; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci platform_set_drvdata(pdev, idev); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci idev->name = dev_name(&pdev->dev); 106162306a36Sopenharmony_ci idev->modes = INDIO_DIRECT_MODE; 106262306a36Sopenharmony_ci idev->info = &at91_adc_info; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci st->irq = platform_get_irq(pdev, 0); 106562306a36Sopenharmony_ci if (st->irq < 0) 106662306a36Sopenharmony_ci return -ENODEV; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci st->reg_base = devm_platform_ioremap_resource(pdev, 0); 106962306a36Sopenharmony_ci if (IS_ERR(st->reg_base)) 107062306a36Sopenharmony_ci return PTR_ERR(st->reg_base); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* 107462306a36Sopenharmony_ci * Disable all IRQs before setting up the handler 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); 107762306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (st->caps->has_tsmr) 108062306a36Sopenharmony_ci ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, 108162306a36Sopenharmony_ci pdev->dev.driver->name, idev); 108262306a36Sopenharmony_ci else 108362306a36Sopenharmony_ci ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, 108462306a36Sopenharmony_ci pdev->dev.driver->name, idev); 108562306a36Sopenharmony_ci if (ret) { 108662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); 108762306a36Sopenharmony_ci return ret; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci st->clk = devm_clk_get(&pdev->dev, "adc_clk"); 109162306a36Sopenharmony_ci if (IS_ERR(st->clk)) { 109262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get the clock.\n"); 109362306a36Sopenharmony_ci ret = PTR_ERR(st->clk); 109462306a36Sopenharmony_ci goto error_free_irq; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci ret = clk_prepare_enable(st->clk); 109862306a36Sopenharmony_ci if (ret) { 109962306a36Sopenharmony_ci dev_err(&pdev->dev, 110062306a36Sopenharmony_ci "Could not prepare or enable the clock.\n"); 110162306a36Sopenharmony_ci goto error_free_irq; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); 110562306a36Sopenharmony_ci if (IS_ERR(st->adc_clk)) { 110662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); 110762306a36Sopenharmony_ci ret = PTR_ERR(st->adc_clk); 110862306a36Sopenharmony_ci goto error_disable_clk; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci ret = clk_prepare_enable(st->adc_clk); 111262306a36Sopenharmony_ci if (ret) { 111362306a36Sopenharmony_ci dev_err(&pdev->dev, 111462306a36Sopenharmony_ci "Could not prepare or enable the ADC clock.\n"); 111562306a36Sopenharmony_ci goto error_disable_clk; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* 111962306a36Sopenharmony_ci * Prescaler rate computation using the formula from the Atmel's 112062306a36Sopenharmony_ci * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being 112162306a36Sopenharmony_ci * specified by the electrical characteristics of the board. 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_ci mstrclk = clk_get_rate(st->clk); 112462306a36Sopenharmony_ci adc_clk = clk_get_rate(st->adc_clk); 112562306a36Sopenharmony_ci adc_clk_khz = adc_clk / 1000; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n", 112862306a36Sopenharmony_ci mstrclk, adc_clk); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci prsc = (mstrclk / (2 * adc_clk)) - 1; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (!st->startup_time) { 113362306a36Sopenharmony_ci dev_err(&pdev->dev, "No startup time available.\n"); 113462306a36Sopenharmony_ci ret = -EINVAL; 113562306a36Sopenharmony_ci goto error_disable_adc_clk; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* 114062306a36Sopenharmony_ci * a minimal Sample and Hold Time is necessary for the ADC to guarantee 114162306a36Sopenharmony_ci * the best converted final value between two channels selection 114262306a36Sopenharmony_ci * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci if (st->sample_hold_time > 0) 114562306a36Sopenharmony_ci shtim = round_up((st->sample_hold_time * adc_clk_khz / 1000) 114662306a36Sopenharmony_ci - 1, 1); 114762306a36Sopenharmony_ci else 114862306a36Sopenharmony_ci shtim = 0; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask; 115162306a36Sopenharmony_ci reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask; 115262306a36Sopenharmony_ci if (st->res == st->caps->low_res_bits) 115362306a36Sopenharmony_ci reg |= AT91_ADC_LOWRES; 115462306a36Sopenharmony_ci if (st->sleep_mode) 115562306a36Sopenharmony_ci reg |= AT91_ADC_SLEEP; 115662306a36Sopenharmony_ci reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM; 115762306a36Sopenharmony_ci at91_adc_writel(st, AT91_ADC_MR, reg); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Setup the ADC channels available on the board */ 116062306a36Sopenharmony_ci ret = at91_adc_channel_init(idev); 116162306a36Sopenharmony_ci if (ret < 0) { 116262306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); 116362306a36Sopenharmony_ci goto error_disable_adc_clk; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci init_waitqueue_head(&st->wq_data_avail); 116762306a36Sopenharmony_ci mutex_init(&st->lock); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* 117062306a36Sopenharmony_ci * Since touch screen will set trigger register as period trigger. So 117162306a36Sopenharmony_ci * when touch screen is enabled, then we have to disable hardware 117262306a36Sopenharmony_ci * trigger for classic adc. 117362306a36Sopenharmony_ci */ 117462306a36Sopenharmony_ci if (!st->touchscreen_type) { 117562306a36Sopenharmony_ci ret = at91_adc_buffer_init(idev); 117662306a36Sopenharmony_ci if (ret < 0) { 117762306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); 117862306a36Sopenharmony_ci goto error_disable_adc_clk; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci ret = at91_adc_trigger_init(idev); 118262306a36Sopenharmony_ci if (ret < 0) { 118362306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); 118462306a36Sopenharmony_ci at91_adc_buffer_remove(idev); 118562306a36Sopenharmony_ci goto error_disable_adc_clk; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci } else { 118862306a36Sopenharmony_ci ret = at91_ts_register(idev, pdev); 118962306a36Sopenharmony_ci if (ret) 119062306a36Sopenharmony_ci goto error_disable_adc_clk; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci at91_ts_hw_init(idev, adc_clk_khz); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci ret = iio_device_register(idev); 119662306a36Sopenharmony_ci if (ret < 0) { 119762306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't register the device.\n"); 119862306a36Sopenharmony_ci goto error_iio_device_register; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return 0; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cierror_iio_device_register: 120462306a36Sopenharmony_ci if (!st->touchscreen_type) { 120562306a36Sopenharmony_ci at91_adc_trigger_remove(idev); 120662306a36Sopenharmony_ci at91_adc_buffer_remove(idev); 120762306a36Sopenharmony_ci } else { 120862306a36Sopenharmony_ci at91_ts_unregister(st); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_cierror_disable_adc_clk: 121162306a36Sopenharmony_ci clk_disable_unprepare(st->adc_clk); 121262306a36Sopenharmony_cierror_disable_clk: 121362306a36Sopenharmony_ci clk_disable_unprepare(st->clk); 121462306a36Sopenharmony_cierror_free_irq: 121562306a36Sopenharmony_ci free_irq(st->irq, idev); 121662306a36Sopenharmony_ci return ret; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic int at91_adc_remove(struct platform_device *pdev) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct iio_dev *idev = platform_get_drvdata(pdev); 122262306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci iio_device_unregister(idev); 122562306a36Sopenharmony_ci if (!st->touchscreen_type) { 122662306a36Sopenharmony_ci at91_adc_trigger_remove(idev); 122762306a36Sopenharmony_ci at91_adc_buffer_remove(idev); 122862306a36Sopenharmony_ci } else { 122962306a36Sopenharmony_ci at91_ts_unregister(st); 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci clk_disable_unprepare(st->adc_clk); 123262306a36Sopenharmony_ci clk_disable_unprepare(st->clk); 123362306a36Sopenharmony_ci free_irq(st->irq, idev); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return 0; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic int at91_adc_suspend(struct device *dev) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct iio_dev *idev = dev_get_drvdata(dev); 124162306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 124462306a36Sopenharmony_ci clk_disable_unprepare(st->clk); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci return 0; 124762306a36Sopenharmony_ci} 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_cistatic int at91_adc_resume(struct device *dev) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci struct iio_dev *idev = dev_get_drvdata(dev); 125262306a36Sopenharmony_ci struct at91_adc_state *st = iio_priv(idev); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci clk_prepare_enable(st->clk); 125562306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci return 0; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, 126162306a36Sopenharmony_ci at91_adc_resume); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic const struct at91_adc_trigger at91sam9260_triggers[] = { 126462306a36Sopenharmony_ci { .name = "timer-counter-0", .value = 0x1 }, 126562306a36Sopenharmony_ci { .name = "timer-counter-1", .value = 0x3 }, 126662306a36Sopenharmony_ci { .name = "timer-counter-2", .value = 0x5 }, 126762306a36Sopenharmony_ci { .name = "external", .value = 0xd, .is_external = true }, 126862306a36Sopenharmony_ci}; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic struct at91_adc_caps at91sam9260_caps = { 127162306a36Sopenharmony_ci .calc_startup_ticks = calc_startup_ticks_9260, 127262306a36Sopenharmony_ci .num_channels = 4, 127362306a36Sopenharmony_ci .low_res_bits = 8, 127462306a36Sopenharmony_ci .high_res_bits = 10, 127562306a36Sopenharmony_ci .registers = { 127662306a36Sopenharmony_ci .channel_base = AT91_ADC_CHR(0), 127762306a36Sopenharmony_ci .drdy_mask = AT91_ADC_DRDY, 127862306a36Sopenharmony_ci .status_register = AT91_ADC_SR, 127962306a36Sopenharmony_ci .trigger_register = AT91_ADC_TRGR_9260, 128062306a36Sopenharmony_ci .mr_prescal_mask = AT91_ADC_PRESCAL_9260, 128162306a36Sopenharmony_ci .mr_startup_mask = AT91_ADC_STARTUP_9260, 128262306a36Sopenharmony_ci }, 128362306a36Sopenharmony_ci .triggers = at91sam9260_triggers, 128462306a36Sopenharmony_ci .trigger_number = ARRAY_SIZE(at91sam9260_triggers), 128562306a36Sopenharmony_ci}; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic const struct at91_adc_trigger at91sam9x5_triggers[] = { 128862306a36Sopenharmony_ci { .name = "external-rising", .value = 0x1, .is_external = true }, 128962306a36Sopenharmony_ci { .name = "external-falling", .value = 0x2, .is_external = true }, 129062306a36Sopenharmony_ci { .name = "external-any", .value = 0x3, .is_external = true }, 129162306a36Sopenharmony_ci { .name = "continuous", .value = 0x6 }, 129262306a36Sopenharmony_ci}; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic struct at91_adc_caps at91sam9rl_caps = { 129562306a36Sopenharmony_ci .has_ts = true, 129662306a36Sopenharmony_ci .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ 129762306a36Sopenharmony_ci .num_channels = 6, 129862306a36Sopenharmony_ci .low_res_bits = 8, 129962306a36Sopenharmony_ci .high_res_bits = 10, 130062306a36Sopenharmony_ci .registers = { 130162306a36Sopenharmony_ci .channel_base = AT91_ADC_CHR(0), 130262306a36Sopenharmony_ci .drdy_mask = AT91_ADC_DRDY, 130362306a36Sopenharmony_ci .status_register = AT91_ADC_SR, 130462306a36Sopenharmony_ci .trigger_register = AT91_ADC_TRGR_9G45, 130562306a36Sopenharmony_ci .mr_prescal_mask = AT91_ADC_PRESCAL_9260, 130662306a36Sopenharmony_ci .mr_startup_mask = AT91_ADC_STARTUP_9G45, 130762306a36Sopenharmony_ci }, 130862306a36Sopenharmony_ci .triggers = at91sam9x5_triggers, 130962306a36Sopenharmony_ci .trigger_number = ARRAY_SIZE(at91sam9x5_triggers), 131062306a36Sopenharmony_ci}; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic struct at91_adc_caps at91sam9g45_caps = { 131362306a36Sopenharmony_ci .has_ts = true, 131462306a36Sopenharmony_ci .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ 131562306a36Sopenharmony_ci .num_channels = 8, 131662306a36Sopenharmony_ci .low_res_bits = 8, 131762306a36Sopenharmony_ci .high_res_bits = 10, 131862306a36Sopenharmony_ci .registers = { 131962306a36Sopenharmony_ci .channel_base = AT91_ADC_CHR(0), 132062306a36Sopenharmony_ci .drdy_mask = AT91_ADC_DRDY, 132162306a36Sopenharmony_ci .status_register = AT91_ADC_SR, 132262306a36Sopenharmony_ci .trigger_register = AT91_ADC_TRGR_9G45, 132362306a36Sopenharmony_ci .mr_prescal_mask = AT91_ADC_PRESCAL_9G45, 132462306a36Sopenharmony_ci .mr_startup_mask = AT91_ADC_STARTUP_9G45, 132562306a36Sopenharmony_ci }, 132662306a36Sopenharmony_ci .triggers = at91sam9x5_triggers, 132762306a36Sopenharmony_ci .trigger_number = ARRAY_SIZE(at91sam9x5_triggers), 132862306a36Sopenharmony_ci}; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic struct at91_adc_caps at91sam9x5_caps = { 133162306a36Sopenharmony_ci .has_ts = true, 133262306a36Sopenharmony_ci .has_tsmr = true, 133362306a36Sopenharmony_ci .ts_filter_average = 3, 133462306a36Sopenharmony_ci .ts_pen_detect_sensitivity = 2, 133562306a36Sopenharmony_ci .calc_startup_ticks = calc_startup_ticks_9x5, 133662306a36Sopenharmony_ci .num_channels = 12, 133762306a36Sopenharmony_ci .low_res_bits = 8, 133862306a36Sopenharmony_ci .high_res_bits = 10, 133962306a36Sopenharmony_ci .registers = { 134062306a36Sopenharmony_ci .channel_base = AT91_ADC_CDR0_9X5, 134162306a36Sopenharmony_ci .drdy_mask = AT91_ADC_SR_DRDY_9X5, 134262306a36Sopenharmony_ci .status_register = AT91_ADC_SR_9X5, 134362306a36Sopenharmony_ci .trigger_register = AT91_ADC_TRGR_9X5, 134462306a36Sopenharmony_ci /* prescal mask is same as 9G45 */ 134562306a36Sopenharmony_ci .mr_prescal_mask = AT91_ADC_PRESCAL_9G45, 134662306a36Sopenharmony_ci .mr_startup_mask = AT91_ADC_STARTUP_9X5, 134762306a36Sopenharmony_ci }, 134862306a36Sopenharmony_ci .triggers = at91sam9x5_triggers, 134962306a36Sopenharmony_ci .trigger_number = ARRAY_SIZE(at91sam9x5_triggers), 135062306a36Sopenharmony_ci}; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic struct at91_adc_caps sama5d3_caps = { 135362306a36Sopenharmony_ci .has_ts = true, 135462306a36Sopenharmony_ci .has_tsmr = true, 135562306a36Sopenharmony_ci .ts_filter_average = 3, 135662306a36Sopenharmony_ci .ts_pen_detect_sensitivity = 2, 135762306a36Sopenharmony_ci .calc_startup_ticks = calc_startup_ticks_9x5, 135862306a36Sopenharmony_ci .num_channels = 12, 135962306a36Sopenharmony_ci .low_res_bits = 0, 136062306a36Sopenharmony_ci .high_res_bits = 12, 136162306a36Sopenharmony_ci .registers = { 136262306a36Sopenharmony_ci .channel_base = AT91_ADC_CDR0_9X5, 136362306a36Sopenharmony_ci .drdy_mask = AT91_ADC_SR_DRDY_9X5, 136462306a36Sopenharmony_ci .status_register = AT91_ADC_SR_9X5, 136562306a36Sopenharmony_ci .trigger_register = AT91_ADC_TRGR_9X5, 136662306a36Sopenharmony_ci .mr_prescal_mask = AT91_ADC_PRESCAL_9G45, 136762306a36Sopenharmony_ci .mr_startup_mask = AT91_ADC_STARTUP_9X5, 136862306a36Sopenharmony_ci }, 136962306a36Sopenharmony_ci .triggers = at91sam9x5_triggers, 137062306a36Sopenharmony_ci .trigger_number = ARRAY_SIZE(at91sam9x5_triggers), 137162306a36Sopenharmony_ci}; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic const struct of_device_id at91_adc_dt_ids[] = { 137462306a36Sopenharmony_ci { .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps }, 137562306a36Sopenharmony_ci { .compatible = "atmel,at91sam9rl-adc", .data = &at91sam9rl_caps }, 137662306a36Sopenharmony_ci { .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps }, 137762306a36Sopenharmony_ci { .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps }, 137862306a36Sopenharmony_ci { .compatible = "atmel,sama5d3-adc", .data = &sama5d3_caps }, 137962306a36Sopenharmony_ci {}, 138062306a36Sopenharmony_ci}; 138162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, at91_adc_dt_ids); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic struct platform_driver at91_adc_driver = { 138462306a36Sopenharmony_ci .probe = at91_adc_probe, 138562306a36Sopenharmony_ci .remove = at91_adc_remove, 138662306a36Sopenharmony_ci .driver = { 138762306a36Sopenharmony_ci .name = DRIVER_NAME, 138862306a36Sopenharmony_ci .of_match_table = at91_adc_dt_ids, 138962306a36Sopenharmony_ci .pm = pm_sleep_ptr(&at91_adc_pm_ops), 139062306a36Sopenharmony_ci }, 139162306a36Sopenharmony_ci}; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cimodule_platform_driver(at91_adc_driver); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 139662306a36Sopenharmony_ciMODULE_DESCRIPTION("Atmel AT91 ADC Driver"); 139762306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 1398