From cd41e28e2d0f198ad56840bf8ba13cb41b129bab Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Apr 2006 15:43:41 -0300 Subject: V4L/DVB (3774): Create V4L1 config options V4L1 API is depreciated and should be removed soon from kernel. This patch adds two new options, one to disable V4L1 drivers, and another to disable V4L1 compat module. This way, it would be easy to check what still depends on V4L1 stuff, allowing also to test if app works fine with V4L2 only support. Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index d7670ec1ec1..ad7fa9c86c1 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1141,8 +1141,13 @@ extern char *v4l2_type_names[]; /* Compatibility layer interface -- v4l1-compat module */ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, unsigned int cmd, void *arg); + +#ifdef CONFIG_VIDEO_V4L1_COMPAT int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, int cmd, void *arg, v4l2_kioctl driver_ioctl); +#else +#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL +#endif /* 32 Bits compatibility layer for 64 bits processors */ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd, -- cgit v1.2.3-70-g09d2 From ccf06998fe179ae2cc9517ed1d75433dc0b5032d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 20 May 2006 15:00:15 -0700 Subject: [PATCH] spi: add spi master driver for Freescale MPC83xx SPI controller This driver supports the SPI controller on the MPC83xx SoC devices from Freescale. Note, this driver supports only the simple shift register SPI controller and not the descriptor based CPM or QUICCEngine SPI controller. Signed-off-by: Kumar Gala Signed-off-by: David Brownell Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/Kconfig | 12 ++ drivers/spi/Makefile | 1 + drivers/spi/spi_mpc83xx.c | 483 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/fsl_devices.h | 11 + 4 files changed, 507 insertions(+) create mode 100644 drivers/spi/spi_mpc83xx.c (limited to 'include') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9ce1d01469b..3867c6ef24f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -75,6 +75,18 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_MPC83xx + tristate "Freescale MPC83xx SPI controller" + depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL + select SPI_BITBANG + help + This enables using the Freescale MPC83xx SPI controller in master + mode. + + Note, this driver uniquely supports the SPI controller on the MPC83xx + family of PowerPC processors. The MPC83xx uses a simple set of shift + registers for data (opposed to the CPM based descriptor model). + config SPI_PXA2XX tristate "PXA2xx SSP SPI master" depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 1bca5f95de2..5a410caa03c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o +obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c new file mode 100644 index 00000000000..5d92a7e5cb4 --- /dev/null +++ b/drivers/spi/spi_mpc83xx.c @@ -0,0 +1,483 @@ +/* + * MPC83xx SPI controller driver. + * + * Maintainer: Kumar Gala + * + * Copyright (C) 2006 Polycom, Inc. + * + * 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 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* SPI Controller registers */ +struct mpc83xx_spi_reg { + u8 res1[0x20]; + __be32 mode; + __be32 event; + __be32 mask; + __be32 command; + __be32 transmit; + __be32 receive; +}; + +/* SPI Controller mode register definitions */ +#define SPMODE_CI_INACTIVEHIGH (1 << 29) +#define SPMODE_CP_BEGIN_EDGECLK (1 << 28) +#define SPMODE_DIV16 (1 << 27) +#define SPMODE_REV (1 << 26) +#define SPMODE_MS (1 << 25) +#define SPMODE_ENABLE (1 << 24) +#define SPMODE_LEN(x) ((x) << 20) +#define SPMODE_PM(x) ((x) << 16) + +/* + * Default for SPI Mode: + * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk + */ +#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \ + SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf)) + +/* SPIE register values */ +#define SPIE_NE 0x00000200 /* Not empty */ +#define SPIE_NF 0x00000100 /* Not full */ + +/* SPIM register values */ +#define SPIM_NE 0x00000200 /* Not empty */ +#define SPIM_NF 0x00000100 /* Not full */ + +/* SPI Controller driver's private data. */ +struct mpc83xx_spi { + /* bitbang has to be first */ + struct spi_bitbang bitbang; + struct completion done; + + struct mpc83xx_spi_reg __iomem *base; + + /* rx & tx bufs from the spi_transfer */ + const void *tx; + void *rx; + + /* functions to deal with different sized buffers */ + void (*get_rx) (u32 rx_data, struct mpc83xx_spi *); + u32(*get_tx) (struct mpc83xx_spi *); + + unsigned int count; + u32 irq; + + unsigned nsecs; /* (clock cycle time)/2 */ + + u32 sysclk; + void (*activate_cs) (u8 cs, u8 polarity); + void (*deactivate_cs) (u8 cs, u8 polarity); +}; + +static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val) +{ + out_be32(reg, val); +} + +static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg) +{ + return in_be32(reg); +} + +#define MPC83XX_SPI_RX_BUF(type) \ +void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \ +{ \ + type * rx = mpc83xx_spi->rx; \ + *rx++ = (type)data; \ + mpc83xx_spi->rx = rx; \ +} + +#define MPC83XX_SPI_TX_BUF(type) \ +u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \ +{ \ + u32 data; \ + const type * tx = mpc83xx_spi->tx; \ + data = *tx++; \ + mpc83xx_spi->tx = tx; \ + return data; \ +} + +MPC83XX_SPI_RX_BUF(u8) +MPC83XX_SPI_RX_BUF(u16) +MPC83XX_SPI_RX_BUF(u32) +MPC83XX_SPI_TX_BUF(u8) +MPC83XX_SPI_TX_BUF(u16) +MPC83XX_SPI_TX_BUF(u32) + +static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) +{ + struct mpc83xx_spi *mpc83xx_spi; + u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0; + + mpc83xx_spi = spi_master_get_devdata(spi->master); + + if (value == BITBANG_CS_INACTIVE) { + if (mpc83xx_spi->deactivate_cs) + mpc83xx_spi->deactivate_cs(spi->chip_select, pol); + } + + if (value == BITBANG_CS_ACTIVE) { + u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); + u32 len = spi->bits_per_word; + if (len == 32) + len = 0; + else + len = len - 1; + + /* mask out bits we are going to set */ + regval &= ~0x38ff0000; + + if (spi->mode & SPI_CPHA) + regval |= SPMODE_CP_BEGIN_EDGECLK; + if (spi->mode & SPI_CPOL) + regval |= SPMODE_CI_INACTIVEHIGH; + + regval |= SPMODE_LEN(len); + + if ((mpc83xx_spi->sysclk / spi->max_speed_hz) >= 64) { + u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64); + regval |= SPMODE_PM(pm) | SPMODE_DIV16; + } else { + u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4); + regval |= SPMODE_PM(pm); + } + + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); + if (mpc83xx_spi->activate_cs) + mpc83xx_spi->activate_cs(spi->chip_select, pol); + } +} + +static +int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct mpc83xx_spi *mpc83xx_spi; + u32 regval; + u8 bits_per_word; + u32 hz; + + mpc83xx_spi = spi_master_get_devdata(spi->master); + + if (t) { + bits_per_word = t->bits_per_word; + hz = t->speed_hz; + } else { + bits_per_word = 0; + hz = 0; + } + + /* spi_transfer level calls that work per-word */ + if (!bits_per_word) + bits_per_word = spi->bits_per_word; + + /* Make sure its a bit width we support [4..16, 32] */ + if ((bits_per_word < 4) + || ((bits_per_word > 16) && (bits_per_word != 32))) + return -EINVAL; + + if (bits_per_word <= 8) { + mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8; + mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8; + } else if (bits_per_word <= 16) { + mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16; + mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16; + } else if (bits_per_word <= 32) { + mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32; + mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32; + } else + return -EINVAL; + + /* nsecs = (clock period)/2 */ + if (!hz) + hz = spi->max_speed_hz; + mpc83xx_spi->nsecs = (1000000000 / 2) / hz; + if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000) + return -EINVAL; + + if (bits_per_word == 32) + bits_per_word = 0; + else + bits_per_word = bits_per_word - 1; + + regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); + + /* Mask out bits_per_wordgth */ + regval &= 0xff0fffff; + regval |= SPMODE_LEN(bits_per_word); + + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); + + return 0; +} + +static int mpc83xx_spi_setup(struct spi_device *spi) +{ + struct spi_bitbang *bitbang; + struct mpc83xx_spi *mpc83xx_spi; + int retval; + + if (!spi->max_speed_hz) + return -EINVAL; + + bitbang = spi_master_get_devdata(spi->master); + mpc83xx_spi = spi_master_get_devdata(spi->master); + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + retval = mpc83xx_spi_setup_transfer(spi, NULL); + if (retval < 0) + return retval; + + dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", + __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), + spi->bits_per_word, 2 * mpc83xx_spi->nsecs); + + /* NOTE we _need_ to call chipselect() early, ideally with adapter + * setup, unless the hardware defaults cooperate to avoid confusion + * between normal (active low) and inverted chipselects. + */ + + /* deselect chip (low or high) */ + spin_lock(&bitbang->lock); + if (!bitbang->busy) { + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(mpc83xx_spi->nsecs); + } + spin_unlock(&bitbang->lock); + + return 0; +} + +static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct mpc83xx_spi *mpc83xx_spi; + u32 word; + + mpc83xx_spi = spi_master_get_devdata(spi->master); + + mpc83xx_spi->tx = t->tx_buf; + mpc83xx_spi->rx = t->rx_buf; + mpc83xx_spi->count = t->len; + INIT_COMPLETION(mpc83xx_spi->done); + + /* enable rx ints */ + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE); + + /* transmit word */ + word = mpc83xx_spi->get_tx(mpc83xx_spi); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word); + + wait_for_completion(&mpc83xx_spi->done); + + /* disable rx ints */ + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0); + + return t->len - mpc83xx_spi->count; +} + +irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data, + struct pt_regs * ptregs) +{ + struct mpc83xx_spi *mpc83xx_spi = context_data; + u32 event; + irqreturn_t ret = IRQ_NONE; + + /* Get interrupt events(tx/rx) */ + event = mpc83xx_spi_read_reg(&mpc83xx_spi->base->event); + + /* We need handle RX first */ + if (event & SPIE_NE) { + u32 rx_data = mpc83xx_spi_read_reg(&mpc83xx_spi->base->receive); + + if (mpc83xx_spi->rx) + mpc83xx_spi->get_rx(rx_data, mpc83xx_spi); + + ret = IRQ_HANDLED; + } + + if ((event & SPIE_NF) == 0) + /* spin until TX is done */ + while (((event = + mpc83xx_spi_read_reg(&mpc83xx_spi->base->event)) & + SPIE_NF) == 0) + cpu_relax(); + + mpc83xx_spi->count -= 1; + if (mpc83xx_spi->count) { + if (mpc83xx_spi->tx) { + u32 word = mpc83xx_spi->get_tx(mpc83xx_spi); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, + word); + } + } else { + complete(&mpc83xx_spi->done); + } + + /* Clear the events */ + mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, event); + + return ret; +} + +static int __init mpc83xx_spi_probe(struct platform_device *dev) +{ + struct spi_master *master; + struct mpc83xx_spi *mpc83xx_spi; + struct fsl_spi_platform_data *pdata; + struct resource *r; + u32 regval; + int ret = 0; + + /* Get resources(memory, IRQ) associated with the device */ + master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi)); + + if (master == NULL) { + ret = -ENOMEM; + goto err; + } + + platform_set_drvdata(dev, master); + pdata = dev->dev.platform_data; + + if (pdata == NULL) { + ret = -ENODEV; + goto free_master; + } + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENODEV; + goto free_master; + } + + mpc83xx_spi = spi_master_get_devdata(master); + mpc83xx_spi->bitbang.master = spi_master_get(master); + mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect; + mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer; + mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs; + mpc83xx_spi->sysclk = pdata->sysclk; + mpc83xx_spi->activate_cs = pdata->activate_cs; + mpc83xx_spi->deactivate_cs = pdata->deactivate_cs; + mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8; + mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8; + + mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup; + init_completion(&mpc83xx_spi->done); + + mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1); + if (mpc83xx_spi->base == NULL) { + ret = -ENOMEM; + goto put_master; + } + + mpc83xx_spi->irq = platform_get_irq(dev, 0); + + if (mpc83xx_spi->irq < 0) { + ret = -ENXIO; + goto unmap_io; + } + + /* Register for SPI Interrupt */ + ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq, + 0, "mpc83xx_spi", mpc83xx_spi); + + if (ret != 0) + goto unmap_io; + + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->max_chipselect; + + /* SPI controller initializations */ + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff); + + /* Enable SPI interface */ + regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; + mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); + + ret = spi_bitbang_start(&mpc83xx_spi->bitbang); + + if (ret != 0) + goto free_irq; + + printk(KERN_INFO + "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n", + dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq); + + return ret; + +free_irq: + free_irq(mpc83xx_spi->irq, mpc83xx_spi); +unmap_io: + iounmap(mpc83xx_spi->base); +put_master: + spi_master_put(master); +free_master: + kfree(master); +err: + return ret; +} + +static int __devexit mpc83xx_spi_remove(struct platform_device *dev) +{ + struct mpc83xx_spi *mpc83xx_spi; + struct spi_master *master; + + master = platform_get_drvdata(dev); + mpc83xx_spi = spi_master_get_devdata(master); + + spi_bitbang_stop(&mpc83xx_spi->bitbang); + free_irq(mpc83xx_spi->irq, mpc83xx_spi); + iounmap(mpc83xx_spi->base); + spi_master_put(mpc83xx_spi->bitbang.master); + + return 0; +} + +static struct platform_driver mpc83xx_spi_driver = { + .probe = mpc83xx_spi_probe, + .remove = __devexit_p(mpc83xx_spi_remove), + .driver = { + .name = "mpc83xx_spi", + }, +}; + +static int __init mpc83xx_spi_init(void) +{ + return platform_driver_register(&mpc83xx_spi_driver); +} + +static void __exit mpc83xx_spi_exit(void) +{ + platform_driver_unregister(&mpc83xx_spi_driver); +} + +module_init(mpc83xx_spi_init); +module_exit(mpc83xx_spi_exit); + +MODULE_AUTHOR("Kumar Gala"); +MODULE_DESCRIPTION("Simple MPC83xx SPI Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index a3a0e078f79..16fbe59edeb 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -110,5 +110,16 @@ struct fsl_usb2_platform_data { #define FSL_USB2_PORT0_ENABLED 0x00000001 #define FSL_USB2_PORT1_ENABLED 0x00000002 +struct fsl_spi_platform_data { + u32 initial_spmode; /* initial SPMODE value */ + u16 bus_num; + + /* board specific information */ + u16 max_chipselect; + void (*activate_cs)(u8 cs, u8 polarity); + void (*deactivate_cs)(u8 cs, u8 polarity); + u32 sysclk; +}; + #endif /* _FSL_DEVICE_H_ */ #endif /* __KERNEL__ */ -- cgit v1.2.3-70-g09d2 From 1b81d6637d27a0e6a0506ecef65493b50d859cfc Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 20 May 2006 15:00:16 -0700 Subject: [PATCH] drivers/base/firmware_class.c: cleanups - remove the following global function that is both unused and unimplemented: - register_firmware() - make the following needlessly global function static: - firmware_class_uevent() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/firmware_class/README | 17 ---------- .../firmware_class/firmware_sample_driver.c | 11 ------ drivers/base/firmware_class.c | 39 +++++----------------- include/linux/firmware.h | 1 - 4 files changed, 8 insertions(+), 60 deletions(-) (limited to 'include') diff --git a/Documentation/firmware_class/README b/Documentation/firmware_class/README index 43e836c07ae..e9cc8bb26f7 100644 --- a/Documentation/firmware_class/README +++ b/Documentation/firmware_class/README @@ -105,20 +105,3 @@ on the setup, so I think that the choice on what firmware to make persistent should be left to userspace. - - Why register_firmware()+__init can be useful: - - For boot devices needing firmware. - - To make the transition easier: - The firmware can be declared __init and register_firmware() - called on module_init. Then the firmware is warranted to be - there even if "firmware hotplug userspace" is not there yet or - it doesn't yet provide the needed firmware. - Once the firmware is widely available in userspace, it can be - removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE). - - In either case, if firmware hotplug support is there, it can move the - firmware out of kernel memory into the real filesystem for later - usage. - - Note: If persistence is implemented on top of initramfs, - register_firmware() may not be appropriate. - diff --git a/Documentation/firmware_class/firmware_sample_driver.c b/Documentation/firmware_class/firmware_sample_driver.c index ad3edaba453..87feccdb5c9 100644 --- a/Documentation/firmware_class/firmware_sample_driver.c +++ b/Documentation/firmware_class/firmware_sample_driver.c @@ -5,8 +5,6 @@ * * Sample code on how to use request_firmware() from drivers. * - * Note that register_firmware() is currently useless. - * */ #include @@ -17,11 +15,6 @@ #include "linux/firmware.h" -#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE -#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE -char __init inkernel_firmware[] = "let's say that this is firmware\n"; -#endif - static struct device ghost_device = { .bus_id = "ghost0", }; @@ -104,10 +97,6 @@ static void sample_probe_async(void) static int sample_init(void) { -#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE - register_firmware("sample_driver_fw", inkernel_firmware, - sizeof(inkernel_firmware)); -#endif device_initialize(&ghost_device); /* since there is no real hardware insertion I just call the * sample probe functions here */ diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 47231820523..0c99ae6a340 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -86,18 +86,9 @@ firmware_timeout_store(struct class *class, const char *buf, size_t count) static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_class_dev_release(struct class_device *class_dev); -int firmware_class_uevent(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); -static struct class firmware_class = { - .name = "firmware", - .uevent = firmware_class_uevent, - .release = fw_class_dev_release, -}; - -int -firmware_class_uevent(struct class_device *class_dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int firmware_class_uevent(struct class_device *class_dev, char **envp, + int num_envp, char *buffer, int buffer_size) { struct firmware_priv *fw_priv = class_get_devdata(class_dev); int i = 0, len = 0; @@ -116,6 +107,12 @@ firmware_class_uevent(struct class_device *class_dev, char **envp, return 0; } +static struct class firmware_class = { + .name = "firmware", + .uevent = firmware_class_uevent, + .release = fw_class_dev_release, +}; + static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf) { @@ -493,25 +490,6 @@ release_firmware(const struct firmware *fw) } } -/** - * register_firmware: - provide a firmware image for later usage - * @name: name of firmware image file - * @data: buffer pointer for the firmware image - * @size: size of the data buffer area - * - * Make sure that @data will be available by requesting firmware @name. - * - * Note: This will not be possible until some kind of persistence - * is available. - **/ -void -register_firmware(const char *name, const u8 *data, size_t size) -{ - /* This is meaningless without firmware caching, so until we - * decide if firmware caching is reasonable just leave it as a - * noop */ -} - /* Async support */ struct firmware_work { struct work_struct work; @@ -630,4 +608,3 @@ module_exit(firmware_class_exit); EXPORT_SYMBOL(release_firmware); EXPORT_SYMBOL(request_firmware); EXPORT_SYMBOL(request_firmware_nowait); -EXPORT_SYMBOL(register_firmware); diff --git a/include/linux/firmware.h b/include/linux/firmware.h index 2d716080be4..33d8f2087b6 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -19,5 +19,4 @@ int request_firmware_nowait( void (*cont)(const struct firmware *fw, void *context)); void release_firmware(const struct firmware *fw); -void register_firmware(const char *name, const u8 *data, size_t size); #endif -- cgit v1.2.3-70-g09d2 From 1fc7547d4bfe5c8c8c79e196b955b6fbaa21bfd2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 20 May 2006 15:00:17 -0700 Subject: [PATCH] S3C24XX: GPIO based SPI driver SPI driver for SPI by GPIO on the Samsung S3C24XX series of SoC processors. Signed-off-by: Ben Dooks Cc: Greg KH Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/Kconfig | 8 ++ drivers/spi/Makefile | 1 + drivers/spi/spi_butterfly.c | 1 + drivers/spi/spi_s3c24xx_gpio.c | 188 ++++++++++++++++++++++++++++++++ include/asm-arm/arch-s3c2410/spi-gpio.h | 31 ++++++ 5 files changed, 229 insertions(+) create mode 100644 drivers/spi/spi_s3c24xx_gpio.c create mode 100644 include/asm-arm/arch-s3c2410/spi-gpio.h (limited to 'include') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3867c6ef24f..c60dacfaadd 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -95,6 +95,14 @@ config SPI_PXA2XX The driver can be configured to use any SSP port and additional documentation can be found a Documentation/spi/pxa2xx. +config SPI_S3C24XX_GPIO + tristate "Samsung S3C24XX series SPI by GPIO" + depends on SPI_MASTER && ARCH_S3C2410 && SPI_BITBANG && EXPERIMENTAL + help + SPI driver for Samsung S3C24XX series ARM SoCs using + GPIO lines to provide the SPI bus. This can be used where + the inbuilt hardware cannot provide the transfer mode, or + where the board is using non hardware connected pins. # # Add new SPI master controllers in alphabetical order above this line # diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 5a410caa03c..4dc82c93bfe 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o +obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index ff9e5faa4dc..a006a1ee27a 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -321,6 +321,7 @@ static void butterfly_attach(struct parport *p) * (firmware resets at45, acts as spi slave) or neither (we ignore * both, AVR uses AT45). Here we expect firmware for the first option. */ + pp->info[0].max_speed_hz = 15 * 1000 * 1000; strcpy(pp->info[0].modalias, "mtd_dataflash"); pp->info[0].platform_data = &flash; diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c new file mode 100644 index 00000000000..aacdceb8f44 --- /dev/null +++ b/drivers/spi/spi_s3c24xx_gpio.c @@ -0,0 +1,188 @@ +/* linux/drivers/spi/spi_s3c24xx_gpio.c + * + * Copyright (c) 2006 Ben Dooks + * Copyright (c) 2006 Simtec Electronics + * + * S3C24XX GPIO based SPI driver + * + * 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 + * published by the Free Software Foundation. + * +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +struct s3c2410_spigpio { + struct spi_bitbang bitbang; + + struct s3c2410_spigpio_info *info; + struct platform_device *dev; +}; + +static inline struct s3c2410_spigpio *spidev_to_sg(struct spi_device *spi) +{ + return spi->controller_data; +} + +static inline void setsck(struct spi_device *dev, int on) +{ + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + s3c2410_gpio_setpin(sg->info->pin_clk, on ? 1 : 0); +} + +static inline void setmosi(struct spi_device *dev, int on) +{ + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + s3c2410_gpio_setpin(sg->info->pin_mosi, on ? 1 : 0); +} + +static inline u32 getmiso(struct spi_device *dev) +{ + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + return s3c2410_gpio_getpin(sg->info->pin_miso) ? 1 : 0; +} + +#define spidelay(x) ndelay(x) + +#define EXPAND_BITBANG_TXRX +#include + + +static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); +} + +static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); +} + +static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value) +{ + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + + if (sg->info && sg->info->chip_select) + (sg->info->chip_select)(sg->info, value); +} + +static int s3c2410_spigpio_probe(struct platform_device *dev) +{ + struct spi_master *master; + struct s3c2410_spigpio *sp; + int ret; + int i; + + master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio)); + if (master == NULL) { + dev_err(&dev->dev, "failed to allocate spi master\n"); + ret = -ENOMEM; + goto err; + } + + sp = spi_master_get_devdata(master); + + platform_set_drvdata(dev, sp); + + /* copy in the plkatform data */ + sp->info = dev->dev.platform_data; + + /* setup spi bitbang adaptor */ + sp->bitbang.master = spi_master_get(master); + sp->bitbang.chipselect = s3c2410_spigpio_chipselect; + + sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0; + sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1; + + /* set state of spi pins */ + s3c2410_gpio_setpin(sp->info->pin_clk, 0); + s3c2410_gpio_setpin(sp->info->pin_mosi, 0); + + s3c2410_gpio_cfgpin(sp->info->pin_clk, S3C2410_GPIO_OUTPUT); + s3c2410_gpio_cfgpin(sp->info->pin_mosi, S3C2410_GPIO_OUTPUT); + s3c2410_gpio_cfgpin(sp->info->pin_miso, S3C2410_GPIO_INPUT); + + ret = spi_bitbang_start(&sp->bitbang); + if (ret) + goto err_no_bitbang; + + /* register the chips to go with the board */ + + for (i = 0; i < sp->info->board_size; i++) { + dev_info(&dev->dev, "registering %p: %s\n", + &sp->info->board_info[i], + sp->info->board_info[i].modalias); + + sp->info->board_info[i].controller_data = sp; + spi_new_device(master, sp->info->board_info + i); + } + + return 0; + + err_no_bitbang: + spi_master_put(sp->bitbang.master); + err: + return ret; + +} + +static int s3c2410_spigpio_remove(struct platform_device *dev) +{ + struct s3c2410_spigpio *sp = platform_get_drvdata(dev); + + spi_bitbang_stop(&sp->bitbang); + spi_master_put(sp->bitbang.master); + + return 0; +} + +/* all gpio should be held over suspend/resume, so we should + * not need to deal with this +*/ + +#define s3c2410_spigpio_suspend NULL +#define s3c2410_spigpio_resume NULL + + +static struct platform_driver s3c2410_spigpio_drv = { + .probe = s3c2410_spigpio_probe, + .remove = s3c2410_spigpio_remove, + .suspend = s3c2410_spigpio_suspend, + .resume = s3c2410_spigpio_resume, + .driver = { + .name = "s3c24xx-spi-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c2410_spigpio_init(void) +{ + return platform_driver_register(&s3c2410_spigpio_drv); +} + +static void __exit s3c2410_spigpio_exit(void) +{ + platform_driver_unregister(&s3c2410_spigpio_drv); +} + +module_init(s3c2410_spigpio_init); +module_exit(s3c2410_spigpio_exit); + +MODULE_DESCRIPTION("S3C24XX SPI Driver"); +MODULE_AUTHOR("Ben Dooks, "); +MODULE_LICENSE("GPL"); diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h new file mode 100644 index 00000000000..258c00bca27 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/spi-gpio.h @@ -0,0 +1,31 @@ +/* linux/include/asm-arm/arch-s3c2410/spi.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2410 - SPI Controller platfrom_device info + * + * 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 + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_SPIGPIO_H +#define __ASM_ARCH_SPIGPIO_H __FILE__ + +struct s3c2410_spigpio_info; +struct spi_board_info; + +struct s3c2410_spigpio_info { + unsigned long pin_clk; + unsigned long pin_mosi; + unsigned long pin_miso; + + unsigned long board_size; + struct spi_board_info *board_info; + + void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs); +}; + + +#endif /* __ASM_ARCH_SPIGPIO_H */ -- cgit v1.2.3-70-g09d2 From 7fba53402eb0fb4209c74469814c583b6455e096 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 20 May 2006 15:00:18 -0700 Subject: [PATCH] S3C24XX: hardware SPI driver Hardware based SPI driver for Samsung S3C24XX SoC systems Signed-off-by: Ben Dooks Cc: David Brownell Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi_s3c24xx.c | 453 +++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-s3c2410/spi.h | 29 +++ 4 files changed, 489 insertions(+) create mode 100644 drivers/spi/spi_s3c24xx.c create mode 100644 include/asm-arm/arch-s3c2410/spi.h (limited to 'include') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c60dacfaadd..23334c8bc4c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -108,6 +108,12 @@ config SPI_S3C24XX_GPIO # +config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL + help + SPI driver for Samsung S3C24XX series ARM SoCs + # # There are lots of SPI device types, with sensors and memory # being probably the most widely used ones. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 4dc82c93bfe..8f4cb67997b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o +obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c new file mode 100644 index 00000000000..9de4b5a04d7 --- /dev/null +++ b/drivers/spi/spi_s3c24xx.c @@ -0,0 +1,453 @@ +/* linux/drivers/spi/spi_s3c24xx.c + * + * Copyright (c) 2006 Ben Dooks + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * 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 + * published by the Free Software Foundation. + * +*/ + + +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +struct s3c24xx_spi { + /* bitbang has to be first */ + struct spi_bitbang bitbang; + struct completion done; + + void __iomem *regs; + int irq; + int len; + int count; + + /* data buffers */ + const unsigned char *tx; + unsigned char *rx; + + struct clk *clk; + struct resource *ioarea; + struct spi_master *master; + struct spi_device *curdev; + struct device *dev; + struct s3c2410_spi_info *pdata; +}; + +#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) +#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) + +static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) +{ + return spi_master_get_devdata(sdev->master); +} + +static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) +{ + struct s3c24xx_spi *hw = to_hw(spi); + unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; + unsigned int spcon; + + switch (value) { + case BITBANG_CS_INACTIVE: + if (hw->pdata->set_cs) + hw->pdata->set_cs(hw->pdata, value, cspol); + else + s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1); + break; + + case BITBANG_CS_ACTIVE: + spcon = readb(hw->regs + S3C2410_SPCON); + + if (spi->mode & SPI_CPHA) + spcon |= S3C2410_SPCON_CPHA_FMTB; + else + spcon &= ~S3C2410_SPCON_CPHA_FMTB; + + if (spi->mode & SPI_CPOL) + spcon |= S3C2410_SPCON_CPOL_HIGH; + else + spcon &= ~S3C2410_SPCON_CPOL_HIGH; + + spcon |= S3C2410_SPCON_ENSCK; + + /* write new configration */ + + writeb(spcon, hw->regs + S3C2410_SPCON); + + if (hw->pdata->set_cs) + hw->pdata->set_cs(hw->pdata, value, cspol); + else + s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol); + + break; + + } +} + +static int s3c24xx_spi_setupxfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct s3c24xx_spi *hw = to_hw(spi); + unsigned int bpw; + unsigned int hz; + unsigned int div; + + bpw = t ? t->bits_per_word : spi->bits_per_word; + hz = t ? t->speed_hz : spi->max_speed_hz; + + if (bpw != 8) { + dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); + return -EINVAL; + } + + div = clk_get_rate(hw->clk) / hz; + + /* is clk = pclk / (2 * (pre+1)), or is it + * clk = (pclk * 2) / ( pre + 1) */ + + div = (div / 2) - 1; + + if (div < 0) + div = 1; + + if (div > 255) + div = 255; + + dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz); + writeb(div, hw->regs + S3C2410_SPPRE); + + spin_lock(&hw->bitbang.lock); + if (!hw->bitbang.busy) { + hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); + /* need to ndelay for 0.5 clocktick ? */ + } + spin_unlock(&hw->bitbang.lock); + + return 0; +} + +static int s3c24xx_spi_setup(struct spi_device *spi) +{ + int ret; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if ((spi->mode & SPI_LSB_FIRST) != 0) + return -EINVAL; + + ret = s3c24xx_spi_setupxfer(spi, NULL); + if (ret < 0) { + dev_err(&spi->dev, "setupxfer returned %d\n", ret); + return ret; + } + + dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", + __FUNCTION__, spi->mode, spi->bits_per_word, + spi->max_speed_hz); + + return 0; +} + +static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) +{ + return hw->tx ? hw->tx[count] : 0xff; +} + +static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) +{ + struct s3c24xx_spi *hw = to_hw(spi); + + dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", + t->tx_buf, t->rx_buf, t->len); + + hw->tx = t->tx_buf; + hw->rx = t->rx_buf; + hw->len = t->len; + hw->count = 0; + + /* send the first byte */ + writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); + wait_for_completion(&hw->done); + + return hw->count; +} + +static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs) +{ + struct s3c24xx_spi *hw = dev; + unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); + unsigned int count = hw->count; + + if (spsta & S3C2410_SPSTA_DCOL) { + dev_dbg(hw->dev, "data-collision\n"); + complete(&hw->done); + goto irq_done; + } + + if (!(spsta & S3C2410_SPSTA_READY)) { + dev_dbg(hw->dev, "spi not ready for tx?\n"); + complete(&hw->done); + goto irq_done; + } + + hw->count++; + + if (hw->rx) + hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); + + count++; + + if (count < hw->len) + writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); + else + complete(&hw->done); + + irq_done: + return IRQ_HANDLED; +} + +static int s3c24xx_spi_probe(struct platform_device *pdev) +{ + struct s3c24xx_spi *hw; + struct spi_master *master; + struct spi_board_info *bi; + struct resource *res; + int err = 0; + int i; + + master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); + if (master == NULL) { + dev_err(&pdev->dev, "No memory for spi_master\n"); + err = -ENOMEM; + goto err_nomem; + } + + hw = spi_master_get_devdata(master); + memset(hw, 0, sizeof(struct s3c24xx_spi)); + + hw->master = spi_master_get(master); + hw->pdata = pdev->dev.platform_data; + hw->dev = &pdev->dev; + + if (hw->pdata == NULL) { + dev_err(&pdev->dev, "No platform data supplied\n"); + err = -ENOENT; + goto err_no_pdata; + } + + platform_set_drvdata(pdev, hw); + init_completion(&hw->done); + + /* setup the state for the bitbang driver */ + + hw->bitbang.master = hw->master; + hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; + hw->bitbang.chipselect = s3c24xx_spi_chipsel; + hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; + hw->bitbang.master->setup = s3c24xx_spi_setup; + + dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); + + /* find and map our resources */ + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + err = -ENOENT; + goto err_no_iores; + } + + hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1, + pdev->name); + + if (hw->ioarea == NULL) { + dev_err(&pdev->dev, "Cannot reserve region\n"); + err = -ENXIO; + goto err_no_iores; + } + + hw->regs = ioremap(res->start, (res->end - res->start)+1); + if (hw->regs == NULL) { + dev_err(&pdev->dev, "Cannot map IO\n"); + err = -ENXIO; + goto err_no_iomap; + } + + hw->irq = platform_get_irq(pdev, 0); + if (hw->irq < 0) { + dev_err(&pdev->dev, "No IRQ specified\n"); + err = -ENOENT; + goto err_no_irq; + } + + err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); + if (err) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_no_irq; + } + + hw->clk = clk_get(&pdev->dev, "spi"); + if (IS_ERR(hw->clk)) { + dev_err(&pdev->dev, "No clock for device\n"); + err = PTR_ERR(hw->clk); + goto err_no_clk; + } + + /* for the moment, permanently enable the clock */ + + clk_enable(hw->clk); + + /* program defaults into the registers */ + + writeb(0xff, hw->regs + S3C2410_SPPRE); + writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); + writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); + + /* setup any gpio we can */ + + if (!hw->pdata->set_cs) { + s3c2410_gpio_setpin(hw->pdata->pin_cs, 1); + s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT); + } + + /* register our spi controller */ + + err = spi_bitbang_start(&hw->bitbang); + if (err) { + dev_err(&pdev->dev, "Failed to register SPI master\n"); + goto err_register; + } + + dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown); + + /* register all the devices associated */ + + bi = &hw->pdata->board_info[0]; + for (i = 0; i < hw->pdata->board_size; i++, bi++) { + dev_info(hw->dev, "registering %s\n", bi->modalias); + + bi->controller_data = hw; + spi_new_device(master, bi); + } + + return 0; + + err_register: + clk_disable(hw->clk); + clk_put(hw->clk); + + err_no_clk: + free_irq(hw->irq, hw); + + err_no_irq: + iounmap(hw->regs); + + err_no_iomap: + release_resource(hw->ioarea); + kfree(hw->ioarea); + + err_no_iores: + err_no_pdata: + spi_master_put(hw->master);; + + err_nomem: + return err; +} + +static int s3c24xx_spi_remove(struct platform_device *dev) +{ + struct s3c24xx_spi *hw = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + spi_unregister_master(hw->master); + + clk_disable(hw->clk); + clk_put(hw->clk); + + free_irq(hw->irq, hw); + iounmap(hw->regs); + + release_resource(hw->ioarea); + kfree(hw->ioarea); + + spi_master_put(hw->master); + return 0; +} + + +#ifdef CONFIG_PM + +static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct s3c24xx_spi *hw = platform_get_drvdata(dev); + + clk_disable(hw->clk); + return 0; +} + +static int s3c24xx_spi_resume(struct platform_device *pdev) +{ + struct s3c24xx_spi *hw = platform_get_drvdata(dev); + + clk_enable(hw->clk); + return 0; +} + +#else +#define s3c24xx_spi_suspend NULL +#define s3c24xx_spi_resume NULL +#endif + +static struct platform_driver s3c24xx_spidrv = { + .probe = s3c24xx_spi_probe, + .remove = s3c24xx_spi_remove, + .suspend = s3c24xx_spi_suspend, + .resume = s3c24xx_spi_resume, + .driver = { + .name = "s3c2410-spi", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c24xx_spi_init(void) +{ + return platform_driver_register(&s3c24xx_spidrv); +} + +static void __exit s3c24xx_spi_exit(void) +{ + platform_driver_unregister(&s3c24xx_spidrv); +} + +module_init(s3c24xx_spi_init); +module_exit(s3c24xx_spi_exit); + +MODULE_DESCRIPTION("S3C24XX SPI Driver"); +MODULE_AUTHOR("Ben Dooks, "); +MODULE_LICENSE("GPL"); diff --git a/include/asm-arm/arch-s3c2410/spi.h b/include/asm-arm/arch-s3c2410/spi.h new file mode 100644 index 00000000000..4029a1a1ab4 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/spi.h @@ -0,0 +1,29 @@ +/* linux/include/asm-arm/arch-s3c2410/spi.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2410 - SPI Controller platform_device info + * + * 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 + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_SPI_H +#define __ASM_ARCH_SPI_H __FILE__ + +struct s3c2410_spi_info; +struct spi_board_info; + +struct s3c2410_spi_info { + unsigned long pin_cs; /* simple gpio cs */ + + unsigned long board_size; + struct spi_board_info *board_info; + + void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); +}; + + +#endif /* __ASM_ARCH_SPI_H */ -- cgit v1.2.3-70-g09d2 From 5daa3ba0c6a41a8bb4ba17ad8d5514172e103504 Mon Sep 17 00:00:00 2001 From: Stephen Street Date: Sat, 20 May 2006 15:00:19 -0700 Subject: [PATCH] pxa2xx-spi update Fix some outstanding issues with the pxa2xx_spi driver when running on a PXA270: - Wrong timeout calculation in the setup function due to different peripheral clock rates in the PXAxxx family. - Bad handling of SSSR_TFS interrupts in interrupt_transfer function. - Added locking to interface between the pump_messages workqueue and the pump_transfers tasklet. Much thanks to Juergen Beisert for the extensive testing on the PXA270. Signed-off-by: Stephen Street Signed-off-by: David Brownell Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/pxa2xx_spi.c | 93 +++++++++++++++++++++-------------- include/asm-arm/arch-pxa/pxa2xx_spi.h | 3 ++ 2 files changed, 59 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 596bf820b70..29aec77f98b 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -363,25 +363,30 @@ static void unmap_dma_buffers(struct driver_data *drv_data) } /* caller already set message->status; dma and pio irqs are blocked */ -static void giveback(struct spi_message *message, struct driver_data *drv_data) +static void giveback(struct driver_data *drv_data) { struct spi_transfer* last_transfer; + unsigned long flags; + struct spi_message *msg; - last_transfer = list_entry(message->transfers.prev, + spin_lock_irqsave(&drv_data->lock, flags); + msg = drv_data->cur_msg; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + queue_work(drv_data->workqueue, &drv_data->pump_messages); + spin_unlock_irqrestore(&drv_data->lock, flags); + + last_transfer = list_entry(msg->transfers.prev, struct spi_transfer, transfer_list); if (!last_transfer->cs_change) drv_data->cs_control(PXA2XX_CS_DEASSERT); - message->state = NULL; - if (message->complete) - message->complete(message->context); - - drv_data->cur_msg = NULL; - drv_data->cur_transfer = NULL; - drv_data->cur_chip = NULL; - queue_work(drv_data->workqueue, &drv_data->pump_messages); + msg->state = NULL; + if (msg->complete) + msg->complete(msg->context); } static int wait_ssp_rx_stall(void *ioaddr) @@ -415,10 +420,11 @@ static void dma_handler(int channel, void *data, struct pt_regs *regs) if (irq_status & DCSR_BUSERR) { /* Disable interrupts, clear status and reset DMA */ + write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(0, reg); write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; @@ -454,8 +460,8 @@ static void dma_handler(int channel, void *data, struct pt_regs *regs) "dma_handler: ssp rx stall failed\n"); /* Clear and disable interrupts on SSP and DMA channels*/ - write_SSSR(drv_data->clear_sr, reg); write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + write_SSSR(drv_data->clear_sr, reg); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; if (wait_dma_channel_stop(drv_data->rx_channel) == 0) @@ -497,10 +503,11 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) irq_status = read_SSSR(reg) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { /* Clear and disable interrupts on SSP and DMA channels*/ + write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(0, reg); write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; unmap_dma_buffers(drv_data); @@ -526,10 +533,10 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) { /* Clear and disable interrupts on SSP and DMA channels*/ + write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(0, reg); write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -572,26 +579,30 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - u32 irq_status; struct spi_message *msg = drv_data->cur_msg; void *reg = drv_data->ioaddr; - irqreturn_t handled = IRQ_NONE; unsigned long limit = loops_per_jiffy << 1; + u32 irq_status; + u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? + drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; - while ((irq_status = (read_SSSR(reg) & drv_data->mask_sr))) { + while ((irq_status = read_SSSR(reg) & irq_mask)) { if (irq_status & SSSR_ROR) { /* Clear and disable interrupts */ + write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(0, reg); write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); if (flush(drv_data) == 0) dev_err(&drv_data->pdev->dev, "interrupt_transfer: flush fail\n"); + /* Stop the SSP */ + dev_warn(&drv_data->pdev->dev, "interrupt_transfer: fifo overun\n"); @@ -613,6 +624,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) if (drv_data->tx == drv_data->tx_end) { /* Disable tx interrupt */ write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); + irq_mask = drv_data->mask_sr & ~SSSR_TFS; /* PXA25x_SSP has no timeout, read trailing bytes */ if (drv_data->ssp_type == PXA25x_SSP) { @@ -630,10 +642,10 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) || (drv_data->rx == drv_data->rx_end)) { /* Clear timeout */ + write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(0, reg); write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); /* Update total byte transfered */ msg->actual_length += drv_data->len; @@ -648,24 +660,29 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) /* Schedule transfer tasklet */ tasklet_schedule(&drv_data->pump_transfers); - - return IRQ_HANDLED; } - - /* We did something */ - handled = IRQ_HANDLED; } - return handled; + /* We did something */ + return IRQ_HANDLED; } static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs) { struct driver_data *drv_data = (struct driver_data *)dev_id; + void *reg = drv_data->ioaddr; if (!drv_data->cur_msg) { + + write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); + if (drv_data->ssp_type != PXA25x_SSP) + write_SSTO(0, reg); + write_SSSR(drv_data->clear_sr, reg); + dev_err(&drv_data->pdev->dev, "bad message state " - "in interrupt handler\n"); + "in interrupt handler"); + /* Never fail */ return IRQ_HANDLED; } @@ -694,14 +711,14 @@ static void pump_transfers(unsigned long data) /* Handle for abort */ if (message->state == ERROR_STATE) { message->status = -EIO; - giveback(message, drv_data); + giveback(drv_data); return; } /* Handle end of message */ if (message->state == DONE_STATE) { message->status = 0; - giveback(message, drv_data); + giveback(drv_data); return; } @@ -718,7 +735,7 @@ static void pump_transfers(unsigned long data) if (flush(drv_data) == 0) { dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); message->status = -EIO; - giveback(message, drv_data); + giveback(drv_data); return; } drv_data->n_bytes = chip->n_bytes; @@ -782,7 +799,7 @@ static void pump_transfers(unsigned long data) cr0 = clk_div | SSCR0_Motorola - | SSCR0_DataSize(bits & 0x0f) + | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) | SSCR0_SSE | (bits > 16 ? SSCR0_EDSS : 0); @@ -890,8 +907,6 @@ static void pump_messages(void *data) drv_data->cur_msg = list_entry(drv_data->queue.next, struct spi_message, queue); list_del_init(&drv_data->cur_msg->queue); - drv_data->busy = 1; - spin_unlock_irqrestore(&drv_data->lock, flags); /* Initial message state*/ drv_data->cur_msg->state = START_STATE; @@ -905,6 +920,9 @@ static void pump_messages(void *data) /* Mark as busy and launch transfers */ tasklet_schedule(&drv_data->pump_transfers); + + drv_data->busy = 1; + spin_unlock_irqrestore(&drv_data->lock, flags); } static int transfer(struct spi_device *spi, struct spi_message *msg) @@ -958,7 +976,7 @@ static int setup(struct spi_device *spi) chip->cs_control = null_cs_control; chip->enable_dma = 0; - chip->timeout = 5; + chip->timeout = SSP_TIMEOUT(1000); chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1); chip->dma_burst_size = drv_data->master_info->enable_dma ? DCMD_BURST8 : 0; @@ -971,7 +989,7 @@ static int setup(struct spi_device *spi) if (chip_info->cs_control) chip->cs_control = chip_info->cs_control; - chip->timeout = (chip_info->timeout_microsecs * 10000) / 2712; + chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs); chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold) | SSCR1_TxTresh(chip_info->tx_threshold); @@ -1013,7 +1031,8 @@ static int setup(struct spi_device *spi) chip->cr0 = clk_div | SSCR0_Motorola - | SSCR0_DataSize(spi->bits_per_word & 0x0f) + | SSCR0_DataSize(spi->bits_per_word > 16 ? + spi->bits_per_word - 16 : spi->bits_per_word) | SSCR0_SSE | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0); chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4) @@ -1196,7 +1215,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_master_alloc; } - drv_data->ioaddr = (void *)io_p2v(memory_resource->start); + drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start)); drv_data->ssdr_physical = memory_resource->start + 0x00000010; if (platform_info->ssp_type == PXA25x_SSP) { drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; @@ -1218,7 +1237,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_master_alloc; } - status = request_irq(irq, ssp_int, SA_INTERRUPT, dev->bus_id, drv_data); + status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data); if (status < 0) { dev_err(&pdev->dev, "can not get IRQ\n"); goto out_error_master_alloc; diff --git a/include/asm-arm/arch-pxa/pxa2xx_spi.h b/include/asm-arm/arch-pxa/pxa2xx_spi.h index 1e70908b816..915590c391c 100644 --- a/include/asm-arm/arch-pxa/pxa2xx_spi.h +++ b/include/asm-arm/arch-pxa/pxa2xx_spi.h @@ -27,13 +27,16 @@ #define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00) #define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00) #define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00) +#define SSP_TIMEOUT_SCALE (2712) #elif defined(CONFIG_PXA27x) #define CLOCK_SPEED_HZ 13000000 #define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00) #define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00) #define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00) +#define SSP_TIMEOUT_SCALE (769) #endif +#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE) #define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1))))) #define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2))))) #define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3))))) -- cgit v1.2.3-70-g09d2 From e984bb43f7450312ba66fe0e67a99efa6be3b246 Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Sat, 20 May 2006 15:00:31 -0700 Subject: [PATCH] Align the node_mem_map endpoints to a MAX_ORDER boundary Andy added code to buddy allocator which does not require the zone's endpoints to be aligned to MAX_ORDER. An issue is that the buddy allocator requires the node_mem_map's endpoints to be MAX_ORDER aligned. Otherwise __page_find_buddy could compute a buddy not in node_mem_map for partial MAX_ORDER regions at zone's endpoints. page_is_buddy will detect that these pages at endpoints are not PG_buddy (they were zeroed out by bootmem allocator and not part of zone). Of course the negative here is we could waste a little memory but the positive is eliminating all the old checks for zone boundary conditions. SPARSEMEM won't encounter this issue because of MAX_ORDER size constraint when SPARSEMEM is configured. ia64 VIRTUAL_MEM_MAP doesn't need the logic either because the holes and endpoints are handled differently. This leaves checking alloc_remap and other arches which privately allocate for node_mem_map. Signed-off-by: Bob Picco Acked-by: Mel Gorman Cc: Dave Hansen Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 1 + mm/page_alloc.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index b5c21122c29..36740354d4d 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -22,6 +22,7 @@ #else #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif +#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) struct free_area { struct list_head free_list; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bb3416932ab..253a450c400 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2125,14 +2125,22 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat) #ifdef CONFIG_FLAT_NODE_MEM_MAP /* ia64 gets its own node_mem_map, before this, without bootmem */ if (!pgdat->node_mem_map) { - unsigned long size; + unsigned long size, start, end; struct page *map; - size = (pgdat->node_spanned_pages + 1) * sizeof(struct page); + /* + * The zone's endpoints aren't required to be MAX_ORDER + * aligned but the node_mem_map endpoints must be in order + * for the buddy allocator to function correctly. + */ + start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1); + end = pgdat->node_start_pfn + pgdat->node_spanned_pages; + end = ALIGN(end, MAX_ORDER_NR_PAGES); + size = (end - start) * sizeof(struct page); map = alloc_remap(pgdat->node_id, size); if (!map) map = alloc_bootmem_node(pgdat, size); - pgdat->node_mem_map = map; + pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); } #ifdef CONFIG_FLATMEM /* -- cgit v1.2.3-70-g09d2 From 353b28bafd1b962359a866ff263a7fad833d29a1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 21 May 2006 21:22:53 -0700 Subject: [SPARC]: Add robust futex syscall entries. Signed-off-by: David S. Miller --- arch/sparc/kernel/systbls.S | 3 ++- arch/sparc64/kernel/systbls.S | 8 +++++--- include/asm-sparc/unistd.h | 8 +++++--- include/asm-sparc64/unistd.h | 8 +++++--- 4 files changed, 17 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 6e1135cc03b..2856551bddf 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -79,6 +79,7 @@ sys_call_table: /*285*/ .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64 /*290*/ .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare +/*300*/ .long sys_set_robust_list, sys_get_robust_list #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ @@ -190,6 +191,6 @@ sunos_sys_table: /*290*/ .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_nosys, sunos_nosys, sunos_nosys - .long sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys #endif diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index d4b39cd3031..1136fc465e3 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -78,8 +78,9 @@ sys_call_table32: .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 -/*285*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat +/*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare +/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list #endif /* CONFIG_COMPAT */ @@ -147,8 +148,9 @@ sys_call_table: .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .word sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat .word sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64 -/*285*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat +/*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare +/*300*/ .word sys_set_robust_list, sys_get_robust_list #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) @@ -261,5 +263,5 @@ sunos_sys_table: /*290*/ .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_nosys - .word sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys #endif diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index f5611a721fb..45a57650778 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -316,11 +316,13 @@ #define __NR_pselect6 297 #define __NR_ppoll 298 #define __NR_unshare 299 +#define __NR_set_robust_list 300 +#define __NR_get_robust_list 301 -/* WARNING: You MAY NOT add syscall numbers larger than 299, since +/* WARNING: You MAY NOT add syscall numbers larger than 301, since * all of the syscall tables in the Sparc kernel are - * sized to have 299 entries (starting at zero). Therefore - * find a free slot in the 0-299 range. + * sized to have 301 entries (starting at zero). Therefore + * find a free slot in the 0-301 range. */ #define _syscall0(type,name) \ diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index 68705748bec..998ef4ab0e0 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -318,11 +318,13 @@ #define __NR_pselect6 297 #define __NR_ppoll 298 #define __NR_unshare 299 +#define __NR_set_robust_list 300 +#define __NR_get_robust_list 301 -/* WARNING: You MAY NOT add syscall numbers larger than 299, since +/* WARNING: You MAY NOT add syscall numbers larger than 301, since * all of the syscall tables in the Sparc kernel are - * sized to have 299 entries (starting at zero). Therefore - * find a free slot in the 0-299 range. + * sized to have 301 entries (starting at zero). Therefore + * find a free slot in the 0-301 range. */ #define _syscall0(type,name) \ -- cgit v1.2.3-70-g09d2 From f5565f4a90bdfea99e4bcd8411ff5272ebdbdbf8 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 22 May 2006 16:54:30 -0700 Subject: [IRDA]: fixup type of ->lsap_state Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/net/irda/irlmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h index 86aefb1fda5..c0c895d379b 100644 --- a/include/net/irda/irlmp.h +++ b/include/net/irda/irlmp.h @@ -112,7 +112,7 @@ struct lsap_cb { struct timer_list watchdog_timer; - IRLMP_STATE lsap_state; /* Connection state */ + LSAP_STATE lsap_state; /* Connection state */ notify_t notify; /* Indication/Confirm entry points */ struct qos_info qos; /* QoS for this connection */ -- cgit v1.2.3-70-g09d2 From 42f142371e48fbc44956d57b4e506bb6ce673cd7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 23 May 2006 02:07:22 -0700 Subject: [SPARC64]: Respect gfp_t argument to dma_alloc_coherent(). Using asm-generic/dma-mapping.h does not work because pushing the call down to pci_alloc_coherent() causes the gfp_t argument of dma_alloc_coherent() to be ignored. Fix this by implementing things directly, and adding a gfp_t argument we can use in the internal call down to the PCI DMA implementation of pci_alloc_coherent(). This fixes massive memory corruption when using the sound driver layer, which passes things like __GFP_COMP down into these routines and (correctly) expects that to work. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 4 +- arch/sparc64/kernel/pci_sun4v.c | 4 +- include/asm-sparc64/dma-mapping.h | 141 +++++++++++++++++++++++++++++++++++++- include/asm-sparc64/pci.h | 4 +- 4 files changed, 146 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 8efbc139769..82e5455134c 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -218,7 +218,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) * DMA for PCI device PDEV. Return non-NULL cpu-side address if * successful and set *DMA_ADDRP to the PCI side dma address. */ -static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) +static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -232,7 +232,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr if (order >= 10) return NULL; - first_page = __get_free_pages(GFP_ATOMIC, order); + first_page = __get_free_pages(gfp, order); if (first_page == 0UL) return NULL; memset((char *)first_page, 0, PAGE_SIZE << order); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 9e94db2573a..2b7a1f316a9 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -154,7 +154,7 @@ static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, un __clear_bit(i, arena->map); } -static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) +static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -169,7 +169,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr npages = size >> IO_PAGE_SHIFT; - first_page = __get_free_pages(GFP_ATOMIC, order); + first_page = __get_free_pages(gfp, order); if (unlikely(first_page == 0UL)) return NULL; diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index c7d5804ba76..a8d39f23d43 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -4,7 +4,146 @@ #include #ifdef CONFIG_PCI -#include + +/* we implement the API below in terms of the existing PCI one, + * so include it */ +#include +/* need struct page definitions */ +#include + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_dma_supported(to_pci_dev(dev), mask); +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_iommu_ops->alloc_consistent(to_pci_dev(dev), size, dma_handle, flag); +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); +} + +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); +} + +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, + size, (int)direction); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, + size, (int)direction); +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); +} + +static inline int +dma_mapping_error(dma_addr_t dma_addr) +{ + return pci_dma_mapping_error(dma_addr); +} + #else struct device; diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 7c5a589ea43..e1ea67bc32f 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -42,7 +42,7 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) struct pci_dev; struct pci_iommu_ops { - void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *); + void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *, gfp_t); void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t); dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int); void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int); @@ -59,7 +59,7 @@ extern struct pci_iommu_ops *pci_iommu_ops; */ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle); + return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle, GFP_ATOMIC); } /* Free and unmap a consistent DMA buffer. -- cgit v1.2.3-70-g09d2 From e46e490368f87032a6e54969194413339b35a385 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 22 May 2006 22:35:24 -0700 Subject: [PATCH] sys_sync_file_range(): move exported flags outside __KERNEL__ These flags are needed by userspace - move them outside __KERNEL__ (Pointed out by dwmw2) Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index 3de2bfb2410..f813bc8266a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -213,6 +213,10 @@ extern int dir_notify_enable; #define FIBMAP _IO(0x00,1) /* bmap access */ #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ +#define SYNC_FILE_RANGE_WAIT_BEFORE 1 +#define SYNC_FILE_RANGE_WRITE 2 +#define SYNC_FILE_RANGE_WAIT_AFTER 4 + #ifdef __KERNEL__ #include @@ -758,9 +762,6 @@ extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); extern int fcntl_getlease(struct file *filp); /* fs/sync.c */ -#define SYNC_FILE_RANGE_WAIT_BEFORE 1 -#define SYNC_FILE_RANGE_WRITE 2 -#define SYNC_FILE_RANGE_WAIT_AFTER 4 extern int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte, unsigned int flags); -- cgit v1.2.3-70-g09d2 From 0f0410823792ae0ecb45f2578598b115835ffdbb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 23 May 2006 07:46:40 -0700 Subject: [PATCH] powerpc: wire up sys_[gs]et_robust_list Signed-off-by: David Woodhouse Cc: Benjamin Herrenschmidt Acked-by: Paul Mackerras Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/kernel/systbl.S | 2 ++ arch/powerpc/platforms/cell/spu_callbacks.c | 2 ++ include/asm-powerpc/unistd.h | 4 +++- include/linux/syscalls.h | 6 ++++++ 4 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index cf56a1d499f..26ed1f5ef16 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -338,6 +338,8 @@ SYSCALL(symlinkat) SYSCALL(readlinkat) SYSCALL(fchmodat) SYSCALL(faccessat) +COMPAT_SYS(get_robust_list) +COMPAT_SYS(set_robust_list) /* * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index 5a0f9e3beb2..b47fcc5ddb7 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -333,6 +333,8 @@ void *spu_syscall_table[] = { [__NR_readlinkat] sys_readlinkat, [__NR_fchmodat] sys_fchmodat, [__NR_faccessat] sys_faccessat, + [__NR_get_robust_list] sys_get_robust_list, + [__NR_set_robust_list] sys_set_robust_list, }; long spu_sys_callback(struct spu_syscall_block *s) diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index 908acb44cb8..edde2462bf5 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -321,8 +321,10 @@ #define __NR_readlinkat 296 #define __NR_fchmodat 297 #define __NR_faccessat 298 +#define __NR_get_robust_list 299 +#define __NR_set_robust_list 300 -#define __NR_syscalls 299 +#define __NR_syscalls 301 #ifdef __KERNEL__ #define __NR__exit __NR_exit diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 3996960fc56..60d49e5456e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -52,6 +52,7 @@ struct utimbuf; struct mq_attr; struct compat_stat; struct compat_timeval; +struct robust_list_head; #include #include @@ -581,5 +582,10 @@ asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags); +asmlinkage long sys_get_robust_list(int pid, + struct robust_list_head __user **head_ptr, + size_t __user *len_ptr); +asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, + size_t len); #endif -- cgit v1.2.3-70-g09d2