Commit a3d9d59d authored by Liam Girdwood's avatar Liam Girdwood Committed by Russell King

[ARM PATCH] 2342/1: Support PXA SSP configuration changes when port is open

Patch from Liam Girdwood

This patch allows the PXA SSP port configuration to be changed without
the need to close the port.

Signed-off-by: Liam Girdwood
Signed-off-by: Russell King
parent 1d4d960c
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
* *
* Revision history: * Revision history:
* 22nd Aug 2003 Initial version. * 22nd Aug 2003 Initial version.
* * 20th Dec 2004 Added ssp_config for changing port config without
* closing the port.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -34,6 +35,11 @@ ...@@ -34,6 +35,11 @@
#include <asm/arch/ssp.h> #include <asm/arch/ssp.h>
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#define PXA_SSP_PORTS 3
static DECLARE_MUTEX(sem);
static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct ssp_dev *dev = (struct ssp_dev*) dev_id; struct ssp_dev *dev = (struct ssp_dev*) dev_id;
...@@ -170,6 +176,30 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) ...@@ -170,6 +176,30 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
SSCR0_P(dev->port) = ssp->cr0; SSCR0_P(dev->port) = ssp->cr0;
} }
/**
* ssp_config - configure SSP port settings
* @mode: port operating mode
* @flags: port config flags
* @psp_flags: port PSP config flags
* @speed: port speed
*
* Port MUST be disabled by ssp_disable before making any config changes.
*/
int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
{
dev->mode = mode;
dev->flags = flags;
dev->psp_flags = psp_flags;
dev->speed = speed;
/* set up port type, speed, port settings */
SSCR0_P(dev->port) = (dev->speed | dev->mode);
SSCR1_P(dev->port) = dev->flags;
SSPSP_P(dev->port) = dev->psp_flags;
return 0;
}
/** /**
* ssp_init - setup the SSP port * ssp_init - setup the SSP port
* *
...@@ -180,12 +210,23 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) ...@@ -180,12 +210,23 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
* %-EBUSY if the resources are already in use * %-EBUSY if the resources are already in use
* %0 on success * %0 on success
*/ */
int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags, int ssp_init(struct ssp_dev *dev, u32 port)
u32 speed)
{ {
int ret, irq; int ret, irq;
if (port > PXA_SSP_PORTS || port == 0)
return -ENODEV;
down(&sem);
if (use_count[port - 1]) {
up(&sem);
return -EBUSY;
}
use_count[port - 1]++;
if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
use_count[port - 1]--;
up(&sem);
return -EBUSY; return -EBUSY;
} }
...@@ -213,15 +254,6 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags, ...@@ -213,15 +254,6 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
} }
dev->port = port; dev->port = port;
dev->mode = mode;
dev->flags = flags;
dev->psp_flags = psp_flags;
dev->speed = speed;
/* set up port type, speed, port settings */
SSCR0_P(dev->port) = (dev->speed | dev->mode);
SSCR1_P(dev->port) = dev->flags;
SSPSP_P(dev->port) = dev->psp_flags;
ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev); ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
if (ret) if (ret)
...@@ -252,10 +284,13 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags, ...@@ -252,10 +284,13 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
#endif #endif
} }
up(&sem);
return 0; return 0;
out_region: out_region:
release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
use_count[port - 1]--;
up(&sem);
return ret; return ret;
} }
...@@ -268,6 +303,7 @@ void ssp_exit(struct ssp_dev *dev) ...@@ -268,6 +303,7 @@ void ssp_exit(struct ssp_dev *dev)
{ {
int irq; int irq;
down(&sem);
SSCR0_P(dev->port) &= ~SSCR0_SSE; SSCR0_P(dev->port) &= ~SSCR0_SSE;
/* find irq, save power and turn off SSP port clock */ /* find irq, save power and turn off SSP port clock */
...@@ -306,6 +342,8 @@ void ssp_exit(struct ssp_dev *dev) ...@@ -306,6 +342,8 @@ void ssp_exit(struct ssp_dev *dev)
free_irq(irq, dev); free_irq(irq, dev);
release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
use_count[dev->port - 1]--;
up(&sem);
} }
EXPORT_SYMBOL(ssp_write_word); EXPORT_SYMBOL(ssp_write_word);
...@@ -317,3 +355,9 @@ EXPORT_SYMBOL(ssp_save_state); ...@@ -317,3 +355,9 @@ EXPORT_SYMBOL(ssp_save_state);
EXPORT_SYMBOL(ssp_restore_state); EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init); EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit); EXPORT_SYMBOL(ssp_exit);
EXPORT_SYMBOL(ssp_config);
MODULE_DESCRIPTION("PXA SSP driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");
...@@ -40,8 +40,8 @@ void ssp_enable(struct ssp_dev *dev); ...@@ -40,8 +40,8 @@ void ssp_enable(struct ssp_dev *dev);
void ssp_disable(struct ssp_dev *dev); void ssp_disable(struct ssp_dev *dev);
void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp); void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp);
void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp); void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp);
int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags, int ssp_init(struct ssp_dev *dev, u32 port);
u32 speed); int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed);
void ssp_exit(struct ssp_dev *dev); void ssp_exit(struct ssp_dev *dev);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment