summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-01 09:15:15 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-01 09:15:15 -0800
commitac0f6f927db539e03e1f3f61bcd4ed57d5cde7a9 (patch)
tree816e5ac643b15c2050c64a7075f0f7e13d86ea09 /drivers
parentb1bf9368407ae7e89d8a005bb40beb70a41df539 (diff)
parent9f33be2c3a80bdc2cc08342dd77fac87652e0548 (diff)
downloadop-kernel-dev-ac0f6f927db539e03e1f3f61bcd4ed57d5cde7a9.zip
op-kernel-dev-ac0f6f927db539e03e1f3f61bcd4ed57d5cde7a9.tar.gz
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (100 commits) ARM: Eliminate decompressor -Dstatic= PIC hack ARM: 5958/1: ARM: U300: fix inverted clk round rate ARM: 5956/1: misplaced parentheses ARM: 5955/1: ep93xx: move timer defines into core.c and document ARM: 5954/1: ep93xx: move gpio interrupt support to gpio.c ARM: 5953/1: ep93xx: fix broken build of clock.c ARM: 5952/1: ARM: MM: Add ARM_L1_CACHE_SHIFT_6 for handle inside each ARCH Kconfig ARM: 5949/1: NUC900 add gpio virtual memory map ARM: 5948/1: Enable timer0 to time4 clock support for nuc910 ARM: 5940/2: ARM: MMCI: remove custom DBG macro and printk ARM: make_coherent(): fix problems with highpte, part 2 MM: Pass a PTE pointer to update_mmu_cache() rather than the PTE itself ARM: 5945/1: ep93xx: include correct irq.h in core.c ARM: 5933/1: amba-pl011: support hardware flow control ARM: 5930/1: Add PKMAP area description to memory.txt. ARM: 5929/1: Add checks to detect overlap of memory regions. ARM: 5928/1: Change type of VMALLOC_END to unsigned long. ARM: 5927/1: Make delimiters of DMA area globally visibly. ARM: 5926/1: Add "Virtual kernel memory..." printout. ARM: 5920/1: OMAP4: Enable L2 Cache ... Fix up trivial conflict in arch/arm/mach-mx25/clock.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-pnx.c285
-rw-r--r--drivers/mmc/host/mmci.c41
-rw-r--r--drivers/rtc/rtc-pl031.c365
-rw-r--r--drivers/serial/amba-pl011.c19
-rw-r--r--drivers/spi/amba-pl022.c18
-rw-r--r--drivers/watchdog/pnx4008_wdt.c39
6 files changed, 565 insertions, 202 deletions
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 5d1c260..2b0bd0b 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -20,15 +20,15 @@
#include <linux/platform_device.h>
#include <linux/i2c-pnx.h>
#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
#include <mach/hardware.h>
#include <mach/i2c.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
#define I2C_PNX_TIMEOUT 10 /* msec */
#define I2C_PNX_SPEED_KHZ 100
#define I2C_PNX_REGION_SIZE 0x100
-#define PNX_DEFAULT_FREQ 13 /* MHz */
static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
{
@@ -50,22 +50,21 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}
-static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *data = adap->algo_data;
- struct timer_list *timer = &data->mif.timer;
- int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+ struct timer_list *timer = &alg_data->mif.timer;
+ unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
if (expires <= 1)
expires = 2;
del_timer_sync(timer);
- dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+ dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
jiffies, expires);
timer->expires = jiffies + expires;
- timer->data = (unsigned long)adap;
+ timer->data = (unsigned long)&alg_data;
add_timer(timer);
}
@@ -77,34 +76,34 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
*
* Generate a START signal in the desired mode.
*/
-static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+static int i2c_pnx_start(unsigned char slave_addr,
+ struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
- dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
slave_addr, alg_data->mif.mode);
/* Check for 7 bit slave addresses only */
if (slave_addr & ~0x7f) {
- dev_err(&adap->dev, "%s: Invalid slave address %x. "
- "Only 7-bit addresses are supported\n",
- adap->name, slave_addr);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+ alg_data->adapter.name, slave_addr);
return -EINVAL;
}
/* First, make sure bus is idle */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
/* Somebody else is monopolizing the bus */
- dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, "
- "cntrl = %x, stat = %x\n",
- adap->name, slave_addr,
- ioread32(I2C_REG_CTL(alg_data)),
- ioread32(I2C_REG_STS(alg_data)));
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+ alg_data->adapter.name, slave_addr,
+ ioread32(I2C_REG_CTL(alg_data)),
+ ioread32(I2C_REG_STS(alg_data)));
return -EBUSY;
} else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
/* Sorry, we lost the bus */
- dev_err(&adap->dev, "%s: Arbitration failure. "
- "Slave addr = %02x\n", adap->name, slave_addr);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Arbitration failure. Slave addr = %02x\n",
+ alg_data->adapter.name, slave_addr);
return -EIO;
}
@@ -115,14 +114,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
(slave_addr << 1) | start_bit | alg_data->mif.mode);
/* Write the slave address, START bit and R/W bit */
iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
I2C_REG_TX(alg_data));
- dev_dbg(&adap->dev, "%s(): exit\n", __func__);
+ dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
return 0;
}
@@ -133,13 +132,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
*
* Generate a STOP signal to terminate the master transaction.
*/
-static void i2c_pnx_stop(struct i2c_adapter *adap)
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
/* Only 1 msec max timeout due to interrupt context */
long timeout = 1000;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
/* Write a STOP bit to TX FIFO */
@@ -153,7 +151,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
timeout--;
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
}
@@ -163,12 +161,11 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
*
* Sends one byte of data to the slave
*/
-static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 val;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
if (alg_data->mif.len > 0) {
@@ -184,15 +181,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
alg_data->mif.len--;
iowrite32(val, I2C_REG_TX(alg_data));
- dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__,
- val, alg_data->mif.len + 1);
+ dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+ __func__, val, alg_data->mif.len + 1);
if (alg_data->mif.len == 0) {
if (alg_data->last) {
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
- dev_err(&adap->dev, "The bus is still "
- "active after timeout\n");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
}
/* Disable master interrupts */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -201,14 +198,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine.\n",
__func__);
complete(&alg_data->mif.complete);
}
} else if (alg_data->mif.len == 0) {
/* zero-sized transfer */
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -217,13 +215,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
/* Stop timer. */
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
- "zero-xfer.\n", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine after zero-xfer.\n",
+ __func__);
complete(&alg_data->mif.complete);
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -235,21 +234,21 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
*
* Reads one byte data from the slave
*/
-static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
unsigned int val = 0;
u32 ctl = 0;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
/* Check, whether there is already data,
* or we didn't 'ask' for it yet.
*/
if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
- dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
- "Rx-fifo...\n", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Write dummy data to fill Rx-fifo...\n",
+ __func__);
if (alg_data->mif.len == 1) {
/* Last byte, do not acknowledge next rcv. */
@@ -281,16 +280,16 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
if (alg_data->mif.len > 0) {
val = ioread32(I2C_REG_RX(alg_data));
*alg_data->mif.buf++ = (u8) (val & 0xff);
- dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+ __func__, val, alg_data->mif.len);
alg_data->mif.len--;
if (alg_data->mif.len == 0) {
if (alg_data->last)
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
- dev_err(&adap->dev, "The bus is still "
- "active after timeout\n");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
/* Disable master interrupts */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -304,7 +303,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
}
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -312,11 +311,11 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
{
+ struct i2c_pnx_algo_data *alg_data = dev_id;
u32 stat, ctl;
- struct i2c_adapter *adap = dev_id;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
- dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): mstat = %x mctrl = %x, mode = %d\n",
__func__,
ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)),
@@ -339,10 +338,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
complete(&alg_data->mif.complete);
} else if (stat & mstatus_nai) {
/* Slave did not acknowledge, generate a STOP */
- dev_dbg(&adap->dev, "%s(): "
- "Slave did not acknowledge, generating a STOP.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Slave did not acknowledge, generating a STOP.\n",
__func__);
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -368,9 +367,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
*/
if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
- i2c_pnx_master_xmit(adap);
+ i2c_pnx_master_xmit(alg_data);
} else if (alg_data->mif.mode == I2C_SMBUS_READ) {
- i2c_pnx_master_rcv(adap);
+ i2c_pnx_master_rcv(alg_data);
}
}
}
@@ -379,7 +378,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
stat = ioread32(I2C_REG_STS(alg_data));
iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): exiting, stat = %x ctrl = %x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)));
@@ -388,14 +388,13 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
static void i2c_pnx_timeout(unsigned long data)
{
- struct i2c_adapter *adap = (struct i2c_adapter *)data;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
u32 ctl;
- dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. "
- "Resetting master...\n",
- ioread32(I2C_REG_STS(alg_data)),
- ioread32(I2C_REG_CTL(alg_data)));
+ dev_err(&alg_data->adapter.dev,
+ "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n",
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
/* Reset master and disable interrupts */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -409,15 +408,14 @@ static void i2c_pnx_timeout(unsigned long data)
complete(&alg_data->mif.complete);
}
-static inline void bus_reset_if_active(struct i2c_adapter *adap)
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 stat;
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
- dev_err(&adap->dev,
+ dev_err(&alg_data->adapter.dev,
"%s: Bus is still active after xfer. Reset it...\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
@@ -451,10 +449,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 stat = ioread32(I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): entering: %d messages, stat = %04x.\n",
__func__, num, ioread32(I2C_REG_STS(alg_data)));
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Process transactions in a loop. */
for (i = 0; rc >= 0 && i < num; i++) {
@@ -464,9 +463,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
addr = pmsg->addr;
if (pmsg->flags & I2C_M_TEN) {
- dev_err(&adap->dev,
+ dev_err(&alg_data->adapter.dev,
"%s: 10 bits addr not supported!\n",
- adap->name);
+ alg_data->adapter.name);
rc = -EINVAL;
break;
}
@@ -478,11 +477,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
alg_data->mif.ret = 0;
alg_data->last = (i == num - 1);
- dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
- alg_data->mif.mode,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+ __func__, alg_data->mif.mode, alg_data->mif.len);
- i2c_pnx_arm_timer(adap);
+ i2c_pnx_arm_timer(alg_data);
/* initialize the completion var */
init_completion(&alg_data->mif.complete);
@@ -493,7 +491,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
I2C_REG_CTL(alg_data));
/* Put start-code and slave-address on the bus. */
- rc = i2c_pnx_start(addr, adap);
+ rc = i2c_pnx_start(addr, alg_data);
if (rc < 0)
break;
@@ -502,31 +500,32 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (!(rc = alg_data->mif.ret))
completed++;
- dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Complete, return code = %d.\n",
__func__, rc);
/* Clear TDI and AFI bits in case they are set. */
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
- dev_dbg(&adap->dev,
+ dev_dbg(&alg_data->adapter.dev,
"%s: TDI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
- dev_dbg(&adap->dev,
+ dev_dbg(&alg_data->adapter.dev,
"%s: AFI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
}
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Cleanup to be sure... */
alg_data->mif.buf = NULL;
alg_data->mif.len = 0;
- dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
if (completed != num)
@@ -545,69 +544,92 @@ static struct i2c_algorithm pnx_algorithm = {
.functionality = i2c_pnx_func,
};
+#ifdef CONFIG_PM
static int i2c_pnx_controller_suspend(struct platform_device *pdev,
pm_message_t state)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- return i2c_pnx->suspend(pdev, state);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ /* FIXME: shouldn't this be clk_disable? */
+ clk_enable(alg_data->clk);
+
+ return 0;
}
static int i2c_pnx_controller_resume(struct platform_device *pdev)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- return i2c_pnx->resume(pdev);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ return clk_enable(alg_data->clk);
}
+#else
+#define i2c_pnx_controller_suspend NULL
+#define i2c_pnx_controller_resume NULL
+#endif
static int __devinit i2c_pnx_probe(struct platform_device *pdev)
{
unsigned long tmp;
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
- int freq_mhz;
+ unsigned long freq;
struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
- if (!i2c_pnx || !i2c_pnx->adapter) {
+ if (!i2c_pnx || !i2c_pnx->name) {
dev_err(&pdev->dev, "%s: no platform data supplied\n",
__func__);
ret = -EINVAL;
goto out;
}
- platform_set_drvdata(pdev, i2c_pnx);
-
- if (i2c_pnx->calculate_input_freq)
- freq_mhz = i2c_pnx->calculate_input_freq(pdev);
- else {
- freq_mhz = PNX_DEFAULT_FREQ;
- dev_info(&pdev->dev, "Setting bus frequency to default value: "
- "%d MHz\n", freq_mhz);
+ alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+ if (!alg_data) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
}
- i2c_pnx->adapter->algo = &pnx_algorithm;
+ platform_set_drvdata(pdev, alg_data);
+
+ strlcpy(alg_data->adapter.name, i2c_pnx->name,
+ sizeof(alg_data->adapter.name));
+ alg_data->adapter.dev.parent = &pdev->dev;
+ alg_data->adapter.algo = &pnx_algorithm;
+ alg_data->adapter.algo_data = alg_data;
+ alg_data->adapter.nr = pdev->id;
+ alg_data->i2c_pnx = i2c_pnx;
+
+ alg_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(alg_data->clk)) {
+ ret = PTR_ERR(alg_data->clk);
+ goto out_drvdata;
+ }
- alg_data = i2c_pnx->adapter->algo_data;
init_timer(&alg_data->mif.timer);
alg_data->mif.timer.function = i2c_pnx_timeout;
- alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
+ alg_data->mif.timer.data = (unsigned long)alg_data;
/* Register I/O resource */
- if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE,
+ if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
pdev->name)) {
dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n",
- alg_data->base);
+ i2c_pnx->base);
ret = -ENODEV;
- goto out_drvdata;
+ goto out_clkget;
}
- if (!(alg_data->ioaddr =
- (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+ alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ if (!alg_data->ioaddr) {
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
ret = -ENOMEM;
goto out_release;
}
- i2c_pnx->set_clock_run(pdev);
+ ret = clk_enable(alg_data->clk);
+ if (ret)
+ goto out_unmap;
+
+ freq = clk_get_rate(alg_data->clk);
/*
* Clock Divisor High This value is the number of system clocks
@@ -620,45 +642,47 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/
- tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));
iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
ret = -ENODEV;
- goto out_unmap;
+ goto out_clock;
}
init_completion(&alg_data->mif.complete);
- ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
- 0, pdev->name, i2c_pnx->adapter);
+ ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+ 0, pdev->name, alg_data);
if (ret)
goto out_clock;
/* Register this adapter with the I2C subsystem */
- i2c_pnx->adapter->dev.parent = &pdev->dev;
- i2c_pnx->adapter->nr = pdev->id;
- ret = i2c_add_numbered_adapter(i2c_pnx->adapter);
+ ret = i2c_add_numbered_adapter(&alg_data->adapter);
if (ret < 0) {
dev_err(&pdev->dev, "I2C: Failed to add bus\n");
goto out_irq;
}
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
- i2c_pnx->adapter->name, alg_data->base, alg_data->irq);
+ alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
return 0;
out_irq:
- free_irq(alg_data->irq, i2c_pnx->adapter);
+ free_irq(i2c_pnx->irq, alg_data);
out_clock:
- i2c_pnx->set_clock_stop(pdev);
+ clk_disable(alg_data->clk);
out_unmap:
- iounmap((void *)alg_data->ioaddr);
+ iounmap(alg_data->ioaddr);
out_release:
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+out_clkget:
+ clk_put(alg_data->clk);
out_drvdata:
+ kfree(alg_data);
+err_kzalloc:
platform_set_drvdata(pdev, NULL);
out:
return ret;
@@ -666,15 +690,16 @@ out:
static int __devexit i2c_pnx_remove(struct platform_device *pdev)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- struct i2c_adapter *adap = i2c_pnx->adapter;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
- free_irq(alg_data->irq, i2c_pnx->adapter);
- i2c_del_adapter(adap);
- i2c_pnx->set_clock_stop(pdev);
- iounmap((void *)alg_data->ioaddr);
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+ struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
+
+ free_irq(i2c_pnx->irq, alg_data);
+ i2c_del_adapter(&alg_data->adapter);
+ clk_disable(alg_data->clk);
+ iounmap(alg_data->ioaddr);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ clk_put(alg_data->clk);
+ kfree(alg_data);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 90d168a..84c103a 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -2,6 +2,7 @@
* linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ * Copyright (C) 2010 ST-Ericsson AB.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -34,9 +35,6 @@
#define DRIVER_NAME "mmci-pl18x"
-#define DBG(host,fmt,args...) \
- pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-
static unsigned int fmax = 515633;
/*
@@ -105,8 +103,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
void __iomem *base;
int blksz_bits;
- DBG(host, "blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
+ dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
+ data->blksz, data->blocks, data->flags);
host->data = data;
host->size = data->blksz;
@@ -155,7 +153,7 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
{
void __iomem *base = host->base;
- DBG(host, "op %02x arg %08x flags %08x\n",
+ dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
@@ -184,8 +182,20 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
{
if (status & MCI_DATABLOCKEND) {
host->data_xfered += data->blksz;
+#ifdef CONFIG_ARCH_U300
+ /*
+ * On the U300 some signal or other is
+ * badly routed so that a data write does
+ * not properly terminate with a MCI_DATAEND
+ * status flag. This quirk will make writes
+ * work again.
+ */
+ if (data->flags & MMC_DATA_WRITE)
+ status |= MCI_DATAEND;
+#endif
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+ dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
if (status & MCI_DATACRCFAIL)
data->error = -EILSEQ;
else if (status & MCI_DATATIMEOUT)
@@ -307,7 +317,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
status = readl(base + MMCISTATUS);
- DBG(host, "irq1 %08x\n", status);
+ dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
do {
unsigned long flags;
@@ -401,7 +411,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
status &= readl(host->base + MMCIMASK0);
writel(status, host->base + MMCICLEAR);
- DBG(host, "irq0 %08x\n", status);
+ dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
data = host->data;
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
@@ -428,8 +438,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(host->mrq != NULL);
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
- printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
- mmc_hostname(mmc), mrq->data->blksz);
+ dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
+ mrq->data->blksz);
mrq->cmd->error = -EINVAL;
mmc_request_done(mmc, mrq);
return;
@@ -582,8 +592,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host->hw_designer = amba_manf(dev);
host->hw_revision = amba_rev(dev);
- DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
- DBG(host, "revision = 0x%01x\n", host->hw_revision);
+ dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
+ dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
host->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(host->clk)) {
@@ -608,7 +618,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if (ret < 0)
goto clk_disable;
host->mclk = clk_get_rate(host->clk);
- DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
+ dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
+ host->mclk);
}
host->base = ioremap(dev->res.start, resource_size(&dev->res));
if (!host->base) {
@@ -619,6 +630,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc->ops = &mmci_ops;
mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax);
+ dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+
#ifdef CONFIG_REGULATOR
/* If we're using the regulator framework, try to fetch a regulator */
host->vcc = regulator_get(&dev->dev, "vmmc");
@@ -712,7 +725,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc_add_host(mmc);
- printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+ dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 0264b11..c256aac 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -7,6 +7,9 @@
*
* Copyright 2006 (c) MontaVista Software, Inc.
*
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * Copyright 2010 (c) ST-Ericsson AB
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -18,6 +21,9 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/version.h>
/*
* Register definitions
@@ -30,35 +36,207 @@
#define RTC_RIS 0x14 /* Raw interrupt status register */
#define RTC_MIS 0x18 /* Masked interrupt status register */
#define RTC_ICR 0x1c /* Interrupt clear register */
+/* ST variants have additional timer functionality */
+#define RTC_TDR 0x20 /* Timer data read register */
+#define RTC_TLR 0x24 /* Timer data load register */
+#define RTC_TCR 0x28 /* Timer control register */
+#define RTC_YDR 0x30 /* Year data read register */
+#define RTC_YMR 0x34 /* Year match register */
+#define RTC_YLR 0x38 /* Year data load register */
+
+#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
+
+#define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */
+
+/* Common bit definitions for Interrupt status and control registers */
+#define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */
+#define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
+
+/* Common bit definations for ST v2 for reading/writing time */
+#define RTC_SEC_SHIFT 0
+#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
+#define RTC_MIN_SHIFT 6
+#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
+#define RTC_HOUR_SHIFT 12
+#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
+#define RTC_WDAY_SHIFT 17
+#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
+#define RTC_MDAY_SHIFT 20
+#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
+#define RTC_MON_SHIFT 25
+#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
+
+#define RTC_TIMER_FREQ 32768
struct pl031_local {
struct rtc_device *rtc;
void __iomem *base;
+ u8 hw_designer;
+ u8 hw_revision:4;
};
-static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+static int pl031_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long imsc;
+
+ /* Clear any pending alarm interrupts. */
+ writel(RTC_BIT_AI, ldata->base + RTC_ICR);
+
+ imsc = readl(ldata->base + RTC_IMSC);
+
+ if (enabled == 1)
+ writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
+ else
+ writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
+
+ return 0;
+}
+
+/*
+ * Convert Gregorian date to ST v2 RTC format.
+ */
+static int pl031_stv2_tm_to_time(struct device *dev,
+ struct rtc_time *tm, unsigned long *st_time,
+ unsigned long *bcd_year)
+{
+ int year = tm->tm_year + 1900;
+ int wday = tm->tm_wday;
+
+ /* wday masking is not working in hardware so wday must be valid */
+ if (wday < -1 || wday > 6) {
+ dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
+ return -EINVAL;
+ } else if (wday == -1) {
+ /* wday is not provided, calculate it here */
+ unsigned long time;
+ struct rtc_time calc_tm;
+
+ rtc_tm_to_time(tm, &time);
+ rtc_time_to_tm(time, &calc_tm);
+ wday = calc_tm.tm_wday;
+ }
+
+ *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
+
+ *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
+ | (tm->tm_mday << RTC_MDAY_SHIFT)
+ | ((wday + 1) << RTC_WDAY_SHIFT)
+ | (tm->tm_hour << RTC_HOUR_SHIFT)
+ | (tm->tm_min << RTC_MIN_SHIFT)
+ | (tm->tm_sec << RTC_SEC_SHIFT);
+
+ return 0;
+}
+
+/*
+ * Convert ST v2 RTC format to Gregorian date.
+ */
+static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
+ struct rtc_time *tm)
+{
+ tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
+ tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
+ tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
+ tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
+ tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
+ tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
+ tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
+
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year -= 1900;
+
+ return 0;
+}
+
+static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
+ readl(ldata->base + RTC_YDR), tm);
+
+ return 0;
+}
+
+static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ unsigned long bcd_year;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YLR);
+ writel(time, ldata->base + RTC_LR);
+ }
+
+ return ret;
+}
+
+static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct rtc_device *rtc = dev_id;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_update_irq(rtc, 1, RTC_AF);
+ ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
+ readl(ldata->base + RTC_YMR), &alarm->time);
- return IRQ_HANDLED;
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
+
+ return ret;
}
-static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long time;
+ unsigned long bcd_year;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = pl031_stv2_tm_to_time(dev, &alarm->time,
+ &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YMR);
+ writel(time, ldata->base + RTC_MR);
+
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+{
+ struct pl031_local *ldata = dev_id;
+ unsigned long rtcmis;
+ unsigned long events = 0;
+
+ rtcmis = readl(ldata->base + RTC_MIS);
+ if (rtcmis) {
+ writel(rtcmis, ldata->base + RTC_ICR);
+
+ if (rtcmis & RTC_BIT_AI)
+ events |= (RTC_AF | RTC_IRQF);
+
+ /* Timer interrupt is only available in ST variants */
+ if ((rtcmis & RTC_BIT_PI) &&
+ (ldata->hw_designer == AMBA_VENDOR_ST))
+ events |= (RTC_PF | RTC_IRQF);
+
+ rtc_update_irq(ldata->rtc, 1, events);
- switch (cmd) {
- case RTC_AIE_OFF:
- writel(1, ldata->base + RTC_MIS);
- return 0;
- case RTC_AIE_ON:
- writel(0, ldata->base + RTC_MIS);
- return 0;
+ return IRQ_HANDLED;
}
- return -ENOIOCTLCMD;
+ return IRQ_NONE;
}
static int pl031_read_time(struct device *dev, struct rtc_time *tm)
@@ -74,11 +252,14 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned long time;
struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_tm_to_time(tm, &time);
- writel(time, ldata->base + RTC_LR);
+ ret = rtc_tm_to_time(tm, &time);
- return 0;
+ if (ret == 0)
+ writel(time, ldata->base + RTC_LR);
+
+ return ret;
}
static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
@@ -86,8 +267,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
struct pl031_local *ldata = dev_get_drvdata(dev);
rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
- alarm->pending = readl(ldata->base + RTC_RIS);
- alarm->enabled = readl(ldata->base + RTC_IMSC);
+
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
return 0;
}
@@ -96,22 +278,71 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
unsigned long time;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = rtc_tm_to_time(&alarm->time, &time);
+ if (ret == 0) {
+ writel(time, ldata->base + RTC_MR);
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+/* Periodic interrupt is only available in ST variants. */
+static int pl031_irq_set_state(struct device *dev, int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ if (enabled == 1) {
+ /* Clear any pending timer interrupt. */
+ writel(RTC_BIT_PI, ldata->base + RTC_ICR);
+
+ writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
+ ldata->base + RTC_IMSC);
- rtc_tm_to_time(&alarm->time, &time);
+ /* Now start the timer */
+ writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
+ ldata->base + RTC_TCR);
- writel(time, ldata->base + RTC_MR);
- writel(!alarm->enabled, ldata->base + RTC_MIS);
+ } else {
+ writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
+ ldata->base + RTC_IMSC);
+
+ /* Also stop the timer */
+ writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
+ ldata->base + RTC_TCR);
+ }
+ /* Wait at least 1 RTC32 clock cycle to ensure next access
+ * to RTC_TCR will succeed.
+ */
+ udelay(40);
return 0;
}
-static const struct rtc_class_ops pl031_ops = {
- .ioctl = pl031_ioctl,
- .read_time = pl031_read_time,
- .set_time = pl031_set_time,
- .read_alarm = pl031_read_alarm,
- .set_alarm = pl031_set_alarm,
-};
+static int pl031_irq_set_freq(struct device *dev, int freq)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ /* Cant set timer if it is already enabled */
+ if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
+ dev_err(dev, "can't change frequency while timer enabled\n");
+ return -EINVAL;
+ }
+
+ /* If self start bit in RTC_TCR is set timer will start here,
+ * but we never set that bit. Instead we start the timer when
+ * set_state is called with enabled == 1.
+ */
+ writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
+
+ return 0;
+}
static int pl031_remove(struct amba_device *adev)
{
@@ -131,18 +362,20 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
{
int ret;
struct pl031_local *ldata;
+ struct rtc_class_ops *ops = id->data;
ret = amba_request_regions(adev, NULL);
if (ret)
goto err_req;
- ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+ ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
if (!ldata) {
ret = -ENOMEM;
goto out;
}
ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
+
if (!ldata->base) {
ret = -ENOMEM;
goto out_no_remap;
@@ -150,24 +383,36 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
amba_set_drvdata(adev, ldata);
- if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED,
- "rtc-pl031", ldata->rtc)) {
- ret = -EIO;
- goto out_no_irq;
- }
+ ldata->hw_designer = amba_manf(adev);
+ ldata->hw_revision = amba_rev(adev);
+
+ dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
+ dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
- ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
- THIS_MODULE);
+ /* Enable the clockwatch on ST Variants */
+ if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
+ (ldata->hw_revision > 1))
+ writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
+ ldata->base + RTC_CR);
+
+ ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
+ THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc);
goto out_no_rtc;
}
+ if (request_irq(adev->irq[0], pl031_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+
return 0;
-out_no_rtc:
- free_irq(adev->irq[0], ldata->rtc);
out_no_irq:
+ rtc_device_unregister(ldata->rtc);
+out_no_rtc:
iounmap(ldata->base);
amba_set_drvdata(adev, NULL);
out_no_remap:
@@ -175,13 +420,57 @@ out_no_remap:
out:
amba_release_regions(adev);
err_req:
+
return ret;
}
+/* Operations for the original ARM version */
+static struct rtc_class_ops arm_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+};
+
+/* The First ST derivative */
+static struct rtc_class_ops stv1_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
+/* And the second ST derivative */
+static struct rtc_class_ops stv2_pl031_ops = {
+ .read_time = pl031_stv2_read_time,
+ .set_time = pl031_stv2_set_time,
+ .read_alarm = pl031_stv2_read_alarm,
+ .set_alarm = pl031_stv2_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
static struct amba_id pl031_ids[] __initdata = {
{
.id = 0x00041031,
.mask = 0x000fffff,
+ .data = &arm_pl031_ops,
+ },
+ /* ST Micro variants */
+ {
+ .id = 0x00180031,
+ .mask = 0x00ffffff,
+ .data = &stv1_pl031_ops,
+ },
+ {
+ .id = 0x00280031,
+ .mask = 0x00ffffff,
+ .data = &stv2_pl031_ops,
},
{0, 0},
};
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index ef7adc8..ce6c353 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -71,6 +71,7 @@ struct uart_amba_port {
unsigned int im; /* interrupt mask */
unsigned int old_status;
unsigned int ifls; /* vendor-specific */
+ bool autorts;
};
/* There is by now at least one vendor with differing details, so handle it */
@@ -308,6 +309,11 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+
+ if (uap->autorts) {
+ /* We need to disable auto-RTS if we want to turn RTS off */
+ TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+ }
#undef TIOCMBIT
writew(cr, uap->port.membase + UART011_CR);
@@ -437,6 +443,7 @@ static void pl011_shutdown(struct uart_port *port)
/*
* disable the port
*/
+ uap->autorts = false;
writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
/*
@@ -456,6 +463,7 @@ static void
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
@@ -532,6 +540,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
old_cr = readw(port->membase + UART011_CR);
writew(0, port->membase + UART011_CR);
+ if (termios->c_cflag & CRTSCTS) {
+ if (old_cr & UART011_CR_RTS)
+ old_cr |= UART011_CR_RTSEN;
+
+ old_cr |= UART011_CR_CTSEN;
+ uap->autorts = true;
+ } else {
+ old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
+ uap->autorts = false;
+ }
+
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index ff5bbb9..9aeb681 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -363,6 +363,7 @@ struct pl022 {
void *rx_end;
enum ssp_reading read;
enum ssp_writing write;
+ u32 exp_fifo_level;
};
/**
@@ -501,6 +502,9 @@ static int flush(struct pl022 *pl022)
while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
readw(SSP_DR(pl022->virtbase));
} while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+
+ pl022->exp_fifo_level = 0;
+
return limit;
}
@@ -583,10 +587,9 @@ static void readwriter(struct pl022 *pl022)
* errons in 8bit wide transfers on ARM variants (just 8 words
* FIFO, means only 8x8 = 64 bits in FIFO) at least.
*
- * FIXME: currently we have no logic to account for this.
- * perhaps there is even something broken in HW regarding
- * 8bit transfers (it doesn't fail on 16bit) so this needs
- * more investigation...
+ * To prevent this issue, the TX FIFO is only filled to the
+ * unused RX FIFO fill length, regardless of what the TX
+ * FIFO status flag indicates.
*/
dev_dbg(&pl022->adev->dev,
"%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
@@ -613,11 +616,12 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->rx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level--;
}
/*
- * Write as much as you can, while keeping an eye on the RX FIFO!
+ * Write as much as possible up to the RX FIFO size
*/
- while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+ while ((pl022->exp_fifo_level < pl022->vendor->fifodepth)
&& (pl022->tx < pl022->tx_end)) {
switch (pl022->write) {
case WRITING_NULL:
@@ -634,6 +638,7 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->tx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level++;
/*
* This inner reader takes care of things appearing in the RX
* FIFO as we're transmitting. This will happen a lot since the
@@ -660,6 +665,7 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->rx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level--;
}
}
/*
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 430a584..c7a9479 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -96,9 +96,6 @@ static void wdt_enable(void)
{
spin_lock(&io_lock);
- if (wdt_clk)
- clk_set_rate(wdt_clk, 1);
-
/* stop counter, initiate counter reset */
__raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
/*wait for reset to complete. 100% guarantee event */
@@ -125,19 +122,25 @@ static void wdt_disable(void)
spin_lock(&io_lock);
__raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
- if (wdt_clk)
- clk_set_rate(wdt_clk, 0);
spin_unlock(&io_lock);
}
static int pnx4008_wdt_open(struct inode *inode, struct file *file)
{
+ int ret;
+
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ ret = clk_enable(wdt_clk);
+ if (ret) {
+ clear_bit(WDT_IN_USE, &wdt_status);
+ return ret;
+ }
+
wdt_enable();
return nonseekable_open(inode, file);
@@ -225,6 +228,7 @@ static int pnx4008_wdt_release(struct inode *inode, struct file *file)
printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
wdt_disable();
+ clk_disable(wdt_clk);
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@@ -273,25 +277,33 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
}
wdt_base = (void __iomem *)IO_ADDRESS(res->start);
- wdt_clk = clk_get(&pdev->dev, "wdt_ck");
+ wdt_clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(wdt_clk)) {
ret = PTR_ERR(wdt_clk);
release_resource(wdt_mem);
kfree(wdt_mem);
goto out;
- } else
- clk_set_rate(wdt_clk, 1);
+ }
+
+ ret = clk_enable(wdt_clk);
+ if (ret) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ goto out;
+ }
ret = misc_register(&pnx4008_wdt_miscdev);
if (ret < 0) {
printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
release_resource(wdt_mem);
kfree(wdt_mem);
- clk_set_rate(wdt_clk, 0);
+ clk_disable(wdt_clk);
+ clk_put(wdt_clk);
} else {
boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
WDIOF_CARDRESET : 0;
wdt_disable(); /*disable for now */
+ clk_disable(wdt_clk);
set_bit(WDT_DEVICE_INITED, &wdt_status);
}
@@ -302,11 +314,10 @@ out:
static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&pnx4008_wdt_miscdev);
- if (wdt_clk) {
- clk_set_rate(wdt_clk, 0);
- clk_put(wdt_clk);
- wdt_clk = NULL;
- }
+
+ clk_disable(wdt_clk);
+ clk_put(wdt_clk);
+
if (wdt_mem) {
release_resource(wdt_mem);
kfree(wdt_mem);
OpenPOWER on IntegriCloud