*
* Revision history:
* 22nd Aug 2003 Initial version.
- *
+ * 20th Dec 2004 Added ssp_config for changing port config without
+ * closing the port.
*/
#include <linux/module.h>
#include <asm/arch/ssp.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)
{
struct ssp_dev *dev = (struct ssp_dev*) dev_id;
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
*
* %-EBUSY if the resources are already in use
* %0 on success
*/
-int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
- u32 speed)
+int ssp_init(struct ssp_dev *dev, u32 port)
{
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")) {
+ use_count[port - 1]--;
+ up(&sem);
return -EBUSY;
}
}
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);
if (ret)
#endif
}
+ up(&sem);
return 0;
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;
}
{
int irq;
+ down(&sem);
SSCR0_P(dev->port) &= ~SSCR0_SSE;
/* find irq, save power and turn off SSP port clock */
free_irq(irq, dev);
release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ use_count[dev->port - 1]--;
+ up(&sem);
}
EXPORT_SYMBOL(ssp_write_word);
EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit);
+EXPORT_SYMBOL(ssp_config);
+
+MODULE_DESCRIPTION("PXA SSP driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+