/* * Driver for the ADC present in the Atmel AT91 evaluation boards. * * Copyright 2011 Free Electrons * * Licensed under the GPLv2 or later. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Registers */ #define AT91_ADC_CR 0x00 /* Control Register */ #define AT91_ADC_SWRST (1 << 0) /* Software Reset */ #define AT91_ADC_START (1 << 1) /* Start Conversion */ #define AT91_ADC_MR 0x04 /* Mode Register */ #define AT91_ADC_TSAMOD (3 << 0) /* ADC mode */ #define AT91_ADC_TSAMOD_ADC_ONLY_MODE (0 << 0) /* ADC Mode */ #define AT91_ADC_TSAMOD_TS_ONLY_MODE (1 << 0) /* Touch Screen Only Mode */ #define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */ #define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */ #define AT91_ADC_TRGSEL_TC0 (0 << 1) #define AT91_ADC_TRGSEL_TC1 (1 << 1) #define AT91_ADC_TRGSEL_TC2 (2 << 1) #define AT91_ADC_TRGSEL_EXTERNAL (6 << 1) #define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */ #define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */ #define AT91_ADC_PENDET (1 << 6) /* Pen contact detection enable */ #define AT91_ADC_PRESCAL_9260 (0x3f << 8) /* Prescalar Rate Selection */ #define AT91_ADC_PRESCAL_9G45 (0xff << 8) #define AT91_ADC_PRESCAL_(x) ((x) << 8) #define AT91_ADC_STARTUP_9260 (0x1f << 16) /* Startup Up Time */ #define AT91_ADC_STARTUP_9G45 (0x7f << 16) #define AT91_ADC_STARTUP_9X5 (0xf << 16) #define AT91_ADC_STARTUP_(x) ((x) << 16) #define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */ #define AT91_ADC_SHTIM_(x) ((x) << 24) #define AT91_ADC_PENDBC (0x0f << 28) /* Pen Debounce time */ #define AT91_ADC_PENDBC_(x) ((x) << 28) #define AT91_ADC_TSR 0x0C #define AT91_ADC_TSR_SHTIM (0xf << 24) /* Sample & Hold Time */ #define AT91_ADC_TSR_SHTIM_(x) ((x) << 24) #define AT91_ADC_CHER 0x10 /* Channel Enable Register */ #define AT91_ADC_CHDR 0x14 /* Channel Disable Register */ #define AT91_ADC_CHSR 0x18 /* Channel Status Register */ #define AT91_ADC_CH(n) (1 << (n)) /* Channel Number */ #define AT91_ADC_SR 0x1C /* Status Register */ #define AT91_ADC_EOC(n) (1 << (n)) /* End of Conversion on Channel N */ #define AT91_ADC_OVRE(n) (1 << ((n) + 8))/* Overrun Error on Channel N */ #define AT91_ADC_DRDY (1 << 16) /* Data Ready */ #define AT91_ADC_GOVRE (1 << 17) /* General Overrun Error */ #define AT91_ADC_ENDRX (1 << 18) /* End of RX Buffer */ #define AT91_ADC_RXFUFF (1 << 19) /* RX Buffer Full */ #define AT91_ADC_SR_9X5 0x30 /* Status Register for 9x5 */ #define AT91_ADC_SR_DRDY_9X5 (1 << 24) /* Data Ready */ #define AT91_ADC_LCDR 0x20 /* Last Converted Data Register */ #define AT91_ADC_LDATA (0x3ff) #define AT91_ADC_IER 0x24 /* Interrupt Enable Register */ #define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */ #define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */ #define AT91RL_ADC_IER_PEN (1 << 20) #define AT91RL_ADC_IER_NOPEN (1 << 21) #define AT91_ADC_IER_PEN (1 << 29) #define AT91_ADC_IER_NOPEN (1 << 30) #define AT91_ADC_IER_XRDY (1 << 20) #define AT91_ADC_IER_YRDY (1 << 21) #define AT91_ADC_IER_PRDY (1 << 22) #define AT91_ADC_ISR_PENS (1 << 31) #define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */ #define AT91_ADC_DATA (0x3ff) #define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */ #define AT91_ADC_ACR 0x94 /* Analog Control Register */ #define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */ #define AT91_ADC_TSMR 0xB0 #define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */ #define AT91_ADC_TSMR_TSMODE_NONE (0 << 0) #define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0) #define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0) #define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0) #define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */ #define AT91_ADC_TSMR_TSAV_(x) ((x) << 4) #define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */ #define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16) #define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */ #define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28) #define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */ #define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */ #define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */ #define AT91_ADC_TSXPOSR 0xB4 #define AT91_ADC_TSYPOSR 0xB8 #define AT91_ADC_TSPRESSR 0xBC #define AT91_ADC_TRGR_9260 AT91_ADC_MR #define AT91_ADC_TRGR_9G45 0x08 #define AT91_ADC_TRGR_9X5 0xC0 /* Trigger Register bit field */ #define AT91_ADC_TRGR_TRGPER (0xffff << 16) #define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16) #define AT91_ADC_TRGR_TRGMOD (0x7 << 0) #define AT91_ADC_TRGR_NONE (0 << 0) #define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0) #define AT91_ADC_CHAN(st, ch) \ (st->registers->channel_base + (ch * 4)) #define at91_adc_readl(st, reg) \ (readl_relaxed(st->reg_base + reg)) #define at91_adc_writel(st, reg, val) \ (writel_relaxed(val, st->reg_base + reg)) #define DRIVER_NAME "at91_adc" #define MAX_POS_BITS 12 #define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ #define TOUCH_PEN_DETECT_DEBOUNCE_US 200 #define MAX_RLPOS_BITS 10 #define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */ #define TOUCH_SHTIM 0xa #define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */ /** * struct at91_adc_reg_desc - Various informations relative to registers * @channel_base: Base offset for the channel data registers * @drdy_mask: Mask of the DRDY field in the relevant registers (Interruptions registers mostly) * @status_register: Offset of the Interrupt Status Register * @trigger_register: Offset of the Trigger setup register * @mr_prescal_mask: Mask of the PRESCAL field in the adc MR register * @mr_startup_mask: Mask of the STARTUP field in the adc MR register */ struct at91_adc_reg_desc { u8 channel_base; u32 drdy_mask; u8 status_register; u8 trigger_register; u32 mr_prescal_mask; u32 mr_startup_mask; }; struct at91_adc_caps { bool has_ts; /* Support touch screen */ bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */ /* * Numbers of sampling data will be averaged. Can be 0~3. * Hardware can average (2 ^ ts_filter_average) sample data. */ u8 ts_filter_average; /* Pen Detection input pull-up resistor, can be 0~3 */ u8 ts_pen_detect_sensitivity; /* startup time calculate function */ u32 (*calc_startup_ticks)(u32 startup_time, u32 adc_clk_khz); u8 num_channels; struct at91_adc_reg_desc registers; }; struct at91_adc_state { struct clk *adc_clk; u16 *buffer; unsigned long channels_mask; struct clk *clk; bool done; int irq; u16 last_value; int chnb; struct mutex lock; u8 num_channels; void __iomem *reg_base; struct at91_adc_reg_desc *registers; u32 startup_time; u8 sample_hold_time; bool sleep_mode; struct iio_trigger **trig; struct at91_adc_trigger *trigger_list; u32 trigger_number; bool use_external; u32 vref_mv; u32 res; /* resolution used for convertions */ bool low_res; /* the resolution corresponds to the lowest one */ wait_queue_head_t wq_data_avail; struct at91_adc_caps *caps; /* * Following ADC channels are shared by touchscreen: * * CH0 -- Touch screen XP/UL * CH1 -- Touch screen XM/UR * CH2 -- Touch screen YP/LL * CH3 -- Touch screen YM/Sense * CH4 -- Touch screen LR(5-wire only) * * The bitfields below represents the reserved channel in the * touchscreen mode. */ #define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 0) #define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 0) enum atmel_adc_ts_type touchscreen_type; struct input_dev *ts_input; u16 ts_sample_period_val; u32 ts_pressure_threshold; u16 ts_pendbc; bool ts_bufferedmeasure; u32 ts_prev_absx; u32 ts_prev_absy; }; static irqreturn_t at91_adc_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *idev = pf->indio_dev; struct at91_adc_state *st = iio_priv(idev); struct iio_chan_spec const *chan; int i, j = 0; for (i = 0; i < idev->masklength; i++) { if (!test_bit(i, idev->active_scan_mask)) continue; chan = idev->channels + i; st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, chan->channel)); j++; } iio_push_to_buffers_with_timestamp(idev, st->buffer, pf->timestamp); iio_trigger_notify_done(idev->trig); /* Needed to ACK the DRDY interruption */ at91_adc_readl(st, AT91_ADC_LCDR); enable_irq(st->irq); return IRQ_HANDLED; } /* Handler for classic adc channel eoc trigger */ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); if (iio_buffer_enabled(idev)) { disable_irq_nosync(irq); iio_trigger_poll(idev->trig); } else { st->last_value = at91_adc_readl(st, AT91_ADC_CHAN(st, st->chnb)); /* Needed to ACK the DRDY interruption */ at91_adc_readl(st, AT91_ADC_LCDR); st->done = true; wake_up_interruptible(&st->wq_data_avail); } } static int at91_ts_sample(struct at91_adc_state *st) { unsigned int xscale, yscale, reg, z1, z2; unsigned int x, y, pres, xpos, ypos; unsigned int rxp = 1; unsigned int factor = 1000; struct iio_dev *idev = iio_priv_to_dev(st); unsigned int xyz_mask_bits = st->res; unsigned int xyz_mask = (1 << xyz_mask_bits) - 1; /* calculate position */ /* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */ reg = at91_adc_readl(st, AT91_ADC_TSXPOSR); xpos = reg & xyz_mask; x = (xpos << MAX_POS_BITS) - xpos; xscale = (reg >> 16) & xyz_mask; if (xscale == 0) { dev_err(&idev->dev, "Error: xscale == 0!\n"); return -1; } x /= xscale; /* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */ reg = at91_adc_readl(st, AT91_ADC_TSYPOSR); ypos = reg & xyz_mask; y = (ypos << MAX_POS_BITS) - ypos; yscale = (reg >> 16) & xyz_mask; if (yscale == 0) { dev_err(&idev->dev, "Error: yscale == 0!\n"); return -1; } y /= yscale; /* calculate the pressure */ reg = at91_adc_readl(st, AT91_ADC_TSPRESSR); z1 = reg & xyz_mask; z2 = (reg >> 16) & xyz_mask; if (z1 != 0) pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor) / factor; else pres = st->ts_pressure_threshold; /* no pen contacted */ dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n", xpos, xscale, ypos, yscale, z1, z2, pres); if (pres < st->ts_pressure_threshold) { dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n", x, y, pres / factor); input_report_abs(st->ts_input, ABS_X, x); input_report_abs(st->ts_input, ABS_Y, y); input_report_abs(st->ts_input, ABS_PRESSURE, pres); input_report_key(st->ts_input, BTN_TOUCH, 1); input_sync(st->ts_input); } else { dev_dbg(&idev->dev, "pressure too low: not reporting\n"); } return 0; } static irqreturn_t at91_adc_rl_interrupt(int irq, void *private) { struct iio_dev *idev = private; struct at91_adc_state *st = iio_priv(idev); u32 status = at91_adc_readl(st, st->registers->status_register); unsigned int reg; status &= at91_adc_readl(st, AT91_ADC_IMR); if (status & GENMASK(st->num_channels - 1, 0)) handle_adc_eoc_trigger(irq, idev); if (status & AT91RL_ADC_IER_PEN) { /* Disabling pen debounce is required to get a NOPEN irq */ reg = at91_adc_readl(st, AT91_ADC_MR); reg &= ~AT91_ADC_PENDBC; at91_adc_writel(st, AT91_ADC_MR, reg); at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_NOPEN | AT91_ADC_EOC(3)); /* Set up period trigger for sampling */ at91_adc_writel(st, st->registers->trigger_register, AT91_ADC_TRGR_MOD_PERIOD_TRIG | AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); } else if (status & AT91RL_ADC_IER_NOPEN) { reg = at91_adc_readl(st, AT91_ADC_MR); reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; at91_adc_writel(st, AT91_ADC_MR, reg); at91_adc_writel(st, st->registers->trigger_register, AT91_ADC_TRGR_NONE); at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_NOPEN | AT91_ADC_EOC(3)); at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); st->ts_bufferedmeasure = false; input_report_key(st->ts_input, BTN_TOUCH, 0); input_sync(st->ts_input); } else if (status & AT91_ADC_EOC(3) && st->ts_input) { /* Conversion finished and we've a touchscreen */ if (st->ts_bufferedmeasure) { /* * Last measurement is always discarded, since it can * be erroneous. * Always report previous measurement */ input_report_abs(st->ts_input, ABS_X, st->ts_prev_absx); input_report_abs(st->ts_input, ABS_Y, st->ts_prev_absy); input_report_key(st->ts_input, BTN_TOUCH, 1); input_sync(st->ts_input); } else st->ts_bufferedmeasure = true; /* Now make new measurement */ st->ts_prev_absx = at91_adc_readl(st, AT91_ADC_CHAN(st, 3)) << MAX_RLPOS_BITS; st->ts_prev_absx /= at91_adc_readl(st, AT91_ADC_CHAN(st, 2)); st->ts_prev_absy = at91_adc_readl(st, AT91_ADC_CHAN(st, 1)) << MAX_RLPOS_BITS; st->ts_prev_absy /= at91_adc_readl(st, AT91_ADC_CHAN(st, 0)); } return IRQ_HANDLED; } static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) { struct iio_dev *idev = private; struct at91_adc_state *st = iio_priv(idev); u32 status = at91_adc_readl(st, st->registers->status_register); const uint32_t ts_data_irq_mask = AT91_ADC_IER_XRDY | AT91_ADC_IER_YRDY | AT91_ADC_IER_PRDY; if (status & GENMASK(st->num_channels - 1, 0)) handle_adc_eoc_trigger(irq, idev); if (status & AT91_ADC_IER_PEN) { at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN | ts_data_irq_mask); /* Set up period trigger for sampling */ at91_adc_writel(st, st->registers->trigger_register, AT91_ADC_TRGR_MOD_PERIOD_TRIG | AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); } else if (status & AT91_ADC_IER_NOPEN) { at91_adc_writel(st, st->registers->trigger_register, 0); at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN | ts_data_irq_mask); at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); input_report_key(st->ts_input, BTN_TOUCH, 0); input_sync(st->ts_input); } else if ((status & ts_data_irq_mask) == ts_data_irq_mask) { /* Now all touchscreen data is ready */ if (status & AT91_ADC_ISR_PENS) { /* validate data by pen contact */ at91_ts_sample(st); } else { /* triggered by event that is no pen contact, just read * them to clean the interrupt and discard all. */ at91_adc_readl(st, AT91_ADC_TSXPOSR); at91_adc_readl(st, AT91_ADC_TSYPOSR); at91_adc_readl(st, AT91_ADC_TSPRESSR); } } return IRQ_HANDLED; } static int at91_adc_channel_init(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); struct iio_chan_spec *chan_array, *timestamp; int bit, idx = 0; unsigned long rsvd_mask = 0; /* If touchscreen is enable, then reserve the adc channels */ if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE; else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE) rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE; /* set up the channel mask to reserve touchscreen channels */ st->channels_mask &= ~rsvd_mask; idev->num_channels = bitmap_weight(&st->channels_mask, st->num_channels) + 1; chan_array = devm_kzalloc(&idev->dev, ((idev->num_channels + 1) * sizeof(struct iio_chan_spec)), GFP_KERNEL); if (!chan_array) return -ENOMEM; for_each_set_bit(bit, &st->channels_mask, st->num_channels) { struct iio_chan_spec *chan = chan_array + idx; chan->type = IIO_VOLTAGE; chan->indexed = 1; chan->channel = bit; chan->scan_index = idx; chan->scan_type.sign = 'u'; chan->scan_type.realbits = st->res; chan->scan_type.storagebits = 16; chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); idx++; } timestamp = chan_array + idx; timestamp->type = IIO_TIMESTAMP; timestamp->channel = -1; timestamp->scan_index = idx; timestamp->scan_type.sign = 's'; timestamp->scan_type.realbits = 64; timestamp->scan_type.storagebits = 64; idev->channels = chan_array; return idev->num_channels; } static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev, struct at91_adc_trigger *triggers, const char *trigger_name) { struct at91_adc_state *st = iio_priv(idev); int i; for (i = 0; i < st->trigger_number; i++) { char *name = kasprintf(GFP_KERNEL, "%s-dev%d-%s", idev->name, idev->id, triggers[i].name); if (!name) return -ENOMEM; if (strcmp(trigger_name, name) == 0) { kfree(name); if (triggers[i].value == 0) return -EINVAL; return triggers[i].value; } kfree(name); } return -EINVAL; } static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *idev = iio_trigger_get_drvdata(trig); struct at91_adc_state *st = iio_priv(idev); struct at91_adc_reg_desc *reg = st->registers; u32 status = at91_adc_readl(st, reg->trigger_register); int value; u8 bit; value = at91_adc_get_trigger_value_by_name(idev, st->trigger_list, idev->trig->name); if (value < 0) return value; if (state) { st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); if (st->buffer == NULL) return -ENOMEM; at91_adc_writel(st, reg->trigger_register, status | value); for_each_set_bit(bit, idev->active_scan_mask, st->num_channels) { struct iio_chan_spec const *chan = idev->channels + bit; at91_adc_writel(st, AT91_ADC_CHER, AT91_ADC_CH(chan->channel)); } at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask); } else { at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask); at91_adc_writel(st, reg->trigger_register, status & ~value); for_each_set_bit(bit, idev->active_scan_mask, st->num_channels) { struct iio_chan_spec const *chan = idev->channels + bit; at91_adc_writel(st, AT91_ADC_CHDR, AT91_ADC_CH(chan->channel)); } kfree(st->buffer); } return 0; } static const struct iio_trigger_ops at91_adc_trigger_ops = { .set_trigger_state = &at91_adc_configure_trigger, }; static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, struct at91_adc_trigger *trigger) { struct iio_trigger *trig; int ret; trig = iio_trigger_alloc("%s-dev%d-%s", idev->name, idev->id, trigger->name); if (trig == NULL) return NULL; trig->dev.parent = idev->dev.parent; iio_trigger_set_drvdata(trig, idev); trig->ops = &at91_adc_trigger_ops; ret = iio_trigger_register(trig); if (ret) return NULL; return trig; } static int at91_adc_trigger_init(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); int i, ret; st->trig = devm_kcalloc(&idev->dev, st->trigger_number, sizeof(*st->trig), GFP_KERNEL); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; } for (i = 0; i < st->trigger_number; i++) { if (st->trigger_list[i].is_external && !(st->use_external)) continue; st->trig[i] = at91_adc_allocate_trigger(idev, st->trigger_list + i); if (st->trig[i] == NULL) { dev_err(&idev->dev, "Could not allocate trigger %d\n", i); ret = -ENOMEM; goto error_trigger; } } return 0; error_trigger: for (i--; i >= 0; i--) { iio_trigger_unregister(st->trig[i]); iio_trigger_free(st->trig[i]); } error_ret: return ret; } static void at91_adc_trigger_remove(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); int i; for (i = 0; i < st->trigger_number; i++) { iio_trigger_unregister(st->trig[i]); iio_trigger_free(st->trig[i]); } } static int at91_adc_buffer_init(struct iio_dev *idev) { return iio_triggered_buffer_setup(idev, &iio_pollfunc_store_time, &at91_adc_trigger_handler, NULL); } static void at91_adc_buffer_remove(struct iio_dev *idev) { iio_triggered_buffer_cleanup(idev); } static int at91_adc_read_raw(struct iio_dev *idev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct at91_adc_state *st = iio_priv(idev); int ret; switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); st->chnb = chan->channel; at91_adc_writel(st, AT91_ADC_CHER, AT91_ADC_CH(chan->channel)); at91_adc_writel(st, AT91_ADC_IER, BIT(chan->channel)); at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START); ret = wait_event_interruptible_timeout(st->wq_data_avail, st->done, msecs_to_jiffies(1000)); if (ret == 0) ret = -ETIMEDOUT; if (ret < 0) { mutex_unlock(&st->lock); return ret; } *val = st->last_value; at91_adc_writel(st, AT91_ADC_CHDR, AT91_ADC_CH(chan->channel)); at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel)); st->last_value = 0; st->done = false; mutex_unlock(&st->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = st->vref_mv; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; default: break; } return -EINVAL; } static int at91_adc_of_get_resolution(struct at91_adc_state *st, struct platform_device *pdev) { struct iio_dev *idev = iio_priv_to_dev(st); struct device_node *np = pdev->dev.of_node; int count, i, ret = 0; char *res_name, *s; u32 *resolutions; count = of_property_count_strings(np, "atmel,adc-res-names"); if (count < 2) { dev_err(&idev->dev, "You must specified at least two resolution names for " "adc-res-names property in the DT\n"); return count; } resolutions = kmalloc_array(count, sizeof(*resolutions), GFP_KERNEL); if (!resolutions) return -ENOMEM; if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) { dev_err(&idev->dev, "Missing adc-res property in the DT.\n"); ret = -ENODEV; goto ret; } if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name)) res_name = "highres"; for (i = 0; i < count; i++) { if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s)) continue; if (strcmp(res_name, s)) continue; st->res = resolutions[i]; if (!strcmp(res_name, "lowres")) st->low_res = true; else st->low_res = false; dev_info(&idev->dev, "Resolution used: %u bits\n", st->res); goto ret; } dev_err(&idev->dev, "There is no resolution for %s\n", res_name); ret: kfree(resolutions); return ret; } static u32 calc_startup_ticks_9260(u32 startup_time, u32 adc_clk_khz) { /* * Number of ticks needed to cover the startup time of the ADC * as defined in the electrical characteristics of the board, * divided by 8. The formula thus is : * Startup Time = (ticks + 1) * 8 / ADC Clock */ return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8; } static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz) { /* * For sama5d3x and at91sam9x5, the formula changes to: * Startup Time = / ADC Clock */ static const int startup_lookup[] = { 0, 8, 16, 24, 64, 80, 96, 112, 512, 576, 640, 704, 768, 832, 896, 960 }; int i, size = ARRAY_SIZE(startup_lookup); unsigned int ticks; ticks = startup_time * adc_clk_khz / 1000; for (i = 0; i < size; i++) if (ticks < startup_lookup[i]) break; ticks = i; if (ticks == size) /* Reach the end of lookup table */ ticks = size - 1; return ticks; } static const struct of_device_id at91_adc_dt_ids[]; static int at91_adc_probe_dt_ts(struct device_node *node, struct at91_adc_state *st, struct device *dev) { int ret; u32 prop; ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop); if (ret) { dev_info(dev, "ADC Touch screen is disabled.\n"); return 0; } switch (prop) { case 4: case 5: st->touchscreen_type = prop; break; default: dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop); return -EINVAL; } if (!st->caps->has_tsmr) return 0; prop = 0; of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); st->ts_pressure_threshold = prop; if (st->ts_pressure_threshold) { return 0; } else { dev_err(dev, "Invalid pressure threshold for the touchscreen\n"); return -EINVAL; } } static int at91_adc_probe_dt(struct at91_adc_state *st, struct platform_device *pdev) { struct iio_dev *idev = iio_priv_to_dev(st); struct device_node *node = pdev->dev.of_node; struct device_node *trig_node; int i = 0, ret; u32 prop; if (!node) return -EINVAL; st->caps = (struct at91_adc_caps *) of_match_device(at91_adc_dt_ids, &pdev->dev)->data; st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); ret = -EINVAL; goto error_ret; } st->channels_mask = prop; st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); ret = -EINVAL; goto error_ret; } st->startup_time = prop; prop = 0; of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); st->sample_hold_time = prop; if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); ret = -EINVAL; goto error_ret; } st->vref_mv = prop; ret = at91_adc_of_get_resolution(st, pdev); if (ret) goto error_ret; st->registers = &st->caps->registers; st->num_channels = st->caps->num_channels; st->trigger_number = of_get_child_count(node); st->trigger_list = devm_kcalloc(&idev->dev, st->trigger_number, sizeof(struct at91_adc_trigger), GFP_KERNEL); if (!st->trigger_list) { dev_err(&idev->dev, "Could not allocate trigger list memory.\n"); ret = -ENOMEM; goto error_ret; } for_each_child_of_node(node, trig_node) { struct at91_adc_trigger *trig = st->trigger_list + i; const char *name; if (of_property_read_string(trig_node, "trigger-name", &name)) { dev_err(&idev->dev, "Missing trigger-name property in the DT.\n"); ret = -EINVAL; goto error_ret; } trig->name = name; if (of_property_read_u32(trig_node, "trigger-value", &prop)) { dev_err(&idev->dev, "Missing trigger-value property in the DT.\n"); ret = -EINVAL; goto error_ret; } trig->value = prop; trig->is_external = of_property_read_bool(trig_node, "trigger-external"); i++; } /* Check if touchscreen is supported. */ if (st->caps->has_ts) return at91_adc_probe_dt_ts(node, st, &idev->dev); else dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n"); return 0; error_ret: return ret; } static int at91_adc_probe_pdata(struct at91_adc_state *st, struct platform_device *pdev) { struct at91_adc_data *pdata = pdev->dev.platform_data; if (!pdata) return -EINVAL; st->caps = (struct at91_adc_caps *) platform_get_device_id(pdev)->driver_data; st->use_external = pdata->use_external_triggers; st->vref_mv = pdata->vref; st->channels_mask = pdata->channels_used; st->num_channels = st->caps->num_channels; st->startup_time = pdata->startup_time; st->trigger_number = pdata->trigger_number; st->trigger_list = pdata->trigger_list; st->registers = &st->caps->registers; st->touchscreen_type = pdata->touchscreen_type; return 0; } static const struct iio_info at91_adc_info = { .read_raw = &at91_adc_read_raw, }; /* Touchscreen related functions */ static int atmel_ts_open(struct input_dev *dev) { struct at91_adc_state *st = input_get_drvdata(dev); if (st->caps->has_tsmr) at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); else at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); return 0; } static void atmel_ts_close(struct input_dev *dev) { struct at91_adc_state *st = input_get_drvdata(dev); if (st->caps->has_tsmr) at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); else at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); } static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) { struct iio_dev *idev = iio_priv_to_dev(st); u32 reg = 0; u32 tssctim = 0; int i = 0; /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid * pen detect noise. * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock */ st->ts_pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1); while (st->ts_pendbc >> ++i) ; /* Empty! Find the shift offset */ if (abs(st->ts_pendbc - (1 << i)) < abs(st->ts_pendbc - (1 << (i - 1)))) st->ts_pendbc = i; else st->ts_pendbc = i - 1; if (!st->caps->has_tsmr) { reg = at91_adc_readl(st, AT91_ADC_MR); reg |= AT91_ADC_TSAMOD_TS_ONLY_MODE | AT91_ADC_PENDET; reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; at91_adc_writel(st, AT91_ADC_MR, reg); reg = AT91_ADC_TSR_SHTIM_(TOUCH_SHTIM) & AT91_ADC_TSR_SHTIM; at91_adc_writel(st, AT91_ADC_TSR, reg); st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US_RL * adc_clk_khz / 1000) - 1, 1); return 0; } /* Touchscreen Switches Closure time needed for allowing the value to * stabilize. * Switch Closure Time = (TSSCTIM * 4) ADCClock periods */ tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4); dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n", adc_clk_khz, tssctim); if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; else reg = AT91_ADC_TSMR_TSMODE_5WIRE; reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM; reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) & AT91_ADC_TSMR_TSAV; reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC; reg |= AT91_ADC_TSMR_NOTSDMA; reg |= AT91_ADC_TSMR_PENDET_ENA; reg |= 0x03 << 8; /* TSFREQ, needs to be bigger than TSAV */ at91_adc_writel(st, AT91_ADC_TSMR, reg); /* Change adc internal resistor value for better pen detection, * default value is 100 kOhm. * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm * option only available on ES2 and higher */ at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity & AT91_ADC_ACR_PENDETSENS); /* Sample Period Time = (TRGPER + 1) / ADCClock */ st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * adc_clk_khz / 1000) - 1, 1); return 0; } static int at91_ts_register(struct at91_adc_state *st, struct platform_device *pdev) { struct input_dev *input; struct iio_dev *idev = iio_priv_to_dev(st); int ret; input = input_allocate_device(); if (!input) { dev_err(&idev->dev, "Failed to allocate TS device!\n"); return -ENOMEM; } input->name = DRIVER_NAME; input->id.bustype = BUS_HOST; input->dev.parent = &pdev->dev; input->open = atmel_ts_open; input->close = atmel_ts_close; __set_bit(EV_ABS, input->evbit); __set_bit(EV_KEY, input->evbit); __set_bit(BTN_TOUCH, input->keybit); if (st->caps->has_tsmr) { input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0); input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0); input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); } else { if (st->touchscreen_type != ATMEL_ADC_TOUCHSCREEN_4WIRE) { dev_err(&pdev->dev, "This touchscreen controller only support 4 wires\n"); ret = -EINVAL; goto err; } input_set_abs_params(input, ABS_X, 0, (1 << MAX_RLPOS_BITS) - 1, 0, 0); input_set_abs_params(input, ABS_Y, 0, (1 << MAX_RLPOS_BITS) - 1, 0, 0); } st->ts_input = input; input_set_drvdata(input, st); ret = input_register_device(input); if (ret) goto err; return ret; err: input_free_device(st->ts_input); return ret; } static void at91_ts_unregister(struct at91_adc_state *st) { input_unregister_device(st->ts_input); } static int at91_adc_probe(struct platform_device *pdev) { unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim; int ret; struct iio_dev *idev; struct at91_adc_state *st; struct resource *res; u32 reg; idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state)); if (!idev) return -ENOMEM; st = iio_priv(idev); if (pdev->dev.of_node) ret = at91_adc_probe_dt(st, pdev); else ret = at91_adc_probe_pdata(st, pdev); if (ret) { dev_err(&pdev->dev, "No platform data available.\n"); return -EINVAL; } platform_set_drvdata(pdev, idev); idev->dev.parent = &pdev->dev; idev->name = dev_name(&pdev->dev); idev->modes = INDIO_DIRECT_MODE; idev->info = &at91_adc_info; st->irq = platform_get_irq(pdev, 0); if (st->irq < 0) { dev_err(&pdev->dev, "No IRQ ID is designated\n"); return -ENODEV; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); st->reg_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(st->reg_base)) return PTR_ERR(st->reg_base); /* * Disable all IRQs before setting up the handler */ at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); if (st->caps->has_tsmr) ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, pdev->dev.driver->name, idev); else ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, pdev->dev.driver->name, idev); if (ret) { dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); return ret; } st->clk = devm_clk_get(&pdev->dev, "adc_clk"); if (IS_ERR(st->clk)) { dev_err(&pdev->dev, "Failed to get the clock.\n"); ret = PTR_ERR(st->clk); goto error_free_irq; } ret = clk_prepare_enable(st->clk); if (ret) { dev_err(&pdev->dev, "Could not prepare or enable the clock.\n"); goto error_free_irq; } st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); if (IS_ERR(st->adc_clk)) { dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); ret = PTR_ERR(st->adc_clk); goto error_disable_clk; } ret = clk_prepare_enable(st->adc_clk); if (ret) { dev_err(&pdev->dev, "Could not prepare or enable the ADC clock.\n"); goto error_disable_clk; } /* * Prescaler rate computation using the formula from the Atmel's * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being * specified by the electrical characteristics of the board. */ mstrclk = clk_get_rate(st->clk); adc_clk = clk_get_rate(st->adc_clk); adc_clk_khz = adc_clk / 1000; dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n", mstrclk, adc_clk); prsc = (mstrclk / (2 * adc_clk)) - 1; if (!st->startup_time) { dev_err(&pdev->dev, "No startup time available.\n"); ret = -EINVAL; goto error_disable_adc_clk; } ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); /* * a minimal Sample and Hold Time is necessary for the ADC to guarantee * the best converted final value between two channels selection * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock */ if (st->sample_hold_time > 0) shtim = round_up((st->sample_hold_time * adc_clk_khz / 1000) - 1, 1); else shtim = 0; reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask; reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask; if (st->low_res) reg |= AT91_ADC_LOWRES; if (st->sleep_mode) reg |= AT91_ADC_SLEEP; reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM; at91_adc_writel(st, AT91_ADC_MR, reg); /* Setup the ADC channels available on the board */ ret = at91_adc_channel_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); goto error_disable_adc_clk; } init_waitqueue_head(&st->wq_data_avail); mutex_init(&st->lock); /* * Since touch screen will set trigger register as period trigger. So * when touch screen is enabled, then we have to disable hardware * trigger for classic adc. */ if (!st->touchscreen_type) { ret = at91_adc_buffer_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); goto error_disable_adc_clk; } ret = at91_adc_trigger_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); at91_adc_buffer_remove(idev); goto error_disable_adc_clk; } } else { ret = at91_ts_register(st, pdev); if (ret) goto error_disable_adc_clk; at91_ts_hw_init(st, adc_clk_khz); } ret = iio_device_register(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't register the device.\n"); goto error_iio_device_register; } return 0; error_iio_device_register: if (!st->touchscreen_type) { at91_adc_trigger_remove(idev); at91_adc_buffer_remove(idev); } else { at91_ts_unregister(st); } error_disable_adc_clk: clk_disable_unprepare(st->adc_clk); error_disable_clk: clk_disable_unprepare(st->clk); error_free_irq: free_irq(st->irq, idev); return ret; } static int at91_adc_remove(struct platform_device *pdev) { struct iio_dev *idev = platform_get_drvdata(pdev); struct at91_adc_state *st = iio_priv(idev); iio_device_unregister(idev); if (!st->touchscreen_type) { at91_adc_trigger_remove(idev); at91_adc_buffer_remove(idev); } else { at91_ts_unregister(st); } clk_disable_unprepare(st->adc_clk); clk_disable_unprepare(st->clk); free_irq(st->irq, idev); return 0; } #ifdef CONFIG_PM_SLEEP static int at91_adc_suspend(struct device *dev) { struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev)); struct at91_adc_state *st = iio_priv(idev); pinctrl_pm_select_sleep_state(dev); clk_disable_unprepare(st->clk); return 0; } static int at91_adc_resume(struct device *dev) { struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev)); struct at91_adc_state *st = iio_priv(idev); clk_prepare_enable(st->clk); pinctrl_pm_select_default_state(dev); return 0; } #endif static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume); static struct at91_adc_caps at91sam9260_caps = { .calc_startup_ticks = calc_startup_ticks_9260, .num_channels = 4, .registers = { .channel_base = AT91_ADC_CHR(0), .drdy_mask = AT91_ADC_DRDY, .status_register = AT91_ADC_SR, .trigger_register = AT91_ADC_TRGR_9260, .mr_prescal_mask = AT91_ADC_PRESCAL_9260, .mr_startup_mask = AT91_ADC_STARTUP_9260, }, }; static struct at91_adc_caps at91sam9rl_caps = { .has_ts = true, .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ .num_channels = 6, .registers = { .channel_base = AT91_ADC_CHR(0), .drdy_mask = AT91_ADC_DRDY, .status_register = AT91_ADC_SR, .trigger_register = AT91_ADC_TRGR_9G45, .mr_prescal_mask = AT91_ADC_PRESCAL_9260, .mr_startup_mask = AT91_ADC_STARTUP_9G45, }, }; static struct at91_adc_caps at91sam9g45_caps = { .has_ts = true, .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ .num_channels = 8, .registers = { .channel_base = AT91_ADC_CHR(0), .drdy_mask = AT91_ADC_DRDY, .status_register = AT91_ADC_SR, .trigger_register = AT91_ADC_TRGR_9G45, .mr_prescal_mask = AT91_ADC_PRESCAL_9G45, .mr_startup_mask = AT91_ADC_STARTUP_9G45, }, }; static struct at91_adc_caps at91sam9x5_caps = { .has_ts = true, .has_tsmr = true, .ts_filter_average = 3, .ts_pen_detect_sensitivity = 2, .calc_startup_ticks = calc_startup_ticks_9x5, .num_channels = 12, .registers = { .channel_base = AT91_ADC_CDR0_9X5, .drdy_mask = AT91_ADC_SR_DRDY_9X5, .status_register = AT91_ADC_SR_9X5, .trigger_register = AT91_ADC_TRGR_9X5, /* prescal mask is same as 9G45 */ .mr_prescal_mask = AT91_ADC_PRESCAL_9G45, .mr_startup_mask = AT91_ADC_STARTUP_9X5, }, }; static const struct of_device_id at91_adc_dt_ids[] = { { .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps }, { .compatible = "atmel,at91sam9rl-adc", .data = &at91sam9rl_caps }, { .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps }, { .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps }, {}, }; MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); static const struct platform_device_id at91_adc_ids[] = { { .name = "at91sam9260-adc", .driver_data = (unsigned long)&at91sam9260_caps, }, { .name = "at91sam9rl-adc", .driver_data = (unsigned long)&at91sam9rl_caps, }, { .name = "at91sam9g45-adc", .driver_data = (unsigned long)&at91sam9g45_caps, }, { .name = "at91sam9x5-adc", .driver_data = (unsigned long)&at91sam9x5_caps, }, { /* terminator */ } }; MODULE_DEVICE_TABLE(platform, at91_adc_ids); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, .remove = at91_adc_remove, .id_table = at91_adc_ids, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(at91_adc_dt_ids), .pm = &at91_adc_pm_ops, }, }; module_platform_driver(at91_adc_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atmel AT91 ADC Driver"); MODULE_AUTHOR("Maxime Ripard ");