* [RFT/PATCH 01/10] cbus: retu: give it a context structure
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-04 1:40 ` Tony Lindgren
2011-01-03 7:49 ` [RFT/PATCH 02/10] cbus: retu: get rid of retu-user.c Felipe Balbi
` (8 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
This is pretty much a cleanup patch just
adding a context structure for Retu, to avoid
all the globals it had.
Note that this breaks retu-user.c due to moving
the lock around, but that retu-user.c has to
go anyway as it's completely non-standard way
of accessing Retu children.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/retu.c | 126 ++++++++++++++++++++++++++++++++++-----------------
drivers/cbus/retu.h | 2 -
2 files changed, 85 insertions(+), 43 deletions(-)
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
index a2977c9..6e130bf 100644
--- a/drivers/cbus/retu.c
+++ b/drivers/cbus/retu.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/device.h>
@@ -49,11 +50,18 @@
#define RETU_ID 0x01
#define PFX "retu: "
-static int retu_initialized;
-static int retu_is_vilma;
+struct retu {
+ /* Device lock */
+ spinlock_t lock;
+ struct tasklet_struct tasklet;
+ struct device *dev;
-static struct tasklet_struct retu_tasklet;
-spinlock_t retu_lock = SPIN_LOCK_UNLOCKED;
+ int irq;
+
+ bool is_vilma;
+};
+
+static struct retu *the_retu;
struct retu_irq_handler_desc {
int (*func)(unsigned long);
@@ -65,7 +73,7 @@ static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
int retu_get_status(void)
{
- return retu_initialized;
+ return the_retu ? 1 : 0;
}
EXPORT_SYMBOL(retu_get_status);
@@ -77,7 +85,7 @@ EXPORT_SYMBOL(retu_get_status);
*/
int retu_read_reg(unsigned reg)
{
- BUG_ON(!retu_initialized);
+ BUG_ON(!the_retu);
return cbus_read_reg(RETU_ID, reg);
}
EXPORT_SYMBOL(retu_read_reg);
@@ -91,22 +99,23 @@ EXPORT_SYMBOL(retu_read_reg);
*/
void retu_write_reg(unsigned reg, u16 val)
{
- BUG_ON(!retu_initialized);
+ BUG_ON(!the_retu);
cbus_write_reg(RETU_ID, reg, val);
}
EXPORT_SYMBOL(retu_write_reg);
void retu_set_clear_reg_bits(unsigned reg, u16 set, u16 clear)
{
- unsigned long flags;
- u16 w;
+ struct retu *retu = the_retu;
+ unsigned long flags;
+ u16 w;
- spin_lock_irqsave(&retu_lock, flags);
+ spin_lock_irqsave(&retu->lock, flags);
w = retu_read_reg(reg);
w &= ~clear;
w |= set;
retu_write_reg(reg, w);
- spin_unlock_irqrestore(&retu_lock, flags);
+ spin_unlock_irqrestore(&retu->lock, flags);
}
EXPORT_SYMBOL_GPL(retu_set_clear_reg_bits);
@@ -114,15 +123,19 @@ EXPORT_SYMBOL_GPL(retu_set_clear_reg_bits);
int retu_read_adc(int channel)
{
- unsigned long flags;
- int res;
+ struct retu *retu = the_retu;
+ unsigned long flags;
+ int res;
+
+ if (!retu)
+ return -ENODEV;
if (channel < 0 || channel > ADC_MAX_CHAN_NUMBER)
return -EINVAL;
- spin_lock_irqsave(&retu_lock, flags);
+ spin_lock_irqsave(&retu->lock, flags);
- if ((channel == 8) && retu_is_vilma) {
+ if ((channel == 8) && retu->is_vilma) {
int scr = retu_read_reg(RETU_REG_ADCSCR);
int ch = (retu_read_reg(RETU_REG_ADCR) >> 10) & 0xf;
if (((scr & 0xff) != 0) && (ch != 8))
@@ -133,11 +146,11 @@ int retu_read_adc(int channel)
retu_write_reg(RETU_REG_ADCR, channel << 10);
res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
- if (retu_is_vilma)
+ if (retu->is_vilma)
retu_write_reg(RETU_REG_ADCR, (1 << 13));
/* Unlock retu */
- spin_unlock_irqrestore(&retu_lock, flags);
+ spin_unlock_irqrestore(&retu->lock, flags);
return res;
}
@@ -164,15 +177,16 @@ static u16 retu_disable_bogus_irqs(u16 mask)
*/
void retu_disable_irq(int id)
{
- unsigned long flags;
- u16 mask;
+ struct retu *retu = the_retu;
+ unsigned long flags;
+ u16 mask;
- spin_lock_irqsave(&retu_lock, flags);
+ spin_lock_irqsave(&retu->lock, flags);
mask = retu_read_reg(RETU_REG_IMR);
mask |= 1 << id;
mask = retu_disable_bogus_irqs(mask);
retu_write_reg(RETU_REG_IMR, mask);
- spin_unlock_irqrestore(&retu_lock, flags);
+ spin_unlock_irqrestore(&retu->lock, flags);
}
EXPORT_SYMBOL(retu_disable_irq);
@@ -181,19 +195,21 @@ EXPORT_SYMBOL(retu_disable_irq);
*/
void retu_enable_irq(int id)
{
- unsigned long flags;
- u16 mask;
+ struct retu *retu = the_retu;
+ unsigned long flags;
+ u16 mask;
if (id == 3) {
printk("Enabling Retu IRQ %d\n", id);
dump_stack();
}
- spin_lock_irqsave(&retu_lock, flags);
+
+ spin_lock_irqsave(&retu->lock, flags);
mask = retu_read_reg(RETU_REG_IMR);
mask &= ~(1 << id);
mask = retu_disable_bogus_irqs(mask);
retu_write_reg(RETU_REG_IMR, mask);
- spin_unlock_irqrestore(&retu_lock, flags);
+ spin_unlock_irqrestore(&retu->lock, flags);
}
EXPORT_SYMBOL(retu_enable_irq);
@@ -209,9 +225,12 @@ EXPORT_SYMBOL(retu_ack_irq);
/*
* RETU interrupt handler. Only schedules the tasklet.
*/
-static irqreturn_t retu_irq_handler(int irq, void *dev_id)
+static irqreturn_t retu_irq_handler(int irq, void *_retu)
{
- tasklet_schedule(&retu_tasklet);
+ struct retu *retu = _retu;
+
+ tasklet_schedule(&retu->tasklet);
+
return IRQ_HANDLED;
}
@@ -259,9 +278,10 @@ static void retu_tasklet_handler(unsigned long data)
*/
int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
{
- struct retu_irq_handler_desc *hnd;
+ struct retu *retu = the_retu;
+ struct retu_irq_handler_desc *hnd;
- if (!retu_initialized)
+ if (!retu)
return -ENODEV;
if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
@@ -396,30 +416,46 @@ static int retu_allocate_children(struct device *parent)
*/
static int __init retu_probe(struct platform_device *pdev)
{
- int rev, ret;
- int irq;
+ struct retu *retu;
+ int rev;
+ int ret;
+ int irq;
+
+ retu = kzalloc(sizeof(*retu), GFP_KERNEL);
+ if (!retu) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, retu);
+ the_retu = retu;
/* Prepare tasklet */
- tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
+ tasklet_init(&retu->tasklet, retu_tasklet_handler, 0);
+ spin_lock_init(&retu->lock);
irq = platform_get_irq(pdev, 0);
- retu_initialized = 1;
+ retu->irq = irq;
rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
if (rev & (1 << 7))
- retu_is_vilma = 1;
+ retu->is_vilma = true;
- dev_info(&pdev->dev, "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
- (rev >> 4) & 0x07, rev & 0x0f);
+ dev_info(&pdev->dev, "%s v%d.%d found\n",
+ retu->is_vilma ? "Vilma" : "Retu",
+ (rev >> 4) & 0x07, rev & 0x0f);
/* Mask all RETU interrupts */
retu_write_reg(RETU_REG_IMR, 0xffff);
ret = request_irq(irq, retu_irq_handler, 0,
- "retu", 0);
+ "retu", retu);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register IRQ handler\n");
+ tasklet_kill(&retu->tasklet);
+ kfree(retu);
+ the_retu = NULL;
return ret;
}
@@ -432,7 +468,10 @@ static int __init retu_probe(struct platform_device *pdev)
/* Initialize user-space interface */
if (retu_user_init() < 0) {
dev_err(&pdev->dev, "Unable to initialize driver\n");
+ tasklet_kill(&retu->tasklet);
free_irq(irq, 0);
+ kfree(retu);
+ the_retu = NULL;
return ret;
}
#endif
@@ -445,7 +484,9 @@ static int __init retu_probe(struct platform_device *pdev)
#endif
retu_write_reg(RETU_REG_IMR, 0xffff);
free_irq(irq, 0);
- tasklet_kill(&retu_tasklet);
+ tasklet_kill(&retu->tasklet);
+ kfree(retu);
+ the_retu = NULL;
return ret;
}
@@ -454,7 +495,8 @@ static int __init retu_probe(struct platform_device *pdev)
static int __exit retu_remove(struct platform_device *pdev)
{
- int irq;
+ struct retu *retu = platform_get_drvdata(pdev);
+ int irq;
irq = platform_get_irq(pdev, 0);
@@ -463,8 +505,10 @@ static int __exit retu_remove(struct platform_device *pdev)
#endif
/* Mask all RETU interrupts */
retu_write_reg(RETU_REG_IMR, 0xffff);
- free_irq(irq, 0);
- tasklet_kill(&retu_tasklet);
+ free_irq(irq, retu);
+ tasklet_kill(&retu->tasklet);
+ kfree(retu);
+ the_retu = NULL;
return 0;
}
diff --git a/drivers/cbus/retu.h b/drivers/cbus/retu.h
index cf3cf20..1cc486e 100644
--- a/drivers/cbus/retu.h
+++ b/drivers/cbus/retu.h
@@ -73,6 +73,4 @@ int retu_user_init(void);
void retu_user_cleanup(void);
#endif
-extern spinlock_t retu_lock;
-
#endif /* __DRIVERS_CBUS_RETU_H */
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 01/10] cbus: retu: give it a context structure
2011-01-03 7:49 ` [RFT/PATCH 01/10] cbus: retu: give it a context structure Felipe Balbi
@ 2011-01-04 1:40 ` Tony Lindgren
2011-01-04 6:51 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2011-01-04 1:40 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Linux OMAP Mailing List
* Felipe Balbi <balbi@ti.com> [110102 23:49]:
> This is pretty much a cleanup patch just
> adding a context structure for Retu, to avoid
> all the globals it had.
>
> Note that this breaks retu-user.c due to moving
> the lock around, but that retu-user.c has to
> go anyway as it's completely non-standard way
> of accessing Retu children.
FYI, this one alone fails to compile with:
drivers/cbus/retu-user.c: In function 'retu_user_write_with_mask':
drivers/cbus/retu-user.c:208: error: 'retu_lock' undeclared (first use in this function)
drivers/cbus/retu-user.c:208: error: (Each undeclared identifier is reported only once
drivers/cbus/retu-user.c:208: error: for each function it appears in.)
Regards,
Tony
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT/PATCH 01/10] cbus: retu: give it a context structure
2011-01-04 1:40 ` Tony Lindgren
@ 2011-01-04 6:51 ` Felipe Balbi
0 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-04 6:51 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Felipe Balbi, Linux OMAP Mailing List
On Mon, Jan 03, 2011 at 05:40:16PM -0800, Tony Lindgren wrote:
>* Felipe Balbi <balbi@ti.com> [110102 23:49]:
>> This is pretty much a cleanup patch just
>> adding a context structure for Retu, to avoid
>> all the globals it had.
>>
>> Note that this breaks retu-user.c due to moving
>> the lock around, but that retu-user.c has to
>> go anyway as it's completely non-standard way
>> of accessing Retu children.
>
>FYI, this one alone fails to compile with:
Yeah, there's a note on commit log about it. Anyway, I don't know what I
had in mind, I'll drop retu-user.c before this patch and there won't be
problems.
--
balbi
^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFT/PATCH 02/10] cbus: retu: get rid of retu-user.c
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 01/10] cbus: retu: give it a context structure Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 03/10] cbus: retu: move module_* close to the matching symbol Felipe Balbi
` (7 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Drop that non-standard of accessing Retu
as it's bypassing all the correct layers.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Kconfig | 7 -
drivers/cbus/Makefile | 1 -
drivers/cbus/retu-user.c | 424 ----------------------------------------------
drivers/cbus/retu.c | 22 ---
drivers/cbus/retu.h | 5 -
5 files changed, 0 insertions(+), 459 deletions(-)
delete mode 100644 drivers/cbus/retu-user.c
diff --git a/drivers/cbus/Kconfig b/drivers/cbus/Kconfig
index c6b39fb..9a827a2 100644
--- a/drivers/cbus/Kconfig
+++ b/drivers/cbus/Kconfig
@@ -49,13 +49,6 @@ config CBUS_RETU
If you want Retu support, you should say Y here.
-config CBUS_RETU_USER
- depends on CBUS_RETU
- bool "Support for Retu user space functions"
- ---help---
- If you want support for Retu's user space read/write etc. functions,
- you should say Y here.
-
config CBUS_RETU_POWERBUTTON
depends on CBUS_RETU
bool "Support for Retu power button"
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 347c2a4..0ad112f 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -10,5 +10,4 @@ obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
-obj-$(CONFIG_CBUS_RETU_USER) += retu-user.o
obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
diff --git a/drivers/cbus/retu-user.c b/drivers/cbus/retu-user.c
deleted file mode 100644
index c36f356..0000000
--- a/drivers/cbus/retu-user.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/**
- * drivers/cbus/retu-user.c
- *
- * Retu user space interface functions
- *
- * Copyright (C) 2004, 2005 Nokia Corporation
- *
- * Written by Mikko Ylinen <mikko.k.ylinen@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/poll.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-
-#include "retu.h"
-
-#include "user_retu_tahvo.h"
-
-/* Maximum size of IRQ node buffer/pool */
-#define RETU_MAX_IRQ_BUF_LEN 16
-
-#define PFX "retu-user: "
-
-/* Bitmap for marking the interrupt sources as having the handlers */
-static u32 retu_irq_bits;
-
-/* For allowing only one user process to subscribe to the retu interrupts */
-static struct file *retu_irq_subscr = NULL;
-
-/* For poll and IRQ passing */
-struct retu_irq {
- u32 id;
- struct list_head node;
-};
-
-static spinlock_t retu_irqs_lock;
-static struct retu_irq *retu_irq_block;
-static LIST_HEAD(retu_irqs);
-static LIST_HEAD(retu_irqs_reserve);
-
-/* Wait queue - used when user wants to read the device */
-DECLARE_WAIT_QUEUE_HEAD(retu_user_waitqueue);
-
-/* Semaphore to protect irq subscription sequence */
-static struct mutex retu_mutex;
-
-/* This array specifies RETU register types (read/write/toggle) */
-static const u8 retu_access_bits[] = {
- 1,
- 4,
- 3,
- 3,
- 1,
- 3,
- 3,
- 0,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 4,
- 4,
- 3,
- 0,
- 0,
- 0,
- 0,
- 1,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3
-};
-
-/*
- * The handler for all RETU interrupts.
- *
- * arg is the interrupt source in RETU.
- */
-static void retu_user_irq_handler(unsigned long arg)
-{
- struct retu_irq *irq;
-
- retu_ack_irq(arg);
-
- spin_lock(&retu_irqs_lock);
- if (list_empty(&retu_irqs_reserve)) {
- spin_unlock(&retu_irqs_lock);
- return;
- }
- irq = list_entry((&retu_irqs_reserve)->next, struct retu_irq, node);
- irq->id = arg;
- list_move_tail(&irq->node, &retu_irqs);
- spin_unlock(&retu_irqs_lock);
-
- /* wake up waiting thread */
- wake_up(&retu_user_waitqueue);
-}
-
-/*
- * This routine sets up the interrupt handler and marks an interrupt source
- * in RETU as a candidate for signal delivery to the user process.
- */
-static int retu_user_subscribe_to_irq(int id, struct file *filp)
-{
- int ret;
-
- mutex_lock(&retu_mutex);
- if ((retu_irq_subscr != NULL) && (retu_irq_subscr != filp)) {
- mutex_unlock(&retu_mutex);
- return -EBUSY;
- }
- /* Store the file pointer of the first user process registering IRQs */
- retu_irq_subscr = filp;
- mutex_unlock(&retu_mutex);
-
- if (retu_irq_bits & (1 << id))
- return 0;
-
- ret = retu_request_irq(id, retu_user_irq_handler, id, "");
- if (ret < 0)
- return ret;
-
- /* Mark that this interrupt has a handler */
- retu_irq_bits |= 1 << id;
-
- return 0;
-}
-
-/*
- * Unregisters all RETU interrupt handlers.
- */
-static void retu_unreg_irq_handlers(void)
-{
- int id;
-
- if (!retu_irq_bits)
- return;
-
- for (id = 0; id < MAX_RETU_IRQ_HANDLERS; id++)
- if (retu_irq_bits & (1 << id))
- retu_free_irq(id);
-
- retu_irq_bits = 0;
-}
-
-/*
- * Write to RETU register.
- * Returns 0 upon success, a negative error value otherwise.
- */
-static int retu_user_write_with_mask(u32 field, u16 value)
-{
- u32 mask;
- u32 reg;
- u_short tmp;
- unsigned long flags;
-
- mask = MASK(field);
- reg = REG(field);
-
- /* Detect bad mask and reg */
- if (mask == 0 || reg > RETU_REG_MAX ||
- retu_access_bits[reg] == READ_ONLY) {
- printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
- reg, mask);
- return -EINVAL;
- }
-
- /* Justify value according to mask */
- while (!(mask & 1)) {
- value = value << 1;
- mask = mask >> 1;
- }
-
- spin_lock_irqsave(&retu_lock, flags);
- if (retu_access_bits[reg] == TOGGLE) {
- /* No need to detect previous content of register */
- tmp = 0;
- } else {
- /* Read current value of register */
- tmp = retu_read_reg(reg);
- }
-
- /* Generate new value */
- tmp = (tmp & ~MASK(field)) | (value & MASK(field));
- /* Write data to RETU */
- retu_write_reg(reg, tmp);
- spin_unlock_irqrestore(&retu_lock, flags);
-
- return 0;
-}
-
-/*
- * Read RETU register.
- */
-static u32 retu_user_read_with_mask(u32 field)
-{
- u_short value;
- u32 mask, reg;
-
- mask = MASK(field);
- reg = REG(field);
-
- /* Detect bad mask and reg */
- if (mask == 0 || reg > RETU_REG_MAX) {
- printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
- reg, mask);
- return -EINVAL;
- }
-
- /* Read the register */
- value = retu_read_reg(reg) & mask;
-
- /* Right justify value */
- while (!(mask & 1)) {
- value = value >> 1;
- mask = mask >> 1;
- }
-
- return value;
-}
-
-/*
- * Close device
- */
-static int retu_close(struct inode *inode, struct file *filp)
-{
- /* Unregister all interrupts that have been registered */
- if (retu_irq_subscr == filp) {
- retu_unreg_irq_handlers();
- retu_irq_subscr = NULL;
- }
-
- return 0;
-}
-
-/*
- * Device control (ioctl)
- */
-static long retu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct retu_tahvo_write_parms par;
- int ret;
-
- switch (cmd) {
- case URT_IOCT_IRQ_SUBSCR:
- return retu_user_subscribe_to_irq(arg, filp);
- case RETU_IOCH_READ:
- return retu_user_read_with_mask(arg);
- case RETU_IOCX_WRITE:
- ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
- if (ret)
- printk(KERN_ERR "copy_from_user failed: %d\n", ret);
- par.result = retu_user_write_with_mask(par.field, par.value);
- ret = copy_to_user((void __user *) arg, &par, sizeof(par));
- if (ret)
- printk(KERN_ERR "copy_to_user failed: %d\n", ret);
- break;
- case RETU_IOCH_ADC_READ:
- return retu_read_adc(arg);
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-/*
- * Read from device
- */
-static ssize_t retu_read(struct file *filp, char *buf, size_t count,
- loff_t * offp)
-{
- struct retu_irq *irq;
-
- u32 nr, i;
-
- /* read not permitted if neither filp nor anyone has registered IRQs */
- if (retu_irq_subscr != filp)
- return -EPERM;
-
- if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
- return -EINVAL;
-
- nr = count / sizeof(u32);
-
- for (i = 0; i < nr; i++) {
- unsigned long flags;
- u32 irq_id;
- int ret;
-
- ret = wait_event_interruptible(retu_user_waitqueue,
- !list_empty(&retu_irqs));
- if (ret < 0)
- return ret;
-
- spin_lock_irqsave(&retu_irqs_lock, flags);
- irq = list_entry((&retu_irqs)->next, struct retu_irq, node);
- irq_id = irq->id;
- list_move(&irq->node, &retu_irqs_reserve);
- spin_unlock_irqrestore(&retu_irqs_lock, flags);
-
- ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
- sizeof(irq_id));
- if (ret)
- printk(KERN_ERR "copy_to_user failed: %d\n", ret);
- }
-
- return count;
-}
-
-/*
- * Poll method
- */
-static unsigned retu_poll(struct file *filp, struct poll_table_struct *pt)
-{
- if (!list_empty(&retu_irqs))
- return POLLIN;
-
- poll_wait(filp, &retu_user_waitqueue, pt);
-
- if (!list_empty(&retu_irqs))
- return POLLIN;
- else
- return 0;
-}
-
-static struct file_operations retu_user_fileops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = retu_ioctl,
- .read = retu_read,
- .release = retu_close,
- .poll = retu_poll
-};
-
-static struct miscdevice retu_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "retu",
- .fops = &retu_user_fileops
-};
-
-/*
- * Initialization
- *
- * @return 0 if successful, error value otherwise.
- */
-int retu_user_init(void)
-{
- struct retu_irq *irq;
- int res, i;
-
- irq = kzalloc(sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN, GFP_KERNEL);
- if (irq == NULL) {
- printk(KERN_ERR PFX "kzalloc failed\n");
- return -ENOMEM;
- }
-
- for (i = 0; i < RETU_MAX_IRQ_BUF_LEN; i++)
- list_add(&irq[i].node, &retu_irqs_reserve);
-
- retu_irq_block = irq;
-
- spin_lock_init(&retu_irqs_lock);
- mutex_init(&retu_mutex);
-
- /* Request a misc device */
- res = misc_register(&retu_device);
- if (res < 0) {
- printk(KERN_ERR PFX "unable to register misc device for %s\n",
- retu_device.name);
- kfree(irq);
- return res;
- }
-
- return 0;
-}
-
-/*
- * Cleanup.
- */
-void retu_user_cleanup(void)
-{
- /* Unregister our misc device */
- misc_deregister(&retu_device);
- /* Unregister and disable all RETU interrupts used by this module */
- retu_unreg_irq_handlers();
- kfree(retu_irq_block);
-}
-
-MODULE_DESCRIPTION("Retu ASIC user space functions");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mikko Ylinen");
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
index 6e130bf..39d4fa4 100644
--- a/drivers/cbus/retu.c
+++ b/drivers/cbus/retu.c
@@ -396,10 +396,6 @@ static int retu_allocate_children(struct device *parent)
if (!child)
return -ENOMEM;
- child = retu_allocate_child("retu-user", parent);
- if (!child)
- return -ENOMEM;
-
child = retu_allocate_child("retu-wdt", parent);
if (!child)
return -ENOMEM;
@@ -464,24 +460,9 @@ static int __init retu_probe(struct platform_device *pdev)
/* Register power off function */
pm_power_off = retu_power_off;
-#ifdef CONFIG_CBUS_RETU_USER
- /* Initialize user-space interface */
- if (retu_user_init() < 0) {
- dev_err(&pdev->dev, "Unable to initialize driver\n");
- tasklet_kill(&retu->tasklet);
- free_irq(irq, 0);
- kfree(retu);
- the_retu = NULL;
- return ret;
- }
-#endif
-
ret = retu_allocate_children(&pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to allocate Retu children\n");
-#ifdef CONFIG_CBUS_RETU_USER
- retu_user_cleanup();
-#endif
retu_write_reg(RETU_REG_IMR, 0xffff);
free_irq(irq, 0);
tasklet_kill(&retu->tasklet);
@@ -500,9 +481,6 @@ static int __exit retu_remove(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
-#ifdef CONFIG_CBUS_RETU_USER
- retu_user_cleanup();
-#endif
/* Mask all RETU interrupts */
retu_write_reg(RETU_REG_IMR, 0xffff);
free_irq(irq, retu);
diff --git a/drivers/cbus/retu.h b/drivers/cbus/retu.h
index 1cc486e..ada7f2e 100644
--- a/drivers/cbus/retu.h
+++ b/drivers/cbus/retu.h
@@ -68,9 +68,4 @@ void retu_enable_irq(int id);
void retu_disable_irq(int id);
void retu_ack_irq(int id);
-#ifdef CONFIG_CBUS_RETU_USER
-int retu_user_init(void);
-void retu_user_cleanup(void);
-#endif
-
#endif /* __DRIVERS_CBUS_RETU_H */
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 03/10] cbus: retu: move module_* close to the matching symbol
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 01/10] cbus: retu: give it a context structure Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 02/10] cbus: retu: get rid of retu-user.c Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 04/10] cbus: retu: cleanup error path Felipe Balbi
` (6 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Just to make checkpatch.pl a bit happier, move
subsys_initcall() and module_exit() closer to
the init and exit functions of the driver.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/retu.c | 11 +----------
1 files changed, 1 insertions(+), 10 deletions(-)
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
index 39d4fa4..0053d43 100644
--- a/drivers/cbus/retu.c
+++ b/drivers/cbus/retu.c
@@ -498,25 +498,16 @@ static struct platform_driver retu_driver = {
},
};
-/**
- * retu_init - initialise Retu driver
- *
- * Initialise the Retu driver and return 0 if everything worked ok
- */
static int __init retu_init(void)
{
return platform_driver_probe(&retu_driver, retu_probe);
}
+subsys_initcall(retu_init);
-/*
- * Cleanup
- */
static void __exit retu_exit(void)
{
platform_driver_unregister(&retu_driver);
}
-
-subsys_initcall(retu_init);
module_exit(retu_exit);
MODULE_DESCRIPTION("Retu ASIC control");
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 04/10] cbus: retu: cleanup error path
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (2 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 03/10] cbus: retu: move module_* close to the matching symbol Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ Felipe Balbi
` (5 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Trivial cleanup patch shuffling error path
around.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/retu.c | 29 +++++++++++++++++------------
1 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
index 0053d43..7e67e1a 100644
--- a/drivers/cbus/retu.c
+++ b/drivers/cbus/retu.c
@@ -413,14 +413,15 @@ static int retu_allocate_children(struct device *parent)
static int __init retu_probe(struct platform_device *pdev)
{
struct retu *retu;
+
+ int ret = -ENOMEM;
int rev;
- int ret;
int irq;
retu = kzalloc(sizeof(*retu), GFP_KERNEL);
if (!retu) {
dev_err(&pdev->dev, "not enough memory\n");
- return -ENOMEM;
+ goto err0;
}
platform_set_drvdata(pdev, retu);
@@ -449,10 +450,7 @@ static int __init retu_probe(struct platform_device *pdev)
"retu", retu);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register IRQ handler\n");
- tasklet_kill(&retu->tasklet);
- kfree(retu);
- the_retu = NULL;
- return ret;
+ goto err1;
}
set_irq_wake(irq, 1);
@@ -463,15 +461,22 @@ static int __init retu_probe(struct platform_device *pdev)
ret = retu_allocate_children(&pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to allocate Retu children\n");
- retu_write_reg(RETU_REG_IMR, 0xffff);
- free_irq(irq, 0);
- tasklet_kill(&retu->tasklet);
- kfree(retu);
- the_retu = NULL;
- return ret;
+ goto err2;
}
return 0;
+
+err2:
+ retu_write_reg(RETU_REG_IMR, 0xffff);
+ free_irq(irq, retu);
+
+err1:
+ tasklet_kill(&retu->tasklet);
+ kfree(retu);
+ the_retu = NULL;
+
+err0:
+ return ret;
}
static int __exit retu_remove(struct platform_device *pdev)
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (3 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 04/10] cbus: retu: cleanup error path Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-04 1:40 ` Tony Lindgren
2011-01-03 7:49 ` [RFT/PATCH 06/10] cbus: retu: headset: convert to threaded_irq Felipe Balbi
` (4 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Start moving retu to threaded IRQ and while
at that also give retu an irq_chip so children
can use generic request_threaded_irq() calls.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Makefile | 10 +-
drivers/cbus/retu.c | 264 +++++++++++++++++++++----------------------------
drivers/cbus/retu.h | 5 -
3 files changed, 117 insertions(+), 162 deletions(-)
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 0ad112f..3375b82 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_CBUS) += cbus.o
obj-$(CONFIG_CBUS_TAHVO) += tahvo.o
obj-$(CONFIG_CBUS_RETU) += retu.o
obj-$(CONFIG_CBUS_TAHVO_USB) += tahvo-usb.o
-obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
-obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
-obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
-obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
+
+## Disable Retu children until converted to threaded IRQ
+#obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
+#obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
+#obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
+#obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
index 7e67e1a..b67e918 100644
--- a/drivers/cbus/retu.c
+++ b/drivers/cbus/retu.c
@@ -33,6 +33,7 @@
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/fs.h>
+#include <linux/mutex.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@@ -53,23 +54,23 @@
struct retu {
/* Device lock */
spinlock_t lock;
- struct tasklet_struct tasklet;
+ struct mutex irq_lock;
struct device *dev;
+ int irq_base;
+ int nirqs;
int irq;
- bool is_vilma;
-};
+ int ack;
+ bool ack_pending;
-static struct retu *the_retu;
+ int mask;
+ bool mask_pending;
-struct retu_irq_handler_desc {
- int (*func)(unsigned long);
- unsigned long arg;
- char name[8];
+ bool is_vilma;
};
-static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
+static struct retu *the_retu;
int retu_get_status(void)
{
@@ -156,180 +157,135 @@ int retu_read_adc(int channel)
}
EXPORT_SYMBOL(retu_read_adc);
-static u16 retu_disable_bogus_irqs(u16 mask)
+static irqreturn_t retu_irq_handler(int irq, void *_retu)
{
- int i;
-
- for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
- if (mask & (1 << i))
- continue;
- if (retu_irq_handlers[i].func != NULL)
- continue;
- /* an IRQ was enabled but we don't have a handler for it */
- printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
- mask |= (1 << i);
- }
- return mask;
-}
+ struct retu *retu = _retu;
-/*
- * Disable given RETU interrupt
- */
-void retu_disable_irq(int id)
-{
- struct retu *retu = the_retu;
- unsigned long flags;
- u16 mask;
+ int i;
- spin_lock_irqsave(&retu->lock, flags);
- mask = retu_read_reg(RETU_REG_IMR);
- mask |= 1 << id;
- mask = retu_disable_bogus_irqs(mask);
- retu_write_reg(RETU_REG_IMR, mask);
- spin_unlock_irqrestore(&retu->lock, flags);
-}
-EXPORT_SYMBOL(retu_disable_irq);
+ u16 idr;
+ u16 imr;
-/*
- * Enable given RETU interrupt
- */
-void retu_enable_irq(int id)
-{
- struct retu *retu = the_retu;
- unsigned long flags;
- u16 mask;
+ idr = retu_read_reg(RETU_REG_IDR);
+ imr = retu_read_reg(RETU_REG_IMR);
+ idr &= ~imr;
- if (id == 3) {
- printk("Enabling Retu IRQ %d\n", id);
- dump_stack();
+ if (!idr) {
+ dev_vdbg(retu->dev, "No IRQ, spurious?\n");
+ return IRQ_NONE;
}
- spin_lock_irqsave(&retu->lock, flags);
- mask = retu_read_reg(RETU_REG_IMR);
- mask &= ~(1 << id);
- mask = retu_disable_bogus_irqs(mask);
- retu_write_reg(RETU_REG_IMR, mask);
- spin_unlock_irqrestore(&retu->lock, flags);
+ for (i = 0; idr != 0; i++, idr >>= 1) {
+ if (!(idr & 1))
+ continue;
+
+ handle_nested_irq(i);
+ }
+
+ return IRQ_HANDLED;
}
-EXPORT_SYMBOL(retu_enable_irq);
-/*
- * Acknowledge given RETU interrupt
- */
-void retu_ack_irq(int id)
+/* -------------------------------------------------------------------------- */
+
+static void retu_irq_mask(struct irq_data *data)
{
- retu_write_reg(RETU_REG_IDR, 1 << id);
+ struct retu *retu = irq_data_get_irq_chip_data(data);
+ int irq = data->irq;
+
+ retu->mask |= (1 << (irq - retu->irq_base));
+ retu->mask_pending = true;
}
-EXPORT_SYMBOL(retu_ack_irq);
-/*
- * RETU interrupt handler. Only schedules the tasklet.
- */
-static irqreturn_t retu_irq_handler(int irq, void *_retu)
+static void retu_irq_unmask(struct irq_data *data)
{
- struct retu *retu = _retu;
+ struct retu *retu = irq_data_get_irq_chip_data(data);
+ int irq = data->irq;
- tasklet_schedule(&retu->tasklet);
+ retu->mask &= ~(1 << (irq - retu->irq_base));
+ retu->mask_pending = true;
- return IRQ_HANDLED;
}
-/*
- * Tasklet handler
- */
-static void retu_tasklet_handler(unsigned long data)
+static void retu_irq_ack(struct irq_data *data)
{
- struct retu_irq_handler_desc *hnd;
- u16 id;
- u16 im;
- int i;
-
- for (;;) {
- id = retu_read_reg(RETU_REG_IDR);
- im = ~retu_read_reg(RETU_REG_IMR);
- id &= im;
-
- if (!id)
- break;
-
- for (i = 0; id != 0; i++, id >>= 1) {
- if (!(id & 1))
- continue;
- hnd = &retu_irq_handlers[i];
- if (hnd->func == NULL) {
- /* Spurious retu interrupt - disable and ack it */
- printk(KERN_INFO "Spurious Retu interrupt "
- "(id %d)\n", i);
- retu_disable_irq(i);
- retu_ack_irq(i);
- continue;
- }
- hnd->func(hnd->arg);
- /*
- * Don't acknowledge the interrupt here
- * It must be done explicitly
- */
- }
- }
+ struct retu *retu = irq_data_get_irq_chip_data(data);
+ int irq = data->irq;
+
+ retu->ack |= (1 << (irq - retu->irq_base));
+ retu->ack_pending = true;
}
-/*
- * Register the handler for a given RETU interrupt source.
- */
-int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+static void retu_bus_lock(struct irq_data *data)
{
- struct retu *retu = the_retu;
- struct retu_irq_handler_desc *hnd;
+ struct retu *retu = irq_data_get_irq_chip_data(data);
- if (!retu)
- return -ENODEV;
+ mutex_lock(&retu->irq_lock);
+}
- if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
- name == NULL) {
- printk(KERN_ERR PFX "Invalid arguments to %s\n",
- __FUNCTION__);
- return -EINVAL;
+static void retu_bus_sync_unlock(struct irq_data *data)
+{
+ struct retu *retu = irq_data_get_irq_chip_data(data);
+
+ if (retu->mask_pending) {
+ retu_write_reg(RETU_REG_IMR, retu->mask);
+ retu->mask_pending = false;
}
- hnd = &retu_irq_handlers[id];
- if (hnd->func != NULL) {
- printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
- return -EBUSY;
+
+ if (retu->ack_pending) {
+ retu_write_reg(RETU_REG_IDR, retu->ack);
+ retu->ack_pending = false;
}
- printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
- id, name);
- hnd->func = irq_handler;
- hnd->arg = arg;
- strlcpy(hnd->name, name, sizeof(hnd->name));
- retu_ack_irq(id);
- retu_enable_irq(id);
+ mutex_unlock(&retu->irq_lock);
+}
- return 0;
+static struct irq_chip retu_irq_chip = {
+ .name = "retu",
+ .irq_bus_lock = retu_bus_lock,
+ .irq_bus_sync_unlock = retu_bus_sync_unlock,
+ .irq_mask = retu_irq_mask,
+ .irq_unmask = retu_irq_unmask,
+ .irq_ack = retu_irq_ack,
+};
+
+static inline void retu_irq_setup(int irq)
+{
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
}
-EXPORT_SYMBOL(retu_request_irq);
-/*
- * Unregister the handler for a given RETU interrupt source.
- */
-void retu_free_irq(int id)
+static void retu_irq_init(struct retu *retu)
{
- struct retu_irq_handler_desc *hnd;
+ int base = retu->irq_base;
+ int irq;
- if (id >= MAX_RETU_IRQ_HANDLERS) {
- printk(KERN_ERR PFX "Invalid argument to %s\n",
- __FUNCTION__);
- return;
- }
- hnd = &retu_irq_handlers[id];
- if (hnd->func == NULL) {
- printk(KERN_ERR PFX "IRQ %d already freed\n", id);
- return;
+ for (irq = base; irq < base + retu->nirqs; irq++) {
+ set_irq_chip_data(irq, retu);
+ set_irq_chip_and_handler(irq, &retu_irq_chip,
+ handle_simple_irq);
+ set_irq_nested_thread(irq, 1);
+ retu_irq_setup(irq);
}
+}
+
+static void retu_irq_exit(struct retu *retu)
+{
+ int base = retu->irq_base;
+ int irq;
- retu_disable_irq(id);
- hnd->func = NULL;
+ for (irq = base; irq < base + retu->nirqs; irq++) {
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ set_irq_chip_and_handler(irq, NULL, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
}
-EXPORT_SYMBOL(retu_free_irq);
+
+/* -------------------------------------------------------------------------- */
/**
* retu_power_off - Shut down power to system
@@ -428,12 +384,15 @@ static int __init retu_probe(struct platform_device *pdev)
the_retu = retu;
/* Prepare tasklet */
- tasklet_init(&retu->tasklet, retu_tasklet_handler, 0);
spin_lock_init(&retu->lock);
+ mutex_init(&retu->irq_lock);
irq = platform_get_irq(pdev, 0);
retu->irq = irq;
+ retu->nirqs = MAX_RETU_IRQ_HANDLERS;
+
+ retu_irq_init(retu);
rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
if (rev & (1 << 7))
@@ -446,7 +405,7 @@ static int __init retu_probe(struct platform_device *pdev)
/* Mask all RETU interrupts */
retu_write_reg(RETU_REG_IMR, 0xffff);
- ret = request_irq(irq, retu_irq_handler, 0,
+ ret = request_threaded_irq(irq, NULL, retu_irq_handler, 0,
"retu", retu);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register IRQ handler\n");
@@ -471,7 +430,6 @@ err2:
free_irq(irq, retu);
err1:
- tasklet_kill(&retu->tasklet);
kfree(retu);
the_retu = NULL;
@@ -489,7 +447,7 @@ static int __exit retu_remove(struct platform_device *pdev)
/* Mask all RETU interrupts */
retu_write_reg(RETU_REG_IMR, 0xffff);
free_irq(irq, retu);
- tasklet_kill(&retu->tasklet);
+ retu_irq_exit(retu);
kfree(retu);
the_retu = NULL;
diff --git a/drivers/cbus/retu.h b/drivers/cbus/retu.h
index ada7f2e..1b05f3e 100644
--- a/drivers/cbus/retu.h
+++ b/drivers/cbus/retu.h
@@ -62,10 +62,5 @@ int retu_read_reg(unsigned reg);
void retu_write_reg(unsigned reg, u16 val);
void retu_set_clear_reg_bits(unsigned reg, u16 set, u16 clear);
int retu_read_adc(int channel);
-int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
-void retu_free_irq(int id);
-void retu_enable_irq(int id);
-void retu_disable_irq(int id);
-void retu_ack_irq(int id);
#endif /* __DRIVERS_CBUS_RETU_H */
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-03 7:49 ` [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ Felipe Balbi
@ 2011-01-04 1:40 ` Tony Lindgren
2011-01-04 6:52 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2011-01-04 1:40 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Linux OMAP Mailing List
* Felipe Balbi <balbi@ti.com> [110102 23:49]:
> @@ -53,23 +54,23 @@
> struct retu {
> /* Device lock */
> spinlock_t lock;
> - struct tasklet_struct tasklet;
> + struct mutex irq_lock;
> struct device *dev;
>
> + int irq_base;
> + int nirqs;
> int irq;
This one oopses, looks like irq_base is not initialized?
Regards,
Tony
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-04 1:40 ` Tony Lindgren
@ 2011-01-04 6:52 ` Felipe Balbi
2011-01-04 7:46 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-04 6:52 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Felipe Balbi, Linux OMAP Mailing List
On Mon, Jan 03, 2011 at 05:40:02PM -0800, Tony Lindgren wrote:
>* Felipe Balbi <balbi@ti.com> [110102 23:49]:
>> @@ -53,23 +54,23 @@
>> struct retu {
>> /* Device lock */
>> spinlock_t lock;
>> - struct tasklet_struct tasklet;
>> + struct mutex irq_lock;
>> struct device *dev;
>>
>> + int irq_base;
>> + int nirqs;
>> int irq;
>
>This one oopses, looks like irq_base is not initialized?
Aaa, good catch. Sorry for that. Gotta add a platform_data for passing
that around. Will do it on V2.
--
balbi
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-04 6:52 ` Felipe Balbi
@ 2011-01-04 7:46 ` Felipe Balbi
2011-01-04 7:47 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-04 7:46 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Tony Lindgren, Linux OMAP Mailing List
Hi,
On Tue, Jan 04, 2011 at 08:52:29AM +0200, Felipe Balbi wrote:
>On Mon, Jan 03, 2011 at 05:40:02PM -0800, Tony Lindgren wrote:
>>* Felipe Balbi <balbi@ti.com> [110102 23:49]:
>>>@@ -53,23 +54,23 @@
>>> struct retu {
>>> /* Device lock */
>>> spinlock_t lock;
>>>- struct tasklet_struct tasklet;
>>>+ struct mutex irq_lock;
>>> struct device *dev;
>>>
>>>+ int irq_base;
>>>+ int nirqs;
>>> int irq;
>>
>>This one oopses, looks like irq_base is not initialized?
>
>Aaa, good catch. Sorry for that. Gotta add a platform_data for passing
>that around. Will do it on V2.
Looking into <plat/irqs.h> it seems like there will be quite some
ifdeffery added to have support for Retu irq_base (and later Tahvo,
menelaus, ISP, etc etc); so, would you be willing to accept an atomic
counter to keep track of that ?
Something like the following:
static atomic_t omap_irq_base;
int omap_irq_get_base(void)
{
return atomic_read(&omap_irq_base);
}
void omap_irq_set_base(int base)
{
atomic_set(&omap_irq_base, base);
}
void omap_irq_add(int nirqs)
{
atomic_add(nirqs, &omap_irq_base);
}
void omap_irq_sub(int nirqs)
{
atomic_sub(nirqs, &omap_irq_base);
}
static int __init omap_irq_init(void)
{
atomic_set(&omap_irq_base, 0);
return 0;
}
postcore_initcall(omap_irq_init);
Then, INTC will always be the first one to call omap_irq_add():
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 85bf8ca..3d91a11 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <plat/irqs.h>
#include <mach/hardware.h>
#include <asm/mach/irq.h>
@@ -224,6 +225,8 @@ void __init omap_init_irq(void)
set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID);
}
+
+ omap_irq_add(nr_of_irqs);
}
#ifdef CONFIG_ARCH_OMAP3
and when adding e.g. twl4030, we could:
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 3b39ef1..3ae342b 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -31,6 +31,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <plat/irqs.h>
#include <plat/mcspi.h>
#include <plat/board.h>
#include <plat/usb.h>
@@ -571,8 +572,8 @@ static struct twl4030_codec_data sdp3430_codec = {
};
static struct twl4030_platform_data sdp3430_twldata = {
- .irq_base = TWL4030_IRQ_BASE,
- .irq_end = TWL4030_IRQ_END,
+ .irq_base = -EINVAL, /* fixed up later */
+ .irq_end = -EINVAL, /* fixed up later */
/* platform_data for children goes here */
.bci = &sdp3430_bci_data,
@@ -593,6 +594,14 @@ static struct twl4030_platform_data sdp3430_twldata = {
.vpll2 = &sdp3430_vpll2,
};
+static void __init sdp3430_twl_init(void)
+{
+ int irq_base = omap_irq_get_base();
+
+ sdp3430_twldata.irq_base = irq_base;
+ sdp3430_twldata.irq_end = irq_base + TWL4030_BASE_NR_IRQS;
+}
+
static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
@@ -794,6 +803,7 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap_3430sdp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ sdp3430_twl_init();
omap3430_i2c_init();
platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices));
if (omap_rev() > OMAP3430_REV_ES1_0)
either that, or we add several ifdefs to <plat/irqs.h> and maintain that
over time. What do you think ?
--
balbi
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-04 7:46 ` Felipe Balbi
@ 2011-01-04 7:47 ` Felipe Balbi
2011-01-04 19:14 ` Tony Lindgren
0 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-04 7:47 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Tony Lindgren, Linux OMAP Mailing List
On Tue, Jan 04, 2011 at 09:46:15AM +0200, Felipe Balbi wrote:
>@@ -593,6 +594,14 @@ static struct twl4030_platform_data sdp3430_twldata = {
> .vpll2 = &sdp3430_vpll2,
> };
>+static void __init sdp3430_twl_init(void)
>+{
>+ int irq_base = omap_irq_get_base();
>+
>+ sdp3430_twldata.irq_base = irq_base;
>+ sdp3430_twldata.irq_end = irq_base + TWL4030_BASE_NR_IRQS;
>+}
>+
> static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
> {
> I2C_BOARD_INFO("twl4030", 0x48),
this hunk should be:
@@ -593,6 +594,16 @@ static struct twl4030_platform_data sdp3430_twldata = {
.vpll2 = &sdp3430_vpll2,
};
+static void __init sdp3430_twl_init(void)
+{
+ int irq_base = omap_irq_get_base();
+
+ sdp3430_twldata.irq_base = irq_base;
+ sdp3430_twldata.irq_end = irq_base + TWL4030_BASE_NR_IRQS;
+
+ omap_irq_add(TWL4030_BASE_NR_IRQS);
+}
+
static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
otherwise it won't work for other irq_chips
--
balbi
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-04 7:47 ` Felipe Balbi
@ 2011-01-04 19:14 ` Tony Lindgren
2011-01-05 6:37 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2011-01-04 19:14 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Linux OMAP Mailing List
* Felipe Balbi <balbi@ti.com> [110103 23:47]:
> On Tue, Jan 04, 2011 at 09:46:15AM +0200, Felipe Balbi wrote:
> >@@ -593,6 +594,14 @@ static struct twl4030_platform_data sdp3430_twldata = {
> > .vpll2 = &sdp3430_vpll2,
> >};
> >+static void __init sdp3430_twl_init(void)
> >+{
> >+ int irq_base = omap_irq_get_base();
> >+
> >+ sdp3430_twldata.irq_base = irq_base;
> >+ sdp3430_twldata.irq_end = irq_base + TWL4030_BASE_NR_IRQS;
> >+}
> >+
> >static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
> > {
> > I2C_BOARD_INFO("twl4030", 0x48),
>
> this hunk should be:
>
> @@ -593,6 +594,16 @@ static struct twl4030_platform_data sdp3430_twldata = {
> .vpll2 = &sdp3430_vpll2,
> };
> +static void __init sdp3430_twl_init(void)
> +{
> + int irq_base = omap_irq_get_base();
> +
> + sdp3430_twldata.irq_base = irq_base;
> + sdp3430_twldata.irq_end = irq_base + TWL4030_BASE_NR_IRQS;
> +
> + omap_irq_add(TWL4030_BASE_NR_IRQS);
> +}
> +
> static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
> {
> I2C_BOARD_INFO("twl4030", 0x48),
>
> otherwise it won't work for other irq_chips
I think there's been some patches related to this to get rid
of NR_IRQS? Might be worth taking a look at those first as it's
a generic solution.
Regards,
Tony
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-04 19:14 ` Tony Lindgren
@ 2011-01-05 6:37 ` Felipe Balbi
2011-01-07 3:04 ` Tony Lindgren
0 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-05 6:37 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Felipe Balbi, Linux OMAP Mailing List
Hi,
On Tue, Jan 04, 2011 at 11:14:00AM -0800, Tony Lindgren wrote:
> I think there's been some patches related to this to get rid
> of NR_IRQS? Might be worth taking a look at those first as it's
> a generic solution.
Yeah, one way would be to use Sparse IRQ numbering scheme and define
different bases for different IRQ chips. We could use for example,
something like:
IRQ | Chip
=====================
0-299 | INTC
300-499 | TWL4030
500-599 | MENELAUS
600-799 | RETU
800-999 | TAHVO
and so on. But I'm not sure that's good enough (numbers are just from
the top of my head, didn't really check how many IRQs each one have).
The only problem I see is with INTC, what happens if we give it an
interval which ends up not being big enough for next OMAP versions ?
--
balbi
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-05 6:37 ` Felipe Balbi
@ 2011-01-07 3:04 ` Tony Lindgren
2011-01-07 7:48 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2011-01-07 3:04 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Linux OMAP Mailing List
* Felipe Balbi <balbi@ti.com> [110104 22:37]:
> Hi,
>
> On Tue, Jan 04, 2011 at 11:14:00AM -0800, Tony Lindgren wrote:
> > I think there's been some patches related to this to get rid
> > of NR_IRQS? Might be worth taking a look at those first as it's
> > a generic solution.
>
> Yeah, one way would be to use Sparse IRQ numbering scheme and define
> different bases for different IRQ chips. We could use for example,
> something like:
>
> IRQ | Chip
> =====================
> 0-299 | INTC
> 300-499 | TWL4030
> 500-599 | MENELAUS
> 600-799 | RETU
> 800-999 | TAHVO
>
> and so on. But I'm not sure that's good enough (numbers are just from
> the top of my head, didn't really check how many IRQs each one have).
>
> The only problem I see is with INTC, what happens if we give it an
> interval which ends up not being big enough for next OMAP versions ?
I think that's the way to go, but we should not allocate that
many irqs.. We can define the ranges like we already do in irqs.h
based on what gets compiled in. There are few more blocks though:
INTC
GPIO
MPUIO
GIC
FPGA
RETU
TAHVO
MENELAUS
TWL4030
The numbers for INTC we know assuming new omaps will use GIC. The
external chips rarely have more than few interrupts.
Regards,
Tony
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-07 3:04 ` Tony Lindgren
@ 2011-01-07 7:48 ` Felipe Balbi
2011-01-07 17:04 ` Tony Lindgren
0 siblings, 1 reply; 23+ messages in thread
From: Felipe Balbi @ 2011-01-07 7:48 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Felipe Balbi, Linux OMAP Mailing List
On Thu, Jan 06, 2011 at 07:04:50PM -0800, Tony Lindgren wrote:
> * Felipe Balbi <balbi@ti.com> [110104 22:37]:
> > Hi,
> >
> > On Tue, Jan 04, 2011 at 11:14:00AM -0800, Tony Lindgren wrote:
> > > I think there's been some patches related to this to get rid
> > > of NR_IRQS? Might be worth taking a look at those first as it's
> > > a generic solution.
> >
> > Yeah, one way would be to use Sparse IRQ numbering scheme and define
> > different bases for different IRQ chips. We could use for example,
> > something like:
> >
> > IRQ | Chip
> > =====================
> > 0-299 | INTC
> > 300-499 | TWL4030
> > 500-599 | MENELAUS
> > 600-799 | RETU
> > 800-999 | TAHVO
> >
> > and so on. But I'm not sure that's good enough (numbers are just from
> > the top of my head, didn't really check how many IRQs each one have).
> >
> > The only problem I see is with INTC, what happens if we give it an
> > interval which ends up not being big enough for next OMAP versions ?
>
> I think that's the way to go, but we should not allocate that
> many irqs.. We can define the ranges like we already do in irqs.h
> based on what gets compiled in. There are few more blocks though:
The main point of using Sparse IRQ numbering is exactly avoiding
pre-processor branches. Instead of defining ranges only when a device is
compile, we can always keep the range allocated no matter if the device
probes or not. So, I suggest dropping the ifdeffery on <plat/irqs.h> and
move that to something like below:
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 65e20a6..c4fcd9d 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -367,49 +367,28 @@
/* External FPGA handles interrupts on Innovator boards */
#define OMAP_FPGA_IRQ_BASE (OMAP_IRQ_END)
-#ifdef CONFIG_MACH_OMAP_INNOVATOR
#define OMAP_FPGA_NR_IRQS 24
-#else
-#define OMAP_FPGA_NR_IRQS 0
-#endif
#define OMAP_FPGA_IRQ_END (OMAP_FPGA_IRQ_BASE + OMAP_FPGA_NR_IRQS)
/* External TWL4030 can handle interrupts on 2430 and 34xx boards */
#define TWL4030_IRQ_BASE (OMAP_FPGA_IRQ_END)
-#ifdef CONFIG_TWL4030_CORE
#define TWL4030_BASE_NR_IRQS 8
#define TWL4030_PWR_NR_IRQS 8
-#else
-#define TWL4030_BASE_NR_IRQS 0
-#define TWL4030_PWR_NR_IRQS 0
-#endif
#define TWL4030_IRQ_END (TWL4030_IRQ_BASE + TWL4030_BASE_NR_IRQS)
#define TWL4030_PWR_IRQ_BASE TWL4030_IRQ_END
#define TWL4030_PWR_IRQ_END (TWL4030_PWR_IRQ_BASE + TWL4030_PWR_NR_IRQS)
/* External TWL4030 gpio interrupts are optional */
#define TWL4030_GPIO_IRQ_BASE TWL4030_PWR_IRQ_END
-#ifdef CONFIG_GPIO_TWL4030
#define TWL4030_GPIO_NR_IRQS 18
-#else
-#define TWL4030_GPIO_NR_IRQS 0
-#endif
#define TWL4030_GPIO_IRQ_END (TWL4030_GPIO_IRQ_BASE + TWL4030_GPIO_NR_IRQS)
#define TWL6030_IRQ_BASE (OMAP_FPGA_IRQ_END)
-#ifdef CONFIG_TWL4030_CORE
#define TWL6030_BASE_NR_IRQS 20
-#else
-#define TWL6030_BASE_NR_IRQS 0
-#endif
#define TWL6030_IRQ_END (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS)
/* Total number of interrupts depends on the enabled blocks above */
-#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END)
-#define TWL_IRQ_END TWL4030_GPIO_IRQ_END
-#else
-#define TWL_IRQ_END TWL6030_IRQ_END
-#endif
+#define TWL_IRQ_END TWL4030_GPIO_IRQ_END
#define NR_IRQS TWL_IRQ_END
--
balbi
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-07 7:48 ` Felipe Balbi
@ 2011-01-07 17:04 ` Tony Lindgren
2011-01-07 19:15 ` Felipe Balbi
0 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2011-01-07 17:04 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Linux OMAP Mailing List
* Felipe Balbi <balbi@ti.com> [110106 23:47]:
>
> The main point of using Sparse IRQ numbering is exactly avoiding
> pre-processor branches. Instead of defining ranges only when a device is
> compile, we can always keep the range allocated no matter if the device
> probes or not. So, I suggest dropping the ifdeffery on <plat/irqs.h> and
> move that to something like below:
This is fine as long as we we don't run out of allocated IRQs before
switching over to sparse IRQ. The original reason for the ifdeffery
was to keep NR_IRQS below 256 when possible as it optimizes the interrupt
handling in that case. See NR_IRQS in arch/arm/include/asm/hardirq.h
for more info.
Regards,
Tony
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ
2011-01-07 17:04 ` Tony Lindgren
@ 2011-01-07 19:15 ` Felipe Balbi
0 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-07 19:15 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Felipe Balbi, Linux OMAP Mailing List
On Fri, Jan 07, 2011 at 09:04:55AM -0800, Tony Lindgren wrote:
> * Felipe Balbi <balbi@ti.com> [110106 23:47]:
> >
> > The main point of using Sparse IRQ numbering is exactly avoiding
> > pre-processor branches. Instead of defining ranges only when a device is
> > compile, we can always keep the range allocated no matter if the device
> > probes or not. So, I suggest dropping the ifdeffery on <plat/irqs.h> and
> > move that to something like below:
>
> This is fine as long as we we don't run out of allocated IRQs before
> switching over to sparse IRQ. The original reason for the ifdeffery
> was to keep NR_IRQS below 256 when possible as it optimizes the interrupt
> handling in that case. See NR_IRQS in arch/arm/include/asm/hardirq.h
> for more info.
I've sent patches (you're in Cc) enabling SPARSE_IRQ on OMAP. I boot
tested on panda and overo and it was working fine.
--
balbi
^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFT/PATCH 06/10] cbus: retu: headset: convert to threaded_irq
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (4 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 05/10] cbus: retu: move to threaded IRQ and GENIRQ Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 07/10] cbus: retu-pwrbutton: convert to threaded irq Felipe Balbi
` (3 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
use the new irq_chip added to retu.c.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Makefile | 2 +-
drivers/cbus/retu-headset.c | 22 ++++++++++++----------
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 3375b82..841bed5 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
#obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
#obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
#obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
-#obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
+obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
diff --git a/drivers/cbus/retu-headset.c b/drivers/cbus/retu-headset.c
index f5fb50c..2aa4d30 100644
--- a/drivers/cbus/retu-headset.c
+++ b/drivers/cbus/retu-headset.c
@@ -22,6 +22,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/input.h>
@@ -84,7 +86,6 @@ static void retu_headset_det_enable(struct retu_headset *hs)
if (!hs->detection_enabled) {
hs->detection_enabled = 1;
retu_set_clear_reg_bits(RETU_REG_CC1, (1 << 10) | (1 << 8), 0);
- retu_enable_irq(RETU_INT_HOOK);
}
mutex_unlock(&hs->mutex);
}
@@ -96,7 +97,6 @@ static void retu_headset_det_disable(struct retu_headset *hs)
mutex_lock(&hs->mutex);
if (hs->detection_enabled) {
hs->detection_enabled = 0;
- retu_disable_irq(RETU_INT_HOOK);
del_timer_sync(&hs->enable_timer);
del_timer_sync(&hs->detect_timer);
spin_lock_irqsave(&hs->lock, flags);
@@ -177,12 +177,11 @@ static DEVICE_ATTR(enable_det, S_IRUGO | S_IWUSR | S_IWGRP,
retu_headset_enable_det_show,
retu_headset_enable_det_store);
-static void retu_headset_hook_interrupt(unsigned long arg)
+static irqreturn_t retu_headset_hook_interrupt(int irq, void *_hs)
{
- struct retu_headset *hs = (struct retu_headset *) arg;
- unsigned long flags;
+ struct retu_headset *hs = _hs;
+ unsigned long flags;
- retu_ack_irq(RETU_INT_HOOK);
spin_lock_irqsave(&hs->lock, flags);
if (!hs->pressed) {
/* Headset button was just pressed down. */
@@ -192,6 +191,8 @@ static void retu_headset_hook_interrupt(unsigned long arg)
spin_unlock_irqrestore(&hs->lock, flags);
retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8));
mod_timer(&hs->enable_timer, jiffies + msecs_to_jiffies(50));
+
+ return IRQ_HANDLED;
}
static void retu_headset_enable_timer(unsigned long arg)
@@ -257,13 +258,13 @@ static int __init retu_headset_probe(struct platform_device *pdev)
setup_timer(&hs->detect_timer, retu_headset_detect_timer,
(unsigned long) hs);
- r = retu_request_irq(RETU_INT_HOOK, retu_headset_hook_interrupt,
- (unsigned long) hs, "hookdet");
+ r = request_threaded_irq(RETU_INT_HOOK, NULL,
+ retu_headset_hook_interrupt, 0, "hookdet", hs);
if (r != 0) {
dev_err(&pdev->dev, "hookdet IRQ not available\n");
goto err6;
}
- retu_disable_irq(RETU_INT_HOOK);
+
return 0;
err6:
device_remove_file(&pdev->dev, &dev_attr_enable_det);
@@ -289,9 +290,10 @@ static int retu_headset_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_enable_det);
retu_headset_disable(hs);
retu_headset_det_disable(hs);
- retu_free_irq(RETU_INT_HOOK);
+ free_irq(RETU_INT_HOOK, hs);
input_unregister_device(hs->idev);
input_free_device(hs->idev);
+
return 0;
}
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 07/10] cbus: retu-pwrbutton: convert to threaded irq
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (5 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 06/10] cbus: retu: headset: convert to threaded_irq Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 08/10] cbus: retu-rtc: move " Felipe Balbi
` (2 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Drop the timer function and move to threaded
irq infrastructure.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Makefile | 2 +-
drivers/cbus/retu-pwrbutton.c | 37 +++++++++----------------------------
2 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 841bed5..23f82b4 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_CBUS_TAHVO_USB) += tahvo-usb.o
obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
## Disable Retu children until converted to threaded IRQ
-#obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
#obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
#obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
diff --git a/drivers/cbus/retu-pwrbutton.c b/drivers/cbus/retu-pwrbutton.c
index 6b8dfa9..2a5ccb0 100644
--- a/drivers/cbus/retu-pwrbutton.c
+++ b/drivers/cbus/retu-pwrbutton.c
@@ -30,9 +30,10 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/input.h>
-#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -46,15 +47,14 @@
struct retu_pwrbutton {
struct input_dev *idev;
- struct timer_list timer;
int state;
int irq;
};
-static void retubutton_timer_func(unsigned long arg)
+static irqreturn_t retubutton_irq(int irq, void *_pwr)
{
- struct retu_pwrbutton *pwr = (struct retu_pwrbutton *) arg;
+ struct retu_pwrbutton *pwr = _pwr;
int state;
if (retu_read_reg(RETU_REG_STATUS) & RETU_STATUS_PWRONX)
@@ -67,24 +67,10 @@ static void retubutton_timer_func(unsigned long arg)
input_sync(pwr->idev);
pwr->state = state;
}
-}
-
-/**
- * Interrupt function is called whenever power button key is pressed
- * or released.
- */
-static void retubutton_irq(unsigned long arg)
-{
- struct retu_pwrbutton *pwr = (struct retu_pwrbutton *) arg;
- retu_ack_irq(RETU_INT_PWR);
- mod_timer(&pwr->timer, jiffies + msecs_to_jiffies(PWRBTN_DELAY));
+ return IRQ_HANDLED;
}
-/**
- * Init function.
- * Allocates interrupt for power button and registers itself to input layer.
- */
static int __init retubutton_probe(struct platform_device *pdev)
{
struct retu_pwrbutton *pwr;
@@ -99,10 +85,9 @@ static int __init retubutton_probe(struct platform_device *pdev)
pwr->irq = RETU_INT_PWR;
platform_set_drvdata(pdev, pwr);
- setup_timer(&pwr->timer, retubutton_timer_func, (unsigned long) pwr);
- ret = retu_request_irq(pwr->irq, retubutton_irq, (unsigned long) pwr,
- "PwrOnX");
+ ret = request_threaded_irq(pwr->irq, NULL, retubutton_irq, 0,
+ "retu-pwrbutton", pwr);
if (ret < 0) {
dev_err(&pdev->dev, "Cannot allocate irq\n");
goto err1;
@@ -131,7 +116,7 @@ err3:
input_free_device(pwr->idev);
err2:
- retu_free_irq(pwr->irq);
+ free_irq(pwr->irq, pwr);
err1:
kfree(pwr);
@@ -140,15 +125,11 @@ err0:
return ret;
}
-/**
- * Cleanup function which is called when driver is unloaded
- */
static int __exit retubutton_remove(struct platform_device *pdev)
{
struct retu_pwrbutton *pwr = platform_get_drvdata(pdev);
- retu_free_irq(pwr->irq);
- del_timer_sync(&pwr->timer);
+ free_irq(pwr->irq, pwr);
input_unregister_device(pwr->idev);
input_free_device(pwr->idev);
kfree(pwr);
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 08/10] cbus: retu-rtc: move to threaded irq
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (6 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 07/10] cbus: retu-pwrbutton: convert to threaded irq Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 09/10] cbus: retu-rtc: drop the reset_occurred flag Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 10/10] cbus: Makefile: re-enable retu-wdt Felipe Balbi
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Move to the generic threaded irq infrastructure
and drop all the retu-specific magic.
Unfortunately, due to the conversion and lack of
docs, retu_rtc_ioctl() had to be dropped, someone
else with access to docs is free to implement it
later considering the new style of the driver.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Makefile | 2 +-
drivers/cbus/retu-rtc.c | 120 ++++++----------------------------------------
2 files changed, 17 insertions(+), 105 deletions(-)
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 23f82b4..7bfd997 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -10,6 +10,6 @@ obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
## Disable Retu children until converted to threaded IRQ
obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
-#obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
+obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
#obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
diff --git a/drivers/cbus/retu-rtc.c b/drivers/cbus/retu-rtc.c
index cc789ed..6e201aa 100644
--- a/drivers/cbus/retu-rtc.c
+++ b/drivers/cbus/retu-rtc.c
@@ -38,11 +38,9 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/rtc.h>
-#include <linux/workqueue.h>
#include "cbus.h"
#include "retu.h"
@@ -50,8 +48,6 @@
struct retu_rtc {
/* device lock */
struct mutex mutex;
- struct completion sync;
- struct work_struct work;
struct device *dev;
struct rtc_device *rtc;
@@ -59,18 +55,6 @@ struct retu_rtc {
u16 reset_occurred;
};
-#define work_to_rtc(r) (container_of(r, struct retu_rtc, work))
-
-/* This function provides syncronization with the RTCS interrupt handler */
-static void retu_rtc_barrier(struct retu_rtc *rtc)
-{
- INIT_COMPLETION(rtc->sync);
- retu_ack_irq(RETU_INT_RTCS);
- retu_enable_irq(RETU_INT_RTCS);
- wait_for_completion(&rtc->sync);
- retu_disable_irq(RETU_INT_RTCS);
-}
-
static void retu_rtc_do_reset(struct retu_rtc *rtc)
{
u16 ccr1;
@@ -81,7 +65,6 @@ static void retu_rtc_do_reset(struct retu_rtc *rtc)
/* RTC in normal operating mode */
retu_write_reg(RETU_REG_CC1, ccr1 & ~0x0001);
- retu_rtc_barrier(rtc);
/* Disable alarm and RTC WD */
retu_write_reg(RETU_REG_RTCHMAR, 0x7f3f);
/* Set Calibration register to default value */
@@ -91,62 +74,33 @@ static void retu_rtc_do_reset(struct retu_rtc *rtc)
rtc->reset_occurred = 1;
}
-static void retu_rtca_disable(struct retu_rtc *rtc)
+static irqreturn_t retu_rtc_interrupt(int irq, void *_rtc)
{
- retu_disable_irq(RETU_INT_RTCA);
+ struct retu_rtc *rtc = _rtc;
+
+ mutex_lock(&rtc->mutex);
rtc->alarm_expired = 1;
- retu_rtc_barrier(rtc);
retu_write_reg(RETU_REG_RTCHMAR, (24 << 8) | 60);
-}
-
-static void retu_rtca_expired(struct work_struct *work)
-{
- struct retu_rtc *rtc = work_to_rtc(work);
-
- retu_rtca_disable(rtc);
-}
-
-/*
- * RTCHMR RTCHMAR RTCCAL must be accessed within 0.9 s since the seconds
- * interrupt has been signaled in the IDR register
- */
-static void retu_rtcs_interrupt(unsigned long _rtc)
-{
- struct retu_rtc *rtc = (struct retu_rtc *) _rtc;
-
- retu_ack_irq(RETU_INT_RTCS);
- complete_all(&rtc->sync);
-}
-
-static void retu_rtca_interrupt(unsigned long _rtc)
-{
- struct retu_rtc *rtc = (struct retu_rtc *) _rtc;
+ mutex_unlock(&rtc->mutex);
- retu_ack_irq(RETU_INT_RTCA);
- schedule_work(&rtc->work);
+ return IRQ_HANDLED;
}
static int retu_rtc_init_irq(struct retu_rtc *rtc)
{
int ret;
- ret = retu_request_irq(RETU_INT_RTCS, retu_rtcs_interrupt,
- (unsigned long) rtc, "RTCS");
+ ret = request_threaded_irq(RETU_INT_RTCS, NULL, retu_rtc_interrupt,
+ 0, "RTCS", rtc);
if (ret != 0)
return ret;
- /*
- * We will take care of enabling and disabling the interrupt
- * elsewhere, so leave it off by default..
- */
- retu_disable_irq(RETU_INT_RTCS);
- ret = retu_request_irq(RETU_INT_RTCA, retu_rtca_interrupt,
- (unsigned long) rtc, "RTCA");
+ ret = request_threaded_irq(RETU_INT_RTCA, NULL, retu_rtc_interrupt,
+ 0, "RTCA", rtc);
if (ret != 0) {
- retu_free_irq(RETU_INT_RTCS);
+ free_irq(RETU_INT_RTCS, rtc);
return ret;
}
- retu_disable_irq(RETU_INT_RTCA);
return 0;
}
@@ -231,42 +185,7 @@ static int retu_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
-#ifdef CONFIG_RTC_INTF_DEV
-
-static int retu_rtc_ioctl(struct device *dev, unsigned int cmd,
- unsigned long arg)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
-
- mutex_lock(&rtc->mutex);
-
- switch (cmd) {
- case RTC_AIE_OFF:
- retu_disable_irq(RETU_INT_RTCA);
- break;
- case RTC_AIE_ON:
- retu_enable_irq(RETU_INT_RTCA);
- break;
- case RTC_UIE_OFF:
- retu_disable_irq(RETU_INT_RTCS);
- break;
- case RTC_UIE_ON:
- retu_enable_irq(RETU_INT_RTCS);
- break;
- default:
- return -ENOIOCTLCMD;
- }
-
- mutex_unlock(&rtc->mutex);
-
- return 0;
-}
-#else
-#define retu_rtc_ioctl NULL
-#endif
-
static struct rtc_class_ops retu_rtc_ops = {
- .ioctl = retu_rtc_ioctl,
.read_time = retu_rtc_read_time,
.set_time = retu_rtc_set_time,
.read_alarm = retu_rtc_read_alarm,
@@ -287,9 +206,7 @@ static int __init retu_rtc_probe(struct platform_device *pdev)
rtc->dev = &pdev->dev;
platform_set_drvdata(pdev, rtc);
- INIT_WORK(&rtc->work, retu_rtca_expired);
mutex_init(&rtc->mutex);
- init_completion(&rtc->sync);
r = retu_get_status();
if (!r) {
@@ -324,10 +241,8 @@ static int __init retu_rtc_probe(struct platform_device *pdev)
return 0;
err2:
- retu_disable_irq(RETU_INT_RTCS);
- retu_disable_irq(RETU_INT_RTCA);
- retu_free_irq(RETU_INT_RTCS);
- retu_free_irq(RETU_INT_RTCA);
+ free_irq(RETU_INT_RTCS, rtc);
+ free_irq(RETU_INT_RTCA, rtc);
err1:
kfree(rtc);
@@ -340,10 +255,8 @@ static int __devexit retu_rtc_remove(struct platform_device *pdev)
{
struct retu_rtc *rtc = platform_get_drvdata(pdev);
- retu_disable_irq(RETU_INT_RTCS);
- retu_disable_irq(RETU_INT_RTCA);
- retu_free_irq(RETU_INT_RTCS);
- retu_free_irq(RETU_INT_RTCA);
+ free_irq(RETU_INT_RTCS, rtc);
+ free_irq(RETU_INT_RTCA, rtc);
rtc_device_unregister(rtc->rtc);
kfree(rtc);
@@ -361,13 +274,12 @@ static int __init retu_rtc_init(void)
{
return platform_driver_probe(&retu_rtc_driver, retu_rtc_probe);
}
+module_init(retu_rtc_init);
static void __exit retu_rtc_exit(void)
{
platform_driver_unregister(&retu_rtc_driver);
}
-
-module_init(retu_rtc_init);
module_exit(retu_rtc_exit);
MODULE_DESCRIPTION("Retu RTC");
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 09/10] cbus: retu-rtc: drop the reset_occurred flag
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (7 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 08/10] cbus: retu-rtc: move " Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
2011-01-03 7:49 ` [RFT/PATCH 10/10] cbus: Makefile: re-enable retu-wdt Felipe Balbi
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
that flag is never read anyway, only written,
so we can drop it.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/retu-rtc.c | 10 ++--------
1 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/drivers/cbus/retu-rtc.c b/drivers/cbus/retu-rtc.c
index 6e201aa..b2b9472 100644
--- a/drivers/cbus/retu-rtc.c
+++ b/drivers/cbus/retu-rtc.c
@@ -52,7 +52,6 @@ struct retu_rtc {
struct rtc_device *rtc;
u16 alarm_expired;
- u16 reset_occurred;
};
static void retu_rtc_do_reset(struct retu_rtc *rtc)
@@ -71,7 +70,6 @@ static void retu_rtc_do_reset(struct retu_rtc *rtc)
retu_write_reg(RETU_REG_RTCCALR, 0x00c0);
rtc->alarm_expired = 0;
- rtc->reset_occurred = 1;
}
static irqreturn_t retu_rtc_interrupt(int irq, void *_rtc)
@@ -223,14 +221,10 @@ static int __init retu_rtc_probe(struct platform_device *pdev)
goto err1;
}
- /* If the calibration register is zero, we've probably lost
- * power */
- if (retu_read_reg(RETU_REG_RTCCALR) & 0x00ff)
- rtc->reset_occurred = 0;
- else
+ /* If the calibration register is zero, we've probably lost power */
+ if (!(retu_read_reg(RETU_REG_RTCCALR) & 0x00ff))
retu_rtc_do_reset(rtc);
-
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &
retu_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread* [RFT/PATCH 10/10] cbus: Makefile: re-enable retu-wdt
2011-01-03 7:49 [RFT/PATCH 00/10] move retu to threaded IRQ Felipe Balbi
` (8 preceding siblings ...)
2011-01-03 7:49 ` [RFT/PATCH 09/10] cbus: retu-rtc: drop the reset_occurred flag Felipe Balbi
@ 2011-01-03 7:49 ` Felipe Balbi
9 siblings, 0 replies; 23+ messages in thread
From: Felipe Balbi @ 2011-01-03 7:49 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
Now that all conversions have been made,
reenable retu-wdt driver.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/cbus/Makefile | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
index 7bfd997..c5c3940 100644
--- a/drivers/cbus/Makefile
+++ b/drivers/cbus/Makefile
@@ -8,8 +8,7 @@ obj-$(CONFIG_CBUS_RETU) += retu.o
obj-$(CONFIG_CBUS_TAHVO_USB) += tahvo-usb.o
obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
-## Disable Retu children until converted to threaded IRQ
obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
-#obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
+obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
--
1.7.3.4.598.g85356
^ permalink raw reply related [flat|nested] 23+ messages in thread