summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/configs/tegra_harmony_android_defconfig1
-rw-r--r--arch/arm/configs/tegra_whistler_android_defconfig1
-rw-r--r--arch/arm/mach-tegra/board_nvodm.c17
-rw-r--r--arch/arm/mach-tegra/dma.c191
-rw-r--r--arch/arm/mach-tegra/include/mach/board.h6
-rw-r--r--arch/arm/mach-tegra/include/mach/dma.h44
-rw-r--r--arch/arm/mach-tegra/include/mach/pci.h2
-rw-r--r--[-rwxr-xr-x]arch/arm/mach-tegra/nvddk/nvddk_usbphy.c75
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c3
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c14
-rw-r--r--arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c177
-rw-r--r--arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c192
-rw-r--r--arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c81
-rw-r--r--arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c2
-rw-r--r--arch/arm/mach-tegra/pci-enum.c4
-rw-r--r--arch/arm/mach-tegra/pci.c12
-rw-r--r--arch/arm/mach-tegra/power-lp.S2
-rw-r--r--arch/arm/mach-tegra/tegra_rfkill_odm.c44
-rw-r--r--drivers/mmc/host/Kconfig12
-rw-r--r--drivers/mmc/host/sdhci.c26
-rwxr-xr-x[-rw-r--r--]drivers/mmc/host/sdhci.h5
-rw-r--r--drivers/serial/tegra_hsuart.c717
22 files changed, 1046 insertions, 582 deletions
diff --git a/arch/arm/configs/tegra_harmony_android_defconfig b/arch/arm/configs/tegra_harmony_android_defconfig
index 489e7e6253a9..c24816c5b36b 100644
--- a/arch/arm/configs/tegra_harmony_android_defconfig
+++ b/arch/arm/configs/tegra_harmony_android_defconfig
@@ -1484,6 +1484,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y
CONFIG_MMC_SDHCI=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK=y
# CONFIG_MMC_TIFM_SD is not set
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
diff --git a/arch/arm/configs/tegra_whistler_android_defconfig b/arch/arm/configs/tegra_whistler_android_defconfig
index fe2839172cd2..6e341676dba1 100644
--- a/arch/arm/configs/tegra_whistler_android_defconfig
+++ b/arch/arm/configs/tegra_whistler_android_defconfig
@@ -1199,6 +1199,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y
#
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK=y
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
diff --git a/arch/arm/mach-tegra/board_nvodm.c b/arch/arm/mach-tegra/board_nvodm.c
index 237844085c84..b1404b6ff00f 100644
--- a/arch/arm/mach-tegra/board_nvodm.c
+++ b/arch/arm/mach-tegra/board_nvodm.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/synaptics_i2c_rmi.h>
#include <linux/i2c.h>
+#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <asm/mach-types.h>
@@ -56,7 +57,6 @@
#include "mach/nvrm_linux.h"
#include "nvassert.h"
#include "nvodm_query_discovery.h"
-#include "mach/pci.h"
#include <../../../drivers/staging/android/timed_output.h>
@@ -277,13 +277,13 @@ static void __init NvConfigDebugConsole(
return;
}
-void __init pci_tegra_power(int on)
+void tegra_set_voltage(NvU64 guid, int on)
{
u32 settling_time;
const NvOdmPeripheralConnectivity *con = NULL;
int i;
- con = NvOdmPeripheralGetGuid(NV_VDD_PEX_CLK_ODM_ID);
+ con = NvOdmPeripheralGetGuid(guid);
if (con == NULL)
return;
@@ -311,6 +311,12 @@ extern void __init tegra_clk_init(void);
extern void __init tegra_init_snor_controller(void);
#endif
+
+static void tegra_system_power_off(void)
+{
+ tegra_set_voltage(NV_VDD_SoC_ODM_ID, 0);
+}
+
#if !(defined(CONFIG_ENC28J60) && defined(CONFIG_SPI_TEGRA))
#define register_enc28j60() do {} while (0)
#else
@@ -476,11 +482,12 @@ static void __init tegra_machine_init(void)
#endif
#ifdef CONFIG_TEGRA_PCI
- pci_tegra_power(1);
+ tegra_set_voltage( NV_VDD_PEX_CLK_ODM_ID, 1);
#else
- pci_tegra_power(0);
+ tegra_set_voltage( NV_VDD_PEX_CLK_ODM_ID, 0);
#endif
+ pm_power_off = tegra_system_power_off;
}
MACHINE_START(TEGRA_GENERIC, "Tegra generic")
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index fa4186513ce5..bbd3691240ea 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -78,8 +78,6 @@ struct tegra_dma_channel {
unsigned long phys_addr;
int mode;
- int odd_interrupt;
-
/* Register shadow */
unsigned long csr;
unsigned long ahb_seq;
@@ -102,7 +100,6 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch);
void tegra_dma_flush(int channel)
{
-
}
EXPORT_SYMBOL(tegra_dma_flush);
@@ -142,6 +139,8 @@ int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *_req)
struct tegra_dma_req *req = NULL;
int found = 0;
unsigned long irq_flags;
+ int to_transfer;
+ int req_transfer_count;
spin_lock_irqsave(&ch->lock, irq_flags);
list_for_each_entry (req, &ch->list, list) {
@@ -151,80 +150,102 @@ int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *_req)
break;
}
}
- BUG_ON(found==0);
-
- if (found) {
- int to_transfer;
- int req_transfer_count;
-
- /* STOP the DMA and get the transfer count.
- * Getting the transfer count is tricky.
- * - Change the source selector to invalid to stop the DMA from
- * FIFO to memory.
- * - Read the status register to knoe the number of pending
- * bytes to be transfered.
- * - Finally stop or program the DMA to the next buffer in the
- * list.
- */
- csr = ch->csr;
- csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR,
- REQ_SEL, NA31, csr);
- /* Set the enable as that is not shadowed */
- csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR,
- ENB, ENABLE, csr);
- writel(csr, ch->addr + APBDMACHAN_CHANNEL_0_CSR_0);
-
- /* Get the transfer count */
- status = readl(ch->addr + APBDMACHAN_CHANNEL_0_STA_0);
- to_transfer = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, STA,
- COUNT, status);
- req_transfer_count = NV_DRF_VAL(APBDMACHAN_CHANNEL_0,
- CSR, WCOUNT, ch->csr);
-
- req->bytes_transferred = req_transfer_count - to_transfer;
- req->bytes_transferred *= 4;
-
- tegra_dma_stop(ch);
- if (!list_empty(&ch->list)) {
- /* if the list is not empty, queue the next request */
- struct tegra_dma_req *next_req;
- next_req = list_entry(ch->list.next,
- typeof(*next_req), list);
- tegra_dma_update_hw(ch, next_req);
- }
- req->status = -TEGRA_DMA_REQ_ERROR_ABOTRED;
-
+ if (found==0) {
spin_unlock_irqrestore(&ch->lock, irq_flags);
- req->complete(req, req->status);
- spin_lock_irqsave(&ch->lock, irq_flags);
+ return 0;
+ }
+
+ /* STOP the DMA and get the transfer count.
+ * Getting the transfer count is tricky.
+ * - Change the source selector to invalid to stop the DMA from
+ * FIFO to memory.
+ * - Read the status register to know the number of pending
+ * bytes to be transfered.
+ * - Finally stop or program the DMA to the next buffer in the
+ * list.
+ */
+ csr = ch->csr;
+ csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR,
+ REQ_SEL, NA31, csr);
+ /* Set the enable as that is not shadowed */
+ csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR,
+ ENB, ENABLE, csr);
+ writel(csr, ch->addr + APBDMACHAN_CHANNEL_0_CSR_0);
+
+ /* Get the transfer count */
+ status = readl(ch->addr + APBDMACHAN_CHANNEL_0_STA_0);
+ to_transfer = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, STA,
+ COUNT, status);
+ req_transfer_count = NV_DRF_VAL(APBDMACHAN_CHANNEL_0,
+ CSR, WCOUNT, ch->csr);
+
+ req->bytes_transferred = req_transfer_count - to_transfer;
+ req->bytes_transferred *= 4;
+ /* In continous transfer mode, DMA only tracks the count of the
+ * half DMA buffer. So, if the DMA already finished half the DMA
+ * then add the half buffer to the completed count.
+ *
+ * FIXME: There can be a race here. What if the req to
+ * dequue happens at the same time as the DMA just moved to
+ * the new buffer and SW didn't yet received the interrupt?
+ */
+ if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
+ if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
+ req->bytes_transferred += 4 * req_transfer_count;
+ }
+ tegra_dma_stop(ch);
+ if (!list_empty(&ch->list)) {
+ /* if the list is not empty, queue the next request */
+ struct tegra_dma_req *next_req;
+ next_req = list_entry(ch->list.next,
+ typeof(*next_req), list);
+ tegra_dma_update_hw(ch, next_req);
}
+ req->status = -TEGRA_DMA_REQ_ERROR_ABOTRED;
+
spin_unlock_irqrestore(&ch->lock, irq_flags);
- if (found)
- return 0;
- else
- return -ENOENT;
+ /* Callback should be called without any lock */
+ req->complete(req, req->status);
+ return 0;
}
EXPORT_SYMBOL(tegra_dma_dequeue_req);
-int tegra_dma_is_empty(int channel)
+bool tegra_dma_is_empty(int channel)
{
unsigned long irq_flags;
struct tegra_dma_channel *ch = &dma_channels[channel];
- int is_empty;
+ bool is_empty;
spin_lock_irqsave(&ch->lock, irq_flags);
if (list_empty(&ch->list))
- is_empty = 1;
+ is_empty = true;
else
- is_empty = 0;
+ is_empty = false;
spin_unlock_irqrestore(&ch->lock, irq_flags);
-
return is_empty;
}
EXPORT_SYMBOL(tegra_dma_is_empty);
+bool tegra_dma_is_req_inflight(int channel, struct tegra_dma_req *_req)
+{
+ unsigned long irq_flags;
+ struct tegra_dma_channel *ch = &dma_channels[channel];
+ struct tegra_dma_req *req;
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ list_for_each_entry (req, &ch->list, list) {
+ if (req == _req) {
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return true;
+ }
+ }
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return false;
+}
+EXPORT_SYMBOL(tegra_dma_is_req_inflight);
+
int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req)
{
unsigned long irq_flags;
@@ -241,6 +262,7 @@ int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req)
req->bytes_transferred = 0;
req->status = 0;
+ req->buffer_status = 0;
if (list_empty(&ch->list))
start_dma = 1;
@@ -466,9 +488,11 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch)
{
static struct tegra_dma_req *req;
- if (list_empty(&ch->list))
- /* Why did we got an interrupt? */
+ spin_lock(&ch->lock);
+ if (list_empty(&ch->list)) {
+ spin_unlock(&ch->lock);
return;
+ }
req = list_entry(ch->list.next, typeof(*req), list);
if (req) {
@@ -483,33 +507,51 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch)
list_del(&req->list);
req->bytes_transferred = bytes_transferred;
req->status = 0;
+
+ spin_unlock(&ch->lock);
+ /* Callback should be called without any lock */
req->complete(req, 0);
+ spin_lock(&ch->lock);
}
if (!list_empty(&ch->list)) {
req = list_entry(ch->list.next, typeof(*req), list);
tegra_dma_update_hw(ch, req);
}
+ spin_unlock(&ch->lock);
}
static void handle_continuous_dma(struct tegra_dma_channel *ch)
{
static struct tegra_dma_req *req;
- if (list_empty(&ch->list))
- /* Why did we got an interrupt? */
+ spin_lock(&ch->lock);
+ if (list_empty(&ch->list)) {
+ spin_unlock(&ch->lock);
return;
+ }
req = list_entry(ch->list.next, typeof(*req), list);
if (req) {
- ch->odd_interrupt = (~ch->odd_interrupt & 0x1);
- if (ch->odd_interrupt) {
- struct tegra_dma_req *next_req;
- /* Load the next request into the hardware */
- next_req = list_first_entry(ch->list.next,
- typeof(*next_req), list);
- tegra_dma_update_hw_partial(ch, next_req);
- } else {
+ if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
+ /* Load the next request into the hardware, if available
+ * */
+ if (!list_is_last(&req->list, &ch->list)) {
+ struct tegra_dma_req *next_req;
+
+ printk("Queue the next request\n");
+ next_req = list_entry(req->list.next,
+ typeof(*next_req), list);
+ tegra_dma_update_hw_partial(ch, next_req);
+ }
+ req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
+ /* DMA lock is NOT held when callbak is called */
+ spin_unlock(&ch->lock);
+ req->threshold(req, 0);
+ return;
+
+ } else if (req->buffer_status ==
+ TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
/* Callback when the buffer is completely full (i.e on
* the second interrupt */
int bytes_transferred;
@@ -519,12 +561,21 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch)
bytes_transferred += 1;
bytes_transferred <<= 3;
+ req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
req->bytes_transferred = bytes_transferred;
req->status = 0;
list_del(&req->list);
+
+ /* DMA lock is NOT held when callbak is called */
+ spin_unlock(&ch->lock);
req->complete(req, 0);
+ return;
+
+ } else {
+ BUG();
}
}
+ spin_unlock(&ch->lock);
}
static irqreturn_t dma_isr(int irq, void *id)
@@ -546,6 +597,7 @@ static irqreturn_t dma_isr(int irq, void *id)
else
handle_continuous_dma(ch);
+
return IRQ_HANDLED;
}
@@ -608,4 +660,3 @@ fail:
/* FIXME cleanup */
return ret;
}
-
diff --git a/arch/arm/mach-tegra/include/mach/board.h b/arch/arm/mach-tegra/include/mach/board.h
index 10f0f0232b90..51e85fdb7bb5 100644
--- a/arch/arm/mach-tegra/include/mach/board.h
+++ b/arch/arm/mach-tegra/include/mach/board.h
@@ -22,5 +22,11 @@
#define __MACH_TEGRA_BOARD_H
#include <linux/types.h>
+#include "nvodm_pmu.h"
+#include "mach/nvrm_linux.h"
+#include "nvodm_query_discovery.h"
+
+/* ON/off power rail given the GUID */
+void tegra_set_voltage(NvU64 guid, int on);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index 964af099a392..508e2fcf8409 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -34,12 +34,46 @@ enum tegra_dma_req_error {
TEGRA_DMA_REQ_ERROR_ABOTRED,
};
+enum tegra_dma_req_buff_status {
+ TEGRA_DMA_REQ_BUF_STATUS_EMPTY,
+ TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL,
+ TEGRA_DMA_REQ_BUF_STATUS_FULL,
+};
+
struct tegra_dma_req {
struct list_head list;
unsigned int modid;
int instance;
+ /* Called when the req is complete and from the DMA ISR context.
+ * When this is called the req structure is no longer queued by
+ * the DMA channel.
+ *
+ * State of the DMA depends on the number of req it has. If there are
+ * no DMA requests queued up, then it will STOP the DMA. It there are
+ * more requests in the DMA, then it will queue the next request.
+ */
void (*complete)(struct tegra_dma_req *req, int err);
+
+ /* This is a called from the DMA ISR context when the DMA is still in
+ * progress and is actively filling same buffer.
+ *
+ * In case of continous mode receive, this threshold is 1/2 the buffer
+ * size. In other cases, this will not even be called as there is no
+ * hardware support for it.
+ *
+ * In the case of continous mode receive, if there is next req already
+ * queued, DMA programs the HW to use that req when this req is
+ * completed. If there is no "next req" queued, then DMA ISR doesn't do
+ * anything before calling this callback.
+ *
+ * This is mainly used by the cases, where the clients has queued
+ * only one req and want to get some sort of DMA threshold
+ * callback to program the next buffer.
+ *
+ */
+ void (*threshold)(struct tegra_dma_req *req, int err);
+
/* 1 to copy to memory.
* 0 to copy from the memory to device FIFO */
int to_memory;
@@ -57,6 +91,9 @@ struct tegra_dma_req {
int bytes_transferred;
int status;
+ /* DMA completion tracking information */
+ int buffer_status;
+
/* Client specific data */
void *data;
};
@@ -64,12 +101,11 @@ struct tegra_dma_req {
int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req);
int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *req);
void tegra_dma_dequeue(int channel);
-
-/* Returns 1 if there are DMA is empty.
- */
-int tegra_dma_is_empty(int channel);
void tegra_dma_flush(int channel);
+bool tegra_dma_is_req_inflight(int channel, struct tegra_dma_req *req);
+bool tegra_dma_is_empty(int channel);
+
int tegra_dma_allocate_channel(int mode);
void tegra_dma_free_channel(int channel);
diff --git a/arch/arm/mach-tegra/include/mach/pci.h b/arch/arm/mach-tegra/include/mach/pci.h
index 81f149717d05..e5eac3ad5640 100644
--- a/arch/arm/mach-tegra/include/mach/pci.h
+++ b/arch/arm/mach-tegra/include/mach/pci.h
@@ -320,6 +320,4 @@ static inline void __iomem *pci_tegra_config_addr(u8 bus_number,
void pci_tegra_enumerate(void);
-void __init pci_tegra_power(int on);
-
#endif
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
index fe3c3252d39f..435ff7dcc54c 100755..100644
--- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
+++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
@@ -47,6 +47,10 @@
#define MAX_USB_INSTANCES 5
+// On platforms that never disable USB controller clock, use 1KHz as an
+// indicator that USB controller is idle, and core voltage can be scaled down
+#define USBC_IDLE_KHZ (1)
+
static NvDdkUsbPhy *s_pUsbPhy = NULL;
static NvDdkUsbPhyUtmiPadConfig *s_pUtmiPadConfig = NULL;
@@ -247,22 +251,54 @@ UsbPhyDfsBusyHint(
{ NvRmDfsClockId_Emc, 0, 0, NV_TRUE },
{ NvRmDfsClockId_Ahb, 0, 0, NV_TRUE }
};
+ NvError e = NvSuccess;
pUsbHintOn[0].BoostDurationMs = BoostDurationMs;
pUsbHintOn[1].BoostDurationMs = BoostDurationMs;
if (DfsOn)
+ {
+ if (hUsbPhy->Caps.PhyRegInController)
+ {
+ // Indicate USB controller is active
+ NvRmFreqKHz PrefFreq = NvRmPowerModuleGetMaxFrequency(
+ hUsbPhy->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance));
+
+ NV_CHECK_ERROR_CLEANUP(
+ NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
+ hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq,
+ 1, NULL, 0));
+ }
return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice,
hUsbPhy->RmPowerClientId,
pUsbHintOn,
NV_ARRAY_SIZE(pUsbHintOn),
NvRmDfsBusyHintSyncMode_Async);
+ }
else
+ {
+ if (hUsbPhy->Caps.PhyRegInController)
+ {
+ // Indicate USB controller is idle
+ NvRmFreqKHz PrefFreq = USBC_IDLE_KHZ;
+
+ NV_CHECK_ERROR_CLEANUP(
+ NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
+ hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq,
+ 1, NULL, 0));
+ }
return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice,
hUsbPhy->RmPowerClientId,
pUsbHintOff,
NV_ARRAY_SIZE(pUsbHintOff),
NvRmDfsBusyHintSyncMode_Async);
+ }
+
+fail:
+ return e;
}
@@ -274,7 +310,8 @@ UsbPhyInitialize(
NvRmFreqKHz CurrentFreq = 0;
NvRmFreqKHz PrefFreqList[3] = {12000, 60000, NvRmFreqUnspecified};
- //NvOsDebugPrintf("UsbPhyInitialize::VOLTAGE ON\n");
+ // NvOsDebugPrintf("UsbPhyInitialize::VOLTAGE ON, instance %d\n",
+ // hUsbPhy->Instance);
// request power
NV_CHECK_ERROR_CLEANUP(
NvRmPowerVoltageControl(hUsbPhy->hRmDevice,
@@ -288,23 +325,31 @@ UsbPhyInitialize(
NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
hUsbPhy->RmPowerClientId, NV_TRUE));
- if (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy)
+ if (!hUsbPhy->Caps.PhyRegInController)
{
- /* Request for 60MHz clk */
- NV_CHECK_ERROR_CLEANUP(
- NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
- NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
- hUsbPhy->RmPowerClientId, PrefFreqList[1],
- PrefFreqList[1], &PrefFreqList[1], 1, &CurrentFreq, 0));
+ if (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy)
+ {
+ /* Request for 60MHz clk */
+ NV_CHECK_ERROR_CLEANUP(
+ NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
+ hUsbPhy->RmPowerClientId, PrefFreqList[1],
+ PrefFreqList[1], &PrefFreqList[1], 1, &CurrentFreq, 0));
+ }
+ else
+ {
+ /* Request for 12 MHz clk */
+ NV_CHECK_ERROR_CLEANUP(
+ NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
+ hUsbPhy->RmPowerClientId, PrefFreqList[0],
+ PrefFreqList[0], &PrefFreqList[0], 1, &CurrentFreq, 0));
+ }
}
- else
+ // else
{
- /* Request for 12 MHz clk */
- NV_CHECK_ERROR_CLEANUP(
- NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice,
- NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance),
- hUsbPhy->RmPowerClientId, PrefFreqList[0],
- PrefFreqList[0], &PrefFreqList[0], 1, &CurrentFreq, 0));
+ /* No need for actual clock configuration - all USB PLL frequencies
+ are available concurrently in this case. */
}
// Reset controller
diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c
index 198a2b20ce3d..70138eae4d7c 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c
@@ -1279,7 +1279,8 @@ NvRmPrivAp15IsModuleClockException(
Ap15PllUConfigure(hRmDevice, PrefFreqList[0]);
pCstate->SourceClock = 0;
pCstate->Divider = 1;
- pCstate->actual_freq = PrefFreqList[0];
+ pCstate->actual_freq =
+ NvRmPrivGetClockSourceFreq(pCinfo->Sources[0]);
return NV_TRUE;
default:
diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c b/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c
index 87775f87a4db..8ae5c9dfba72 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c
@@ -1471,9 +1471,9 @@ NvRmPowerModuleClockConfig (
// Display configuration always at nominal voltage. UART divider is not
// in CAR, and clock state contains source, rather than UART frequency.
- // Hence, get ready for fastest clock. For other modules use maximum of
- // target and current frequency. Make sure voltage is high enough for
- // maximum module source frequency.
+ // Hence, get ready for fastest clock. Same for USB clock. For other
+ // modules use maximum of target and current frequency. Make sure that
+ // voltage is high enough for maximum module source frequency.
if ((ModuleName == NvRmModuleID_Display) ||
(ModuleName == NvRmModuleID_Dsi))
{
@@ -1482,7 +1482,8 @@ NvRmPowerModuleClockConfig (
}
else
{
- if (ModuleName == NvRmModuleID_Uart)
+ if ((ModuleName == NvRmModuleID_Uart) ||
+ (ModuleName == NvRmModuleID_Usb2Otg))
f = NvRmFreqMaximum;
else
f = NV_MAX(MaxFreq, state->actual_freq);
@@ -1664,7 +1665,7 @@ leave:
(ModuleName == NvRmModuleID_Dsi) || state->Vscale))
{
// Tune voltage level to the actually configured frequency; for Display
- // and UART, use maximum requested frequency. Make sure voltage is
+ // UART, and USB use maximum requested frequency. Make sure voltage is
// updated after display configuration, which may change DVFS clocks.
SourceClockFreq =
s_ClockSourceFreq[(cinfo->Sources[state->SourceClock])];
@@ -1685,7 +1686,8 @@ leave:
}
else
{
- if (ModuleName == NvRmModuleID_Uart)
+ if ((ModuleName == NvRmModuleID_Uart) ||
+ (ModuleName == NvRmModuleID_Usb2Otg))
f = MaxFreq;
else
f = state->actual_freq;
diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c
index 6e61ddd95135..0f7a09446876 100644
--- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c
+++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c
@@ -37,6 +37,9 @@
#define MAX8907B_I2C_SPEED_KHZ 400
#define MAX8907B_I2C_RETRY_CNT 2
+// Maximum i2c transaction count
+#define MAX_TRANSACTION_COUNT 5
+
NvBool Max8907bI2cWrite8(
NvOdmPmuDeviceHandle hDevice,
NvU8 Addr,
@@ -45,14 +48,14 @@ NvBool Max8907bI2cWrite8(
NvU32 i;
NvU8 WriteBuffer[2];
NvOdmI2cTransactionInfo TransactionInfo;
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
WriteBuffer[0] = Addr & 0xFF; // PMU offset
WriteBuffer[1] = Data & 0xFF; // written data
-
+
TransactionInfo.Address = hPmu->DeviceAddr;
TransactionInfo.Buf = &WriteBuffer[0];
TransactionInfo.Flags = NVODM_I2C_IS_WRITE;
@@ -69,12 +72,12 @@ NvBool Max8907bI2cWrite8(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
@@ -86,28 +89,30 @@ NvBool Max8907bI2cRead8(
{
NvU32 i;
NvU8 ReadBuffer = 0;
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
NvOdmI2cTransactionInfo TransactionInfo[2];
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
+ NvU32 TransactionCount = 0;
// Write the PMU offset
ReadBuffer = Addr & 0xFF;
- TransactionInfo[0].Address = hPmu->DeviceAddr;
- TransactionInfo[0].Buf = &ReadBuffer;
- TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
- TransactionInfo[0].NumBytes = 1;
+ TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr;
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer;
+ TransactionInfo[TransactionCount].Flags =
+ NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
- TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1);
- TransactionInfo[1].Buf = &ReadBuffer;
- TransactionInfo[1].Flags = 0;
- TransactionInfo[1].NumBytes = 1;
+ TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer;
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
// Read data from PMU at the specified offset
- status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2,
- MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
+ status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0],
+ TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
if (status == NvOdmI2cStatus_Success)
{
@@ -120,12 +125,12 @@ NvBool Max8907bI2cRead8(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
@@ -137,13 +142,13 @@ NvBool Max8907bI2cWrite32(
{
NvU32 i;
NvU8 WriteBuffer[5];
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
NvOdmI2cTransactionInfo TransactionInfo;
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
- WriteBuffer[0] = (NvU8)(Addr & 0xFF);
+ WriteBuffer[0] = (NvU8)(Addr & 0xFF);
WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF);
WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF);
WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF);
@@ -154,7 +159,7 @@ NvBool Max8907bI2cWrite32(
TransactionInfo.Flags = NVODM_I2C_IS_WRITE;
TransactionInfo.NumBytes = 5;
- status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1,
+ status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1,
MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
if (status == NvOdmI2cStatus_Success)
@@ -165,12 +170,12 @@ NvBool Max8907bI2cWrite32(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
@@ -182,30 +187,32 @@ NvBool Max8907bI2cRead32(
{
NvU32 i;
NvU8 ReadBuffer[5];
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
NvOdmI2cTransactionInfo TransactionInfo[2];
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
+ NvU32 TransactionCount = 0;
ReadBuffer[0] = Addr & 0xFF;
- TransactionInfo[0].Address = hPmu->DeviceAddr;
- TransactionInfo[0].Buf = &ReadBuffer[0];
- TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
- TransactionInfo[0].NumBytes = 1;
+ TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr;
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[0];
+ TransactionInfo[TransactionCount].Flags =
+ NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
- TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1);
- TransactionInfo[1].Buf = &ReadBuffer[0];
- TransactionInfo[1].Flags = 0;
- TransactionInfo[1].NumBytes = 4;
+ TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[0];
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 4;
- status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2,
- MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
+ status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0],
+ TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
if (status == NvOdmI2cStatus_Success)
{
- *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) |
+ *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) |
(ReadBuffer[2] << 8) | ReadBuffer[3];
return NV_TRUE;
@@ -216,12 +223,12 @@ NvBool Max8907bI2cRead32(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
@@ -233,13 +240,14 @@ NvBool Max8907bRtcI2cWriteTime(
{
NvU32 i;
NvU8 WriteBuffer[5];
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
NvOdmI2cTransactionInfo TransactionInfo;
+ NVODMPMU_PRINTF(("\n RTC I2C write: Addr=0x%x, Data=0x%x ", Addr, Data));
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
- WriteBuffer[0] = (NvU8)(Addr & 0xFF);
+ WriteBuffer[0] = (NvU8)(Addr & 0xFF);
WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF);
WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF);
WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF);
@@ -250,7 +258,7 @@ NvBool Max8907bRtcI2cWriteTime(
TransactionInfo.Flags = NVODM_I2C_IS_WRITE;
TransactionInfo.NumBytes = 5;
- status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1,
+ status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1,
MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
if (status == NvOdmI2cStatus_Success)
@@ -261,12 +269,12 @@ NvBool Max8907bRtcI2cWriteTime(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
@@ -278,46 +286,63 @@ NvBool Max8907bRtcI2cReadTime(
{
NvU32 i;
NvU8 ReadBuffer[4];
- NvOdmI2cStatus status = NvOdmI2cStatus_Success;
+ NvOdmI2cStatus status = NvOdmI2cStatus_Success;
Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate;
- NvOdmI2cTransactionInfo TransactionInfo[4];
+ NvOdmI2cTransactionInfo TransactionInfo[MAX_TRANSACTION_COUNT];
+ NVODMPMU_PRINTF(("\n RTC I2C read: Addr=0x%x ", Addr));
for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++)
{
- ReadBuffer[0] = Addr++ & 0xFF;
- ReadBuffer[1] = Addr++ & 0xFF;
- ReadBuffer[2] = Addr++ & 0xFF;
- ReadBuffer[3] = 0;
-
- TransactionInfo[0].Address = MAX8907B_RTC_SLAVE_ADDR;
- TransactionInfo[0].Buf = &ReadBuffer[0];
- TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
- TransactionInfo[0].NumBytes = 1;
-
- // Seconds
- TransactionInfo[1].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1);
- TransactionInfo[1].Buf = &ReadBuffer[0];
- TransactionInfo[1].Flags = 0;
- TransactionInfo[1].NumBytes = 1;
-
- // Minutes
- TransactionInfo[2].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1);
- TransactionInfo[2].Buf = &ReadBuffer[1];
- TransactionInfo[2].Flags = 0;
- TransactionInfo[2].NumBytes = 1;
-
- // Hours
- TransactionInfo[3].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1);
- TransactionInfo[3].Buf = &ReadBuffer[2];
- TransactionInfo[3].Flags = 0;
- TransactionInfo[3].NumBytes = 1;
-
- status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 4,
- MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
+ NvU32 TransactionCount = 0;
+ ReadBuffer[0] = Addr & 0xFF;
+ TransactionInfo[TransactionCount].Address = MAX8907B_RTC_SLAVE_ADDR;
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[0];
+ TransactionInfo[TransactionCount].Flags =
+ NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
+
+ // Seconds / day
+ if (TransactionCount >= MAX_TRANSACTION_COUNT)
+ return NV_FALSE;
+ TransactionInfo[TransactionCount].Address =
+ (MAX8907B_RTC_SLAVE_ADDR | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[0];
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
+
+ // Minutes / month
+ if (TransactionCount >= MAX_TRANSACTION_COUNT)
+ return NV_FALSE;
+ TransactionInfo[TransactionCount].Address =
+ (MAX8907B_RTC_SLAVE_ADDR | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[1];
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
+
+ // Hours / YY1
+ if (TransactionCount >= MAX_TRANSACTION_COUNT)
+ return NV_FALSE;
+ TransactionInfo[TransactionCount].Address =
+ (MAX8907B_RTC_SLAVE_ADDR | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[2];
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
+
+ // Weekday / YY2
+ if (TransactionCount >= MAX_TRANSACTION_COUNT)
+ return NV_FALSE;
+ TransactionInfo[TransactionCount].Address =
+ (MAX8907B_RTC_SLAVE_ADDR | 0x1);
+ TransactionInfo[TransactionCount].Buf = &ReadBuffer[3];
+ TransactionInfo[TransactionCount].Flags = 0;
+ TransactionInfo[TransactionCount++].NumBytes = 1;
+
+ status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0],
+ TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE);
if (status == NvOdmI2cStatus_Success)
{
- *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) |
+ *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) |
(ReadBuffer[2] << 8) | ReadBuffer[3];
return NV_TRUE;
@@ -328,12 +353,12 @@ NvBool Max8907bRtcI2cReadTime(
switch (status)
{
case NvOdmI2cStatus_Timeout:
- NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n"));
+ NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n"));
break;
case NvOdmI2cStatus_SlaveNotFound:
default:
NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: SlaveNotFound\n"));
- break;
+ break;
}
return NV_FALSE;
}
diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c
index 0c179efdf21c..50afb66beba3 100644
--- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c
+++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c
@@ -30,151 +30,215 @@
*
*/
+#include <linux/time.h>
+#include <linux/rtc.h>
#include "max8907b.h"
#include "max8907b_rtc.h"
#include "max8907b_i2c.h"
#include "max8907b_reg.h"
-/**
+/**
* The Maxim 8907B does not have an RTC that simply counts
* seconds from some time t0 (as defined by the OS API).
* Instead, this RTC contains several BCD (Binary Coded Decimal)
* registers, including: seconds, minutes, hours, days, day of
* week, date, etc... These registers account for leap year and
* the various days of the month as well.
-*
+*
* Since the OS interpretation of seconds to a particular
* date/time from some OS-defined t0 is unknown at this level of
* the implementation, it is not possible to translate the given
* seconds into these registers (at least, not without a
* dependency on some OS-specific information).
-*
-* Therefore, this implementation contains a static variable
-* (RtcDays) which is derived from the number of seconds given
-* when Max8907bRtcCountWrite() is called. The seconds, minutes
-* and hours are then programmed to the RTC and used to keep
-* track of the current time within the day.
-*
-* TO DO: Increment the day whenever it rolls over (requires
-* handling an interrupt at midnight each day).
+*
*/
#define MAX8907B_SECONDS_PER_DAY (60*60*24)
#define MAX8907B_SECONDS_PER_HOUR (60*60)
#define MAX8907B_SECONDS_PER_MINUTE (60)
+#define LINUX_RTC_BASE_YEAR 1900
+
static NvBool bRtcNotInitialized = NV_TRUE;
-static NvU32 RtcDays = 0;
-NvBool
+NvBool
Max8907bRtcCountRead(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32* Count)
{
NvU32 data = 0;
NvU32 BcdHours, BcdMinutes, BcdSeconds;
NvU32 Hours, Minutes, Seconds;
+ NvU32 BcdDD, BcdMM, BcdYY1, BcdYY2;
+ NvU32 DD, MM, YY1, YY2, YYYY;
+ // struct rtc_time tm;
- if (Max8907bRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized)
- {
- Max8907bRtcCountWrite(hDevice, 0);
- *Count = 0;
- }
- else
+ *Count = 0;
+ // Read seconds, minute, hour and weekday data from RTC registers
+ if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data))
{
- if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data))
+ NVODMPMU_PRINTF(("\n Read time data-sec=0x%x ", data));
+ // Extract seconds, minute and hour data from RTC registers read
+ BcdHours = (data >> 8) & 0xFF;
+ BcdMinutes = (data >> 16) & 0xFF;
+ BcdSeconds = (data >> 24) & 0xFF;
+
+ // Convert BCT time into decimal values
+ Hours = ((BcdHours & 0xF0)>>4)*10 + (BcdHours & 0xF);
+ Minutes = ((BcdMinutes & 0xF0)>>4)*10 + (BcdMinutes & 0xF);
+ Seconds = ((BcdSeconds & 0xF0)>>4)*10 + (BcdSeconds & 0xF);
+
+ // Read day, month, yy1 and yy2 data from RTC registers
+ if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data))
{
-
- BcdHours = (data >> 8) & 0xFF;
- BcdMinutes = (data >> 16) & 0xFF;
- BcdSeconds = (data >> 24) & 0xFF;
-
- Hours = ((BcdHours & 0xF0)>>4)*10 + (BcdHours & 0xF);
- Minutes = ((BcdMinutes & 0xF0)>>4)*10 + (BcdMinutes & 0xF);
- Seconds = ((BcdSeconds & 0xF0)>>4)*10 + (BcdSeconds & 0xF);
-
- *Count = (Hours * MAX8907B_SECONDS_PER_HOUR) +
- (Minutes * MAX8907B_SECONDS_PER_MINUTE) + Seconds;
+ NVODMPMU_PRINTF(("\n Read time data-year=0x%x ", data));
+ // Extract day, month, yy1 and yy2 data from RTC registers read
+ BcdYY2 = (data & 0xFF);
+ BcdYY1 = (data >> 8) & 0xFF;
+ BcdMM = (data >> 16) & 0xFF;
+ BcdDD = (data >> 24) & 0xFF;
+ // convert bct day/month/year data to decimal values
+ YY2 = ((BcdYY2 & 0xF0)>>4)*10 + (BcdYY2 & 0xF);
+ YY1 = ((BcdYY1 & 0xF0)>>4)*10 + (BcdYY1 & 0xF);
+ YYYY = (YY2 * 100 + YY1) & 0xFFFF;
+ MM = ((BcdMM & 0xF0)>>4)*10 + (BcdMM & 0xF);
+ DD = ((BcdDD & 0xF0)>>4)*10 + (BcdDD & 0xF);
+ // get seconds since reference time value given
+ // year, month, day, hour, minutes and seconds
+ // NOTE: Using linux specific API mktime for conversion
+ *Count = mktime(YYYY, (MM + 1), DD, Hours, Minutes, Seconds);
+ NVODMPMU_PRINTF(("\n Rtc read count=0x%x ", *Count));
+ NVODMPMU_PRINTF(("\n mktime: YYYY=%d MM=%d DD=%d Hr=%d Min=%d "
+ "Sec=%d, *Count=0x%x ", YYYY, (MM + 1), DD, Hours, Minutes,
+ Seconds, *Count));
+#if NV_DEBUG
+ // Call to verify that reverse conversion of seconds matches date
+ rtc_time_to_tm(*Count, &tm);
+ // Check if Local_rtc_time_to_tm can return values sent to mktime
+ NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d "
+ "Min=%d Sec=%d, *Count=0x%x ", (tm.tm_year +
+ LINUX_RTC_BASE_YEAR), tm.tm_mon, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec, *Count));
+#endif
}
else
{
- NvOdmOsDebugPrintf("Max8907bRtcCountRead() error. ");
+ NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. "));
return NV_FALSE;
}
}
+ else
+ {
+ NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. "));
+ return NV_FALSE;
+ }
+ NVODMPMU_PRINTF(("\n *Count=0x%x ", *Count));
return NV_TRUE;
}
-NvBool
+NvBool
Max8907bRtcAlarmCountRead(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32* Count)
{
return NV_FALSE;
}
-NvBool
+NvBool
Max8907bRtcCountWrite(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32 Count)
{
- NvU32 Hours, Minutes, Seconds;
NvU32 BcdHours, BcdMinutes, BcdSeconds;
NvU32 data = 0;
-
- BcdHours = BcdMinutes = BcdSeconds = 0;
-
- RtcDays = Count / MAX8907B_SECONDS_PER_DAY;
-
- Hours = (Count % MAX8907B_SECONDS_PER_DAY) / MAX8907B_SECONDS_PER_HOUR;
- Minutes = ((Count % MAX8907B_SECONDS_PER_DAY) % MAX8907B_SECONDS_PER_HOUR) / MAX8907B_SECONDS_PER_MINUTE;
- Seconds = Count % MAX8907B_SECONDS_PER_MINUTE;
-
- BcdHours = (( Hours/10) << 4) | ( Hours%10);
- BcdMinutes = ((Minutes/10) << 4) | (Minutes%10);
- BcdSeconds = ((Seconds/10) << 4) | (Seconds%10);
+ NvU8 BcdDD, BcdMM, BcdYY1, BcdYY2;
+ NvU16 YYYY;
+ struct rtc_time tm;
+ NvU32 data1;
+
+ NVODMPMU_PRINTF(("\n Rtc write count=0x%x ", Count));
+ // convert seconds since reference time into date
+ // NOTE: using linux specific convert function rtc_time_to_tm
+ rtc_time_to_tm(Count, &tm);
+ NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d Min=%d "
+ "Sec=%d, *Count=0x%x ", (tm.tm_year + LINUX_RTC_BASE_YEAR),
+ (tm.tm_mon + 1), tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, Count));
+
+ // Convert time to bcd format
+ BcdHours = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10);
+ BcdMinutes = ((tm.tm_min/10) << 4) | (tm.tm_min%10);
+ BcdSeconds = ((tm.tm_sec/10) << 4) | (tm.tm_sec%10);
data = (BcdSeconds << 24) | (BcdMinutes << 16) | (BcdHours << 8);
+ // write time - seconds, minutes and hours in a day to RTC registers
if (Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_SEC, data))
{
- bRtcNotInitialized = NV_FALSE;
- return NV_TRUE;
+ // set the day, month, year
+ // Assuming we get the days since 1 Jan 1970
+
+ // convert date to bct format
+ BcdDD = (((NvU8)tm.tm_mday / 10) << 4) | ((NvU8)tm.tm_mday % 10);
+ BcdMM = (((NvU8)tm.tm_mon / 10) << 4) | ((NvU8)tm.tm_mon % 10);
+ YYYY = (NvU16)tm.tm_year + LINUX_RTC_BASE_YEAR;
+ BcdYY1 = (((NvU8)(YYYY % 100) / 10) << 4) | ((NvU8)(YYYY % 100) % 10);
+ BcdYY2 = (((NvU8)(YYYY / 100) / 10) << 4) | ((NvU8)(YYYY / 100) % 10);
+ data = (NvU32)((BcdDD << 24) | (BcdMM << 16) | (BcdYY1 << 8) | BcdYY2);
+ // write date - day, month, and year to RTC registers
+ if (!(Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_DATE, data)))
+ {
+ NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. "));
+ return NV_FALSE;
+ }
+#if NV_DEBUG
+ // verify that read back values from RTC matches written values
+ if (!(Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data1)))
+ {
+ NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. "));
+ return NV_FALSE;
+ }
+ if (data1 == data)
+ {
+ NVODMPMU_PRINTF(("\n Write read Success. "));
+ return NV_TRUE;
+ }
+ else
+ {
+ // return error when read data does not match written data
+ NVODMPMU_PRINTF(("\n Error: write data=0x%x, rd data=0x%x. ", data, data1));
+ return NV_FALSE;
+ }
+#endif
}
else
{
- NvOdmOsDebugPrintf("Max8907bRtcCountWrite() error. ");
+ NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. "));
return NV_FALSE;
}
}
-NvBool
+NvBool
Max8907bRtcAlarmCountWrite(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32 Count)
{
return NV_FALSE;
}
-NvBool
+NvBool
Max8907bRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice)
{
return NV_FALSE;
}
-NvBool
+NvBool
Max8907bRtcAlarmIntEnable(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvBool Enable)
{
return NV_FALSE;
}
-NvBool
-Max8907bRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice)
-{
- return NV_TRUE;
-}
-
NvBool
Max8907bIsRtcInitialized(NvOdmPmuDeviceHandle hDevice)
{
diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c
index d897eb9f4ee3..29f52e2d7ae0 100644
--- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c
+++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c
@@ -30,10 +30,20 @@
*
*/
+#include <linux/time.h>
#include "nvodm_pmu_tps6586x_rtc.h"
#include "nvodm_pmu_tps6586x_i2c.h"
#include "tps6586x_reg.h"
+// macro SHIFT_TO_2009 if 1, uses 2009 as reference year instead of 1970
+// This is because RTC in PMU TPS6586x can store duration of 34 years,
+// else we cannot retain date beyond 2004
+#define SHIFT_TO_2009 1
+#if SHIFT_TO_2009
+static unsigned long epoch = 2009;
+static unsigned long epoch_sec = 0;
+#endif
+
static NvBool bRtcNotInitialized = NV_TRUE;
/* Read RTC count register */
@@ -43,12 +53,12 @@ Tps6586xRtcCountRead(
NvU32* Count)
{
NvU32 ReadBuffer[2];
-
+
// 1) The I2C address pointer must not be left pointing in the range 0xC6 to 0xCA
// 2) The maximum time for the address pointer to be in this range is 1ms
// 3) Always read RTC_ALARM2 in the following order to prevent the address pointer
- // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI
-
+ // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI
+
if (Tps6586xRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized)
{
Tps6586xRtcCountWrite(hDevice, 0);
@@ -59,55 +69,76 @@ Tps6586xRtcCountRead(
// The unit of the RTC count is second!!! 1024 tick = 1s.
// Read all 40 bit and right move 10 = Read the hightest 32bit and right move 2
Tps6586xI2cRead32(hDevice, TPS6586x_RC6_RTC_COUNT4, &ReadBuffer[0]);
-
+
Tps6586xI2cRead8(hDevice, TPS6586x_RCA_RTC_COUNT0, &ReadBuffer[1]);
-
+
Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer[1]);
-
+
// return second
*Count = ReadBuffer[0]>>2;
}
-
+#if SHIFT_TO_2009
+ // calculate epoch_sec once
+ if (!epoch_sec)
+ epoch_sec = mktime(epoch,1,1,0,0,0);
+ *Count += epoch_sec;
+#endif
+
return NV_TRUE;
}
/* Write RTC count register */
-NvBool
+NvBool
Tps6586xRtcCountWrite(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32 Count)
{
NvU32 ReadBuffer = 0;
-
+#if SHIFT_TO_2009
+ // calculate epoch_sec once
+ if (!epoch_sec)
+ epoch_sec = mktime(epoch,1,1,0,0,0);
+ if (Count < (NvU32)epoch_sec)
+ {
+ // prevent setting date earlier than 'epoch'
+ pr_warning("\n Date being set cannot be earlier than least year=%d. "
+ "Setting as least year. ", (int)epoch);
+ // base year seconds count is 0
+ Count = 0;
+ }
+ else
+ Count -= (NvU32)epoch_sec;
+#endif
+
// To enable incrementing of the RTC_COUNT[39:0] from an initial value set by the host,
- // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches
+ // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches
// the operating range
-
+
// Clear RTC_ENABLE before writing RTC_COUNT
Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer);
ReadBuffer = ReadBuffer & 0xDF;
Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer);
-
+
Tps6586xI2cWrite32(hDevice, TPS6586x_RC6_RTC_COUNT4, (Count<<2));
- Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0);
-
+ Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0);
+
// Set RTC_ENABLE after writing RTC_COUNT
Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer);
ReadBuffer = ReadBuffer | 0x20;
Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer);
-
+
if (bRtcNotInitialized)
bRtcNotInitialized = NV_FALSE;
-
+
return NV_TRUE;
}
/* Read RTC alarm count register */
-NvBool
+NvBool
Tps6586xRtcAlarmCountRead(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32* Count)
{
return NV_FALSE;
@@ -115,9 +146,9 @@ Tps6586xRtcAlarmCountRead(
/* Write RTC alarm count register */
-NvBool
+NvBool
Tps6586xRtcAlarmCountWrite(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvU32 Count)
{
return NV_FALSE;
@@ -125,7 +156,7 @@ Tps6586xRtcAlarmCountWrite(
/* Reads RTC alarm interrupt mask status */
-NvBool
+NvBool
Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice)
{
return NV_FALSE;
@@ -133,9 +164,9 @@ Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice)
/* Enables / Disables the RTC alarm interrupt */
-NvBool
+NvBool
Tps6586xRtcAlarmIntEnable(
- NvOdmPmuDeviceHandle hDevice,
+ NvOdmPmuDeviceHandle hDevice,
NvBool Enable)
{
return NV_FALSE;
@@ -143,7 +174,7 @@ Tps6586xRtcAlarmIntEnable(
/* Checks if boot was from nopower / powered state */
-NvBool
+NvBool
Tps6586xRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice)
{
NvU32 Data = 0;
diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
index 7aded70cbb6c..ed5e81da1d38 100644
--- a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
+++ b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c
@@ -1187,7 +1187,7 @@ NvOdmQueryGetUsbProperty(NvOdmIoModule OdmIoModule,
(NvOdmUsbChargerType_SE0 | NvOdmUsbChargerType_SE1 | NvOdmUsbChargerType_SK),
20,
NV_TRUE,
- NvOdmUsbModeType_Device,
+ NvOdmUsbModeType_OTG,
NvOdmUsbIdPinType_CableId,
NvOdmUsbConnectorsMuxType_None,
NV_FALSE
diff --git a/arch/arm/mach-tegra/pci-enum.c b/arch/arm/mach-tegra/pci-enum.c
index 4f8c614ff8fc..1bcf659fe696 100644
--- a/arch/arm/mach-tegra/pci-enum.c
+++ b/arch/arm/mach-tegra/pci-enum.c
@@ -494,7 +494,7 @@ static void pci_tegra_setup_pci_device(struct pci_tegra_device *dev)
}
dev->res[bar_index].flags = IORESOURCE_MEM;
- dev->res[bar_index].start = 0;
+ dev->res[bar_index].start = addr;
dev->res[bar_index].end =
dev->res[bar_index].start + size - 1;
@@ -522,7 +522,7 @@ static void pci_tegra_setup_pci_device(struct pci_tegra_device *dev)
/* Handle 64 bit addresses by forcing to 32 bit addresses */
if ((flags == 0x0c) || (flags==0x04)) {
bar_index++;
- BUG_ON(bar_index < 6);
+ BUG_ON(bar_index > PCI_STD_RESOURCE_END);
pci_conf_write32(dev->bus, dev->devfn, bar_index * 4
+ PCI_BASE_ADDRESS_0, 0);
}
diff --git a/arch/arm/mach-tegra/pci.c b/arch/arm/mach-tegra/pci.c
index c4ced311e223..5118692b1b79 100644
--- a/arch/arm/mach-tegra/pci.c
+++ b/arch/arm/mach-tegra/pci.c
@@ -33,6 +33,7 @@
#include <mach/pci.h>
#include <mach/nvrm_linux.h>
+#include <mach/board.h>
#include "nvrm_pmu.h"
#include "nvodm_query_discovery.h"
@@ -362,7 +363,7 @@ static int __init pci_tegra_setup(int nr, struct pci_sys_data *data)
0, NULL);
NvRmPowerModuleClockControl(s_hRmGlobal, NvRmPrivModuleID_Pcie,
pci_tegra_powerid, NV_FALSE);
- pci_tegra_power(0);
+ tegra_set_voltage(NV_VDD_PEX_CLK_ODM_ID, 0);
return 0;
}
pci_tegra_device_attached = true;
@@ -402,12 +403,21 @@ static struct pci_bus __init *pci_tegra_scan_bus(int nr,
return NULL;
}
+int pci_tegra_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int ret = 0;
+ pci_tegra_read_conf(dev->bus, dev->devfn, PCI_INTERRUPT_LINE,
+ sizeof(int), &ret);
+ return (ret & 0x000000ff);
+}
+
static struct hw_pci pci_tegra_data __initdata = {
.nr_controllers = 2,
.preinit = pci_tegra_preinit,
.setup = pci_tegra_setup,
.scan = pci_tegra_scan_bus,
.swizzle = pci_std_swizzle,
+ .map_irq = pci_tegra_map_irq,
};
late_initcall(pcie_tegra_init);
diff --git a/arch/arm/mach-tegra/power-lp.S b/arch/arm/mach-tegra/power-lp.S
index 48c09640fd30..acc7645e34c1 100644
--- a/arch/arm/mach-tegra/power-lp.S
+++ b/arch/arm/mach-tegra/power-lp.S
@@ -66,7 +66,9 @@ wait_for_other_cores:
beq finish_power_state
//Save the local timers
+ stmfd sp!, {r1}
bl save_local_timers
+ ldmfd sp!, {r1}
//Ok we can save state for core0 now
save_arm_state:
diff --git a/arch/arm/mach-tegra/tegra_rfkill_odm.c b/arch/arm/mach-tegra/tegra_rfkill_odm.c
index ff4ebfb4361d..0ef0f060b9b0 100644
--- a/arch/arm/mach-tegra/tegra_rfkill_odm.c
+++ b/arch/arm/mach-tegra/tegra_rfkill_odm.c
@@ -34,7 +34,7 @@
#define DRIVER_DESC "Nvidia Tegra rfkill"
static NvRmGpioHandle hGpio = NULL;
-static NvRmGpioPinHandle hBlueToothPowerPin = 0;
+static NvRmGpioPinHandle hBlueToothResetPin = 0;
static NvU32 blueToothPowerRailId = 0xff;
static struct rfkill *bt = NULL;
@@ -47,7 +47,7 @@ static int bluetooth_set_power(void *data, enum rfkill_state state)
NvU32 settletime = 0;
NvU32 GpioLevel;
- if (blueToothPowerRailId == 0xff || !hBlueToothPowerPin || !hGpio)
+ if (blueToothPowerRailId == 0xff || !hBlueToothResetPin || !hGpio)
return -ENXIO;
hPmu = NvOdmServicesPmuOpen();
@@ -58,21 +58,24 @@ static int bluetooth_set_power(void *data, enum rfkill_state state)
case RFKILL_STATE_UNBLOCKED:
NvOdmServicesPmuGetCapabilities(hPmu, blueToothPowerRailId,
&vddrailcap);
- NvOdmServicesPmuSetVoltage(hPmu, blueToothPowerRailId,
+ NvOdmServicesPmuSetVoltage(hPmu, blueToothPowerRailId,
vddrailcap.requestMilliVolts, &settletime);
if (settletime)
NvOdmOsWaitUS(settletime);
- /* Enable power */
+ /* Pulse a reset */
GpioLevel = 0;
- NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1);
+ NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1);
/* Configure as output */
- NvRmGpioConfigPins(hGpio, &hBlueToothPowerPin, 1,
+ NvRmGpioConfigPins(hGpio, &hBlueToothResetPin, 1,
NvRmGpioPinMode_Output);
-
+
+ /* Give 5 milli seconds for the reset pulse */
+ NvOdmOsSleepMS(5);
+
GpioLevel = 1;
- NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1);
+ NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1);
printk(KERN_INFO "Bluetooth power ON\n");
break;
@@ -80,13 +83,13 @@ static int bluetooth_set_power(void *data, enum rfkill_state state)
case RFKILL_STATE_SOFT_BLOCKED:
/* Disable power */
GpioLevel = 0;
- NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1);
+ NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1);
/* Configure as output */
- NvRmGpioConfigPins(hGpio, &hBlueToothPowerPin, 1,
+ NvRmGpioConfigPins(hGpio, &hBlueToothResetPin, 1,
NvRmGpioPinMode_Output);
- NvOdmServicesPmuSetVoltage( hPmu, blueToothPowerRailId,
+ NvOdmServicesPmuSetVoltage( hPmu, blueToothPowerRailId,
NVODM_VOLTAGE_OFF, &settletime);
if (settletime)
NvOdmOsWaitUS(settletime);
@@ -112,7 +115,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev)
NvU64 bluetooth = NV_ODM_GUID('b','l','u','t','o','o','t','h');
/* conn will be null if bluetooth is not present. */
- conn =
+ conn =
NvOdmPeripheralGetGuid(bluetooth);
if (!conn)
return -ENXIO;
@@ -121,7 +124,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev)
if (conn->AddressList[i].Interface == NvOdmIoModule_Gpio) {
port = conn->AddressList[i].Instance;
pin = conn->AddressList[i].Address;
- }
+ }
if (conn->AddressList[i].Interface == NvOdmIoModule_Vdd) {
blueToothPowerRailId = conn->AddressList[i].Address;
}
@@ -137,7 +140,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev)
printk(KERN_ERR "NvRmGpioOpen failed\n");
return -ENXIO;
}
- err = NvRmGpioAcquirePinHandle(hGpio, port, pin, &hBlueToothPowerPin);
+ err = NvRmGpioAcquirePinHandle(hGpio, port, pin, &hBlueToothResetPin);
if (err) {
printk(KERN_ERR "NvRmGpioAcquirePinHandle failed\n");
NvRmGpioClose(hGpio);
@@ -146,7 +149,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev)
rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED);
bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED);
-
+
bt = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH);
if (!bt) {
rc = -ENOMEM;
@@ -163,12 +166,12 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev)
rc = rfkill_register(bt);
if (rc)
goto fail;
-
+
return rc;
fail:
- if (hBlueToothPowerPin)
- NvRmGpioReleasePinHandles(hGpio, &hBlueToothPowerPin, 1);
+ if (hBlueToothResetPin)
+ NvRmGpioReleasePinHandles(hGpio, &hBlueToothResetPin, 1);
if (hGpio)
NvRmGpioClose(hGpio);
@@ -183,8 +186,8 @@ static int __init tegra_rfkill_remove(struct platform_device *pdev)
rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED);
bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED);
- if (hBlueToothPowerPin)
- NvRmGpioReleasePinHandles(hGpio, &hBlueToothPowerPin, 1);
+ if (hBlueToothResetPin)
+ NvRmGpioReleasePinHandles(hGpio, &hBlueToothResetPin, 1);
if (hGpio)
NvRmGpioClose(hGpio);
@@ -214,4 +217,3 @@ static int __init tegra_rfkill_init(void)
module_init(tegra_rfkill_init);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 3f8a5bb69e42..aca32075e12d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -37,6 +37,18 @@ config MMC_SDHCI
If unsure, say N.
+config MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ depends on MMC_SDHCI
+ bool "Dynamically control the card clock for SD memory devices"
+ default y
+ help
+ On certain embedded devices, leaving the card clock enabled to
+ SD memory devices with no active transactions can increase power
+ consumption. Enable this option to automatically disable the card
+ clock after transfers complete.
+
+ If unsure, say N here.
+
config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8bb9366bbf0c..a0591db8c152 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
+#include <linux/mmc/card.h>
#include <linux/leds.h>
@@ -134,6 +135,9 @@ static void sdhci_init(struct sdhci_host *host)
writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ host->last_clock = 0;
+#endif
}
static void sdhci_activate_led(struct sdhci_host *host)
@@ -909,7 +913,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0)
goto out;
-
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ host->last_clock = clock;
+#endif
div = 0;
if (host->ops->set_clock)
div = host->ops->set_clock(host, clock);
@@ -1010,6 +1016,15 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
unsigned long flags;
host = mmc_priv(mmc);
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ if (host->mmc->card != NULL) {
+ if (host->mmc->card->type != MMC_TYPE_SDIO) {
+ if (host->last_clock)
+ /* Enable clock */
+ sdhci_set_clock(host, host->last_clock);
+ }
+ }
+#endif
spin_lock_irqsave(&host->lock, flags);
@@ -1240,7 +1255,14 @@ static void sdhci_tasklet_finish(unsigned long param)
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
-
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ /* Disable clock */
+ if (host->mmc->card != NULL) {
+ if (host->mmc->card->type != MMC_TYPE_SDIO) {
+ sdhci_set_clock(host, 0);
+ }
+ }
+#endif
mmc_request_done(host->mmc, mrq);
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 5805e301e604..fe800af6b7d0 100644..100755
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -58,7 +58,7 @@
#define SDHCI_CARD_PRESENT 0x00010000
#define SDHCI_WRITE_PROTECT 0x00080000
-#define SDHCI_HOST_CONTROL 0x28
+#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_8BITBUS 0x20
@@ -246,6 +246,9 @@ struct sdhci_host {
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ unsigned int last_clock; /* Last used clock (MHz) */
+#endif
unsigned short power; /* Current voltage */
struct mmc_request *mrq; /* Current request */
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c
index fac5e5eff24f..e58473a88fa5 100644
--- a/drivers/serial/tegra_hsuart.c
+++ b/drivers/serial/tegra_hsuart.c
@@ -47,9 +47,15 @@
#include "nvrm_interrupt.h"
#include "nvrm_power.h"
-#define UART_RX_DMA_PING_BUFFER_SIZE 0x800
-static int use_dma = 1;
+#define TX_EMPTY_STATUS (NV_DRF_DEF(UART, LSR, TMTY, EMPTY) | \
+ NV_DRF_DEF(UART, LSR, THRE, EMPTY))
+
+#define UART_RX_DMA_BUFFER_SIZE (4 * 1024 * 16)
+
+static int tx_force_pio = 0;
+static int rx_force_pio = 0;
+
struct tegra_uart_port {
struct uart_port uport;
@@ -62,6 +68,7 @@ struct tegra_uart_port {
NvOsPhysAddr phys;
NvU32 size;
struct clk *clk;
+ unsigned int baud;
/* Register shadow */
unsigned char fcr_shadow;
@@ -85,7 +92,7 @@ struct tegra_uart_port {
int tx_dma;
/* DMA requests */
- struct tegra_dma_req rx_dma_req[2];
+ struct tegra_dma_req rx_dma_req;
int rx_dma;
struct tegra_dma_req tx_dma_req;
@@ -95,12 +102,45 @@ struct tegra_uart_port {
int rx_pio_buffer_size;
bool use_rx_dma;
- bool dma_for_tx;
+ bool use_tx_dma;
+
+ bool tx_pio_inflight;
+
+ struct work_struct work;
+ struct workqueue_struct *work_queue;
- struct tasklet_struct tasklet;
};
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)
{
@@ -122,22 +162,120 @@ static inline int tegra_uart_isbreak(struct uart_port *u)
return 0;
}
-static inline void tegra_uart_set_rts(struct tegra_uart_port *t,
- int logical_value)
+void tegra_rx_dma_threshold_callback(struct tegra_dma_req *req, int err)
{
- unsigned char mcr;
+ struct uart_port *u = req->data;
+ struct tegra_uart_port *t;
+ unsigned long flags;
- /* To set to logical value 0, set the bit to 1 and vice versa */
- mcr = t->mcr_shadow;
- if (logical_value)
- mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS, FORCE_RTS_LOW, mcr);
- else
- mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS, FORCE_RTS_HI, mcr);
+ t = container_of(u, struct tegra_uart_port, uport);
- if (mcr != t->mcr_shadow) {
- writeb(mcr, t->regs + UART_MCR_0);
- t->mcr_shadow = mcr;
+ spin_lock_irqsave(&u->lock, flags);
+
+ u->mctrl &= ~TIOCM_RTS;
+ u->mctrl &= ~TIOCM_DTR;
+ tegra_set_mctrl(u, u->mctrl);
+
+ tegra_dma_dequeue(t->rx_dma);
+
+ u->mctrl |= TIOCM_RTS;
+ u->mctrl |= TIOCM_DTR;
+ tegra_set_mctrl(u, u->mctrl);
+
+ spin_unlock_irqrestore(&u->lock, flags);
+}
+
+/* It is expected that the callers take the UART lock when this API is called.
+ *
+ * There are 2 contexts when this function is called:
+ *
+ * 1. DMA ISR - DMA ISR triggers the threshold complete calback, which calls the
+ * dequue API which in-turn calls this callback. UART lock is taken during
+ * the call to the threshold callback.
+ *
+ * 2. UART ISR - UART calls the dequue API which in-turn will call this API.
+ * In this case, UART ISR takes the UART lock.
+ * */
+void tegra_rx_dma_complete_callback(struct tegra_dma_req *req, int err)
+{
+ struct uart_port *u = req->data;
+ struct tegra_uart_port *t;
+ struct tty_struct *tty = u->info->port.tty;
+
+ /* If we are here, DMA is stopped */
+
+ t = container_of(u, struct tegra_uart_port, uport);
+ if (req->bytes_transferred) {
+ t->uport.icount.rx += req->bytes_transferred;
+ tty_insert_flip_string(tty,
+ ((unsigned char *)(req->virt_addr)),
+ req->bytes_transferred);
+ dev_dbg(u->dev, "Received %d bytes\n", req->bytes_transferred);
+ }
+
+ if (req->status == -TEGRA_DMA_REQ_ERROR_ABOTRED) {
+ do_handle_rx_pio(u);
}
+
+ spin_unlock(&u->lock);
+ tty_flip_buffer_push(u->info->port.tty);
+ spin_lock(&u->lock);
+
+ /* Enqueue the request again */
+ tegra_dma_enqueue_req(t->rx_dma, req);
+}
+
+/* Lock already taken */
+static void do_handle_rx_dma(struct uart_port *u)
+{
+ struct tegra_uart_port *t;
+
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ u->mctrl &= ~TIOCM_RTS;
+ u->mctrl &= ~TIOCM_DTR;
+ tegra_set_mctrl(u, u->mctrl);
+
+ tegra_dma_dequeue(t->rx_dma);
+
+ u->mctrl |= TIOCM_RTS;
+ u->mctrl |= TIOCM_DTR;
+ tegra_set_mctrl(u, u->mctrl);
+
+}
+
+static char do_decode_rx_error(struct uart_port *u)
+{
+ struct tegra_uart_port *t;
+ char flag = TTY_NORMAL;
+ unsigned char lsr;
+
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ lsr = readb(t->regs + UART_LSR_0);
+ if (lsr & NV_DRF_DEF(UART, LSR, OVRF, OVERRUN_ERROR)) {
+ /* Overrrun error */
+ flag |= TTY_OVERRUN;
+ t->uport.icount.overrun++;
+ dev_err(u->dev, "Got overrun errors\n");
+ } else if (lsr & NV_DRF_DEF(UART, LSR, PERR, PARITY_ERR)) {
+ /* Parity error */
+ flag |= TTY_PARITY;
+ t->uport.icount.parity++;
+ dev_err(u->dev, "Got Parity errors\n");
+ } else if (lsr & NV_DRF_DEF(UART, LSR, FERR, FRAME_ERR)) {
+ flag |= TTY_FRAME;
+ dev_err(u->dev, "Got frame errors\n");
+ } else if (lsr & NV_DRF_DEF(UART, LSR, BRK, BREAK)) {
+ dev_err(u->dev, "Got Break \n");
+ /* If FIFO read error without any data, reset Rx FIFO */
+ if (!(lsr & 0x1) && (lsr & 0x80)) {
+ unsigned char fcr = t->fcr_shadow;
+ fcr |= 0x2;
+ writeb(fcr, t->regs + UART_IIR_FCR_0);
+ }
+ }
+ return flag;
}
static void do_handle_rx_pio(struct uart_port *u)
@@ -152,115 +290,116 @@ static void do_handle_rx_pio(struct uart_port *u)
unsigned char lsr;
unsigned char ch;
- lsr = readb(t->regs + UART_LSR_0);
- if (lsr & NV_DRF_DEF(UART, LSR, OVRF, OVERRUN_ERROR)) {
- /* Overrrun error */
- flag |= TTY_OVERRUN;
- t->uport.icount.overrun++;
- dev_err(u->dev, "Got overrun errors\n");
- } else if (lsr & NV_DRF_DEF(UART, LSR, PERR, PARITY_ERR)) {
- /* Parity error */
- flag |= TTY_PARITY;
- t->uport.icount.parity++;
- dev_err(u->dev, "Got Parity errors\n");
- } else if (lsr & NV_DRF_DEF(UART, LSR, FERR, FRAME_ERR)) {
- flag |= TTY_FRAME;
- dev_err(u->dev, "Got frame errors\n");
- } else if (lsr & NV_DRF_DEF(UART, LSR, BRK, BREAK)) {
- dev_err(u->dev, "Got Break \n");
- /* If FIFO read error without any data, reset Rx FIFO */
- if (!(lsr & 0x1) && (lsr & 0x80)) {
- unsigned char fcr = t->fcr_shadow;
- fcr |= 0x2;
- writeb(fcr, t->regs + UART_IIR_FCR_0);
- }
- } else if (lsr & NV_DRF_DEF(UART, LSR, FIFOE, ERR)) {
- unsigned char fcr;
- fcr = t->fcr_shadow;
- fcr = NV_FLD_SET_DRF_DEF(UART, IIR_FCR,
- RX_CLR, CLEAR, fcr);
- writeb(fcr, t->regs + UART_IIR_FCR_0);
- dev_err(u->dev, "Got fifo errors\n");
- }
+ flag = do_decode_rx_error(u);
+ lsr = readb(t->regs + UART_LSR_0);
if (!(lsr & NV_DRF_DEF(UART, LSR, RDR, DATA_IN_FIFO)))
break;
ch = readb(t->regs + UART_THR_DLAB_0_0);
dev_vdbg(u->dev, "%c\n", ch);
- if (!uart_handle_sysrq_char(u, c))
+ if (!uart_handle_sysrq_char(u, c)) {
tty_insert_flip_char(tty, ch, flag);
+ t->uport.icount.rx ++;
+ }
} while (1);
return;
}
-static void tegra_dma_tasklet_func(unsigned long data)
+
+static void tegra_tx_dma_workqueue(struct work_struct *w)
{
- struct uart_port *u = (struct uart_port *)data;
+ struct uart_port *u;
struct tegra_uart_port *t;
- struct circ_buf *xmit = &u->info->xmit;
+ struct circ_buf *xmit;
unsigned int count;
unsigned int to_send;
unsigned long flags;
- t = container_of(u, struct tegra_uart_port, uport);
+ t = container_of(w, struct tegra_uart_port, work);
+ u = &t->uport;
+ xmit = &u->info->xmit;
+
spin_lock_irqsave(&u->lock, flags);
- if (uart_circ_chars_pending(xmit)) {
- dma_sync_single_for_device(u->dev, t->tx_dma_phys,
- t->tx_dma_size, DMA_BIDIRECTIONAL);
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ /* DMA request is already queued, just return */
+ if (tegra_dma_is_req_inflight(t->tx_dma, &t->tx_dma_req)) {
+ spin_unlock_irqrestore(&u->lock, flags);
+ return;
+ }
- to_send = CIRC_CNT_TO_END(xmit->head, xmit->tail,
- UART_XMIT_SIZE);
+ /* 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);
+ }
- /* DMA can only handle 4 byte aligned trasfers. So, align the
- * size */
- count = (to_send >> 2) << 2;
- if (count && !(xmit->tail & 0x3)) {
- dev_vdbg(u->dev, "Tx DMA starting 0x%x size %d\n",
- xmit->tail, count);
- t->tx_dma_req.source_addr = t->tx_dma_phys + xmit->tail;
- t->tx_dma_req.size = count;
+ /* Update the DMA tail pointer */
+ xmit->tail += t->tx_dma_req.size;
+ xmit->tail &= UART_XMIT_SIZE - 1;
+ u->icount.tx += t->tx_dma_req.size;
+ t->tx_dma_req.size = 0;
- xmit->tail += count;
- xmit->tail &= UART_XMIT_SIZE - 1;
- u->icount.tx += count;
+ /* PIO is in flight. Just return */
+ if (t->tx_pio_inflight == true) {
+ spin_unlock_irqrestore(&u->lock, flags);
+ return;
+ }
- tegra_dma_enqueue_req(t->tx_dma, &t->tx_dma_req);
+ if (uart_circ_empty(xmit)) {
+ spin_unlock_irqrestore(&u->lock, flags);
+ return;
+ }
- /* Just return as the rest of the chars, if any, will
- * be scheduled when the DMA is completed */
- 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);
- } else {
- /* Use PIO for cases that cannot be handled by the DMA.
- * FIXME: We need to optimize this.
- * */
- if (tegra_dma_is_empty(t->tx_dma)) {
- count = to_send & 0x3;
- while (count) {
- unsigned char lsr;
-
- lsr = readb(t->regs + UART_LSR_0);
- if (!(lsr & (NV_DRF_DEF(UART, LSR,
- TMTY, EMPTY))))
- goto end;
- writeb(xmit->buf[xmit->tail],
- t->regs + UART_THR_DLAB_0_0);
- xmit->tail = (xmit->tail + 1) &
- (UART_XMIT_SIZE - 1);
- u->icount.tx++;
- count--;
- }
- }
+ 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)) {
+ dev_dbg(u->dev, "Tx DMA starting 0x%x size %d\n",
+ xmit->tail, count);
+
+ 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_pio_inflight = false;
+
+ tegra_dma_enqueue_req(t->tx_dma, &t->tx_dma_req);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(u);
+ spin_unlock_irqrestore(&u->lock, flags);
+ return;
+
+ } else {
+ /* Trasnfer 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);
+
+ if (!t->tx_pio_inflight) {
+ t->tx_pio_inflight = true;
+ t->ier_shadow = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0,
+ IE_THR, ENABLE, t->ier_shadow);
+ writeb(t->ier_shadow, t->regs + UART_IER_DLAB_0_0);
}
+ spin_unlock_irqrestore(&u->lock, flags);
+ return;
+
}
-end:
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(u);
- spin_unlock_irqrestore(&u->lock, flags);
}
static void do_handle_modem_signal(struct uart_port *u)
@@ -299,6 +438,7 @@ static void do_handle_tx_pio(struct uart_port *u)
t->ier_shadow = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0,
IE_THR, DISABLE, t->ier_shadow);
writeb(t->ier_shadow, t->regs + UART_IER_DLAB_0_0);
+ t->tx_pio_inflight = false;
break;
}
@@ -314,52 +454,13 @@ static void do_handle_tx_pio(struct uart_port *u)
void tegra_tx_dma_complete_callback(struct tegra_dma_req *req, int err)
{
- tasklet_schedule((struct tasklet_struct *)req->data);
-}
-
-void do_handle_rx_dma(struct uart_port *u, int eord_int)
-{
+ struct uart_port *u = (struct uart_port *)req->data;
struct tegra_uart_port *t;
- unsigned char ier;
-
- t = container_of(u, struct tegra_uart_port, uport);
- if (eord_int) {
- /* As per hw spec, to clear EORD interrupt, we need to disable
- * and then re-enable the interrupt.
- */
- ier = t->ier_shadow;
- ier = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0, IE_EORD,
- DISABLE, ier);
- writeb(ier, t->regs + UART_IER_DLAB_0_0);
- ier = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0, IE_EORD,
- ENABLE, ier);
- writeb(ier, t->regs + UART_IER_DLAB_0_0);
- }
- tegra_dma_dequeue(t->rx_dma);
-}
-
-void tegra_rx_dma_complete_callback(struct tegra_dma_req *req, int err)
-{
- struct uart_port *u = req->data;
- struct tegra_uart_port *t;
- struct tty_struct *tty = u->info->port.tty;
-
- t = container_of(u, struct tegra_uart_port, uport);
- if (req->bytes_transferred) {
- tty_insert_flip_string(tty,
- ((unsigned char *)(req->virt_addr)),
- req->bytes_transferred);
- }
-
- if (req->status == -TEGRA_DMA_REQ_ERROR_ABOTRED) {
- /* Drain the FIFO entries, only for the aborted requests */
- do_handle_rx_pio(u);
- }
-
- tty_flip_buffer_push(u->info->port.tty);
+ if (err == -TEGRA_DMA_REQ_ERROR_ABOTRED)
+ return;
- /* Enqueue the request again */
- tegra_dma_enqueue_req(t->rx_dma, req);
+ t = container_of(u, struct tegra_uart_port, uport);
+ queue_work(t->work_queue, &t->work);
}
static irqreturn_t tegra_uart_isr(int irq, void *data)
@@ -367,12 +468,15 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
struct uart_port *u = (struct uart_port *)data;
struct tegra_uart_port *t;
unsigned char iir_fcr;
+ unsigned char ier;
+ spin_lock(&u->lock);
t = container_of(u, struct tegra_uart_port, uport);
/* FIXME why do we need to loop here? */
while (1) {
iir_fcr = readb(t->regs + UART_IIR_FCR_0);
if (iir_fcr & NV_DRF_DEF(UART, IIR_FCR, IS_STA, NO_INTR_PEND)) {
+ spin_unlock(&u->lock);
return IRQ_HANDLED;
}
@@ -384,20 +488,34 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
case 1: /* Transmit interrupt only triggered when using PIO */
do_handle_tx_pio(u);
break;
+ case 4: /* End of data */
+ /* As per hw spec, to clear EORD interrupt, we need
+ * to disable and then re-enable the interrupt.
+ */
+ ier = t->ier_shadow;
+ ier = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0, IE_EORD,
+ DISABLE, ier);
+ writeb(ier, t->regs + UART_IER_DLAB_0_0);
+ ier = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0, IE_EORD,
+ ENABLE, ier);
+ writeb(ier, t->regs + UART_IER_DLAB_0_0);
+ /* fallthrough */
case 2: /* Receive */
- case 3: /* Receive error */
case 6: /* Rx timeout */
- if (likely(t->use_rx_dma))
- do_handle_rx_dma(u, 0);
- else
+ if (likely(t->use_rx_dma)) {
+ do_handle_rx_dma(u);
+ } else {
do_handle_rx_pio(u);
- tty_flip_buffer_push(u->info->port.tty);
+
+ spin_unlock(&u->lock);
+ tty_flip_buffer_push(u->info->port.tty);
+ spin_lock(&u->lock);
+ }
break;
- case 4: /* End of data */
- do_handle_rx_dma(u, 1);
- tty_flip_buffer_push(u->info->port.tty);
+ case 3: /* Receive error */
+ /* FIXME how to handle this? Why do we get here */
+ do_decode_rx_error(u);
break;
-
case 5: /* break nothing to handle */
case 7: /* break nothing to handle */
break;
@@ -407,19 +525,40 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
static void tegra_stop_rx(struct uart_port *u)
{
- dev_vdbg(u->dev, "+tegra_stop_rx\n");
- dev_vdbg(u->dev, "-tegra_stop_rx\n");
return;
}
-static int tegra_uart_hwinit(struct tegra_uart_port *t)
+static void tegra_uart_hw_deinit(struct tegra_uart_port *t)
+{
+ unsigned char fcr;
+
+ /* Disable interrupts */
+ writeb(0, t->regs + UART_IER_DLAB_0_0);
+
+ /* Reset the Rx and Tx FIFOs */
+ fcr = t->fcr_shadow;
+ fcr = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, TX_CLR, CLEAR, fcr);
+ fcr = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, RX_CLR, CLEAR, fcr);
+ writeb(fcr, t->regs + UART_IIR_FCR_0);
+
+ NvRmModuleReset(s_hRmGlobal, t->modid);
+ clk_disable(t->clk);
+ NvRmSetModuleTristate(s_hRmGlobal, t->modid, NV_TRUE);
+}
+
+static int tegra_uart_hw_init(struct tegra_uart_port *t)
{
unsigned char fcr;
unsigned char mcr;
unsigned char ier;
NvError err;
- dev_vdbg(t->uport.dev, "+tegra_uart_hwinit\n");
+ dev_vdbg(t->uport.dev, "+tegra_uart_hw_init\n");
+
+ t->fcr_shadow = 0;
+ t->mcr_shadow = 0;
+ t->lcr_shadow = 0;
+ t->ier_shadow = 0;
err = NvRmSetModuleTristate(s_hRmGlobal, t->modid, NV_FALSE);
if (err != NvSuccess) {
@@ -428,8 +567,6 @@ static int tegra_uart_hwinit(struct tegra_uart_port *t)
}
clk_enable(t->clk);
-
- tegra_set_baudrate(t, 9600);
NvRmModuleReset(s_hRmGlobal, t->modid);
/* Reset the FIFO twice with some delay to make sure that the FIFOs are
@@ -471,7 +608,7 @@ static int tegra_uart_hwinit(struct tegra_uart_port *t)
t->fcr_shadow = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, RX_TRIG,
FIFO_COUNT_GREATER_4, t->fcr_shadow);
- if (t->dma_for_tx) {
+ if (t->use_tx_dma) {
t->fcr_shadow = NV_FLD_SET_DRF_DEF(UART, IIR_FCR, TX_TRIG,
FIFO_COUNT_GREATER_4, t->fcr_shadow);
} else {
@@ -495,7 +632,9 @@ static int tegra_uart_hwinit(struct tegra_uart_port *t)
*/
mcr = t->mcr_shadow;
mcr = NV_FLD_SET_DRF_DEF(UART, MCR, CTS_EN, ENABLE, mcr);
- mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS_EN, ENABLE, mcr);
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS_EN, DISABLE, mcr);
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS, FORCE_RTS_HI, mcr);
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, DTR, FORCE_DTR_HI, mcr);
t->mcr_shadow = mcr;
writeb(mcr, t->regs + UART_MCR_0);
@@ -529,68 +668,56 @@ static int tegra_uart_hwinit(struct tegra_uart_port *t)
t->ier_shadow = ier;
writeb(ier, t->regs + UART_IER_DLAB_0_0);
- dev_vdbg(t->uport.dev, "-tegra_uart_hwinit\n");
+ dev_vdbg(t->uport.dev, "-tegra_uart_hw_init\n");
return 0;
fail:
- dev_vdbg(t->uport.dev, "-tegra_uart_hwinit\n");
+ dev_err(t->uport.dev, "HW init failed\n");
return -ENODEV;
}
static int tegra_uart_init_rx_dma(struct tegra_uart_port *t)
{
- int i;
+ dma_addr_t rx_dma_phys;
+ void *rx_dma_virt;
- /* Rx uses 1 DMA channel and 2 chained buffers */
t->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINOUS);
if (t->rx_dma < 0)
return -ENODEV;
- memset(t->rx_dma_req, 0, sizeof(t->rx_dma_req));
- for (i=0; i<2; i++) {
- dma_addr_t rx_dma_phys;
- void *rx_dma_virt;
+ memset(&t->rx_dma_req, 0, sizeof(t->rx_dma_req));
- t->rx_dma_req[i].size = UART_RX_DMA_PING_BUFFER_SIZE * 2;
- /* Allocate receive DMA buffer
- * This buffer can hold data for 50 ms with 4.5 Mbps data rate.
- */
- rx_dma_virt = dma_alloc_coherent(t->uport.dev,
- t->rx_dma_req[i].size, &rx_dma_phys, GFP_KERNEL);
- if (!rx_dma_virt) {
- dev_err(t->uport.dev, "DMA buffers allocate failed \n");
- goto fail;
- }
- t->rx_dma_req[i].dest_addr = rx_dma_phys;
- t->rx_dma_req[i].virt_addr = rx_dma_virt;
+ t->rx_dma_req.size = UART_RX_DMA_BUFFER_SIZE;
+ rx_dma_virt = dma_alloc_coherent(t->uport.dev,
+ t->rx_dma_req.size, &rx_dma_phys, GFP_KERNEL);
+ if (!rx_dma_virt) {
+ dev_err(t->uport.dev, "DMA buffers allocate failed \n");
+ goto fail;
}
-
- for (i=0; i<2; i++) {
- t->rx_dma_req[i].source_addr = t->phys;
- t->rx_dma_req[i].source_wrap = 4;
- t->rx_dma_req[i].dest_wrap = 0;
- t->rx_dma_req[i].to_memory = 1;
- t->rx_dma_req[i].modid = NvRmModuleID_Uart;
- t->rx_dma_req[i].instance = t->uport.line;
- t->rx_dma_req[i].complete = tegra_rx_dma_complete_callback;
- t->rx_dma_req[i].size = t->rx_dma_req[i].size;
- t->rx_dma_req[i].data = &t->uport;
- INIT_LIST_HEAD(&(t->rx_dma_req[i].list));
- if (tegra_dma_enqueue_req(t->rx_dma, &t->rx_dma_req[i])) {
- dev_err(t->uport.dev, "Could not enqueue Rx DMA req\n");
- goto fail;
- }
+ t->rx_dma_req.dest_addr = rx_dma_phys;
+ t->rx_dma_req.virt_addr = rx_dma_virt;
+
+ t->rx_dma_req.source_addr = t->phys;
+ t->rx_dma_req.source_wrap = 4;
+ t->rx_dma_req.dest_wrap = 0;
+ t->rx_dma_req.to_memory = 1;
+ t->rx_dma_req.modid = NvRmModuleID_Uart;
+ t->rx_dma_req.instance = t->uport.line;
+ t->rx_dma_req.complete = tegra_rx_dma_complete_callback;
+ t->rx_dma_req.threshold = tegra_rx_dma_threshold_callback;
+ t->rx_dma_req.data = &t->uport;
+ INIT_LIST_HEAD(&(t->rx_dma_req.list));
+ if (tegra_dma_enqueue_req(t->rx_dma, &t->rx_dma_req)) {
+ dev_err(t->uport.dev, "Could not enqueue Rx DMA req\n");
+ goto fail;
}
return 0;
fail:
tegra_dma_free_channel(t->rx_dma);
- if (t->rx_dma_req[0].dest_addr)
- dma_free_coherent(t->uport.dev, t->rx_dma_req[0].size,
- t->rx_dma_req[0].virt_addr, t->rx_dma_req[0].dest_addr);
- if (t->rx_dma_req[1].dest_addr)
- dma_free_coherent(t->uport.dev, t->rx_dma_req[1].size,
- t->rx_dma_req[1].virt_addr, t->rx_dma_req[1].dest_addr);
+ if (t->rx_dma_req.dest_addr)
+ dma_free_coherent(t->uport.dev, t->rx_dma_req.size,
+ t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
return -ENODEV;
}
@@ -613,16 +740,16 @@ static int tegra_startup(struct uart_port *u)
t->irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal, t->modid, 0);
BUG_ON(t->irq == (NvU32)(-1));
- t->dma_for_tx = false;
- if (use_dma) {
+ t->use_tx_dma = false;
+ if (!tx_force_pio) {
t->tx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
if (t->tx_dma >= 0)
- t->dma_for_tx = true;
+ t->use_tx_dma = true;
}
- if (t->dma_for_tx) {
+ 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_BIDIRECTIONAL);
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
t->tx_dma_size = UART_XMIT_SIZE;
t->tx_dma_offset = 0;
@@ -636,15 +763,16 @@ static int tegra_startup(struct uart_port *u)
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 = &t->tasklet;
+ t->tx_dma_req.data = u;
+ t->tx_dma_req.size = 0;
}
t->use_rx_dma = false;
- if (use_dma) {
+ if (!rx_force_pio) {
if (!tegra_uart_init_rx_dma(t))
t->use_rx_dma = true;
}
- ret = tegra_uart_hwinit(t);
+ ret = tegra_uart_hw_init(t);
if (ret)
goto fail;
@@ -664,57 +792,35 @@ fail:
return ret;
}
-#define TX_EMPTY_STATUS (NV_DRF_DEF(UART, LSR, TMTY, EMPTY) | \
- NV_DRF_DEF(UART, LSR, THRE, EMPTY))
-
static void tegra_shutdown(struct uart_port *u)
{
- int timeout = 10;
-
struct tegra_uart_port *t;
+ unsigned long flags;
+ spin_lock_irqsave(&u->lock, flags);
t = container_of(u, struct tegra_uart_port, uport);
dev_vdbg(u->dev, "+tegra_shutdown\n");
- if (!t->dma_for_tx) {
- /* wait for 10 msec to drain the Tx buffer, if not empty */
- unsigned char lsr;
- do {
- lsr = readb(t->regs + UART_LSR_0);
- if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS)
- break;
- timeout--;
- msleep(1);
- } while (timeout);
- } else {
- do {
- timeout = 10;
- if (tegra_dma_is_empty(t->tx_dma))
- break;
- timeout--;
- msleep(1);
- } while (timeout);
- if (!timeout)
- dev_info(u->dev, "DMA wait timedout\n");
+ if (t->use_tx_dma) {
+ /* FIXME: dequeue means abort. Should we need to abort
+ * or wait for the DMA to complete?
+ */
+ tegra_dma_dequeue_req(t->tx_dma, &t->tx_dma_req);
+ t->tx_dma_req.size = 0;
}
+ tegra_uart_hw_deinit(t);
+ spin_unlock_irqrestore(&u->lock, flags);
if (t->use_rx_dma) {
- tegra_dma_flush(t->rx_dma);
+ dma_free_coherent(u->dev, t->rx_dma_req.size,
+ t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
tegra_dma_free_channel(t->rx_dma);
- dma_free_coherent(u->dev, t->rx_dma_req[0].size,
- t->rx_dma_req[0].virt_addr, t->rx_dma_req[0].dest_addr);
- dma_free_coherent(u->dev, t->rx_dma_req[1].size,
- t->rx_dma_req[1].virt_addr, t->rx_dma_req[1].dest_addr);
}
- if (t->dma_for_tx) {
+ if (t->use_tx_dma) {
tegra_dma_free_channel(t->tx_dma);
}
- clk_disable(t->clk);
-
- NvRmSetModuleTristate(s_hRmGlobal, t->modid, NV_TRUE);
free_irq(t->irq, u);
-
dev_vdbg(u->dev, "-tegra_shutdown\n");
}
@@ -733,7 +839,27 @@ static unsigned int tegra_get_mctrl(struct uart_port *u)
static void tegra_set_mctrl(struct uart_port *u, unsigned int mctrl)
{
- dev_vdbg(u->dev, "tegra_set_mctrl\n");
+ unsigned char mcr;
+ struct tegra_uart_port *t;
+
+ dev_vdbg(u->dev, "tegra_set_mctrl called with %d\n", mctrl);
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ mcr = t->mcr_shadow;
+ if (mctrl & TIOCM_RTS)
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS, FORCE_RTS_LOW, mcr);
+ else
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, RTS, FORCE_RTS_HI, mcr);
+
+ if (mctrl & TIOCM_DTR)
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, DTR, FORCE_DTR_LOW, mcr);
+ else
+ mcr = NV_FLD_SET_DRF_DEF(UART, MCR, DTR, FORCE_DTR_HI, mcr);
+
+ if (mcr != t->mcr_shadow) {
+ writeb(mcr, t->regs + UART_MCR_0);
+ t->mcr_shadow = mcr;
+ }
return;
}
@@ -759,6 +885,8 @@ static int tegra_request_port(struct uart_port *u)
static void tegra_release_port(struct uart_port *u)
{
+
+
}
static unsigned int tegra_tx_empty(struct uart_port *u)
@@ -770,20 +898,21 @@ static unsigned int tegra_tx_empty(struct uart_port *u)
t = container_of(u, struct tegra_uart_port, uport);
dev_vdbg(u->dev, "+tegra_tx_empty\n");
+ if (t->use_tx_dma) {
+ if (tegra_dma_is_req_inflight(t->tx_dma, &t->tx_dma_req))
+ return 0;
+ }
lsr = readb(t->regs + UART_LSR_0);
if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS)
ret = TIOCSER_TEMT;
else
ret = 0;
-
dev_vdbg(u->dev, "-tegra_tx_empty\n");
return 0;
}
static void tegra_stop_tx(struct uart_port *u)
{
- dev_vdbg(u->dev, "+tegra_stop_tx\n");
- dev_vdbg(u->dev, "-tegra_stop_tx\n");
return;
}
@@ -793,25 +922,20 @@ static void tegra_start_tx_locked(struct uart_port *u)
t = container_of(u, struct tegra_uart_port, uport);
- // dev_vdbg(t->uport.dev, "+tegra_start_tx_locked\n");
+ dev_vdbg(t->uport.dev, "+tegra_start_tx_locked\n");
- if (!t->dma_for_tx) {
+ if (!t->use_tx_dma) {
/* Enable interrupt on transmit FIFO empty, if it is disabled */
- if (!(t->ier_shadow & NV_DRF_DEF(UART, IER_DLAB_0, IE_THR,
- ENABLE))) {
+ if (!t->tx_pio_inflight) {
+ t->tx_pio_inflight = true;
t->ier_shadow = NV_FLD_SET_DRF_DEF(UART, IER_DLAB_0,
IE_THR, ENABLE, t->ier_shadow);
writeb(t->ier_shadow, t->regs + UART_IER_DLAB_0_0);
}
} else {
- /* If DMA is empty try to scheule new requests */
- if (tegra_dma_is_empty(t->tx_dma)) {
- dev_vdbg(t->uport.dev, "Scheduling Tx\n");
- tasklet_schedule(&t->tasklet);
- }
+ queue_work(t->work_queue, &t->work);
}
-
- // dev_vdbg(t->uport.dev, "-tegra_start_tx_locked\n");
+ dev_vdbg(t->uport.dev, "-tegra_start_tx_locked\n");
}
static void tegra_enable_ms(struct uart_port *u)
@@ -830,6 +954,9 @@ static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud)
NvError err;
unsigned char lcr;
+ if (t->baud == baud)
+ return;
+
clock = (baud * 16) / 1000;
clock = clock ? clock : 1;
@@ -848,10 +975,10 @@ static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud)
return;
}
- /* FIXME is this division correct? */
- divisor = (actual_clock * 1000) / 16;
+ divisor = (actual_clock * 1000);
+ do_div(divisor, 16);
divisor += baud/2;
- divisor /= baud;
+ do_div(divisor, baud);
lcr = t->lcr_shadow;
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, DLAB, ENABLE, lcr);
@@ -863,7 +990,8 @@ static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud)
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, DLAB, DISABLE, lcr);
writeb(lcr, t->regs + UART_LCR_0);
- dev_dbg(t->uport.dev, "Baud %d clock freq %d and divisor of %d\n",
+ t->baud = baud;
+ dev_info(t->uport.dev, "Baud %d clock freq %d and divisor of %d\n",
baud, actual_clock, divisor);
}
@@ -892,18 +1020,18 @@ void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
lcr = t->lcr_shadow;
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, PAR, NO_PARITY, lcr);
if (PARENB == (c_cflag & PARENB)) {
- if (PARODD == (c_cflag & PARODD)) {
- strlcat(debug_string, "even parity ", 50);
+ if (CMSPAR == (c_cflag & CMSPAR)) {
+ strlcat(debug_string, "space parity ", 50);
+ /* FIXME What is space parity? */
+ /* data |= SPACE_PARITY; */
+ } else if (c_cflag & PARODD) {
+ strlcat(debug_string, "ODD parity ", 50);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, PAR, PARITY, lcr);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, EVEN, DISABLE, lcr);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, SET_P, NO_PARITY,
lcr);
- } else if (CMSPAR == (c_cflag & CMSPAR)) {
- strlcat(debug_string, "space parity ", 50);
- /* FIXME What is space parity? */
- /* data |= SPACE_PARITY; */
} else {
- strlcat(debug_string, "odd parity ", 50);
+ strlcat(debug_string, "Even parity ", 50);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, PAR, PARITY, lcr);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, EVEN, ENABLE, lcr);
lcr = NV_FLD_SET_DRF_DEF(UART, LCR, SET_P, NO_PARITY,
@@ -951,36 +1079,49 @@ void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
return;
}
-static void tegra_pm(struct uart_port *u, unsigned int state,
- unsigned int oldstate)
+/*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void tegra_flush_buffer(struct uart_port *u)
{
+ struct tegra_uart_port *t;
+ dev_vdbg(u->dev, "tegra_flush_buffer called");
+
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ if (t->use_tx_dma) {
+ tegra_dma_dequeue_req(t->tx_dma, &t->tx_dma_req);
+ t->tx_dma_req.size = 0;
+ }
+ return;
}
-static const char *tegra_type(struct uart_port *u)
-{
+
+static void tegra_pm(struct uart_port *u, unsigned int state,
+ unsigned int oldstate) {
+
+}
+
+static const char *tegra_type(struct uart_port *u) {
return 0;
}
static struct uart_ops tegra_uart_ops = {
.tx_empty = tegra_tx_empty,
-
.set_mctrl = tegra_set_mctrl,
.get_mctrl = tegra_get_mctrl,
-
.stop_tx = tegra_stop_tx,
.start_tx = tegra_start_tx_locked,
.stop_rx = tegra_stop_rx,
-
+ .flush_buffer = tegra_flush_buffer,
.enable_ms = tegra_enable_ms,
.break_ctl = tegra_break_ctl,
-
.startup = tegra_startup,
.shutdown = tegra_shutdown,
.set_termios = tegra_set_termios,
-
.pm = tegra_pm,
.type = tegra_type,
-
.request_port = tegra_request_port,
.release_port = tegra_release_port,
};
@@ -1015,6 +1156,8 @@ static int __devexit tegra_uart_remove(struct platform_device *pdev)
u = &t->uport;
uart_remove_one_port(&tegra_uart_driver, u);
+ destroy_workqueue(t->work_queue);
+
platform_set_drvdata(pdev, NULL);
NvRmSetModuleTristate(s_hRmGlobal, t->modid, NV_TRUE);
@@ -1032,7 +1175,7 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
struct uart_port *u;
int ret;
char clk_name[MAX_CLK_NAME_CHARS];
-
+ char name[64];
if (pdev->id < 0 || pdev->id > tegra_uart_driver.nr) {
printk(KERN_ERR "Invalid Uart instance (%d) \n", pdev->id);
return -ENODEV;
@@ -1058,9 +1201,6 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
goto fail;
}
- tasklet_init(&t->tasklet, tegra_dma_tasklet_func,
- (unsigned long)u);
-
if (NvRmSetModuleTristate(s_hRmGlobal,
t->modid, NV_FALSE) != NvSuccess) {
dev_err(u->dev, "No Pin Mux - not registering the port\n");
@@ -1078,11 +1218,16 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
return ret;
}
+ snprintf(name, sizeof(name), "tegra_hsuart_%d", u->line);
+ t->work_queue = create_singlethread_workqueue(name);
+ if (t->work_queue == NULL) {
+ dev_err(u->dev, "Failed to create work queue\n");
+ goto fail;
+ }
+ INIT_WORK(&t->work, tegra_tx_dma_workqueue);
printk(KERN_INFO "Registered UART port %s%d\n",
tegra_uart_driver.dev_name, u->line);
-
return ret;
-
fail:
kfree(t);
return -ENODEV;