aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDima Zavin <dima@android.com>2011-06-28 23:12:17 -0700
committerDima Zavin <dima@android.com>2011-06-28 23:12:17 -0700
commitb10049da714e57153cacb7e31efc41a8ba0ae5d2 (patch)
tree5365632f1bd7e26deb0967a7db927fed043bc2d0
parent6d8c3e7e0725603712a7d8e614137133a44bf136 (diff)
parentb03012db4df147d762410b051266bad0ca909368 (diff)
downloadkernel_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.c26
-rw-r--r--drivers/video/omap2/dss/dsi.c6
-rw-r--r--drivers/watchdog/omap_wdt.c100
-rw-r--r--drivers/watchdog/omap_wdt.h4
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,