summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/rtc-tegra-odm.c29
-rw-r--r--drivers/serial/tegra_hsuart.c122
-rwxr-xr-xdrivers/usb/host/ehci-tegra.c42
3 files changed, 88 insertions, 105 deletions
diff --git a/drivers/rtc/rtc-tegra-odm.c b/drivers/rtc/rtc-tegra-odm.c
index 49a48c60fc84..a5ff518c5aa6 100644
--- a/drivers/rtc/rtc-tegra-odm.c
+++ b/drivers/rtc/rtc-tegra-odm.c
@@ -33,9 +33,6 @@
#include <nvodm_pmu.h>
-#define SET_YEAR(Y) (Y-1900)
-#define SET_MONTH(M) (M-1)
-
/* Create a custom rtc structrue and move this to that structure */
static NvOdmPmuDeviceHandle hPmu = NULL;
@@ -51,20 +48,7 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
return -1;
}
- if (!now) {
- tm->tm_sec = 0;
- tm->tm_min = 0;
- tm->tm_hour = 0;
- tm->tm_mday = 1;
- tm->tm_mon = SET_MONTH(5);
- tm->tm_year = SET_YEAR(2009);
- tm->tm_wday = 0;
- tm->tm_yday = 0;
- tm->tm_isdst = 0;
- } else {
- rtc_time_to_tm(now, tm);
- }
-
+ rtc_time_to_tm(now, tm);
return 0;
}
@@ -95,12 +79,23 @@ static struct rtc_class_ops tegra_rtc_ops = {
static int __init tegra_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
+ NvU32 initial;
if (NvOdmPmuDeviceOpen(&hPmu) == NV_FALSE) {
pr_debug("%s: NvOdmPmuDeviceOpen failed\n", pdev->name);
return -ENXIO;
}
+ /* if the SoCs PMU has't been properly initialized, a bogus large
+ * value may be returned which triggers the Y2038 bug in the kernel.
+ * work-around this issue by checking the initial value of the PMU
+ * and then clobbering it if the value is bogus */
+
+ if (NvOdmPmuReadRtc(hPmu, &initial) && ((time_t)initial < 0))
+ NvOdmPmuWriteRtc(hPmu, 0);
+
+
+
rtc = rtc_device_register(pdev->name, &pdev->dev,
&tegra_rtc_ops, THIS_MODULE);
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c
index 90c5bd235273..489283a88402 100644
--- a/drivers/serial/tegra_hsuart.c
+++ b/drivers/serial/tegra_hsuart.c
@@ -56,7 +56,6 @@
static int tx_force_pio = 0;
static int rx_force_pio = 0;
-
struct tegra_uart_port {
struct uart_port uport;
char port_name[32];
@@ -86,7 +85,6 @@ struct tegra_uart_port {
void *tx_dma_virt;
dma_addr_t tx_dma_phys;
int tx_dma_size;
- int tx_dma_offset;
/* Rm DMA handles */
int tx_dma;
@@ -104,7 +102,7 @@ struct tegra_uart_port {
bool use_rx_dma;
bool use_tx_dma;
- bool tx_pio_inflight;
+ bool tx_pio_inflight;
struct work_struct work;
struct workqueue_struct *work_queue;
@@ -114,33 +112,6 @@ struct tegra_uart_port {
static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud);
static void tegra_set_mctrl(struct uart_port *u, unsigned int mctrl);
static void do_handle_rx_pio(struct uart_port *u);
-static inline bool tegra_wait_for_tx_fifo_empty(struct uart_port *u);
-
-/*
- * Attempts to wait for some time before to make sure that the data is drained.
- * Assumes that the caller has taken the u->lock.
- *
- * */
-static inline bool tegra_wait_for_tx_fifo_empty(struct uart_port *u)
-{
- /* FIXME compute the correct value based on the baud rate */
- struct tegra_uart_port *t;
- int timeout = 10;
- unsigned char lsr;
-
- t = container_of(u, struct tegra_uart_port, uport);
- do {
- lsr = readb(t->regs + UART_LSR_0);
- if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS)
- return true;
- spin_unlock(&u->lock);
- msleep(1);
- spin_lock(&u->lock);
- timeout--;
- } while (timeout);
-
- return false;
-}
static inline int tegra_uart_isbreak(struct uart_port *u)
{
@@ -313,7 +284,6 @@ static void tegra_tx_dma_workqueue(struct work_struct *w)
struct uart_port *u;
struct tegra_uart_port *t;
struct circ_buf *xmit;
- unsigned int count;
unsigned int to_send;
unsigned long flags;
@@ -333,9 +303,19 @@ static void tegra_tx_dma_workqueue(struct work_struct *w)
/* DMA just finished. Wait for the FIFO to drain. */
if (t->tx_dma_req.size) {
- bool empty;
- empty = tegra_wait_for_tx_fifo_empty(u);
- BUG_ON(empty != true);
+ /* FIXME: Do a better job on computing the delay */
+ int timeout = 10;
+ unsigned char lsr;
+ do {
+ lsr = readb(t->regs + UART_LSR_0);
+ if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS)
+ break;
+ spin_unlock_irqrestore(&u->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&u->lock, flags);
+ timeout--;
+ } while (timeout);
+ BUG_ON(timeout == 0);
}
/* Update the DMA tail pointer */
@@ -354,38 +334,32 @@ static void tegra_tx_dma_workqueue(struct work_struct *w)
spin_unlock_irqrestore(&u->lock, flags);
return;
}
-
- dma_sync_single_for_device(u->dev, t->tx_dma_phys,
- t->tx_dma_size, DMA_TO_DEVICE);
-
to_send = CIRC_CNT_TO_END(xmit->head, xmit->tail,
UART_XMIT_SIZE);
-
- /* DMA can only handle 4 byte aligned trasfers. So, align the
- * size */
- count = (to_send >> 2) << 2;
- if (count && !(xmit->tail & 0x3)) {
+ to_send &= ~0x3;
+ if (to_send) {
dev_dbg(u->dev, "Tx DMA starting 0x%x size %d\n",
- xmit->tail, count);
+ xmit->tail, to_send);
+
+ memcpy(t->tx_dma_virt, xmit->buf + xmit->tail, to_send);
t->fcr_shadow = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, TX_TRIG,
FIFO_COUNT_GREATER_4, t->fcr_shadow);
writeb(t->fcr_shadow, t->regs + UART_IIR_FCR_0);
- t->tx_dma_req.source_addr = t->tx_dma_phys + xmit->tail;
- t->tx_dma_req.size = count;
+ t->tx_dma_req.source_addr = t->tx_dma_phys;
+ t->tx_dma_req.size = to_send;
t->tx_pio_inflight = false;
tegra_dma_enqueue_req(t->tx_dma, &t->tx_dma_req);
+ spin_unlock_irqrestore(&u->lock, flags);
+ /* Wakeup tty layer if we are below threshold. Unlock port lock
+ * before we wakeup */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(u);
- spin_unlock_irqrestore(&u->lock, flags);
- return;
-
} else {
- /* Trasnfer in PIO mode */
-
+ /* Transfer in PIO mode */
t->fcr_shadow = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, TX_TRIG,
FIFO_COUNT_GREATER_8, t->fcr_shadow);
writeb(t->fcr_shadow, t->regs + UART_IIR_FCR_0);
@@ -397,9 +371,8 @@ static void tegra_tx_dma_workqueue(struct work_struct *w)
writeb(t->ier_shadow, t->regs + UART_IER_DLAB_0_0);
}
spin_unlock_irqrestore(&u->lock, flags);
- return;
-
}
+ return;
}
static void do_handle_modem_signal(struct uart_port *u)
@@ -736,7 +709,6 @@ static int tegra_startup(struct uart_port *u)
struct tegra_uart_port *t = container_of(u,
struct tegra_uart_port, uport);
int ret = 0;
- struct circ_buf *xmit = &u->info->xmit;
t = container_of(u, struct tegra_uart_port, uport);
sprintf(t->port_name, "tegra_uart_%d", u->line);
@@ -757,24 +729,28 @@ static int tegra_startup(struct uart_port *u)
t->use_tx_dma = true;
}
if (t->use_tx_dma) {
- t->tx_dma_virt = xmit->buf;
- t->tx_dma_phys = dma_map_single(u->dev, xmit->buf,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
- t->tx_dma_size = UART_XMIT_SIZE;
- t->tx_dma_offset = 0;
-
- /* Setup the DMA Tx request structure which doesn't change */
- INIT_LIST_HEAD(&t->tx_dma_req.list);
- t->tx_dma_req.modid = NvRmModuleID_Uart;
- t->tx_dma_req.instance = u->line;
- t->tx_dma_req.complete = tegra_tx_dma_complete_callback;
- t->tx_dma_req.to_memory = 0;
-
- t->tx_dma_req.dest_addr = t->phys;
- t->tx_dma_req.dest_wrap = 4;
- t->tx_dma_req.source_wrap = 0;
- t->tx_dma_req.data = u;
- t->tx_dma_req.size = 0;
+ t->tx_dma_virt = dma_alloc_writecombine(t->uport.dev,
+ UART_XMIT_SIZE, &t->tx_dma_phys, GFP_KERNEL);
+ if (t->tx_dma_virt) {
+ t->tx_dma_size = UART_XMIT_SIZE;
+
+ /* Setup the DMA Tx request structure
+ * which doesn't change */
+ INIT_LIST_HEAD(&t->tx_dma_req.list);
+ t->tx_dma_req.modid = NvRmModuleID_Uart;
+ t->tx_dma_req.instance = u->line;
+ t->tx_dma_req.complete = tegra_tx_dma_complete_callback;
+ t->tx_dma_req.to_memory = 0;
+
+ t->tx_dma_req.dest_addr = t->phys;
+ t->tx_dma_req.dest_wrap = 4;
+ t->tx_dma_req.source_wrap = 0;
+ t->tx_dma_req.data = u;
+ t->tx_dma_req.size = 0;
+ } else {
+ tegra_dma_free_channel(t->tx_dma);
+ t->use_tx_dma = false;
+ }
}
t->use_rx_dma = false;
@@ -820,6 +796,8 @@ static void tegra_shutdown(struct uart_port *u)
tegra_dma_free_channel(t->rx_dma);
}
if (t->use_tx_dma) {
+ dma_free_coherent(u->dev, t->tx_dma_size, t->tx_dma_virt,
+ t->tx_dma_phys);
tegra_dma_free_channel(t->tx_dma);
}
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index ba8e45a87f3c..505cee6c94e4 100755
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -264,18 +264,6 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
return retval;
}
-static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
-{
- printk("%s called\n", __func__);
- return 0;
-}
-
-static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
-{
- printk("%s called\n", __func__);
- return 0;
-}
-
static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra Ehci host controller",
@@ -295,8 +283,8 @@ static const struct hc_driver tegra_ehci_hc_driver = {
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = tegra_ehci_hub_control,
- .bus_suspend = tegra_ehci_bus_suspend,
- .bus_resume = tegra_ehci_bus_resume,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
};
@@ -470,12 +458,34 @@ static int tegra_ehci_remove(struct platform_device *pdev)
static int tegra_ehci_suspend(struct platform_device *pdev,
pm_message_t message)
{
- printk("%s called\n", __func__);
+ struct tegra_hcd_platform_data *pdata;
+ NvError Err;
+ pdata = (struct tegra_hcd_platform_data *)pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Cannot run without platform data\n");
+ return -1;
+ }
+ Err = NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0);
+ if (Err != NvSuccess) {
+ dev_err(&pdev->dev, "\n Usb Phy down error=0x%x ", Err);
+ return -1;
+ }
return 0;
}
static int tegra_ehci_resume(struct platform_device *pdev)
{
- printk("%s called\n", __func__);
+ struct tegra_hcd_platform_data *pdata;
+ NvError Err;
+ pdata = (struct tegra_hcd_platform_data *)pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Cannot run without platform data\n");
+ return -1;
+ }
+ Err = NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0);
+ if (Err != NvSuccess) {
+ dev_err(&pdev->dev, "\n Usb Phy Up error=0x%x ", Err);
+ return -1;
+ }
return 0;
}