Commit 7c8f0236 authored by Lee Jones's avatar Lee Jones

mfd: ab8500-gpadc: Optimise GPADC driver

Optimise GPADC driver:
 * for code readability and maintenance by grouping similar cheking
 * for performance by grouping several writing to control register
Signed-off-by: default avatarAlexandre Bourdiol <alexandre.bourdiol@stericsson.com>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Reviewed-by: default avatarPhilippe LANGLAIS <philippe.langlais@stericsson.com>
Acked-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent bc6b4132
...@@ -360,7 +360,12 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -360,7 +360,12 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
{ {
int ret; int ret;
int looplimit = 0; int looplimit = 0;
unsigned long completion_timeout;
u8 val, low_data, high_data, low_data2, high_data2; u8 val, low_data, high_data, low_data2, high_data2;
u8 val_reg1 = 0;
unsigned int delay_min = 0;
unsigned int delay_max = 0;
u8 data_low_addr, data_high_addr;
if (!gpadc) if (!gpadc)
return -ENODEV; return -ENODEV;
...@@ -392,12 +397,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -392,12 +397,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
} }
/* Enable GPADC */ /* Enable GPADC */
ret = abx500_mask_and_set_register_interruptible(gpadc->dev, val_reg1 |= EN_GPADC;
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
if (ret < 0) {
dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
goto out;
}
/* Select the channel source and set average samples */ /* Select the channel source and set average samples */
switch (avg_sample) { switch (avg_sample) {
...@@ -415,9 +415,13 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -415,9 +415,13 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
break; break;
} }
if (conv_type == ADC_HW) if (conv_type == ADC_HW) {
ret = abx500_set_register_interruptible(gpadc->dev, ret = abx500_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val); AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val);
val_reg1 |= EN_TRIG_EDGE;
if (trig_edge)
val_reg1 |= EN_FALLING;
}
else else
ret = abx500_set_register_interruptible(gpadc->dev, ret = abx500_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val); AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val);
...@@ -432,123 +436,42 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -432,123 +436,42 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
* charging current sense if it needed, ABB 3.0 needs some special * charging current sense if it needed, ABB 3.0 needs some special
* treatment too. * treatment too.
*/ */
if ((conv_type == ADC_HW) && (trig_edge)) {
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_FALLING, EN_FALLING);
}
switch (channel) { switch (channel) {
case MAIN_CHARGER_C: case MAIN_CHARGER_C:
case USB_CHARGER_C: case USB_CHARGER_C:
if (conv_type == ADC_HW) val_reg1 |= EN_BUF | EN_ICHAR;
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | EN_ICHAR | EN_TRIG_EDGE,
EN_BUF | EN_ICHAR | EN_TRIG_EDGE);
else
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | EN_ICHAR,
EN_BUF | EN_ICHAR);
break;
case XTAL_TEMP:
if (conv_type == ADC_HW)
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | EN_TRIG_EDGE,
EN_BUF | EN_TRIG_EDGE);
else
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF ,
EN_BUF);
break;
case VBAT_TRUE_MEAS:
if (conv_type == ADC_HW)
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | EN_TRIG_EDGE,
EN_BUF | EN_TRIG_EDGE);
else
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF ,
EN_BUF);
break;
case BAT_CTRL_AND_IBAT:
case VBAT_MEAS_AND_IBAT:
case VBAT_TRUE_MEAS_AND_IBAT:
case BAT_TEMP_AND_IBAT:
if (conv_type == ADC_HW)
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_TRIG_EDGE,
EN_TRIG_EDGE);
else
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF,
0);
break; break;
case BTEMP_BALL: case BTEMP_BALL:
if (!is_ab8500_2p0_or_earlier(gpadc->parent)) { if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
if (conv_type == ADC_HW) val_reg1 |= EN_BUF | BTEMP_PULL_UP;
/* Turn on btemp pull-up on ABB 3.0 */ /*
ret = abx500_mask_and_set_register_interruptible * Delay might be needed for ABB8500 cut 3.0, if not,
(gpadc->dev, * remove when hardware will be availible
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, */
EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE, delay_min = 1000; /* Delay in micro seconds */
EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE); delay_max = 10000; /* large range to optimise sleep mode */
else
ret = abx500_mask_and_set_register_interruptible
(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | BTEMP_PULL_UP,
EN_BUF | BTEMP_PULL_UP);
/*
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* when hardware will be available
*/
usleep_range(1000, 1000);
break; break;
} }
/* Intentional fallthrough */ /* Intentional fallthrough */
default: default:
if (conv_type == ADC_HW) val_reg1 |= EN_BUF;
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
EN_BUF | EN_TRIG_EDGE,
EN_BUF | EN_TRIG_EDGE);
else
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
AB8500_GPADC,
AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
break; break;
} }
/* Write configuration to register */
ret = abx500_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, val_reg1);
if (ret < 0) { if (ret < 0) {
dev_err(gpadc->dev, dev_err(gpadc->dev,
"gpadc_conversion: select falling edge failed\n"); "gpadc_conversion: set Control register failed\n");
goto out; goto out;
} }
/* Set trigger delay timer */ if (delay_min != 0)
usleep_range(delay_min, delay_max);
if (conv_type == ADC_HW) { if (conv_type == ADC_HW) {
/* Set trigger delay timer */
ret = abx500_set_register_interruptible(gpadc->dev, ret = abx500_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer); AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer);
if (ret < 0) { if (ret < 0) {
...@@ -556,10 +479,11 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -556,10 +479,11 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
"gpadc_conversion: trig timer failed\n"); "gpadc_conversion: trig timer failed\n");
goto out; goto out;
} }
} completion_timeout = 2 * HZ;
data_low_addr = AB8500_GPADC_AUTODATAL_REG;
/* Start SW conversion */ data_high_addr = AB8500_GPADC_AUTODATAH_REG;
if (conv_type == ADC_SW) { } else {
/* Start SW conversion */
ret = abx500_mask_and_set_register_interruptible(gpadc->dev, ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
ADC_SW_CONV, ADC_SW_CONV); ADC_SW_CONV, ADC_SW_CONV);
...@@ -568,61 +492,35 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, ...@@ -568,61 +492,35 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
"gpadc_conversion: start s/w conv failed\n"); "gpadc_conversion: start s/w conv failed\n");
goto out; goto out;
} }
completion_timeout = msecs_to_jiffies(CONVERSION_TIME);
data_low_addr = AB8500_GPADC_MANDATAL_REG;
data_high_addr = AB8500_GPADC_MANDATAH_REG;
} }
/* wait for completion of conversion */ /* wait for completion of conversion */
if (conv_type == ADC_HW) { if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, completion_timeout)) {
2 * HZ)) { dev_err(gpadc->dev,
dev_err(gpadc->dev, "timeout didn't receive GPADC conv interrupt\n");
"timeout didn't receive hw GPADC conv interrupt\n"); ret = -EINVAL;
ret = -EINVAL; goto out;
goto out;
}
} else {
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
msecs_to_jiffies(CONVERSION_TIME))) {
dev_err(gpadc->dev,
"timeout didn't receive sw GPADC conv interrupt\n");
ret = -EINVAL;
goto out;
}
} }
/* Read the converted RAW data */ /* Read the converted RAW data */
if (conv_type == ADC_HW) { ret = abx500_get_register_interruptible(gpadc->dev,
ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, data_low_addr, &low_data);
AB8500_GPADC, AB8500_GPADC_AUTODATAL_REG, &low_data); if (ret < 0) {
if (ret < 0) { dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
dev_err(gpadc->dev, goto out;
"gpadc_conversion: read hw low data failed\n"); }
goto out;
}
ret = abx500_get_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_AUTODATAH_REG, &high_data);
if (ret < 0) {
dev_err(gpadc->dev,
"gpadc_conversion: read hw high data failed\n");
goto out;
}
} else {
ret = abx500_get_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_MANDATAL_REG, &low_data);
if (ret < 0) {
dev_err(gpadc->dev,
"gpadc_conversion: read sw low data failed\n");
goto out;
}
ret = abx500_get_register_interruptible(gpadc->dev, ret = abx500_get_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_MANDATAH_REG, &high_data); AB8500_GPADC, data_high_addr, &high_data);
if (ret < 0) { if (ret < 0) {
dev_err(gpadc->dev, dev_err(gpadc->dev, "gpadc_conversion: read high data failed\n");
"gpadc_conversion: read sw high data failed\n"); goto out;
goto out;
}
} }
/* Check if double convertion is required */ /* Check if double convertion is required */
if ((channel == BAT_CTRL_AND_IBAT) || if ((channel == BAT_CTRL_AND_IBAT) ||
(channel == VBAT_MEAS_AND_IBAT) || (channel == VBAT_MEAS_AND_IBAT) ||
......
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