Skip to content

Commit

Permalink
AT91: IIO: Move the SoC specific informations to the ADC driver
Browse files Browse the repository at this point in the history
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Cc: Patrice Vilchez <patrice.vilchez@atmel.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  • Loading branch information
mripard authored and Nicolas Ferre committed Jan 11, 2012
1 parent e715952 commit 87beb0b
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 28 deletions.
9 changes: 0 additions & 9 deletions arch/arm/mach-at91/at91sam9260_devices.c
Expand Up @@ -1365,15 +1365,6 @@ void __init at91_add_device_adc(struct at91_adc_data *data)
if (test_bit(3, &data->channels_used)) if (test_bit(3, &data->channels_used))
at91_set_A_periph(AT91_PIN_PC3, 0); at91_set_A_periph(AT91_PIN_PC3, 0);


/*
* The electrical characteristics part of the AT91SAM9G20 datasheet
* sets the ADC clock to 5MHz.
*/
data->adc_clock = 5000000;

data->num_channels = 4;
data->startup_time = 10;

adc_data = *data; adc_data = *data;
platform_device_register(&at91_adc_device); platform_device_register(&at91_adc_device);
} }
Expand Down
52 changes: 46 additions & 6 deletions drivers/staging/iio/adc/at91_adc.c
Expand Up @@ -24,6 +24,22 @@
#include <linux/platform_data/at91_adc.h> #include <linux/platform_data/at91_adc.h>


#include <mach/at91_adc.h> #include <mach/at91_adc.h>
#include <mach/cpu.h>

/**
* struct at91_adc_desc - description of the ADC on the board
* @clock: ADC clock as specified by the datasheet, in Hz.
* @num_channels: global number of channels available on the board (to
specify which channels are indeed in use on the
board, see the channels_used bitmask in the platform
data)
* @startup_time: startup time of the ADC in microseconds
*/
struct at91_adc_desc {
u32 clock;
u8 num_channels;
u8 startup_time;
};


struct at91_adc_state { struct at91_adc_state {
struct clk *clk; struct clk *clk;
Expand All @@ -35,8 +51,25 @@ struct at91_adc_state {
void __iomem *reg_base; void __iomem *reg_base;
unsigned int vref_mv; unsigned int vref_mv;
unsigned long channels_mask; unsigned long channels_mask;
struct at91_adc_desc *desc;
};

static struct at91_adc_desc at91_adc_desc_sam9g20 = {
.clock = 5000000,
.num_channels = 4,
.startup_time = 10,
}; };


static int at91_adc_select_soc(struct at91_adc_state *st)
{
if (cpu_is_at91sam9g20()) {
st->desc = &at91_adc_desc_sam9g20;
return 0;
}

return -ENODEV;
}

static inline u32 at91_adc_reg_read(struct at91_adc_state *st, static inline u32 at91_adc_reg_read(struct at91_adc_state *st,
u8 reg) u8 reg)
{ {
Expand Down Expand Up @@ -72,18 +105,19 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
static int at91_adc_channel_init(struct iio_dev *idev, static int at91_adc_channel_init(struct iio_dev *idev,
struct at91_adc_data *pdata) struct at91_adc_data *pdata)
{ {
struct at91_adc_state *st = iio_priv(idev);
struct iio_chan_spec *chan_array; struct iio_chan_spec *chan_array;
int bit, idx = 0; int bit, idx = 0;


idev->num_channels = bitmap_weight(&pdata->channels_used, idev->num_channels = bitmap_weight(&pdata->channels_used,
pdata->num_channels); st->desc->num_channels);
chan_array = kcalloc(idev->num_channels, sizeof(struct iio_chan_spec), chan_array = kcalloc(idev->num_channels, sizeof(struct iio_chan_spec),
GFP_KERNEL); GFP_KERNEL);


if (chan_array == NULL) if (chan_array == NULL)
return -ENOMEM; return -ENOMEM;


for_each_set_bit(bit, &pdata->channels_used, pdata->num_channels) { for_each_set_bit(bit, &pdata->channels_used, st->desc->num_channels) {
struct iio_chan_spec *chan = chan_array + idx; struct iio_chan_spec *chan = chan_array + idx;
chan->type = IIO_VOLTAGE; chan->type = IIO_VOLTAGE;
chan->indexed = 1; chan->indexed = 1;
Expand Down Expand Up @@ -186,6 +220,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
idev->info = &at91_adc_info; idev->info = &at91_adc_info;


st = iio_priv(idev); st = iio_priv(idev);
ret = at91_adc_select_soc(st);
if (ret) {
dev_err(&pdev->dev, "SoC unknown\n");
goto error_free_device;
}

st->irq = platform_get_irq(pdev, 0); st->irq = platform_get_irq(pdev, 0);
if (st->irq < 0) { if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQ ID is designated\n"); dev_err(&pdev->dev, "No IRQ ID is designated\n");
Expand Down Expand Up @@ -238,7 +278,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
goto error_free_clk; goto error_free_clk;
} }


if (!pdata->adc_clock) { if (!st->desc->clock) {
dev_err(&pdev->dev, "No ADCClock available.\n"); dev_err(&pdev->dev, "No ADCClock available.\n");
ret = -EINVAL; ret = -EINVAL;
goto error_free_clk; goto error_free_clk;
Expand All @@ -249,9 +289,9 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
* datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
* specified by the electrical characteristics of the board. * specified by the electrical characteristics of the board.
*/ */
prsc = (mstrclk / (2 * pdata->adc_clock)) - 1; prsc = (mstrclk / (2 * st->desc->clock)) - 1;


if (!pdata->startup_time) { if (!st->desc->startup_time) {
dev_err(&pdev->dev, "No startup time available.\n"); dev_err(&pdev->dev, "No startup time available.\n");
ret = -EINVAL; ret = -EINVAL;
goto error_free_clk; goto error_free_clk;
Expand All @@ -262,7 +302,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
* defined in the electrical characteristics of the board, divided by 8. * defined in the electrical characteristics of the board, divided by 8.
* The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
*/ */
ticks = round_up((pdata->startup_time * pdata->adc_clock / ticks = round_up((st->desc->startup_time * st->desc->clock /
1000000) - 1, 8) / 8; 1000000) - 1, 8) / 8;
at91_adc_reg_write(st, AT91_ADC_MR, at91_adc_reg_write(st, AT91_ADC_MR,
(AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
Expand Down
20 changes: 7 additions & 13 deletions include/linux/platform_data/at91_adc.h
Expand Up @@ -15,20 +15,14 @@
#ifndef _AT91_ADC_H_ #ifndef _AT91_ADC_H_
#define _AT91_ADC_H_ #define _AT91_ADC_H_


/**
* struct at91_adc_data - platform data for ADC driver
* @channels_use: channels in use on the board as a bitmask
* @vref: Reference voltage for the ADC in millvolts
*/
struct at91_adc_data { struct at91_adc_data {
/* ADC Clock as specified by the datasheet, in Hz. */ u32 channels_used;
unsigned int adc_clock; u16 vref;
/*
* Global number of channels available (to specify which channels are
* indeed used on the board, see the channels_used bitmask).
*/
u8 num_channels;
/* Channels in use on the board as a bitmask */
unsigned long channels_used;
/* Startup time of the ADC, in microseconds. */
u8 startup_time;
/* Reference voltage for the ADC in millivolts */
unsigned short vref;
}; };


extern void __init at91_add_device_adc(struct at91_adc_data *data); extern void __init at91_add_device_adc(struct at91_adc_data *data);
Expand Down

0 comments on commit 87beb0b

Please sign in to comment.