diff options
author | Dima Zavin <dima@android.com> | 2011-06-28 23:12:17 -0700 |
---|---|---|
committer | Dima Zavin <dima@android.com> | 2011-06-28 23:12:17 -0700 |
commit | b10049da714e57153cacb7e31efc41a8ba0ae5d2 (patch) | |
tree | 5365632f1bd7e26deb0967a7db927fed043bc2d0 | |
parent | 6d8c3e7e0725603712a7d8e614137133a44bf136 (diff) | |
parent | b03012db4df147d762410b051266bad0ca909368 (diff) | |
download | kernel_samsung_tuna-b10049da714e57153cacb7e31efc41a8ba0ae5d2.zip kernel_samsung_tuna-b10049da714e57153cacb7e31efc41a8ba0ae5d2.tar.gz kernel_samsung_tuna-b10049da714e57153cacb7e31efc41a8ba0ae5d2.tar.bz2 |
Merge branch 'linux-omap-3.0' into android-omap-3.0
-rw-r--r-- | drivers/usb/otg/twl6030-usb.c | 26 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 6 | ||||
-rw-r--r-- | drivers/watchdog/omap_wdt.c | 100 | ||||
-rw-r--r-- | drivers/watchdog/omap_wdt.h | 4 |
4 files changed, 123 insertions, 13 deletions
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index cfb5aa7..6272e93 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c @@ -95,11 +95,15 @@ struct twl6030_usb { struct regulator *usb3v3; + /* used to set vbus, in atomic path */ + struct work_struct set_vbus_work; + int irq1; int irq2; u8 linkstat; u8 asleep; bool irq_enabled; + bool vbus_enable; unsigned long features; }; @@ -370,20 +374,28 @@ static int twl6030_enable_irq(struct otg_transceiver *x) return 0; } -static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled) +static void otg_set_vbus_work(struct work_struct *data) { - struct twl6030_usb *twl = xceiv_to_twl(x); - + struct twl6030_usb *twl = container_of(data, struct twl6030_usb, + set_vbus_work); /* * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1 * register. This enables boost mode. */ - if (enabled) + if (twl->vbus_enable) twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, CHARGERUSB_CTRL1); - else + else twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, CHARGERUSB_CTRL1); +} + +static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled) +{ + struct twl6030_usb *twl = xceiv_to_twl(x); + + twl->vbus_enable = enabled; + schedule_work(&twl->set_vbus_work); return 0; } @@ -444,6 +456,9 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier); + INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); + + twl->vbus_enable = false; twl->irq_enabled = true; status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, @@ -494,6 +509,7 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev) regulator_put(twl->usb3v3); pdata->phy_exit(twl->dev); device_remove_file(twl->dev, &dev_attr_vbus); + cancel_work_sync(&twl->set_vbus_work); kfree(twl); return 0; diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 4a49a8c..c16b933 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3770,6 +3770,11 @@ int dsi_video_mode_enable(struct omap_dss_device *dssdev, u8 data_type) r = FLD_MOD(r, 1, 9, 9); dsi_write_reg(dsidev, DSI_VC_CTRL(0), r); + r = dsi_read_reg(dsidev, DSI_VC_CTRL(1)); + r = FLD_MOD(r, 0, 4, 4); + r = FLD_MOD(r, 1, 9, 9); + dsi_write_reg(dsidev, DSI_VC_CTRL(1), r); + word_count = dssdev->panel.timings.x_res * 3; header = FLD_VAL(0, 31, 24) | /* ECC */ FLD_VAL(word_count, 23, 8) | /* WORD_COUNT */ @@ -3777,6 +3782,7 @@ int dsi_video_mode_enable(struct omap_dss_device *dssdev, u8 data_type) FLD_VAL(data_type, 5, 0); dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(0), header); + dsi_vc_enable(dsidev, 1, 1); dsi_vc_enable(dsidev, 0, 1); dsi_if_enable(dsidev, 1); diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 2b4acb8..48648f8 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -43,6 +43,8 @@ #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> #include <mach/hardware.h> #include <plat/prcm.h> @@ -54,6 +56,10 @@ static unsigned timer_margin; module_param(timer_margin, uint, 0); MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); +static int kernelpet = 1; +module_param(kernelpet, int, 0); +MODULE_PARM_DESC(kernelpet, "pet watchdog in kernel via irq"); + static unsigned int wdt_trgr_pattern = 0x1234; static spinlock_t wdt_lock; @@ -63,6 +69,8 @@ struct omap_wdt_dev { int omap_wdt_users; struct resource *mem; struct miscdevice omap_wdt_miscdev; + int irq; + struct work_struct sitter; }; static void omap_wdt_ping(struct omap_wdt_dev *wdev) @@ -122,6 +130,7 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout) static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) { u32 pre_margin = GET_WLDR_VAL(timer_margin); + u32 delay_period = GET_WLDR_VAL(timer_margin / 2); void __iomem *base = wdev->base; pm_runtime_get_sync(wdev->dev); @@ -134,15 +143,38 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) cpu_relax(); + /* Set delay interrupt to half the watchdog interval. */ + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 1 << 5) + cpu_relax(); + __raw_writel(delay_period, base + OMAP_WATCHDOG_WDLY); + pm_runtime_put_sync(wdev->dev); } -/* - * Allow only one task to hold it open - */ -static int omap_wdt_open(struct inode *inode, struct file *file) +static void omap_wdt_dogsitter(struct work_struct *work) +{ + struct omap_wdt_dev *wdev = + container_of(work, struct omap_wdt_dev, sitter); + + pm_runtime_get_sync(wdev->dev); + omap_wdt_ping(wdev); + pm_runtime_put_sync(wdev->dev); +} + +static irqreturn_t omap_wdt_interrupt(int irq, void *dev_id) +{ + struct omap_wdt_dev *wdev = dev_id; + void __iomem *base = wdev->base; + u32 i; + + schedule_work(&wdev->sitter); + i = __raw_readl(base + OMAP_WATCHDOG_WIRQSTAT); + __raw_writel(i, base + OMAP_WATCHDOG_WIRQSTAT); + return IRQ_HANDLED; +} + +static int omap_wdt_setup(struct omap_wdt_dev *wdev) { - struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); void __iomem *base = wdev->base; if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) @@ -158,20 +190,41 @@ static int omap_wdt_open(struct inode *inode, struct file *file) while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) cpu_relax(); - file->private_data = (void *) wdev; - omap_wdt_set_timeout(wdev); omap_wdt_ping(wdev); /* trigger loading of new timeout value */ + + /* Enable delay interrupt */ + + if (kernelpet && wdev->irq) + __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENSET); + omap_wdt_enable(wdev); pm_runtime_put_sync(wdev->dev); + return 0; +} +/* + * Allow only one task to hold it open + */ +static int omap_wdt_open(struct inode *inode, struct file *file) +{ + struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); + int ret; + + ret = omap_wdt_setup(wdev); + + if (ret) + return ret; + + file->private_data = (void *) wdev; return nonseekable_open(inode, file); } static int omap_wdt_release(struct inode *inode, struct file *file) { struct omap_wdt_dev *wdev = file->private_data; + void __iomem *base = wdev->base; /* * Shut off the timer unless NOWAYOUT is defined. @@ -181,6 +234,12 @@ static int omap_wdt_release(struct inode *inode, struct file *file) omap_wdt_disable(wdev); + if (kernelpet && wdev->irq) { + /* Disable delay interrupt */ + __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENCLR); + cancel_work_sync(&wdev->sitter); + } + pm_runtime_put_sync(wdev->dev); #else printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); @@ -272,7 +331,7 @@ static const struct file_operations omap_wdt_fops = { static int __devinit omap_wdt_probe(struct platform_device *pdev) { - struct resource *res, *mem; + struct resource *res, *mem, *res_irq; struct omap_wdt_dev *wdev; int ret; @@ -294,6 +353,8 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev) goto err_busy; } + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); if (!wdev) { ret = -ENOMEM; @@ -310,6 +371,18 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev) goto err_ioremap; } + INIT_WORK(&wdev->sitter, omap_wdt_dogsitter); + + if (res_irq) { + ret = request_irq(res_irq->start, omap_wdt_interrupt, 0, + dev_name(&pdev->dev), wdev); + + if (ret) + goto err_irq; + + wdev->irq = res_irq->start; + } + platform_set_drvdata(pdev, wdev); pm_runtime_enable(wdev->dev); @@ -335,10 +408,18 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev) omap_wdt_dev = pdev; + if (kernelpet && wdev->irq) + return omap_wdt_setup(wdev); + return 0; err_misc: platform_set_drvdata(pdev, NULL); + + if (wdev->irq) + free_irq(wdev->irq, wdev); + +err_irq: iounmap(wdev->base); err_ioremap: @@ -377,6 +458,9 @@ static int __devexit omap_wdt_remove(struct platform_device *pdev) release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); + if (wdev->irq) + free_irq(wdev->irq, wdev); + iounmap(wdev->base); kfree(wdev); diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h index 09b774c..c9980d3 100644 --- a/drivers/watchdog/omap_wdt.h +++ b/drivers/watchdog/omap_wdt.h @@ -38,7 +38,11 @@ #define OMAP_WATCHDOG_LDR (0x2c) #define OMAP_WATCHDOG_TGR (0x30) #define OMAP_WATCHDOG_WPS (0x34) +#define OMAP_WATCHDOG_WDLY (0x44) #define OMAP_WATCHDOG_SPR (0x48) +#define OMAP_WATCHDOG_WIRQSTAT (0x58) +#define OMAP_WATCHDOG_WIRQENSET (0x5c) +#define OMAP_WATCHDOG_WIRQENCLR (0x60) /* Using the prescaler, the OMAP watchdog could go for many * months before firing. These limits work without scaling, |