Commit c253ed32 authored by Sascha Hauer's avatar Sascha Hauer Committed by Alexey Mednyy

mfd: mc13xxx: Add mc34708 adc support

The mc34708 has an improved adc. The older variants will always convert
a fixed order of channels. The mc34708 can do up to eight conversions
in arbitrary channel order. Currently this extended feature is not
supported. We only support touchscreen conversions now, which will
be sampled in a data format compatible to the older chips in order
to keep the API between the mfd and the touchscreen driver.
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
parent 9ec156c3
......@@ -48,6 +48,25 @@
#define MC13XXX_ADC2 45
#define MC34708_ADC3 46
#define MC34708_ADC4 47
#define MC13XXX_ADC_WORKING (1 << 0)
#define MC34708_IRQ_TSDONE 1
#define MC34708_ADC0_TSEN (1 << 12)
#define MC34708_ADC0_TSSTART (1 << 13)
#define MC34708_ADC0_TSSTOP(x) (((x) & 0x7) << 16)
#define MC34708_ADC3_TSSEL(step, ch) ((ch) << (8 + 2 * (step)))
#define MC34708_ADC1_TSDLY1(d) ((d) << 12)
#define MC34708_ADC1_TSDLY2(d) ((d) << 16)
#define MC34708_ADC1_TSDLY3(d) ((d) << 20)
#define MC34708_TS_X 1
#define MC34708_TS_Y 2
#define MC34708_TS_R 3
void mc13xxx_lock(struct mc13xxx *mc13xxx)
{
if (!mutex_trylock(&mc13xxx->lock)) {
......@@ -233,7 +252,7 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
#define MC13XXX_ADC_WORKING (1 << 0)
int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
static int mc13xxx_adc_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
unsigned int channel, u8 ato, bool atox,
unsigned int *sample)
{
......@@ -326,6 +345,96 @@ out:
return ret;
}
static int mc34708_adc_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
unsigned int channel, u8 ato, bool atox,
unsigned int *sample)
{
int ret, i;
u32 adc0, adc3, adc1, old_adc0;
struct mc13xxx_adcdone_data adcdone_data = {
.mc13xxx = mc13xxx,
};
switch (mode) {
case MC13XXX_ADC_MODE_TS:
adc0 = MC34708_ADC0_TSEN | MC34708_ADC0_TSSTART | MC34708_ADC0_TSSTOP(7);
adc1 = MC34708_ADC1_TSDLY1(0xf) |
MC34708_ADC1_TSDLY2(0xf) |
MC34708_ADC1_TSDLY3(0xf);
adc3 = MC34708_ADC3_TSSEL(0, MC34708_TS_X) |
MC34708_ADC3_TSSEL(1, MC34708_TS_Y) |
MC34708_ADC3_TSSEL(2, MC34708_TS_X) |
MC34708_ADC3_TSSEL(3, MC34708_TS_Y) |
MC34708_ADC3_TSSEL(4, MC34708_TS_X) |
MC34708_ADC3_TSSEL(5, MC34708_TS_R) |
MC34708_ADC3_TSSEL(6, MC34708_TS_Y) |
MC34708_ADC3_TSSEL(7, MC34708_TS_R);
break;
case MC13XXX_ADC_MODE_SINGLE_CHAN:
case MC13XXX_ADC_MODE_MULT_CHAN:
/* Not yet implemented */
return -ENOSYS;
default:
return -EINVAL;
}
init_completion(&adcdone_data.done);
mc13xxx_lock(mc13xxx);
if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) {
ret = -EBUSY;
goto out;
}
mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
mc13xxx_irq_request(mc13xxx, MC34708_IRQ_TSDONE,
mc13xxx_handler_adcdone, __func__, &adcdone_data);
mc13xxx_irq_ack(mc13xxx, MC34708_IRQ_TSDONE);
mc13xxx_reg_write(mc13xxx, MC34708_ADC3, adc3);
mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
mc13xxx_unlock(mc13xxx);
ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
mc13xxx_lock(mc13xxx);
mc13xxx_irq_free(mc13xxx, MC34708_IRQ_TSDONE, &adcdone_data);
if (!ret) {
ret = -ETIMEDOUT;
goto out;
}
for (i = 0; i < 4; i++)
mc13xxx_reg_read(mc13xxx, MC34708_ADC4 + i, &sample[i]);
out:
ret = mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, old_adc0);
mc13xxx->adcflags &= ~MC13XXX_ADC_WORKING;
mc13xxx_unlock(mc13xxx);
return ret;
}
int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
unsigned int channel, u8 ato, bool atox,
unsigned int *sample)
{
return mc13xxx->variant->adc_do_conversion(mc13xxx, mode, channel, ato,
atox, sample);
}
EXPORT_SYMBOL_GPL(mc13xxx_adc_do_conversion);
static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
......@@ -480,18 +589,21 @@ EXPORT_SYMBOL_GPL(mc13xxx_common_exit);
struct mc13xxx_variant mc13xxx_variant_mc13783 = {
.name = "mc13783",
.print_revision = mc13xxx_print_revision,
.adc_do_conversion = mc13xxx_adc_conversion,
};
EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783);
struct mc13xxx_variant mc13xxx_variant_mc13892 = {
.name = "mc13892",
.print_revision = mc13xxx_print_revision,
.adc_do_conversion = mc13xxx_adc_conversion,
};
EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13892);
struct mc13xxx_variant mc13xxx_variant_mc34708 = {
.name = "mc34708",
.print_revision = mc34708_print_revision,
.adc_do_conversion = mc34708_adc_conversion,
};
EXPORT_SYMBOL_GPL(mc13xxx_variant_mc34708);
......
......@@ -22,6 +22,9 @@ struct mc13xxx;
struct mc13xxx_variant {
const char *name;
void (*print_revision)(struct mc13xxx *mc13xxx, u32 revision);
int (*adc_do_conversion)(struct mc13xxx *mc13xxx, unsigned int mode,
unsigned int channel, u8 ato, bool atox,
unsigned int *sample);
};
extern struct mc13xxx_variant
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment