Commit 8c1f422c authored by Felipe Balbi's avatar Felipe Balbi Committed by Tony Lindgren

i2c: move twl4030-madc to new registration style

Moving twl4030-madc to new style registration just like
the other twl4030 children.

Cc: Mikko Ylinen <mikko.k.ylinen@nokia.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 2e056215
...@@ -355,12 +355,17 @@ static struct twl4030_usb_data sdp2430_usb_data = { ...@@ -355,12 +355,17 @@ static struct twl4030_usb_data sdp2430_usb_data = {
.usb_mode = T2_USB_MODE_ULPI, .usb_mode = T2_USB_MODE_ULPI,
}; };
static struct twl4030_madc_platform_data sdp2430_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data sdp2430_twldata = { static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE, .irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END, .irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */ /* platform_data for children goes here */
.gpio = &sdp2430_gpio_data, .gpio = &sdp2430_gpio_data,
.madc = &sdp2430_madc_data,
.keypad = &sdp2430_kp_data, .keypad = &sdp2430_kp_data,
.usb = &sdp2430_usb_data, .usb = &sdp2430_usb_data,
}; };
......
...@@ -310,12 +310,17 @@ static struct twl4030_usb_data sdp3430_usb_data = { ...@@ -310,12 +310,17 @@ static struct twl4030_usb_data sdp3430_usb_data = {
.usb_mode = T2_USB_MODE_ULPI, .usb_mode = T2_USB_MODE_ULPI,
}; };
static struct twl4030_madc_platform_data sdp3430_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data sdp3430_twldata = { static struct twl4030_platform_data sdp3430_twldata = {
.irq_base = TWL4030_IRQ_BASE, .irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END, .irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */ /* platform_data for children goes here */
.gpio = &sdp3430_gpio_data, .gpio = &sdp3430_gpio_data,
.madc = &sdp3430_madc_data,
.keypad = &sdp3430_kp_data, .keypad = &sdp3430_kp_data,
.usb = &sdp3430_usb_data, .usb = &sdp3430_usb_data,
}; };
......
...@@ -193,11 +193,16 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = { ...@@ -193,11 +193,16 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = {
.irq_end = TWL4030_GPIO_IRQ_END, .irq_end = TWL4030_GPIO_IRQ_END,
}; };
static struct twl4030_madc_platform_data ldp_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data ldp_twldata = { static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE, .irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END, .irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */ /* platform_data for children goes here */
.madc = &ldp_madc_data,
.usb = &ldp_usb_data, .usb = &ldp_usb_data,
.gpio = &ldp_gpio_data, .gpio = &ldp_gpio_data,
}; };
......
...@@ -236,12 +236,17 @@ static struct twl4030_usb_data omap2evm_usb_data = { ...@@ -236,12 +236,17 @@ static struct twl4030_usb_data omap2evm_usb_data = {
.usb_mode = T2_USB_MODE_ULPI, .usb_mode = T2_USB_MODE_ULPI,
}; };
static struct twl4030_madc_platform_data omap2evm_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data omap2evm_twldata = { static struct twl4030_platform_data omap2evm_twldata = {
.irq_base = TWL4030_IRQ_BASE, .irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END, .irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */ /* platform_data for children goes here */
.keypad = &omap2evm_kp_data, .keypad = &omap2evm_kp_data,
.madc = &omap2evm_madc_data,
.usb = &omap2evm_usb_data, .usb = &omap2evm_usb_data,
.gpio = &omap2evm_gpio_data, .gpio = &omap2evm_gpio_data,
}; };
......
...@@ -128,12 +128,17 @@ static struct twl4030_keypad_data omap3evm_kp_data = { ...@@ -128,12 +128,17 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
.irq = TWL4030_MODIRQ_KEYPAD, .irq = TWL4030_MODIRQ_KEYPAD,
}; };
static struct twl4030_madc_platform_data omap3evm_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data omap3evm_twldata = { static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE, .irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END, .irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */ /* platform_data for children goes here */
.keypad = &omap3evm_kp_data, .keypad = &omap3evm_kp_data,
.madc = &omap3evm_madc_data,
.usb = &omap3evm_usb_data, .usb = &omap3evm_usb_data,
.gpio = &omap3evm_gpio_data, .gpio = &omap3evm_gpio_data,
}; };
......
...@@ -69,6 +69,12 @@ ...@@ -69,6 +69,12 @@
#define twl_has_gpio() false #define twl_has_gpio() false
#endif #endif
#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
#define twl_has_madc() true
#else
#define twl_has_madc() false
#endif
/* Primary Interrupt Handler on TWL4030 Registers */ /* Primary Interrupt Handler on TWL4030 Registers */
/* Register Definitions */ /* Register Definitions */
...@@ -772,6 +778,27 @@ static int add_children(struct twl4030_platform_data *pdata) ...@@ -772,6 +778,27 @@ static int add_children(struct twl4030_platform_data *pdata)
} }
} }
if (twl_has_madc() && pdata->madc) {
pdev = platform_device_alloc("twl4030_madc", -1);
if (pdev) {
twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
pdev->dev.parent = &twl->client->dev;
device_init_wakeup(&pdev->dev, 1);
status = platform_device_add_data(pdev, pdata->madc,
sizeof(*pdata->madc));
if (status < 0) {
platform_device_put(pdev);
goto err;
}
status = platform_device_add(pdev);
if (status < 0)
platform_device_put(pdev);
} else {
status = -ENOMEM;
goto err;
}
}
err: err:
pr_err("failed to add twl4030's children\n"); pr_err("failed to add twl4030's children\n");
return status; return status;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/i2c/twl4030.h> #include <linux/i2c/twl4030.h>
#include <linux/i2c/twl4030-madc.h> #include <linux/i2c/twl4030-madc.h>
...@@ -37,13 +38,16 @@ ...@@ -37,13 +38,16 @@
#define TWL4030_MADC_PFX "twl4030-madc: " #define TWL4030_MADC_PFX "twl4030-madc: "
static struct twl4030_madc_data { struct twl4030_madc_data {
struct device *dev;
struct mutex lock; struct mutex lock;
struct work_struct ws; struct work_struct ws;
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
} twl4030_madc; int imr;
int isr;
};
static const char irq_pin = 1; /* XXX Read from platfrom data */ static struct twl4030_madc_data *the_madc;
static static
const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
...@@ -66,35 +70,43 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { ...@@ -66,35 +70,43 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
}, },
}; };
static void twl4030_madc_read(u8 reg, u8 *val) static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
{ {
int ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg); int ret;
if (ret) u8 val;
printk(KERN_ERR TWL4030_MADC_PFX
"unable to read register 0x%X\n", reg); ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
if (ret) {
dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
return ret;
}
return val;
} }
static void twl4030_madc_write(u8 reg, u8 val) static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
{ {
int ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg); int ret;
ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
if (ret) if (ret)
printk(KERN_ERR TWL4030_MADC_PFX dev_err(madc->dev, "unable to write register 0x%X\n", reg);
"unable to write register 0x%X\n", reg);
} }
static int twl4030_madc_channel_raw_read(u8 reg) static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
{ {
u8 msb, lsb; u8 msb, lsb;
/* For each ADC channel, we have MSB and LSB register pair. MSB address /* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the addr of LSB register */ * is always LSB address+1. reg parameter is the addr of LSB register */
twl4030_madc_read(reg+1, &msb); msb = twl4030_madc_read(madc, reg + 1);
twl4030_madc_read(reg, &lsb); lsb = twl4030_madc_read(madc, reg);
return (int)(((msb << 8) | lsb) >> 6); return (int)(((msb << 8) | lsb) >> 6);
} }
static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf) static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
u8 reg_base, u16 channels, int *buf)
{ {
int count = 0; int count = 0;
u8 reg, i; u8 reg, i;
...@@ -105,47 +117,40 @@ static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf) ...@@ -105,47 +117,40 @@ static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf)
for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) { for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
if (channels & (1<<i)) { if (channels & (1<<i)) {
reg = reg_base + 2*i; reg = reg_base + 2*i;
buf[i] = twl4030_madc_channel_raw_read(reg); buf[i] = twl4030_madc_channel_raw_read(madc, reg);
count++; count++;
} }
} }
return count; return count;
} }
static void twl4030_madc_enable_irq(int id) static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
{ {
u8 val; u8 val;
static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; val = twl4030_madc_read(madc, madc->imr);
twl4030_madc_read(imr, &val);
val &= ~(1 << id); val &= ~(1 << id);
twl4030_madc_write(imr, val); twl4030_madc_write(madc, madc->imr, val);
} }
static void twl4030_madc_disable_irq(int id) static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
{ {
u8 val; u8 val;
static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; val = twl4030_madc_read(madc, madc->imr);
twl4030_madc_read(imr, &val);
val |= (1 << id); val |= (1 << id);
twl4030_madc_write(imr, val); twl4030_madc_write(madc, madc->imr, val);
} }
static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev) static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
{ {
struct twl4030_madc_data *madc = _madc;
u8 isr_val, imr_val; u8 isr_val, imr_val;
static u8 isr, imr;
int i; int i;
imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
isr = (irq_pin == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
/* Use COR to ack interrupts since we have no shared IRQs in ISRx */ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
twl4030_madc_read(isr, &isr_val); isr_val = twl4030_madc_read(madc, madc->isr);
twl4030_madc_read(imr, &imr_val); imr_val = twl4030_madc_read(madc, madc->imr);
isr_val &= ~imr_val; isr_val &= ~imr_val;
...@@ -154,11 +159,11 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev) ...@@ -154,11 +159,11 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
if (!(isr_val & (1<<i))) if (!(isr_val & (1<<i)))
continue; continue;
twl4030_madc_disable_irq(i); twl4030_madc_disable_irq(madc, i);
twl4030_madc.requests[i].result_pending = 1; madc->requests[i].result_pending = 1;
} }
schedule_work(&twl4030_madc.ws); schedule_work(&madc->ws);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -166,14 +171,16 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev) ...@@ -166,14 +171,16 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
static void twl4030_madc_work(struct work_struct *ws) static void twl4030_madc_work(struct work_struct *ws)
{ {
const struct twl4030_madc_conversion_method *method; const struct twl4030_madc_conversion_method *method;
struct twl4030_madc_data *madc;
struct twl4030_madc_request *r; struct twl4030_madc_request *r;
int len, i; int len, i;
mutex_lock(&twl4030_madc.lock); madc = container_of(ws, struct twl4030_madc_data, ws);
mutex_lock(&madc->lock);
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &twl4030_madc.requests[i]; r = &madc->requests[i];
/* No pending results for this method, move to next one */ /* No pending results for this method, move to next one */
if (!r->result_pending) if (!r->result_pending)
...@@ -182,7 +189,7 @@ static void twl4030_madc_work(struct work_struct *ws) ...@@ -182,7 +189,7 @@ static void twl4030_madc_work(struct work_struct *ws)
method = &twl4030_conversion_methods[r->method]; method = &twl4030_conversion_methods[r->method];
/* Read results */ /* Read results */
len = twl4030_madc_read_channels(method->rbase, len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf); r->channels, r->rbuf);
/* Return results to caller */ /* Return results to caller */
...@@ -196,23 +203,25 @@ static void twl4030_madc_work(struct work_struct *ws) ...@@ -196,23 +203,25 @@ static void twl4030_madc_work(struct work_struct *ws)
r->active = 0; r->active = 0;
} }
mutex_unlock(&twl4030_madc.lock); mutex_unlock(&madc->lock);
} }
static int twl4030_madc_set_irq(struct twl4030_madc_request *req) static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
struct twl4030_madc_request *req)
{ {
struct twl4030_madc_request *p; struct twl4030_madc_request *p;
p = &twl4030_madc.requests[req->method]; p = &madc->requests[req->method];
memcpy(p, req, sizeof *req); memcpy(p, req, sizeof *req);
twl4030_madc_enable_irq(req->method); twl4030_madc_enable_irq(madc, req->method);
return 0; return 0;
} }
static inline void twl4030_madc_start_conversion(int conv_method) static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
int conv_method)
{ {
const struct twl4030_madc_conversion_method *method; const struct twl4030_madc_conversion_method *method;
...@@ -221,7 +230,7 @@ static inline void twl4030_madc_start_conversion(int conv_method) ...@@ -221,7 +230,7 @@ static inline void twl4030_madc_start_conversion(int conv_method)
switch (conv_method) { switch (conv_method) {
case TWL4030_MADC_SW1: case TWL4030_MADC_SW1:
case TWL4030_MADC_SW2: case TWL4030_MADC_SW2:
twl4030_madc_write(method->ctrl, TWL4030_MADC_SW_START); twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
break; break;
case TWL4030_MADC_RT: case TWL4030_MADC_RT:
default: default:
...@@ -229,14 +238,16 @@ static inline void twl4030_madc_start_conversion(int conv_method) ...@@ -229,14 +238,16 @@ static inline void twl4030_madc_start_conversion(int conv_method)
} }
} }
static void twl4030_madc_wait_conversion_ready_ms(u8 *time, u8 status_reg) static void twl4030_madc_wait_conversion_ready_ms(
struct twl4030_madc_data *madc,
u8 *time, u8 status_reg)
{ {
u8 reg = 0; u8 reg = 0;
do { do {
msleep(1); msleep(1);
(*time)--; (*time)--;
twl4030_madc_read(status_reg, &reg); reg = twl4030_madc_read(madc, status_reg);
} while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) && } while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
(*time != 0)); (*time != 0));
} }
...@@ -251,7 +262,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ...@@ -251,7 +262,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
return -EINVAL; return -EINVAL;
/* Do we have a conversion request ongoing */ /* Do we have a conversion request ongoing */
if (twl4030_madc.requests[req->method].active) if (the_madc->requests[req->method].active)
return -EBUSY; return -EBUSY;
ch_msb = (req->channels >> 8) & 0xff; ch_msb = (req->channels >> 8) & 0xff;
...@@ -259,22 +270,22 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ...@@ -259,22 +270,22 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
method = &twl4030_conversion_methods[req->method]; method = &twl4030_conversion_methods[req->method];
mutex_lock(&twl4030_madc.lock); mutex_lock(&the_madc->lock);
/* Select channels to be converted */ /* Select channels to be converted */
twl4030_madc_write(method->sel + 1, ch_msb); twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
twl4030_madc_write(method->sel, ch_lsb); twl4030_madc_write(the_madc, method->sel, ch_lsb);
/* Select averaging for all channels if do_avg is set */ /* Select averaging for all channels if do_avg is set */
if (req->do_avg) { if (req->do_avg) {
twl4030_madc_write(method->avg + 1, ch_msb); twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
twl4030_madc_write(method->avg, ch_lsb); twl4030_madc_write(the_madc, method->avg, ch_lsb);
} }
if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) { if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
twl4030_madc_set_irq(req); twl4030_madc_set_irq(the_madc, req);
twl4030_madc_start_conversion(req->method); twl4030_madc_start_conversion(the_madc, req->method);
twl4030_madc.requests[req->method].active = 1; the_madc->requests[req->method].active = 1;
ret = 0; ret = 0;
goto out; goto out;
} }
...@@ -285,32 +296,33 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ...@@ -285,32 +296,33 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
goto out; goto out;
} }
twl4030_madc_start_conversion(req->method); twl4030_madc_start_conversion(the_madc, req->method);
twl4030_madc.requests[req->method].active = 1; the_madc->requests[req->method].active = 1;
/* Wait until conversion is ready (ctrl register returns EOC) */ /* Wait until conversion is ready (ctrl register returns EOC) */
wait_time = 50; wait_time = 50;
twl4030_madc_wait_conversion_ready_ms(&wait_time, method->ctrl); twl4030_madc_wait_conversion_ready_ms(the_madc,
&wait_time, method->ctrl);
if (wait_time == 0) { if (wait_time == 0) {
printk(KERN_ERR TWL4030_MADC_PFX "conversion timeout!\n"); dev_dbg(the_madc->dev, "conversion timeout!\n");
ret = -EAGAIN; ret = -EAGAIN;
goto out; goto out;
} }
ret = twl4030_madc_read_channels(method->rbase, req->channels, ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
req->rbuf); req->rbuf);
twl4030_madc.requests[req->method].active = 0; the_madc->requests[req->method].active = 0;
out: out:
mutex_unlock(&twl4030_madc.lock); mutex_unlock(&the_madc->lock);
return ret; return ret;
} }
EXPORT_SYMBOL(twl4030_madc_conversion); EXPORT_SYMBOL(twl4030_madc_conversion);
static int twl4030_madc_set_current_generator(int chan, int on) static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
int chan, int on)
{ {
int ret; int ret;
u8 regval; u8 regval;
...@@ -332,16 +344,16 @@ static int twl4030_madc_set_current_generator(int chan, int on) ...@@ -332,16 +344,16 @@ static int twl4030_madc_set_current_generator(int chan, int on)
return ret; return ret;
} }
static int twl4030_madc_set_power(int on) static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
{ {
u8 regval; u8 regval;
twl4030_madc_read(TWL4030_MADC_CTRL1, &regval); regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
if (on) if (on)
regval |= TWL4030_MADC_MADCON; regval |= TWL4030_MADC_MADCON;
else else
regval &= ~TWL4030_MADC_MADCON; regval &= ~TWL4030_MADC_MADCON;
twl4030_madc_write(TWL4030_MADC_CTRL1, regval); twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
return 0; return 0;
} }
...@@ -354,7 +366,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp, ...@@ -354,7 +366,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
ret = copy_from_user(&par, (void __user *) arg, sizeof(par)); ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
if (ret) { if (ret) {
printk(KERN_ERR TWL4030_MADC_PFX "copy_from_user: %d\n", ret); dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
return -EACCES; return -EACCES;
} }
...@@ -364,7 +376,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp, ...@@ -364,7 +376,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
if (par.channel >= TWL4030_MADC_MAX_CHANNELS) if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
return -EINVAL; return -EINVAL;
req.channels = (1<<par.channel); req.channels = (1 << par.channel);
req.do_avg = par.average; req.do_avg = par.average;
req.method = TWL4030_MADC_SW1; req.method = TWL4030_MADC_SW1;
req.func_cb = NULL; req.func_cb = NULL;
...@@ -384,7 +396,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp, ...@@ -384,7 +396,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
ret = copy_to_user((void __user *) arg, &par, sizeof(par)); ret = copy_to_user((void __user *) arg, &par, sizeof(par));
if (ret) { if (ret) {
printk(KERN_ERR TWL4030_MADC_PFX "copy_to_user: %d\n", ret); dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
return -EACCES; return -EACCES;
} }
...@@ -398,22 +410,37 @@ static struct file_operations twl4030_madc_fileops = { ...@@ -398,22 +410,37 @@ static struct file_operations twl4030_madc_fileops = {
static struct miscdevice twl4030_madc_device = { static struct miscdevice twl4030_madc_device = {
.minor = MISC_DYNAMIC_MINOR, .minor = MISC_DYNAMIC_MINOR,
.name = "twl4030-adc", .name = "twl4030-madc",
.fops = &twl4030_madc_fileops .fops = &twl4030_madc_fileops
}; };
static int __init twl4030_madc_init(void) static int __init twl4030_madc_probe(struct platform_device *pdev)
{ {
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
int ret; int ret;
u8 regval; u8 regval;
madc = kzalloc(sizeof *madc, GFP_KERNEL);
if (!madc)
return -ENOMEM;
if (!pdata) {
dev_dbg(&pdev->dev, "platform_data not available\n");
ret = -EINVAL;
goto err_pdata;
}
madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
ret = misc_register(&twl4030_madc_device); ret = misc_register(&twl4030_madc_device);
if (ret == -1) { if (ret) {
printk(KERN_ERR TWL4030_MADC_PFX "misc_register() failed!\n"); dev_dbg(&pdev->dev, "could not register misc_device\n");
return ret; goto err_misc;
} }
twl4030_madc_set_power(1); twl4030_madc_set_power(madc, 1);
twl4030_madc_set_current_generator(0, 1); twl4030_madc_set_current_generator(madc, 0, 1);
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
&regval, TWL4030_BCI_BCICTL1); &regval, TWL4030_BCI_BCICTL1);
...@@ -424,32 +451,66 @@ static int __init twl4030_madc_init(void) ...@@ -424,32 +451,66 @@ static int __init twl4030_madc_init(void)
regval, TWL4030_BCI_BCICTL1); regval, TWL4030_BCI_BCICTL1);
ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler, ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler,
IRQF_DISABLED, "twl4030_madc", &twl4030_madc); IRQF_DISABLED, "twl4030_madc", madc);
if (ret) if (ret) {
printk(KERN_ERR TWL4030_MADC_PFX "request_irq: %d\n", ret); dev_dbg(&pdev->dev, "could not request irq\n");
goto err_irq;
}
mutex_init(&twl4030_madc.lock); platform_set_drvdata(pdev, madc);
mutex_init(&madc->lock);
INIT_WORK(&madc->ws, twl4030_madc_work);
INIT_WORK(&twl4030_madc.ws, twl4030_madc_work); the_madc = madc;
printk(KERN_INFO TWL4030_MADC_PFX "initialised\n"); return 0;
err_irq:
misc_deregister(&twl4030_madc_device);
err_misc:
err_pdata:
kfree(madc);
return ret; return ret;
} }
static void __exit twl4030_madc_exit(void) static int __exit twl4030_madc_remove(struct platform_device *pdev)
{ {
twl4030_madc_set_power(0); struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
twl4030_madc_set_current_generator(0, 0);
free_irq(TWL4030_MODIRQ_MADC, &twl4030_madc); twl4030_madc_set_power(madc, 0);
cancel_work_sync(&twl4030_madc.ws); twl4030_madc_set_current_generator(madc, 0, 0);
free_irq(TWL4030_MODIRQ_MADC, madc);
cancel_work_sync(&madc->ws);
misc_deregister(&twl4030_madc_device); misc_deregister(&twl4030_madc_device);
return 0;
} }
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
.remove = __exit_p(twl4030_madc_remove),
.driver = {
.name = "twl4030_madc",
.owner = THIS_MODULE,
},
};
static int __init twl4030_madc_init(void)
{
return platform_driver_register(&twl4030_madc_driver);
}
module_init(twl4030_madc_init); module_init(twl4030_madc_init);
static void __exit twl4030_madc_exit(void)
{
platform_driver_unregister(&twl4030_madc_driver);
}
module_exit(twl4030_madc_exit); module_exit(twl4030_madc_exit);
MODULE_ALIAS("i2c:twl4030-adc"); MODULE_ALIAS("platform:twl4030-madc");
MODULE_AUTHOR("Nokia Corporation"); MODULE_AUTHOR("Nokia Corporation");
MODULE_DESCRIPTION("twl4030 ADC driver"); MODULE_DESCRIPTION("twl4030 ADC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -67,6 +67,10 @@ struct twl4030_gpio_platform_data { ...@@ -67,6 +67,10 @@ struct twl4030_gpio_platform_data {
unsigned gpio, unsigned ngpio); unsigned gpio, unsigned ngpio);
}; };
struct twl4030_madc_platform_data {
int irq_line;
};
struct twl4030_keypad_data { struct twl4030_keypad_data {
int rows; int rows;
int cols; int cols;
...@@ -88,6 +92,7 @@ struct twl4030_usb_data { ...@@ -88,6 +92,7 @@ struct twl4030_usb_data {
struct twl4030_platform_data { struct twl4030_platform_data {
unsigned irq_base, irq_end; unsigned irq_base, irq_end;
struct twl4030_gpio_platform_data *gpio; struct twl4030_gpio_platform_data *gpio;
struct twl4030_madc_platform_data *madc;
struct twl4030_keypad_data *keypad; struct twl4030_keypad_data *keypad;
struct twl4030_usb_data *usb; struct twl4030_usb_data *usb;
......
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