diff options
Diffstat (limited to 'drivers')
307 files changed, 14293 insertions, 43542 deletions
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 06ddd91ffeda..74b829817891 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -60,7 +60,7 @@ static unsigned int ns_to_tim_reg(unsigned int tim_mult, unsigned int nsecs) * Compute # of eclock periods to get desired duration in * nanoseconds. */ - val = DIV_ROUND_UP(nsecs * (octeon_get_clock_rate() / 1000000), + val = DIV_ROUND_UP(nsecs * (octeon_get_io_clock_rate() / 1000000), 1000 * tim_mult); return val; diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index af0600143d1c..82bbb5967aa9 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -29,33 +29,33 @@ static struct vfsmount *dev_mnt; #if defined CONFIG_DEVTMPFS_MOUNT -static int dev_mount = 1; +static int mount_dev = 1; #else -static int dev_mount; +static int mount_dev; #endif static DEFINE_MUTEX(dirlock); static int __init mount_param(char *str) { - dev_mount = simple_strtoul(str, NULL, 0); + mount_dev = simple_strtoul(str, NULL, 0); return 1; } __setup("devtmpfs.mount=", mount_param); -static int dev_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *dev_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { #ifdef CONFIG_TMPFS - return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt); + return mount_single(fs_type, flags, data, shmem_fill_super); #else - return get_sb_single(fs_type, flags, data, ramfs_fill_super, mnt); + return mount_single(fs_type, flags, data, ramfs_fill_super); #endif } static struct file_system_type dev_fs_type = { .name = "devtmpfs", - .get_sb = dev_get_sb, + .mount = dev_mount, .kill_sb = kill_litter_super, }; @@ -351,7 +351,7 @@ int devtmpfs_mount(const char *mntdir) { int err; - if (!dev_mount) + if (!mount_dev) return 0; if (!dev_mnt) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 126ca492dd08..02c652be83e7 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -143,7 +143,7 @@ static int rpm_check_suspend_allowed(struct device *dev) /* Pending resume requests take precedence over suspends. */ else if ((dev->power.deferred_resume - && dev->power.status == RPM_SUSPENDING) + && dev->power.runtime_status == RPM_SUSPENDING) || (dev->power.request_pending && dev->power.request == RPM_REQ_RESUME)) retval = -EAGAIN; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 4b33a18c32e0..06e2812ba124 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1112,6 +1112,8 @@ static void blkback_changed(struct xenbus_device *dev, case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 17e380f5f818..94821ab01c6d 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -19,6 +19,7 @@ #include <linux/klist.h> #include <linux/agp_backend.h> #include <linux/log2.h> +#include <linux/slab.h> #include <asm/parisc-device.h> #include <asm/ropes.h> diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index 6b8e6d18a8e6..3740e327f180 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -79,7 +79,7 @@ static int __write_console(const char *data, int len) return sent; } -static int write_console(uint32_t vtermno, const char *data, int len) +static int domU_write_console(uint32_t vtermno, const char *data, int len) { int ret = len; @@ -102,7 +102,7 @@ static int write_console(uint32_t vtermno, const char *data, int len) return ret; } -static int read_console(uint32_t vtermno, char *buf, int len) +static int domU_read_console(uint32_t vtermno, char *buf, int len) { struct xencons_interface *intf = xencons_interface(); XENCONS_RING_IDX cons, prod; @@ -123,28 +123,62 @@ static int read_console(uint32_t vtermno, char *buf, int len) return recv; } -static const struct hv_ops hvc_ops = { - .get_chars = read_console, - .put_chars = write_console, +static struct hv_ops domU_hvc_ops = { + .get_chars = domU_read_console, + .put_chars = domU_write_console, .notifier_add = notifier_add_irq, .notifier_del = notifier_del_irq, .notifier_hangup = notifier_hangup_irq, }; -static int __init xen_init(void) +static int dom0_read_console(uint32_t vtermno, char *buf, int len) +{ + return HYPERVISOR_console_io(CONSOLEIO_read, len, buf); +} + +/* + * Either for a dom0 to write to the system console, or a domU with a + * debug version of Xen + */ +static int dom0_write_console(uint32_t vtermno, const char *str, int len) +{ + int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); + if (rc < 0) + return 0; + + return len; +} + +static struct hv_ops dom0_hvc_ops = { + .get_chars = dom0_read_console, + .put_chars = dom0_write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int __init xen_hvc_init(void) { struct hvc_struct *hp; + struct hv_ops *ops; - if (!xen_pv_domain() || - xen_initial_domain() || - !xen_start_info->console.domU.evtchn) + if (!xen_pv_domain()) return -ENODEV; - xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + if (xen_initial_domain()) { + ops = &dom0_hvc_ops; + xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); + } else { + if (!xen_start_info->console.domU.evtchn) + return -ENODEV; + + ops = &domU_hvc_ops; + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + } if (xencons_irq < 0) xencons_irq = 0; /* NO_IRQ */ - hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256); + hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); if (IS_ERR(hp)) return PTR_ERR(hp); @@ -161,7 +195,7 @@ void xen_console_resume(void) rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); } -static void __exit xen_fini(void) +static void __exit xen_hvc_fini(void) { if (hvc) hvc_remove(hvc); @@ -169,29 +203,24 @@ static void __exit xen_fini(void) static int xen_cons_init(void) { + struct hv_ops *ops; + if (!xen_pv_domain()) return 0; - hvc_instantiate(HVC_COOKIE, 0, &hvc_ops); + if (xen_initial_domain()) + ops = &dom0_hvc_ops; + else + ops = &domU_hvc_ops; + + hvc_instantiate(HVC_COOKIE, 0, ops); return 0; } -module_init(xen_init); -module_exit(xen_fini); +module_init(xen_hvc_init); +module_exit(xen_hvc_fini); console_initcall(xen_cons_init); -static void raw_console_write(const char *str, int len) -{ - while(len > 0) { - int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); - if (rc <= 0) - break; - - str += rc; - len -= rc; - } -} - #ifdef CONFIG_EARLY_PRINTK static void xenboot_write_console(struct console *console, const char *string, unsigned len) @@ -199,19 +228,22 @@ static void xenboot_write_console(struct console *console, const char *string, unsigned int linelen, off = 0; const char *pos; - raw_console_write(string, len); + dom0_write_console(0, string, len); + + if (xen_initial_domain()) + return; - write_console(0, "(early) ", 8); + domU_write_console(0, "(early) ", 8); while (off < len && NULL != (pos = strchr(string+off, '\n'))) { linelen = pos-string+off; if (off + linelen > len) break; - write_console(0, string+off, linelen); - write_console(0, "\r\n", 2); + domU_write_console(0, string+off, linelen); + domU_write_console(0, "\r\n", 2); off += linelen + 1; } if (off < len) - write_console(0, string+off, len-off); + domU_write_console(0, string+off, len-off); } struct console xenboot_console = { @@ -223,7 +255,7 @@ struct console xenboot_console = { void xen_raw_console_write(const char *str) { - raw_console_write(str, strlen(str)); + dom0_write_console(0, str, strlen(str)); } void xen_raw_printk(const char *fmt, ...) diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 1b8ee590b4ca..f64582b0f623 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -188,25 +188,43 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) } /** - * tty_audit_push_task - Flush task's pending audit data + * tty_audit_push_task - Flush task's pending audit data + * @tsk: task pointer + * @loginuid: sender login uid + * @sessionid: sender session id + * + * Called with a ref on @tsk held. Try to lock sighand and get a + * reference to the tty audit buffer if available. + * Flush the buffer or return an appropriate error code. */ -void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) +int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) { - struct tty_audit_buf *buf; + struct tty_audit_buf *buf = ERR_PTR(-EPERM); + unsigned long flags; - spin_lock_irq(&tsk->sighand->siglock); - buf = tsk->signal->tty_audit_buf; - if (buf) - atomic_inc(&buf->count); - spin_unlock_irq(&tsk->sighand->siglock); - if (!buf) - return; + if (!lock_task_sighand(tsk, &flags)) + return -ESRCH; + + if (tsk->signal->audit_tty) { + buf = tsk->signal->tty_audit_buf; + if (buf) + atomic_inc(&buf->count); + } + unlock_task_sighand(tsk, &flags); + + /* + * Return 0 when signal->audit_tty set + * but tsk->signal->tty_audit_buf == NULL. + */ + if (!buf || IS_ERR(buf)) + return PTR_ERR(buf); mutex_lock(&buf->mutex); tty_audit_buf_push(tsk, loginuid, sessionid, buf); mutex_unlock(&buf->mutex); tty_audit_buf_put(buf); + return 0; } /** diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 79d1542f31c0..6ee23592700a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -200,11 +200,11 @@ config PL330_DMA platform_data for a dma-pl330 device. config PCH_DMA - tristate "Topcliff PCH DMA support" + tristate "Topcliff (Intel EG20T) PCH DMA support" depends on PCI && X86 select DMA_ENGINE help - Enable support for the Topcliff PCH DMA engine. + Enable support for the Topcliff (Intel EG20T) PCH DMA engine. config IMX_SDMA tristate "i.MX SDMA support" diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dd9b4ba8d32d..3143ac795eb0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -116,6 +116,18 @@ config GPIO_SCH This driver can also be built as a module. If so, the module will be called sch-gpio. +config GPIO_VX855 + tristate "VIA VX855/VX875 GPIO" + depends on GPIOLIB + select MFD_CORE + select MFD_VX855 + help + Support access to the VX855/VX875 GPIO lines through the gpio library. + + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index da2ecde5abdd..bdf3ddec0652 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -40,3 +40,4 @@ obj-$(CONFIG_GPIO_SCH) += sch_gpio.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o +obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c index 4e1f1b9d5e67..7c9e6a052c45 100644 --- a/drivers/gpio/stmpe-gpio.c +++ b/drivers/gpio/stmpe-gpio.c @@ -30,6 +30,7 @@ struct stmpe_gpio { struct mutex irq_lock; int irq_base; + unsigned norequest_mask; /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -103,6 +104,9 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); struct stmpe *stmpe = stmpe_gpio->stmpe; + if (stmpe_gpio->norequest_mask & (1 << offset)) + return -EINVAL; + return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO); } @@ -287,8 +291,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) int irq; pdata = stmpe->pdata->gpio; - if (!pdata) - return -ENODEV; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -302,6 +304,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->dev = &pdev->dev; stmpe_gpio->stmpe = stmpe; + stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0; stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; @@ -312,11 +315,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); if (ret) - return ret; + goto out_free; ret = stmpe_gpio_irq_init(stmpe_gpio); if (ret) - goto out_free; + goto out_disable; ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); @@ -342,6 +345,8 @@ out_freeirq: free_irq(irq, stmpe_gpio); out_removeirq: stmpe_gpio_irq_remove(stmpe_gpio); +out_disable: + stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: kfree(stmpe_gpio); return ret; diff --git a/drivers/gpio/vx855_gpio.c b/drivers/gpio/vx855_gpio.c new file mode 100644 index 000000000000..8a98ee5d5f6c --- /dev/null +++ b/drivers/gpio/vx855_gpio.c @@ -0,0 +1,332 @@ +/* + * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO + * + * Copyright (C) 2009 VIA Technologies, Inc. + * Copyright (C) 2010 One Laptop per Child + * Author: Harald Welte <HaraldWelte@viatech.com> + * All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/pci.h> +#include <linux/io.h> + +#define MODULE_NAME "vx855_gpio" + +/* The VX855 south bridge has the following GPIO pins: + * GPI 0...13 General Purpose Input + * GPO 0...12 General Purpose Output + * GPIO 0...14 General Purpose I/O (Open-Drain) + */ + +#define NR_VX855_GPI 14 +#define NR_VX855_GPO 13 +#define NR_VX855_GPIO 15 + +#define NR_VX855_GPInO (NR_VX855_GPI + NR_VX855_GPO) +#define NR_VX855_GP (NR_VX855_GPI + NR_VX855_GPO + NR_VX855_GPIO) + +struct vx855_gpio { + struct gpio_chip gpio; + spinlock_t lock; + u32 io_gpi; + u32 io_gpo; + bool gpi_reserved; + bool gpo_reserved; +}; + +/* resolve a GPIx into the corresponding bit position */ +static inline u_int32_t gpi_i_bit(int i) +{ + if (i < 10) + return 1 << i; + else + return 1 << (i + 14); +} + +static inline u_int32_t gpo_o_bit(int i) +{ + if (i < 11) + return 1 << i; + else + return 1 << (i + 14); +} + +static inline u_int32_t gpio_i_bit(int i) +{ + if (i < 14) + return 1 << (i + 10); + else + return 1 << (i + 14); +} + +static inline u_int32_t gpio_o_bit(int i) +{ + if (i < 14) + return 1 << (i + 11); + else + return 1 << (i + 13); +} + +/* Mapping betwee numeric GPIO ID and the actual GPIO hardware numbering: + * 0..13 GPI 0..13 + * 14..26 GPO 0..12 + * 27..41 GPIO 0..14 + */ + +static int vx855gpio_direction_input(struct gpio_chip *gpio, + unsigned int nr) +{ + struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio); + unsigned long flags; + u_int32_t reg_out; + + /* Real GPI bits are always in input direction */ + if (nr < NR_VX855_GPI) + return 0; + + /* Real GPO bits cannot be put in output direction */ + if (nr < NR_VX855_GPInO) + return -EINVAL; + + /* Open Drain GPIO have to be set to one */ + spin_lock_irqsave(&vg->lock, flags); + reg_out = inl(vg->io_gpo); + reg_out |= gpio_o_bit(nr - NR_VX855_GPInO); + outl(reg_out, vg->io_gpo); + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr) +{ + struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio); + u_int32_t reg_in; + int ret = 0; + + if (nr < NR_VX855_GPI) { + reg_in = inl(vg->io_gpi); + if (reg_in & gpi_i_bit(nr)) + ret = 1; + } else if (nr < NR_VX855_GPInO) { + /* GPO don't have an input bit, we need to read it + * back from the output register */ + reg_in = inl(vg->io_gpo); + if (reg_in & gpo_o_bit(nr - NR_VX855_GPI)) + ret = 1; + } else { + reg_in = inl(vg->io_gpi); + if (reg_in & gpio_i_bit(nr - NR_VX855_GPInO)) + ret = 1; + } + + return ret; +} + +static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr, + int val) +{ + struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio); + unsigned long flags; + u_int32_t reg_out; + + /* True GPI cannot be switched to output mode */ + if (nr < NR_VX855_GPI) + return; + + spin_lock_irqsave(&vg->lock, flags); + reg_out = inl(vg->io_gpo); + if (nr < NR_VX855_GPInO) { + if (val) + reg_out |= gpo_o_bit(nr - NR_VX855_GPI); + else + reg_out &= ~gpo_o_bit(nr - NR_VX855_GPI); + } else { + if (val) + reg_out |= gpio_o_bit(nr - NR_VX855_GPInO); + else + reg_out &= ~gpio_o_bit(nr - NR_VX855_GPInO); + } + outl(reg_out, vg->io_gpo); + spin_unlock_irqrestore(&vg->lock, flags); +} + +static int vx855gpio_direction_output(struct gpio_chip *gpio, + unsigned int nr, int val) +{ + /* True GPI cannot be switched to output mode */ + if (nr < NR_VX855_GPI) + return -EINVAL; + + /* True GPO don't need to be switched to output mode, + * and GPIO are open-drain, i.e. also need no switching, + * so all we do is set the level */ + vx855gpio_set(gpio, nr, val); + + return 0; +} + +static const char *vx855gpio_names[NR_VX855_GP] = { + "VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4", + "VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9", + "VX855_GPI10", "VX855_GPI11", "VX855_GPI12", "VX855_GPI13", + "VX855_GPO0", "VX855_GPO1", "VX855_GPO2", "VX855_GPO3", "VX855_GPO4", + "VX855_GPO5", "VX855_GPO6", "VX855_GPO7", "VX855_GPO8", "VX855_GPO9", + "VX855_GPO10", "VX855_GPO11", "VX855_GPO12", + "VX855_GPIO0", "VX855_GPIO1", "VX855_GPIO2", "VX855_GPIO3", + "VX855_GPIO4", "VX855_GPIO5", "VX855_GPIO6", "VX855_GPIO7", + "VX855_GPIO8", "VX855_GPIO9", "VX855_GPIO10", "VX855_GPIO11", + "VX855_GPIO12", "VX855_GPIO13", "VX855_GPIO14" +}; + +static void vx855gpio_gpio_setup(struct vx855_gpio *vg) +{ + struct gpio_chip *c = &vg->gpio; + + c->label = "VX855 South Bridge"; + c->owner = THIS_MODULE; + c->direction_input = vx855gpio_direction_input; + c->direction_output = vx855gpio_direction_output; + c->get = vx855gpio_get; + c->set = vx855gpio_set; + c->dbg_show = NULL; + c->base = 0; + c->ngpio = NR_VX855_GP; + c->can_sleep = 0; + c->names = vx855gpio_names; +} + +/* This platform device is ordinarily registered by the vx855 mfd driver */ +static __devinit int vx855gpio_probe(struct platform_device *pdev) +{ + struct resource *res_gpi; + struct resource *res_gpo; + struct vx855_gpio *vg; + int ret; + + res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0); + res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (!res_gpi || !res_gpo) + return -EBUSY; + + vg = kzalloc(sizeof(*vg), GFP_KERNEL); + if (!vg) + return -ENOMEM; + + platform_set_drvdata(pdev, vg); + + dev_info(&pdev->dev, "found VX855 GPIO controller\n"); + vg->io_gpi = res_gpi->start; + vg->io_gpo = res_gpo->start; + spin_lock_init(&vg->lock); + + /* + * A single byte is used to control various GPIO ports on the VX855, + * and in the case of the OLPC XO-1.5, some of those ports are used + * for switches that are interpreted and exposed through ACPI. ACPI + * will have reserved the region, so our own reservation will not + * succeed. Ignore and continue. + */ + + if (!request_region(res_gpi->start, resource_size(res_gpi), + MODULE_NAME "_gpi")) + dev_warn(&pdev->dev, + "GPI I/O resource busy, probably claimed by ACPI\n"); + else + vg->gpi_reserved = true; + + if (!request_region(res_gpo->start, resource_size(res_gpo), + MODULE_NAME "_gpo")) + dev_warn(&pdev->dev, + "GPO I/O resource busy, probably claimed by ACPI\n"); + else + vg->gpo_reserved = true; + + vx855gpio_gpio_setup(vg); + + ret = gpiochip_add(&vg->gpio); + if (ret) { + dev_err(&pdev->dev, "failed to register GPIOs\n"); + goto out_release; + } + + return 0; + +out_release: + if (vg->gpi_reserved) + release_region(res_gpi->start, resource_size(res_gpi)); + if (vg->gpo_reserved) + release_region(res_gpi->start, resource_size(res_gpo)); + platform_set_drvdata(pdev, NULL); + kfree(vg); + return ret; +} + +static int __devexit vx855gpio_remove(struct platform_device *pdev) +{ + struct vx855_gpio *vg = platform_get_drvdata(pdev); + struct resource *res; + + if (gpiochip_remove(&vg->gpio)) + dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); + + if (vg->gpi_reserved) { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, resource_size(res)); + } + if (vg->gpo_reserved) { + res = platform_get_resource(pdev, IORESOURCE_IO, 1); + release_region(res->start, resource_size(res)); + } + + platform_set_drvdata(pdev, NULL); + kfree(vg); + return 0; +} + +static struct platform_driver vx855gpio_driver = { + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, + .probe = vx855gpio_probe, + .remove = __devexit_p(vx855gpio_remove), +}; + +static int vx855gpio_init(void) +{ + return platform_driver_register(&vx855gpio_driver); +} +module_init(vx855gpio_init); + +static void vx855gpio_exit(void) +{ + platform_driver_unregister(&vx855gpio_driver); +} +module_exit(vx855gpio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>"); +MODULE_DESCRIPTION("GPIO driver for the VIA VX855 chipset"); +MODULE_ALIAS("platform:vx855_gpio"); diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c index 2ac9a16d3daa..618398e4ed8e 100644 --- a/drivers/gpio/wm8994-gpio.c +++ b/drivers/gpio/wm8994-gpio.c @@ -140,6 +140,7 @@ static struct gpio_chip template_chip = { .get = wm8994_gpio_get, .direction_output = wm8994_gpio_direction_out, .set = wm8994_gpio_set, + .to_irq = wm8994_gpio_to_irq, .dbg_show = wm8994_gpio_dbg_show, .can_sleep = 1, }; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fd455a2fdd12..c950be3cce21 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -396,6 +396,16 @@ config I2C_IMX This driver can also be built as a module. If so, the module will be called i2c-imx. +config I2C_INTEL_MID + tristate "Intel Moorestown/Medfield Platform I2C controller" + depends on PCI + help + Say Y here if you have an Intel Moorestown/Medfield platform I2C + controller. + + This support is also available as a module. If so, the module + will be called i2c-intel-mid. + config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 033ad413f328..84cb16ae6f9e 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o +obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c new file mode 100644 index 000000000000..80f70d3a744d --- /dev/null +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -0,0 +1,1135 @@ +/* + * Support for Moorestown/Medfield I2C chip + * + * Copyright (c) 2009 Intel Corporation. + * Copyright (c) 2009 Synopsys. Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, version + * 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> + +#define DRIVER_NAME "i2c-intel-mid" +#define VERSION "Version 0.5ac2" +#define PLATFORM "Moorestown/Medfield" + +/* Tables use: 0 Moorestown, 1 Medfield */ +#define NUM_PLATFORMS 2 +enum platform_enum { + MOORESTOWN = 0, + MEDFIELD = 1, +}; + +enum mid_i2c_status { + STATUS_IDLE = 0, + STATUS_READ_START, + STATUS_READ_IN_PROGRESS, + STATUS_READ_SUCCESS, + STATUS_WRITE_START, + STATUS_WRITE_SUCCESS, + STATUS_XFER_ABORT, + STATUS_STANDBY +}; + +/** + * struct intel_mid_i2c_private - per device I²C context + * @adap: core i2c layer adapter information + * @dev: device reference for power management + * @base: register base + * @speed: speed mode for this port + * @complete: completion object for transaction wait + * @abort: reason for last abort + * @rx_buf: pointer into working receive buffer + * @rx_buf_len: receive buffer length + * @status: adapter state machine + * @msg: the message we are currently processing + * @platform: the MID device type we are part of + * @lock: transaction serialization + * + * We allocate one of these per device we discover, it holds the core + * i2c layer objects and the data we need to track privately. + */ +struct intel_mid_i2c_private { + struct i2c_adapter adap; + struct device *dev; + void __iomem *base; + int speed; + struct completion complete; + int abort; + u8 *rx_buf; + int rx_buf_len; + enum mid_i2c_status status; + struct i2c_msg *msg; + enum platform_enum platform; + struct mutex lock; +}; + +#define NUM_SPEEDS 3 + +#define ACTIVE 0 +#define STANDBY 1 + + +/* Control register */ +#define IC_CON 0x00 +#define SLV_DIS (1 << 6) /* Disable slave mode */ +#define RESTART (1 << 5) /* Send a Restart condition */ +#define ADDR_10BIT (1 << 4) /* 10-bit addressing */ +#define STANDARD_MODE (1 << 1) /* standard mode */ +#define FAST_MODE (2 << 1) /* fast mode */ +#define HIGH_MODE (3 << 1) /* high speed mode */ +#define MASTER_EN (1 << 0) /* Master mode */ + +/* Target address register */ +#define IC_TAR 0x04 +#define IC_TAR_10BIT_ADDR (1 << 12) /* 10-bit addressing */ +#define IC_TAR_SPECIAL (1 << 11) /* Perform special I2C cmd */ +#define IC_TAR_GC_OR_START (1 << 10) /* 0: Gerneral Call Address */ + /* 1: START BYTE */ +/* Slave Address Register */ +#define IC_SAR 0x08 /* Not used in Master mode */ + +/* High Speed Master Mode Code Address Register */ +#define IC_HS_MADDR 0x0c + +/* Rx/Tx Data Buffer and Command Register */ +#define IC_DATA_CMD 0x10 +#define IC_RD (1 << 8) /* 1: Read 0: Write */ + +/* Standard Speed Clock SCL High Count Register */ +#define IC_SS_SCL_HCNT 0x14 + +/* Standard Speed Clock SCL Low Count Register */ +#define IC_SS_SCL_LCNT 0x18 + +/* Fast Speed Clock SCL High Count Register */ +#define IC_FS_SCL_HCNT 0x1c + +/* Fast Spedd Clock SCL Low Count Register */ +#define IC_FS_SCL_LCNT 0x20 + +/* High Speed Clock SCL High Count Register */ +#define IC_HS_SCL_HCNT 0x24 + +/* High Speed Clock SCL Low Count Register */ +#define IC_HS_SCL_LCNT 0x28 + +/* Interrupt Status Register */ +#define IC_INTR_STAT 0x2c /* Read only */ +#define R_GEN_CALL (1 << 11) +#define R_START_DET (1 << 10) +#define R_STOP_DET (1 << 9) +#define R_ACTIVITY (1 << 8) +#define R_RX_DONE (1 << 7) +#define R_TX_ABRT (1 << 6) +#define R_RD_REQ (1 << 5) +#define R_TX_EMPTY (1 << 4) +#define R_TX_OVER (1 << 3) +#define R_RX_FULL (1 << 2) +#define R_RX_OVER (1 << 1) +#define R_RX_UNDER (1 << 0) + +/* Interrupt Mask Register */ +#define IC_INTR_MASK 0x30 /* Read and Write */ +#define M_GEN_CALL (1 << 11) +#define M_START_DET (1 << 10) +#define M_STOP_DET (1 << 9) +#define M_ACTIVITY (1 << 8) +#define M_RX_DONE (1 << 7) +#define M_TX_ABRT (1 << 6) +#define M_RD_REQ (1 << 5) +#define M_TX_EMPTY (1 << 4) +#define M_TX_OVER (1 << 3) +#define M_RX_FULL (1 << 2) +#define M_RX_OVER (1 << 1) +#define M_RX_UNDER (1 << 0) + +/* Raw Interrupt Status Register */ +#define IC_RAW_INTR_STAT 0x34 /* Read Only */ +#define GEN_CALL (1 << 11) /* General call */ +#define START_DET (1 << 10) /* (RE)START occured */ +#define STOP_DET (1 << 9) /* STOP occured */ +#define ACTIVITY (1 << 8) /* Bus busy */ +#define RX_DONE (1 << 7) /* Not used in Master mode */ +#define TX_ABRT (1 << 6) /* Transmit Abort */ +#define RD_REQ (1 << 5) /* Not used in Master mode */ +#define TX_EMPTY (1 << 4) /* TX FIFO <= threshold */ +#define TX_OVER (1 << 3) /* TX FIFO overflow */ +#define RX_FULL (1 << 2) /* RX FIFO >= threshold */ +#define RX_OVER (1 << 1) /* RX FIFO overflow */ +#define RX_UNDER (1 << 0) /* RX FIFO empty */ + +/* Receive FIFO Threshold Register */ +#define IC_RX_TL 0x38 + +/* Transmit FIFO Treshold Register */ +#define IC_TX_TL 0x3c + +/* Clear Combined and Individual Interrupt Register */ +#define IC_CLR_INTR 0x40 +#define CLR_INTR (1 << 0) + +/* Clear RX_UNDER Interrupt Register */ +#define IC_CLR_RX_UNDER 0x44 +#define CLR_RX_UNDER (1 << 0) + +/* Clear RX_OVER Interrupt Register */ +#define IC_CLR_RX_OVER 0x48 +#define CLR_RX_OVER (1 << 0) + +/* Clear TX_OVER Interrupt Register */ +#define IC_CLR_TX_OVER 0x4c +#define CLR_TX_OVER (1 << 0) + +#define IC_CLR_RD_REQ 0x50 + +/* Clear TX_ABRT Interrupt Register */ +#define IC_CLR_TX_ABRT 0x54 +#define CLR_TX_ABRT (1 << 0) +#define IC_CLR_RX_DONE 0x58 + +/* Clear ACTIVITY Interrupt Register */ +#define IC_CLR_ACTIVITY 0x5c +#define CLR_ACTIVITY (1 << 0) + +/* Clear STOP_DET Interrupt Register */ +#define IC_CLR_STOP_DET 0x60 +#define CLR_STOP_DET (1 << 0) + +/* Clear START_DET Interrupt Register */ +#define IC_CLR_START_DET 0x64 +#define CLR_START_DET (1 << 0) + +/* Clear GEN_CALL Interrupt Register */ +#define IC_CLR_GEN_CALL 0x68 +#define CLR_GEN_CALL (1 << 0) + +/* Enable Register */ +#define IC_ENABLE 0x6c +#define ENABLE (1 << 0) + +/* Status Register */ +#define IC_STATUS 0x70 /* Read Only */ +#define STAT_SLV_ACTIVITY (1 << 6) /* Slave not in idle */ +#define STAT_MST_ACTIVITY (1 << 5) /* Master not in idle */ +#define STAT_RFF (1 << 4) /* RX FIFO Full */ +#define STAT_RFNE (1 << 3) /* RX FIFO Not Empty */ +#define STAT_TFE (1 << 2) /* TX FIFO Empty */ +#define STAT_TFNF (1 << 1) /* TX FIFO Not Full */ +#define STAT_ACTIVITY (1 << 0) /* Activity Status */ + +/* Transmit FIFO Level Register */ +#define IC_TXFLR 0x74 /* Read Only */ +#define TXFLR (1 << 0) /* TX FIFO level */ + +/* Receive FIFO Level Register */ +#define IC_RXFLR 0x78 /* Read Only */ +#define RXFLR (1 << 0) /* RX FIFO level */ + +/* Transmit Abort Source Register */ +#define IC_TX_ABRT_SOURCE 0x80 +#define ABRT_SLVRD_INTX (1 << 15) +#define ABRT_SLV_ARBLOST (1 << 14) +#define ABRT_SLVFLUSH_TXFIFO (1 << 13) +#define ARB_LOST (1 << 12) +#define ABRT_MASTER_DIS (1 << 11) +#define ABRT_10B_RD_NORSTRT (1 << 10) +#define ABRT_SBYTE_NORSTRT (1 << 9) +#define ABRT_HS_NORSTRT (1 << 8) +#define ABRT_SBYTE_ACKDET (1 << 7) +#define ABRT_HS_ACKDET (1 << 6) +#define ABRT_GCALL_READ (1 << 5) +#define ABRT_GCALL_NOACK (1 << 4) +#define ABRT_TXDATA_NOACK (1 << 3) +#define ABRT_10ADDR2_NOACK (1 << 2) +#define ABRT_10ADDR1_NOACK (1 << 1) +#define ABRT_7B_ADDR_NOACK (1 << 0) + +/* Enable Status Register */ +#define IC_ENABLE_STATUS 0x9c +#define IC_EN (1 << 0) /* I2C in an enabled state */ + +/* Component Parameter Register 1*/ +#define IC_COMP_PARAM_1 0xf4 +#define APB_DATA_WIDTH (0x3 << 0) + +/* added by xiaolin --begin */ +#define SS_MIN_SCL_HIGH 4000 +#define SS_MIN_SCL_LOW 4700 +#define FS_MIN_SCL_HIGH 600 +#define FS_MIN_SCL_LOW 1300 +#define HS_MIN_SCL_HIGH_100PF 60 +#define HS_MIN_SCL_LOW_100PF 120 + +#define STANDARD 0 +#define FAST 1 +#define HIGH 2 + +#define NUM_SPEEDS 3 + +static int speed_mode[6] = { + FAST, + FAST, + FAST, + STANDARD, + FAST, + FAST +}; + +static int ctl_num = 6; +module_param_array(speed_mode, int, &ctl_num, S_IRUGO); +MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)"); + +/** + * intel_mid_i2c_disable - Disable I2C controller + * @adap: struct pointer to i2c_adapter + * + * Return Value: + * 0 success + * -EBUSY if device is busy + * -ETIMEDOUT if i2c cannot be disabled within the given time + * + * I2C bus state should be checked prior to disabling the hardware. If bus is + * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable + * I2C controller. + */ +static int intel_mid_i2c_disable(struct i2c_adapter *adap) +{ + struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); + int err = 0; + int count = 0; + int ret1, ret2; + static const u16 delay[NUM_SPEEDS] = {100, 25, 3}; + + /* Set IC_ENABLE to 0 */ + writel(0, i2c->base + IC_ENABLE); + + /* Check if device is busy */ + dev_dbg(&adap->dev, "mrst i2c disable\n"); + while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1) + || (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) { + udelay(delay[i2c->speed]); + writel(0, i2c->base + IC_ENABLE); + dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n", + count, i2c->speed); + if (count++ > 10) { + err = -ETIMEDOUT; + break; + } + } + + /* Clear all interrupts */ + readl(i2c->base + IC_CLR_INTR); + readl(i2c->base + IC_CLR_STOP_DET); + readl(i2c->base + IC_CLR_START_DET); + readl(i2c->base + IC_CLR_ACTIVITY); + readl(i2c->base + IC_CLR_TX_ABRT); + readl(i2c->base + IC_CLR_RX_OVER); + readl(i2c->base + IC_CLR_RX_UNDER); + readl(i2c->base + IC_CLR_TX_OVER); + readl(i2c->base + IC_CLR_RX_DONE); + readl(i2c->base + IC_CLR_GEN_CALL); + + /* Disable all interupts */ + writel(0x0000, i2c->base + IC_INTR_MASK); + + return err; +} + +/** + * intel_mid_i2c_hwinit - Initialize the I2C hardware registers + * @dev: pci device struct pointer + * + * This function will be called in intel_mid_i2c_probe() before device + * registration. + * + * Return Values: + * 0 success + * -EBUSY i2c cannot be disabled + * -ETIMEDOUT i2c cannot be disabled + * -EFAULT If APB data width is not 32-bit wide + * + * I2C should be disabled prior to other register operation. If failed, an + * errno is returned. Mask and Clear all interrpts, this should be done at + * first. Set common registers which will not be modified during normal + * transfers, including: controll register, FIFO threshold and clock freq. + * Check APB data width at last. + */ +static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c) +{ + int err; + + static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = { + { 0x75, 0x15, 0x07 }, + { 0x04c, 0x10, 0x06 } + }; + static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = { + { 0x7C, 0x21, 0x0E }, + { 0x053, 0x19, 0x0F } + }; + + /* Disable i2c first */ + err = intel_mid_i2c_disable(&i2c->adap); + if (err) + return err; + + /* + * Setup clock frequency and speed mode + * Enable restart condition, + * enable master FSM, disable slave FSM, + * use target address when initiating transfer + */ + + writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN, + i2c->base + IC_CON); + writel(hcnt[i2c->platform][i2c->speed], + i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3))); + writel(lcnt[i2c->platform][i2c->speed], + i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3))); + + /* Set tranmit & receive FIFO threshold to zero */ + writel(0x0, i2c->base + IC_RX_TL); + writel(0x0, i2c->base + IC_TX_TL); + + return 0; +} + +/** + * intel_mid_i2c_func - Return the supported three I2C operations. + * @adapter: i2c_adapter struct pointer + */ +static u32 intel_mid_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; +} + +/** + * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages + * are equal. + * @p1: first i2c_msg + * @p2: second i2c_msg + * + * Return Values: + * 0 if addresses are equal + * 1 if not equal + * + * Within a single transfer, the I2C client may need to send its address more + * than once. So a check if the addresses match is needed. + */ +static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1, + const struct i2c_msg *p2) +{ + if (p1->addr != p2->addr) + return 1; + if ((p1->flags ^ p2->flags) & I2C_M_TEN) + return 1; + return 0; +} + +/** + * intel_mid_i2c_abort - To handle transfer abortions and print error messages. + * @adap: i2c_adapter struct pointer + * + * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be + * distingushed. At present, no circumstances have been found out that + * multiple errors would be occured simutaneously, so we simply use the + * register value directly. + * + * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need + * a few extra steps) + */ +static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c) +{ + /* Read about source register */ + int abort = i2c->abort; + struct i2c_adapter *adap = &i2c->adap; + + /* Single transfer error check: + * According to databook, TX/RX FIFOs would be flushed when + * the abort interrupt occured. + */ + if (abort & ABRT_MASTER_DIS) + dev_err(&adap->dev, + "initiate master operation with master mode disabled.\n"); + if (abort & ABRT_10B_RD_NORSTRT) + dev_err(&adap->dev, + "RESTART disabled and master sent READ cmd in 10-bit addressing.\n"); + + if (abort & ABRT_SBYTE_NORSTRT) { + dev_err(&adap->dev, + "RESTART disabled and user is trying to send START byte.\n"); + writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE); + writel(RESTART, i2c->base + IC_CON); + writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR); + } + + if (abort & ABRT_SBYTE_ACKDET) + dev_err(&adap->dev, + "START byte was not acknowledged.\n"); + if (abort & ABRT_TXDATA_NOACK) + dev_dbg(&adap->dev, + "No acknowledgement received from slave.\n"); + if (abort & ABRT_10ADDR2_NOACK) + dev_dbg(&adap->dev, + "The 2nd address byte of the 10-bit address was not acknowledged.\n"); + if (abort & ABRT_10ADDR1_NOACK) + dev_dbg(&adap->dev, + "The 1st address byte of 10-bit address was not acknowledged.\n"); + if (abort & ABRT_7B_ADDR_NOACK) + dev_dbg(&adap->dev, + "I2C slave device not acknowledged.\n"); + + /* Clear TX_ABRT bit */ + readl(i2c->base + IC_CLR_TX_ABRT); + i2c->status = STATUS_XFER_ABORT; +} + +/** + * xfer_read - Internal function to implement master read transfer. + * @adap: i2c_adapter struct pointer + * @buf: buffer in i2c_msg + * @length: number of bytes to be read + * + * Return Values: + * 0 if the read transfer succeeds + * -ETIMEDOUT if cannot read the "raw" interrupt register + * -EINVAL if a transfer abort occurred + * + * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to + * data transfer. The actual "read" operation will be performed if an RX_FULL + * interrupt occurred. + * + * Note there may be two interrupt signals captured, one should read + * IC_RAW_INTR_STAT to separate between errors and actual data. + */ +static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +{ + struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); + int i = length; + int err; + + if (length >= 256) { + dev_err(&adap->dev, + "I2C FIFO cannot support larger than 256 bytes\n"); + return -EMSGSIZE; + } + + INIT_COMPLETION(i2c->complete); + + readl(i2c->base + IC_CLR_INTR); + writel(0x0044, i2c->base + IC_INTR_MASK); + + i2c->status = STATUS_READ_START; + + while (i--) + writel(IC_RD, i2c->base + IC_DATA_CMD); + + i2c->status = STATUS_READ_START; + err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); + if (!err) { + dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); + intel_mid_i2c_hwinit(i2c); + return -ETIMEDOUT; + } + if (i2c->status == STATUS_READ_SUCCESS) + return 0; + else + return -EIO; +} + +/** + * xfer_write - Internal function to implement master write transfer. + * @adap: i2c_adapter struct pointer + * @buf: buffer in i2c_msg + * @length: number of bytes to be read + * + * Return Values: + * 0 if the read transfer succeeds + * -ETIMEDOUT if we cannot read the "raw" interrupt register + * -EINVAL if a transfer abort occured + * + * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to + * data transfer. The actual "write" operation will be performed when the + * RX_FULL interrupt signal occurs. + * + * Note there may be two interrupt signals captured, one should read + * IC_RAW_INTR_STAT to separate between errors and actual data. + */ +static int xfer_write(struct i2c_adapter *adap, + unsigned char *buf, int length) +{ + struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); + int i, err; + + if (length >= 256) { + dev_err(&adap->dev, + "I2C FIFO cannot support larger than 256 bytes\n"); + return -EMSGSIZE; + } + + INIT_COMPLETION(i2c->complete); + + readl(i2c->base + IC_CLR_INTR); + writel(0x0050, i2c->base + IC_INTR_MASK); + + i2c->status = STATUS_WRITE_START; + for (i = 0; i < length; i++) + writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD); + + i2c->status = STATUS_WRITE_START; + err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); + if (!err) { + dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); + intel_mid_i2c_hwinit(i2c); + return -ETIMEDOUT; + } else { + if (i2c->status == STATUS_WRITE_SUCCESS) + return 0; + else + return -EIO; + } +} + +static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg) +{ + struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); + int err; + u32 reg; + u32 bit_mask; + u32 mode; + + /* Disable device first */ + err = intel_mid_i2c_disable(adap); + if (err) { + dev_err(&adap->dev, + "Cannot disable i2c controller, timeout\n"); + return err; + } + + mode = (1 + i2c->speed) << 1; + /* set the speed mode */ + reg = readl(i2c->base + IC_CON); + if ((reg & 0x06) != mode) { + dev_dbg(&adap->dev, "set mode %d\n", i2c->speed); + writel((reg & ~0x6) | mode, i2c->base + IC_CON); + } + + reg = readl(i2c->base + IC_CON); + /* use 7-bit addressing */ + if (pmsg->flags & I2C_M_TEN) { + if ((reg & ADDR_10BIT) != ADDR_10BIT) { + dev_dbg(&adap->dev, "set i2c 10 bit address mode\n"); + writel(reg | ADDR_10BIT, i2c->base + IC_CON); + } + } else { + if ((reg & ADDR_10BIT) != 0x0) { + dev_dbg(&adap->dev, "set i2c 7 bit address mode\n"); + writel(reg & ~ADDR_10BIT, i2c->base + IC_CON); + } + } + /* enable restart conditions */ + reg = readl(i2c->base + IC_CON); + if ((reg & RESTART) != RESTART) { + dev_dbg(&adap->dev, "enable restart conditions\n"); + writel(reg | RESTART, i2c->base + IC_CON); + } + + /* enable master FSM */ + reg = readl(i2c->base + IC_CON); + dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); + writel(reg | MASTER_EN, i2c->base + IC_CON); + if ((reg & SLV_DIS) != SLV_DIS) { + dev_dbg(&adap->dev, "enable master FSM\n"); + writel(reg | SLV_DIS, i2c->base + IC_CON); + dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); + } + + /* use target address when initiating transfer */ + reg = readl(i2c->base + IC_TAR); + bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START; + + if ((reg & bit_mask) != 0x0) { + dev_dbg(&adap->dev, + "WR: use target address when intiating transfer, i2c_tx_target\n"); + writel(reg & ~bit_mask, i2c->base + IC_TAR); + } + + /* set target address to the I2C slave address */ + dev_dbg(&adap->dev, + "set target address to the I2C slave address, addr is %x\n", + pmsg->addr); + writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0), + i2c->base + IC_TAR); + + /* Enable I2C controller */ + writel(ENABLE, i2c->base + IC_ENABLE); + + return 0; +} + +/** + * intel_mid_i2c_xfer - Main master transfer routine. + * @adap: i2c_adapter struct pointer + * @pmsg: i2c_msg struct pointer + * @num: number of i2c_msg + * + * Return Values: + * + number of messages transfered + * -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS + * -EINVAL If the address in i2c_msg is invalid + * + * This function will be registered in i2c-core and exposed to external + * I2C clients. + * 1. Disable I2C controller + * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT + * 3. Check if address in i2c_msg is valid + * 4. Enable I2C controller + * 5. Perform real transfer (call xfer_read or xfer_write) + * 6. Wait until the current transfer is finished (check bus state) + * 7. Mask and clear all interrupts + */ +static int intel_mid_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *pmsg, + int num) +{ + struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); + int i, err = 0; + + /* if number of messages equal 0*/ + if (num == 0) + return 0; + + pm_runtime_get(i2c->dev); + + mutex_lock(&i2c->lock); + dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num); + dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr); + + + if (i2c->status != STATUS_IDLE) { + dev_err(&adap->dev, "Adapter %d in transfer/standby\n", + adap->nr); + mutex_unlock(&i2c->lock); + pm_runtime_put(i2c->dev); + return -1; + } + + + for (i = 1; i < num; i++) { + /* Message address equal? */ + if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) { + dev_err(&adap->dev, "Invalid address in msg[%d]\n", i); + mutex_unlock(&i2c->lock); + pm_runtime_put(i2c->dev); + return -EINVAL; + } + } + + if (intel_mid_i2c_setup(adap, pmsg)) { + mutex_unlock(&i2c->lock); + pm_runtime_put(i2c->dev); + return -EINVAL; + } + + for (i = 0; i < num; i++) { + i2c->msg = pmsg; + i2c->status = STATUS_IDLE; + /* Read or Write */ + if (pmsg->flags & I2C_M_RD) { + dev_dbg(&adap->dev, "I2C_M_RD\n"); + err = xfer_read(adap, pmsg->buf, pmsg->len); + } else { + dev_dbg(&adap->dev, "I2C_M_WR\n"); + err = xfer_write(adap, pmsg->buf, pmsg->len); + } + if (err < 0) + break; + dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i); + pmsg++; /* next message */ + } + + /* Mask interrupts */ + writel(0x0000, i2c->base + IC_INTR_MASK); + /* Clear all interrupts */ + readl(i2c->base + IC_CLR_INTR); + + i2c->status = STATUS_IDLE; + mutex_unlock(&i2c->lock); + pm_runtime_put(i2c->dev); + + return err; +} + +static int intel_mid_i2c_runtime_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); + struct i2c_adapter *adap = to_i2c_adapter(dev); + int err; + + if (i2c->status != STATUS_IDLE) + return -1; + + intel_mid_i2c_disable(adap); + + err = pci_save_state(pdev); + if (err) { + dev_err(dev, "pci_save_state failed\n"); + return err; + } + + err = pci_set_power_state(pdev, PCI_D3hot); + if (err) { + dev_err(dev, "pci_set_power_state failed\n"); + return err; + } + i2c->status = STATUS_STANDBY; + + return 0; +} + +static int intel_mid_i2c_runtime_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); + int err; + + if (i2c->status != STATUS_STANDBY) + return 0; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + dev_err(dev, "pci_enable_device failed\n"); + return err; + } + + i2c->status = STATUS_IDLE; + + intel_mid_i2c_hwinit(i2c); + return err; +} + +static void i2c_isr_read(struct intel_mid_i2c_private *i2c) +{ + struct i2c_msg *msg = i2c->msg; + int rx_num; + u32 len; + u8 *buf; + + if (!(msg->flags & I2C_M_RD)) + return; + + if (i2c->status != STATUS_READ_IN_PROGRESS) { + len = msg->len; + buf = msg->buf; + } else { + len = i2c->rx_buf_len; + buf = i2c->rx_buf; + } + + rx_num = readl(i2c->base + IC_RXFLR); + + for (; len > 0 && rx_num > 0; len--, rx_num--) + *buf++ = readl(i2c->base + IC_DATA_CMD); + + if (len > 0) { + i2c->status = STATUS_READ_IN_PROGRESS; + i2c->rx_buf_len = len; + i2c->rx_buf = buf; + } else + i2c->status = STATUS_READ_SUCCESS; + + return; +} + +static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev) +{ + struct intel_mid_i2c_private *i2c = dev; + u32 stat = readl(i2c->base + IC_INTR_STAT); + + if (!stat) + return IRQ_NONE; + + dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat); + stat &= 0x54; + + if (i2c->status != STATUS_WRITE_START && + i2c->status != STATUS_READ_START && + i2c->status != STATUS_READ_IN_PROGRESS) + goto err; + + if (stat & TX_ABRT) + i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE); + + readl(i2c->base + IC_CLR_INTR); + + if (stat & TX_ABRT) { + intel_mid_i2c_abort(i2c); + goto exit; + } + + if (stat & RX_FULL) { + i2c_isr_read(i2c); + goto exit; + } + + if (stat & TX_EMPTY) { + if (readl(i2c->base + IC_STATUS) & 0x4) + i2c->status = STATUS_WRITE_SUCCESS; + } + +exit: + if (i2c->status == STATUS_READ_SUCCESS || + i2c->status == STATUS_WRITE_SUCCESS || + i2c->status == STATUS_XFER_ABORT) { + /* Clear all interrupts */ + readl(i2c->base + IC_CLR_INTR); + /* Mask interrupts */ + writel(0, i2c->base + IC_INTR_MASK); + complete(&i2c->complete); + } +err: + return IRQ_HANDLED; +} + +static struct i2c_algorithm intel_mid_i2c_algorithm = { + .master_xfer = intel_mid_i2c_xfer, + .functionality = intel_mid_i2c_func, +}; + + +static const struct dev_pm_ops intel_mid_i2c_pm_ops = { + .runtime_suspend = intel_mid_i2c_runtime_suspend, + .runtime_resume = intel_mid_i2c_runtime_resume, +}; + +/** + * intel_mid_i2c_probe - I2C controller initialization routine + * @dev: pci device + * @id: device id + * + * Return Values: + * 0 success + * -ENODEV If cannot allocate pci resource + * -ENOMEM If the register base remapping failed, or + * if kzalloc failed + * + * Initialization steps: + * 1. Request for PCI resource + * 2. Remap the start address of PCI resource to register base + * 3. Request for device memory region + * 4. Fill in the struct members of intel_mid_i2c_private + * 5. Call intel_mid_i2c_hwinit() for hardware initialization + * 6. Register I2C adapter in i2c-core + */ +static int __devinit intel_mid_i2c_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct intel_mid_i2c_private *mrst; + unsigned long start, len; + int err, busnum; + void __iomem *base = NULL; + + dev_dbg(&dev->dev, "Get into probe function for I2C\n"); + err = pci_enable_device(dev); + if (err) { + dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n", + err); + goto exit; + } + + /* Determine the address of the I2C area */ + start = pci_resource_start(dev, 0); + len = pci_resource_len(dev, 0); + if (!start || len == 0) { + dev_err(&dev->dev, "base address not set\n"); + err = -ENODEV; + goto exit; + } + dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n", + PLATFORM, start, len); + + err = pci_request_region(dev, 0, DRIVER_NAME); + if (err) { + dev_err(&dev->dev, "failed to request I2C region " + "0x%lx-0x%lx\n", start, + (unsigned long)pci_resource_end(dev, 0)); + goto exit; + } + + base = ioremap_nocache(start, len); + if (!base) { + dev_err(&dev->dev, "I/O memory remapping failed\n"); + err = -ENOMEM; + goto fail0; + } + + /* Allocate the per-device data structure, intel_mid_i2c_private */ + mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL); + if (mrst == NULL) { + dev_err(&dev->dev, "can't allocate interface\n"); + err = -ENOMEM; + goto fail1; + } + + /* Initialize struct members */ + snprintf(mrst->adap.name, sizeof(mrst->adap.name), + "MRST/Medfield I2C at %lx", start); + mrst->adap.owner = THIS_MODULE; + mrst->adap.algo = &intel_mid_i2c_algorithm; + mrst->adap.dev.parent = &dev->dev; + mrst->dev = &dev->dev; + mrst->base = base; + mrst->speed = STANDARD; + mrst->abort = 0; + mrst->rx_buf_len = 0; + mrst->status = STATUS_IDLE; + + pci_set_drvdata(dev, mrst); + i2c_set_adapdata(&mrst->adap, mrst); + + mrst->adap.nr = busnum = id->driver_data; + if (dev->device <= 0x0804) + mrst->platform = MOORESTOWN; + else + mrst->platform = MEDFIELD; + + dev_dbg(&dev->dev, "I2C%d\n", busnum); + + if (ctl_num > busnum) { + if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS) + dev_warn(&dev->dev, "invalid speed %d ignored.\n", + speed_mode[busnum]); + else + mrst->speed = speed_mode[busnum]; + } + + /* Initialize i2c controller */ + err = intel_mid_i2c_hwinit(mrst); + if (err < 0) { + dev_err(&dev->dev, "I2C interface initialization failed\n"); + goto fail2; + } + + mutex_init(&mrst->lock); + init_completion(&mrst->complete); + + /* Clear all interrupts */ + readl(mrst->base + IC_CLR_INTR); + writel(0x0000, mrst->base + IC_INTR_MASK); + + err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED, + mrst->adap.name, mrst); + if (err) { + dev_err(&dev->dev, "Failed to request IRQ for I2C controller: " + "%s", mrst->adap.name); + goto fail2; + } + + /* Adapter registration */ + err = i2c_add_numbered_adapter(&mrst->adap); + if (err) { + dev_err(&dev->dev, "Adapter %s registration failed\n", + mrst->adap.name); + goto fail3; + } + + dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n", + (mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield", + busnum); + + pm_runtime_enable(&dev->dev); + return 0; + +fail3: + free_irq(dev->irq, mrst); +fail2: + pci_set_drvdata(dev, NULL); + kfree(mrst); +fail1: + iounmap(base); +fail0: + pci_release_region(dev, 0); +exit: + return err; +} + +static void __devexit intel_mid_i2c_remove(struct pci_dev *dev) +{ + struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev); + intel_mid_i2c_disable(&mrst->adap); + if (i2c_del_adapter(&mrst->adap)) + dev_err(&dev->dev, "Failed to delete i2c adapter"); + + free_irq(dev->irq, mrst); + pci_set_drvdata(dev, NULL); + iounmap(mrst->base); + kfree(mrst); + pci_release_region(dev, 0); +} + +static struct pci_device_id intel_mid_i2c_ids[] = { + /* Moorestown */ + { PCI_VDEVICE(INTEL, 0x0802), 0 }, + { PCI_VDEVICE(INTEL, 0x0803), 1 }, + { PCI_VDEVICE(INTEL, 0x0804), 2 }, + /* Medfield */ + { PCI_VDEVICE(INTEL, 0x0817), 3,}, + { PCI_VDEVICE(INTEL, 0x0818), 4 }, + { PCI_VDEVICE(INTEL, 0x0819), 5 }, + { PCI_VDEVICE(INTEL, 0x082C), 0 }, + { PCI_VDEVICE(INTEL, 0x082D), 1 }, + { PCI_VDEVICE(INTEL, 0x082E), 2 }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids); + +static struct pci_driver intel_mid_i2c_driver = { + .name = DRIVER_NAME, + .id_table = intel_mid_i2c_ids, + .probe = intel_mid_i2c_probe, + .remove = __devexit_p(intel_mid_i2c_remove), +}; + +static int __init intel_mid_i2c_init(void) +{ + return pci_register_driver(&intel_mid_i2c_driver); +} + +static void __exit intel_mid_i2c_exit(void) +{ + pci_unregister_driver(&intel_mid_i2c_driver); +} + +module_init(intel_mid_i2c_init); +module_exit(intel_mid_i2c_exit); + +MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>"); +MODULE_DESCRIPTION("I2C driver for Moorestown Platform"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 73de8ade10b1..c9fffd0389fe 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 ST-Ericsson + * Copyright (C) 2009 ST-Ericsson SA * Copyright (C) 2009 STMicroelectronics * * I2C master mode controller driver, used in Nomadik 8815 @@ -103,6 +103,9 @@ /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 +/* per-transfer delay, required for the hardware to stabilize */ +#define I2C_DELAY 150 + enum i2c_status { I2C_NOP, I2C_ON_GOING, @@ -118,7 +121,7 @@ enum i2c_operation { }; /* controller response timeout in ms */ -#define I2C_TIMEOUT_MS 500 +#define I2C_TIMEOUT_MS 2000 /** * struct i2c_nmk_client - client specific data @@ -250,6 +253,8 @@ static int init_hw(struct nmk_i2c_dev *dev) { int stat; + clk_enable(dev->clk); + stat = flush_i2c_fifo(dev); if (stat) return stat; @@ -263,6 +268,9 @@ static int init_hw(struct nmk_i2c_dev *dev) dev->cli.operation = I2C_NO_OPERATION; + clk_disable(dev->clk); + + udelay(I2C_DELAY); return 0; } @@ -431,7 +439,6 @@ static int read_i2c(struct nmk_i2c_dev *dev) (void) init_hw(dev); status = -ETIMEDOUT; } - return status; } @@ -502,9 +509,9 @@ static int write_i2c(struct nmk_i2c_dev *dev) /** * nmk_i2c_xfer() - I2C transfer function used by kernel framework - * @i2c_adap - Adapter pointer to the controller - * @msgs[] - Pointer to data to be written. - * @num_msgs - Number of messages to be executed + * @i2c_adap: Adapter pointer to the controller + * @msgs: Pointer to data to be written. + * @num_msgs: Number of messages to be executed * * This is the function called by the generic kernel i2c_transfer() * or i2c_smbus...() API calls. Note that this code is protected by the @@ -559,6 +566,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (status) return status; + clk_enable(dev->clk); + /* setup the i2c controller */ setup_i2c_controller(dev); @@ -591,10 +600,13 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, dev_err(&dev->pdev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); + clk_disable(dev->clk); return status; } - mdelay(1); + udelay(I2C_DELAY); } + clk_disable(dev->clk); + /* return the no. messages processed */ if (status) return status; @@ -605,6 +617,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, /** * disable_interrupts() - disable the interrupts * @dev: private data of controller + * @irq: interrupt number */ static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq) { @@ -794,10 +807,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_I2C - | I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA - | I2C_FUNC_SMBUS_I2C_BLOCK; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm nmk_i2c_algo = { @@ -857,8 +867,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) goto err_no_clk; } - clk_enable(dev->clk); - adap = &dev->adap; adap->dev.parent = &pdev->dev; adap->owner = THIS_MODULE; @@ -895,7 +903,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) return 0; err_init_hw: - clk_disable(dev->clk); err_add_adap: clk_put(dev->clk); err_no_clk: @@ -928,7 +935,6 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) iounmap(dev->virtbase); if (res) release_mem_region(res->start, resource_size(res)); - clk_disable(dev->clk); clk_put(dev->clk); platform_set_drvdata(pdev, NULL); kfree(dev); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6a292ea5e35c..6c00c107ebf3 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -554,18 +554,23 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, int retry; int ret; + clk_enable(i2c->clk); + for (retry = 0; retry < adap->retries; retry++) { ret = s3c24xx_i2c_doxfer(i2c, msgs, num); - if (ret != -EAGAIN) + if (ret != -EAGAIN) { + clk_disable(i2c->clk); return ret; + } dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); udelay(100); } + clk_disable(i2c->clk); return -EREMOTEIO; } @@ -910,6 +915,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); + clk_disable(i2c->clk); return 0; err_cpufreq: @@ -977,7 +983,9 @@ static int s3c24xx_i2c_resume(struct device *dev) struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); i2c->suspended = 0; + clk_enable(i2c->clk); s3c24xx_i2c_init(i2c); + clk_disable(i2c->clk); return 0; } diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 97d98fbf5849..58c51cddc100 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -838,7 +838,7 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) { - hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x23 : 0x21); + hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23); } /** @@ -1173,8 +1173,9 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) u16 mcr; pci_read_config_word(dev, mcr_addr, &mcr); - pci_write_config_word(dev, mcr_addr, (mcr | 0x8000)); - /* now read cable id register */ + pci_write_config_word(dev, mcr_addr, mcr | 0x8000); + /* Debounce, then read cable ID register */ + udelay(10); pci_read_config_byte(dev, 0x5a, &scr1); pci_write_config_word(dev, mcr_addr, mcr); } else if (chip_type >= HPT370) { @@ -1185,10 +1186,11 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) u8 scr2 = 0; pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, (scr2 & ~1)); - /* now read cable id register */ + pci_write_config_byte(dev, 0x5b, scr2 & ~1); + /* Debounce, then read cable ID register */ + udelay(10); pci_read_config_byte(dev, 0x5a, &scr1); - pci_write_config_byte(dev, 0x5b, scr2); + pci_write_config_byte(dev, 0x5b, scr2); } else pci_read_config_byte(dev, 0x5a, &scr1); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 06b14bc9a1d4..d4136908f916 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -449,7 +449,6 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) ide_hwif_t *hwif = drive->hwif; const struct ide_dma_ops *dma_ops = hwif->dma_ops; struct ide_cmd *cmd = &hwif->cmd; - struct request *rq; ide_startstop_t ret = ide_stopped; /* @@ -487,14 +486,10 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) ide_dma_off_quietly(drive); /* - * un-busy drive etc and make sure request is sane + * make sure request is sane */ - rq = hwif->rq; - if (rq) { - hwif->rq = NULL; - rq->errors = 0; - ide_requeue_and_plug(drive, rq); - } + if (hwif->rq) + hwif->rq->errors = 0; return ret; } diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 12d5bf76302c..8c8afc716b98 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -362,13 +362,13 @@ bail: return ret; } -static int ipathfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ipathfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - int ret = get_sb_single(fs_type, flags, data, - ipathfs_fill_super, mnt); - if (ret >= 0) - ipath_super = mnt->mnt_sb; + struct dentry *ret; + ret = mount_single(fs_type, flags, data, ipathfs_fill_super); + if (!IS_ERR(ret)) + ipath_super = ret->d_sb; return ret; } @@ -411,7 +411,7 @@ bail: static struct file_system_type ipathfs_fs_type = { .owner = THIS_MODULE, .name = "ipathfs", - .get_sb = ipathfs_get_sb, + .mount = ipathfs_mount, .kill_sb = ipathfs_kill_super, }; diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index 7e433d75c775..f99bddc01716 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -555,13 +555,13 @@ bail: return ret; } -static int qibfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - int ret = get_sb_single(fs_type, flags, data, - qibfs_fill_super, mnt); - if (ret >= 0) - qib_super = mnt->mnt_sb; + struct dentry *ret; + ret = mount_single(fs_type, flags, data, qibfs_fill_super); + if (!IS_ERR(ret)) + qib_super = ret->d_sb; return ret; } @@ -603,7 +603,7 @@ int qibfs_remove(struct qib_devdata *dd) static struct file_system_type qibfs_fs_type = { .owner = THIS_MODULE, .name = "ipathfs", - .get_sb = qibfs_get_sb, + .mount = qibfs_mount, .kill_sb = qibfs_kill_super, }; diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index 80af44608018..7de0ded4ccc3 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c @@ -27,27 +27,37 @@ #include <linux/mfd/max8925.h> #include <linux/slab.h> +#define SW_INPUT (1 << 7) /* 0/1 -- up/down */ #define HARDRESET_EN (1 << 7) #define PWREN_EN (1 << 7) struct max8925_onkey_info { struct input_dev *idev; struct i2c_client *i2c; - int irq; + struct device *dev; + int irq[2]; }; /* - * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds. + * MAX8925 gives us an interrupt when ONKEY is pressed or released. * max8925_set_bits() operates I2C bus and may sleep. So implement * it in thread IRQ handler. */ static irqreturn_t max8925_onkey_handler(int irq, void *data) { struct max8925_onkey_info *info = data; - - input_report_key(info->idev, KEY_POWER, 1); + int ret, event; + + ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS); + if (ret & SW_INPUT) + event = 1; + else + event = 0; + input_report_key(info->idev, KEY_POWER, event); input_sync(info->idev); + dev_dbg(info->dev, "onkey event:%d\n", event); + /* Enable hardreset to halt if system isn't shutdown on time */ max8925_set_bits(info->i2c, MAX8925_SYSENSEL, HARDRESET_EN, HARDRESET_EN); @@ -59,14 +69,42 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_onkey_info *info; - int error; + int irq[2], error; + + irq[0] = platform_get_irq(pdev, 0); + if (irq[0] < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } + irq[1] = platform_get_irq(pdev, 1); + if (irq[1] < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); if (!info) return -ENOMEM; info->i2c = chip->i2c; - info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC; + info->dev = &pdev->dev; + irq[0] += chip->irq_base; + irq[1] += chip->irq_base; + + error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler, + IRQF_ONESHOT, "onkey-down", info); + if (error < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + irq[0], error); + goto out; + } + error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler, + IRQF_ONESHOT, "onkey-up", info); + if (error < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + irq[1], error); + goto out_irq; + } info->idev = input_allocate_device(); if (!info->idev) { @@ -79,32 +117,29 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) info->idev->phys = "max8925_on/input0"; info->idev->id.bustype = BUS_I2C; info->idev->dev.parent = &pdev->dev; + info->irq[0] = irq[0]; + info->irq[1] = irq[1]; info->idev->evbit[0] = BIT_MASK(EV_KEY); info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); - error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler, - IRQF_ONESHOT, "onkey", info); - if (error < 0) { - dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", - info->irq, error); - goto out_irq; - } error = input_register_device(info->idev); if (error) { dev_err(chip->dev, "Can't register input device: %d\n", error); - goto out; + goto out_reg; } platform_set_drvdata(pdev, info); return 0; -out: - free_irq(info->irq, info); -out_irq: +out_reg: input_free_device(info->idev); out_input: + free_irq(info->irq[1], info); +out_irq: + free_irq(info->irq[0], info); +out: kfree(info); return error; } @@ -113,7 +148,8 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev) { struct max8925_onkey_info *info = platform_get_drvdata(pdev); - free_irq(info->irq, info); + free_irq(info->irq[0], info); + free_irq(info->irq[1], info); input_unregister_device(info->idev); kfree(info); diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index ebb11907d402..e0c024db2ca5 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -276,6 +276,8 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 2b83850997c3..b4faed7fe0d3 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -125,16 +125,16 @@ fail: return -ENOMEM; } -static int capifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *capifs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt); + return mount_single(fs_type, flags, data, capifs_fill_super); } static struct file_system_type capifs_fs_type = { .owner = THIS_MODULE, .name = "capifs", - .get_sb = capifs_get_sb, + .mount = capifs_mount, .kill_sb = kill_anon_super, }; diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index b7677106cff8..e672b44ee172 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -24,26 +24,17 @@ #define LED_CURRENT_MASK (0x07 << 5) #define LED_BLINK_ON_MASK (0x07) -#define LED_BLINK_PERIOD_MASK (0x0F << 3) #define LED_BLINK_MASK (0x7F) #define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) -#define LED_BLINK_PERIOD(x) ((x & 0xF) * 530 + 930) #define LED_BLINK_ON_MIN LED_BLINK_ON(0) #define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) -#define LED_BLINK_PERIOD_MIN LED_BLINK_PERIOD(0) -#define LED_BLINK_PERIOD_MAX LED_BLINK_PERIOD(0xE) +#define LED_ON_CONTINUOUS (0x0F << 3) #define LED_TO_ON(x) ((x - 66) / 66) -#define LED_TO_PERIOD(x) ((x - 930) / 530) #define LED1_BLINK_EN (1 << 1) #define LED2_BLINK_EN (1 << 2) -enum { - SET_BRIGHTNESS, - SET_BLINK, -}; - struct pm860x_led { struct led_classdev cdev; struct i2c_client *i2c; @@ -54,8 +45,6 @@ struct pm860x_led { int port; int iset; - int command; - int offset; unsigned char brightness; unsigned char current_brightness; @@ -95,10 +84,12 @@ static inline int __blink_off(int port) case PM8606_LED1_GREEN: case PM8606_LED1_BLUE: ret = PM8606_RGB1A; + break; case PM8606_LED2_RED: case PM8606_LED2_GREEN: case PM8606_LED2_BLUE: ret = PM8606_RGB2A; + break; } return ret; } @@ -122,60 +113,35 @@ static inline int __blink_ctl_mask(int port) return ret; } -static int __led_set(struct pm860x_led *led, int command) +static void pm860x_led_work(struct work_struct *work) { - struct pm860x_chip *chip = led->chip; - int mask, ret; + struct pm860x_led *led; + struct pm860x_chip *chip; + int mask; + + led = container_of(work, struct pm860x_led, work); + chip = led->chip; mutex_lock(&led->lock); - switch (command) { - case SET_BRIGHTNESS: - if ((led->current_brightness == 0) && led->brightness) { - if (led->iset) { - ret = pm860x_set_bits(led->i2c, led->offset, - LED_CURRENT_MASK, led->iset); - if (ret < 0) - goto out; - } - } else if (led->brightness == 0) { - ret = pm860x_set_bits(led->i2c, led->offset, - LED_CURRENT_MASK, 0); - if (ret < 0) - goto out; + if ((led->current_brightness == 0) && led->brightness) { + if (led->iset) { + pm860x_set_bits(led->i2c, __led_off(led->port), + LED_CURRENT_MASK, led->iset); } - ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK, - led->brightness); - if (ret < 0) - goto out; - led->current_brightness = led->brightness; - dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", - led->offset, led->brightness); - break; - case SET_BLINK: - ret = pm860x_set_bits(led->i2c, led->offset, - LED_BLINK_MASK, led->blink_data); - if (ret < 0) - goto out; - mask = __blink_ctl_mask(led->port); - ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); - if (ret < 0) - goto out; - dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n", - led->blink_on, led->blink_off); - break; + pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); + } else if (led->brightness == 0) { + pm860x_set_bits(led->i2c, __led_off(led->port), + LED_CURRENT_MASK, 0); + mask = __blink_ctl_mask(led->port); + pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); } -out: + pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, + led->brightness); + led->current_brightness = led->brightness; + dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", + __led_off(led->port), led->brightness); mutex_unlock(&led->lock); - return 0; -} - -static void pm860x_led_work(struct work_struct *work) -{ - struct pm860x_led *led; - - led = container_of(work, struct pm860x_led, work); - __led_set(led, led->command); } static void pm860x_led_set(struct led_classdev *cdev, @@ -183,42 +149,10 @@ static void pm860x_led_set(struct led_classdev *cdev, { struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); - data->offset = __led_off(data->port); data->brightness = value >> 3; - data->command = SET_BRIGHTNESS; schedule_work(&data->work); } -static int pm860x_led_blink(struct led_classdev *cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); - int period, on; - - on = *delay_on; - if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX)) - return -EINVAL; - - on = LED_TO_ON(on); - on = LED_BLINK_ON(on); - - period = on + *delay_off; - if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX)) - return -EINVAL; - period = LED_TO_PERIOD(period); - period = LED_BLINK_PERIOD(period); - - data->offset = __blink_off(data->port); - data->blink_on = on; - data->blink_off = period - data->blink_on; - data->blink_data = (period << 3) | data->blink_on; - data->command = SET_BLINK; - schedule_work(&data->work); - - return 0; -} - static int __check_device(struct pm860x_led_pdata *pdata, char *name) { struct pm860x_led_pdata *p = pdata; @@ -257,7 +191,7 @@ static int pm860x_led_probe(struct platform_device *pdev) pm860x_pdata = pdev->dev.parent->platform_data; pdata = pm860x_pdata->led; } else { - dev_err(&pdev->dev, "missing platform data\n"); + dev_err(&pdev->dev, "No platform data!\n"); return -EINVAL; } @@ -279,7 +213,6 @@ static int pm860x_led_probe(struct platform_device *pdev) data->current_brightness = 0; data->cdev.name = data->name; data->cdev.brightness_set = pm860x_led_set; - data->cdev.blink_set = pm860x_led_blink; mutex_init(&data->lock); INIT_WORK(&data->work, pm860x_led_work); diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index e4fb58db5454..5a1ffe3527aa 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -212,7 +212,7 @@ static struct page *read_sb_page(mddev_t *mddev, loff_t offset, target = rdev->sb_start + offset + index * (PAGE_SIZE/512); - if (sync_page_io(rdev->bdev, target, + if (sync_page_io(rdev, target, roundup(size, bdev_logical_block_size(rdev->bdev)), page, READ)) { page->index = index; @@ -343,7 +343,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) atomic_inc(&bitmap->pending_writes); set_buffer_locked(bh); set_buffer_mapped(bh); - submit_bh(WRITE, bh); + submit_bh(WRITE | REQ_UNPLUG | REQ_SYNC, bh); bh = bh->b_this_page; } @@ -1101,7 +1101,7 @@ static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) bitmap_checkfree(bitmap, page); } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, - sector_t offset, int *blocks, + sector_t offset, sector_t *blocks, int create); /* @@ -1115,7 +1115,7 @@ void bitmap_daemon_work(mddev_t *mddev) unsigned long j; unsigned long flags; struct page *page = NULL, *lastpage = NULL; - int blocks; + sector_t blocks; void *paddr; struct dm_dirty_log *log = mddev->bitmap_info.log; @@ -1258,7 +1258,7 @@ void bitmap_daemon_work(mddev_t *mddev) } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, - sector_t offset, int *blocks, + sector_t offset, sector_t *blocks, int create) __releases(bitmap->lock) __acquires(bitmap->lock) @@ -1316,7 +1316,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect } while (sectors) { - int blocks; + sector_t blocks; bitmap_counter_t *bmc; spin_lock_irq(&bitmap->lock); @@ -1381,7 +1381,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto success = 0; while (sectors) { - int blocks; + sector_t blocks; unsigned long flags; bitmap_counter_t *bmc; @@ -1423,7 +1423,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto } EXPORT_SYMBOL(bitmap_endwrite); -static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, +static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded) { bitmap_counter_t *bmc; @@ -1452,7 +1452,7 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *bloc return rv; } -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded) { /* bitmap_start_sync must always report on multiples of whole @@ -1463,7 +1463,7 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, * Return the 'or' of the result. */ int rv = 0; - int blocks1; + sector_t blocks1; *blocks = 0; while (*blocks < (PAGE_SIZE>>9)) { @@ -1476,7 +1476,7 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, } EXPORT_SYMBOL(bitmap_start_sync); -void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int aborted) { bitmap_counter_t *bmc; unsigned long flags; @@ -1515,7 +1515,7 @@ void bitmap_close_sync(struct bitmap *bitmap) * RESYNC bit wherever it is still on */ sector_t sector = 0; - int blocks; + sector_t blocks; if (!bitmap) return; while (sector < bitmap->mddev->resync_max_sectors) { @@ -1528,7 +1528,7 @@ EXPORT_SYMBOL(bitmap_close_sync); void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) { sector_t s = 0; - int blocks; + sector_t blocks; if (!bitmap) return; @@ -1562,7 +1562,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n * be 0 at this point */ - int secs; + sector_t secs; bitmap_counter_t *bmc; spin_lock_irq(&bitmap->lock); bmc = bitmap_get_counter(bitmap, offset, &secs, 1); @@ -1790,7 +1790,7 @@ int bitmap_load(mddev_t *mddev) * All chunks should be clean, but some might need_sync. */ while (sector < mddev->resync_max_sectors) { - int blocks; + sector_t blocks; bitmap_start_sync(bitmap, sector, &blocks, 0); sector += blocks; } diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index e872a7bad6b8..931a7a7c3796 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -271,8 +271,8 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int behind); void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int success, int behind); -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded); -void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded); +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int aborted); void bitmap_close_sync(struct bitmap *bitmap); void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 1a8987884614..339fdc670751 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -210,7 +210,7 @@ static int make_request(mddev_t *mddev, struct bio *bio) } } if (failit) { - struct bio *b = bio_clone(bio, GFP_NOIO); + struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev); b->bi_bdev = conf->rdev->bdev; b->bi_private = bio; b->bi_end_io = faulty_fail; diff --git a/drivers/md/md.c b/drivers/md/md.c index 225815197a3d..4e957f3140a8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -57,8 +57,6 @@ #define DEBUG 0 #define dprintk(x...) ((void)(DEBUG && printk(x))) -static DEFINE_MUTEX(md_mutex); - #ifndef MODULE static void autostart_arrays(int part); #endif @@ -69,6 +67,8 @@ static DEFINE_SPINLOCK(pers_lock); static void md_print_devices(void); static DECLARE_WAIT_QUEUE_HEAD(resync_wait); +static struct workqueue_struct *md_wq; +static struct workqueue_struct *md_misc_wq; #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } @@ -149,6 +149,72 @@ static const struct block_device_operations md_fops; static int start_readonly; +/* bio_clone_mddev + * like bio_clone, but with a local bio set + */ + +static void mddev_bio_destructor(struct bio *bio) +{ + mddev_t *mddev, **mddevp; + + mddevp = (void*)bio; + mddev = mddevp[-1]; + + bio_free(bio, mddev->bio_set); +} + +struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, + mddev_t *mddev) +{ + struct bio *b; + mddev_t **mddevp; + + if (!mddev || !mddev->bio_set) + return bio_alloc(gfp_mask, nr_iovecs); + + b = bio_alloc_bioset(gfp_mask, nr_iovecs, + mddev->bio_set); + if (!b) + return NULL; + mddevp = (void*)b; + mddevp[-1] = mddev; + b->bi_destructor = mddev_bio_destructor; + return b; +} +EXPORT_SYMBOL_GPL(bio_alloc_mddev); + +struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, + mddev_t *mddev) +{ + struct bio *b; + mddev_t **mddevp; + + if (!mddev || !mddev->bio_set) + return bio_clone(bio, gfp_mask); + + b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, + mddev->bio_set); + if (!b) + return NULL; + mddevp = (void*)b; + mddevp[-1] = mddev; + b->bi_destructor = mddev_bio_destructor; + __bio_clone(b, bio); + if (bio_integrity(bio)) { + int ret; + + ret = bio_integrity_clone(b, bio, gfp_mask, mddev->bio_set); + + if (ret < 0) { + bio_put(b); + return NULL; + } + } + + return b; +} +EXPORT_SYMBOL_GPL(bio_clone_mddev); + /* * We have a system wide 'event count' that is incremented * on any 'interesting' event, and readers of /proc/mdstat @@ -300,7 +366,7 @@ static void md_end_flush(struct bio *bio, int err) if (atomic_dec_and_test(&mddev->flush_pending)) { /* The pre-request flush has finished */ - schedule_work(&mddev->flush_work); + queue_work(md_wq, &mddev->flush_work); } bio_put(bio); } @@ -321,7 +387,7 @@ static void submit_flushes(mddev_t *mddev) atomic_inc(&rdev->nr_pending); atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - bi = bio_alloc(GFP_KERNEL, 0); + bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev); bi->bi_end_io = md_end_flush; bi->bi_private = rdev; bi->bi_bdev = rdev->bdev; @@ -369,7 +435,7 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) submit_flushes(mddev); if (atomic_dec_and_test(&mddev->flush_pending)) - schedule_work(&mddev->flush_work); + queue_work(md_wq, &mddev->flush_work); } EXPORT_SYMBOL(md_flush_request); @@ -428,6 +494,8 @@ static void mddev_delayed_delete(struct work_struct *ws); static void mddev_put(mddev_t *mddev) { + struct bio_set *bs = NULL; + if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) return; if (!mddev->raid_disks && list_empty(&mddev->disks) && @@ -435,19 +503,22 @@ static void mddev_put(mddev_t *mddev) /* Array is not configured at all, and not held active, * so destroy it */ list_del(&mddev->all_mddevs); + bs = mddev->bio_set; + mddev->bio_set = NULL; if (mddev->gendisk) { - /* we did a probe so need to clean up. - * Call schedule_work inside the spinlock - * so that flush_scheduled_work() after - * mddev_find will succeed in waiting for the - * work to be done. + /* We did a probe so need to clean up. Call + * queue_work inside the spinlock so that + * flush_workqueue() after mddev_find will + * succeed in waiting for the work to be done. */ INIT_WORK(&mddev->del_work, mddev_delayed_delete); - schedule_work(&mddev->del_work); + queue_work(md_misc_wq, &mddev->del_work); } else kfree(mddev); } spin_unlock(&all_mddevs_lock); + if (bs) + bioset_free(bs); } void mddev_init(mddev_t *mddev) @@ -691,7 +762,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, * if zero is reached. * If an error occurred, call md_error */ - struct bio *bio = bio_alloc(GFP_NOIO, 1); + struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); bio->bi_bdev = rdev->bdev; bio->bi_sector = sector; @@ -722,16 +793,16 @@ static void bi_complete(struct bio *bio, int error) complete((struct completion*)bio->bi_private); } -int sync_page_io(struct block_device *bdev, sector_t sector, int size, - struct page *page, int rw) +int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, + struct page *page, int rw) { - struct bio *bio = bio_alloc(GFP_NOIO, 1); + struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev); struct completion event; int ret; rw |= REQ_SYNC | REQ_UNPLUG; - bio->bi_bdev = bdev; + bio->bi_bdev = rdev->bdev; bio->bi_sector = sector; bio_add_page(bio, page, size, 0); init_completion(&event); @@ -757,7 +828,7 @@ static int read_disk_sb(mdk_rdev_t * rdev, int size) return 0; - if (!sync_page_io(rdev->bdev, rdev->sb_start, size, rdev->sb_page, READ)) + if (!sync_page_io(rdev, rdev->sb_start, size, rdev->sb_page, READ)) goto fail; rdev->sb_loaded = 1; return 0; @@ -1850,7 +1921,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) synchronize_rcu(); INIT_WORK(&rdev->del_work, md_delayed_delete); kobject_get(&rdev->kobj); - schedule_work(&rdev->del_work); + queue_work(md_misc_wq, &rdev->del_work); } /* @@ -2108,6 +2179,8 @@ repeat: if (!mddev->persistent) { clear_bit(MD_CHANGE_CLEAN, &mddev->flags); clear_bit(MD_CHANGE_DEVS, &mddev->flags); + if (!mddev->external) + clear_bit(MD_CHANGE_PENDING, &mddev->flags); wake_up(&mddev->sb_wait); return; } @@ -4192,10 +4265,10 @@ static int md_alloc(dev_t dev, char *name) shift = partitioned ? MdpMinorShift : 0; unit = MINOR(mddev->unit) >> shift; - /* wait for any previous instance if this device - * to be completed removed (mddev_delayed_delete). + /* wait for any previous instance of this device to be + * completely removed (mddev_delayed_delete). */ - flush_scheduled_work(); + flush_workqueue(md_misc_wq); mutex_lock(&disks_mutex); error = -EEXIST; @@ -4378,6 +4451,9 @@ int md_run(mddev_t *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } + if (mddev->bio_set == NULL) + mddev->bio_set = bioset_create(BIO_POOL_SIZE, sizeof(mddev)); + spin_lock(&pers_lock); pers = find_pers(mddev->level, mddev->clevel); if (!pers || !try_module_get(pers->owner)) { @@ -5885,16 +5961,14 @@ static int md_open(struct block_device *bdev, fmode_t mode) mddev_t *mddev = mddev_find(bdev->bd_dev); int err; - mutex_lock(&md_mutex); if (mddev->gendisk != bdev->bd_disk) { /* we are racing with mddev_put which is discarding this * bd_disk. */ mddev_put(mddev); /* Wait until bdev->bd_disk is definitely gone */ - flush_scheduled_work(); + flush_workqueue(md_misc_wq); /* Then retry the open from the top */ - mutex_unlock(&md_mutex); return -ERESTARTSYS; } BUG_ON(mddev != bdev->bd_disk->private_data); @@ -5908,7 +5982,6 @@ static int md_open(struct block_device *bdev, fmode_t mode) check_disk_size_change(mddev->gendisk, bdev); out: - mutex_unlock(&md_mutex); return err; } @@ -5917,10 +5990,8 @@ static int md_release(struct gendisk *disk, fmode_t mode) mddev_t *mddev = disk->private_data; BUG_ON(!mddev); - mutex_lock(&md_mutex); atomic_dec(&mddev->openers); mddev_put(mddev); - mutex_unlock(&md_mutex); return 0; } @@ -6052,7 +6123,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); if (mddev->event_work.func) - schedule_work(&mddev->event_work); + queue_work(md_misc_wq, &mddev->event_work); md_new_event_inintr(mddev); } @@ -7212,12 +7283,23 @@ static void md_geninit(void) static int __init md_init(void) { - if (register_blkdev(MD_MAJOR, "md")) - return -1; - if ((mdp_major=register_blkdev(0, "mdp"))<=0) { - unregister_blkdev(MD_MAJOR, "md"); - return -1; - } + int ret = -ENOMEM; + + md_wq = alloc_workqueue("md", WQ_RESCUER, 0); + if (!md_wq) + goto err_wq; + + md_misc_wq = alloc_workqueue("md_misc", 0, 0); + if (!md_misc_wq) + goto err_misc_wq; + + if ((ret = register_blkdev(MD_MAJOR, "md")) < 0) + goto err_md; + + if ((ret = register_blkdev(0, "mdp")) < 0) + goto err_mdp; + mdp_major = ret; + blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE, md_probe, NULL, NULL); blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE, @@ -7228,8 +7310,16 @@ static int __init md_init(void) md_geninit(); return 0; -} +err_mdp: + unregister_blkdev(MD_MAJOR, "md"); +err_md: + destroy_workqueue(md_misc_wq); +err_misc_wq: + destroy_workqueue(md_wq); +err_wq: + return ret; +} #ifndef MODULE @@ -7316,6 +7406,8 @@ static __exit void md_exit(void) export_array(mddev); mddev->hold_active = 0; } + destroy_workqueue(md_misc_wq); + destroy_workqueue(md_wq); } subsys_initcall(md_init); diff --git a/drivers/md/md.h b/drivers/md/md.h index 112a2c32db0c..d05bab55df4e 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -331,6 +331,8 @@ struct mddev_s struct attribute_group *to_remove; struct plug_handle *plug; /* if used by personality */ + struct bio_set *bio_set; + /* Generic flush handling. * The last to finish preflush schedules a worker to submit * the rest of the request (without the REQ_FLUSH flag). @@ -495,7 +497,7 @@ extern void md_flush_request(mddev_t *mddev, struct bio *bio); extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, sector_t sector, int size, struct page *page); extern void md_super_wait(mddev_t *mddev); -extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, +extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, struct page *page, int rw); extern void md_do_sync(mddev_t *mddev); extern void md_new_event(mddev_t *mddev); @@ -517,4 +519,8 @@ extern void md_rdev_init(mdk_rdev_t *rdev); extern void mddev_suspend(mddev_t *mddev); extern void mddev_resume(mddev_t *mddev); +extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, + mddev_t *mddev); +extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, + mddev_t *mddev); #endif /* _MD_MD_H */ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 378a25894c57..45f8324196ec 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -100,7 +100,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) * Allocate bios : 1 for reading, n-1 for writing */ for (j = pi->raid_disks ; j-- ; ) { - bio = bio_alloc(gfp_flags, RESYNC_PAGES); + bio = bio_kmalloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_bio; r1_bio->bios[j] = bio; @@ -306,6 +306,28 @@ static void raid1_end_read_request(struct bio *bio, int error) rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); } +static void r1_bio_write_done(r1bio_t *r1_bio, int vcnt, struct bio_vec *bv, + int behind) +{ + if (atomic_dec_and_test(&r1_bio->remaining)) + { + /* it really is the end of this request */ + if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { + /* free extra copy of the data pages */ + int i = vcnt; + while (i--) + safe_put_page(bv[i].bv_page); + } + /* clear the bitmap if all writes complete successfully */ + bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, + r1_bio->sectors, + !test_bit(R1BIO_Degraded, &r1_bio->state), + behind); + md_write_end(r1_bio->mddev); + raid_end_bio_io(r1_bio); + } +} + static void raid1_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); @@ -373,21 +395,7 @@ static void raid1_end_write_request(struct bio *bio, int error) * Let's see if all mirrored write operations have finished * already. */ - if (atomic_dec_and_test(&r1_bio->remaining)) { - if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { - /* free extra copy of the data pages */ - int i = bio->bi_vcnt; - while (i--) - safe_put_page(bio->bi_io_vec[i].bv_page); - } - /* clear the bitmap if all writes complete successfully */ - bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, - r1_bio->sectors, - !test_bit(R1BIO_Degraded, &r1_bio->state), - behind); - md_write_end(r1_bio->mddev); - raid_end_bio_io(r1_bio); - } + r1_bio_write_done(r1_bio, bio->bi_vcnt, bio->bi_io_vec, behind); if (to_put) bio_put(to_put); @@ -411,11 +419,13 @@ static void raid1_end_write_request(struct bio *bio, int error) static int read_balance(conf_t *conf, r1bio_t *r1_bio) { const sector_t this_sector = r1_bio->sector; - int new_disk = conf->last_used, disk = new_disk; - int wonly_disk = -1; const int sectors = r1_bio->sectors; + int new_disk = -1; + int start_disk; + int i; sector_t new_distance, current_distance; mdk_rdev_t *rdev; + int choose_first; rcu_read_lock(); /* @@ -426,54 +436,33 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) retry: if (conf->mddev->recovery_cp < MaxSector && (this_sector + sectors >= conf->next_resync)) { - /* Choose the first operational device, for consistancy */ - new_disk = 0; - - for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); - r1_bio->bios[new_disk] == IO_BLOCKED || - !rdev || !test_bit(In_sync, &rdev->flags) - || test_bit(WriteMostly, &rdev->flags); - rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) { - - if (rdev && test_bit(In_sync, &rdev->flags) && - r1_bio->bios[new_disk] != IO_BLOCKED) - wonly_disk = new_disk; - - if (new_disk == conf->raid_disks - 1) { - new_disk = wonly_disk; - break; - } - } - goto rb_out; + choose_first = 1; + start_disk = 0; + } else { + choose_first = 0; + start_disk = conf->last_used; } - /* make sure the disk is operational */ - for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); - r1_bio->bios[new_disk] == IO_BLOCKED || - !rdev || !test_bit(In_sync, &rdev->flags) || - test_bit(WriteMostly, &rdev->flags); - rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) { - - if (rdev && test_bit(In_sync, &rdev->flags) && - r1_bio->bios[new_disk] != IO_BLOCKED) - wonly_disk = new_disk; - - if (new_disk <= 0) - new_disk = conf->raid_disks; - new_disk--; - if (new_disk == disk) { - new_disk = wonly_disk; + for (i = 0 ; i < conf->raid_disks ; i++) { + int disk = start_disk + i; + if (disk >= conf->raid_disks) + disk -= conf->raid_disks; + + rdev = rcu_dereference(conf->mirrors[disk].rdev); + if (r1_bio->bios[disk] == IO_BLOCKED + || rdev == NULL + || !test_bit(In_sync, &rdev->flags)) + continue; + + new_disk = disk; + if (!test_bit(WriteMostly, &rdev->flags)) break; - } } - if (new_disk < 0) + if (new_disk < 0 || choose_first) goto rb_out; - disk = new_disk; - /* now disk == new_disk == starting point for search */ - /* * Don't change to another disk for sequential reads: */ @@ -482,20 +471,21 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) if (this_sector == conf->mirrors[new_disk].head_position) goto rb_out; - current_distance = abs(this_sector - conf->mirrors[disk].head_position); - - /* Find the disk whose head is closest */ + current_distance = abs(this_sector + - conf->mirrors[new_disk].head_position); - do { - if (disk <= 0) - disk = conf->raid_disks; - disk--; + /* look for a better disk - i.e. head is closer */ + start_disk = new_disk; + for (i = 1; i < conf->raid_disks; i++) { + int disk = start_disk + 1; + if (disk >= conf->raid_disks) + disk -= conf->raid_disks; rdev = rcu_dereference(conf->mirrors[disk].rdev); - - if (!rdev || r1_bio->bios[disk] == IO_BLOCKED || - !test_bit(In_sync, &rdev->flags) || - test_bit(WriteMostly, &rdev->flags)) + if (r1_bio->bios[disk] == IO_BLOCKED + || rdev == NULL + || !test_bit(In_sync, &rdev->flags) + || test_bit(WriteMostly, &rdev->flags)) continue; if (!atomic_read(&rdev->nr_pending)) { @@ -507,11 +497,9 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) current_distance = new_distance; new_disk = disk; } - } while (disk != conf->last_used); + } rb_out: - - if (new_disk >= 0) { rdev = rcu_dereference(conf->mirrors[new_disk].rdev); if (!rdev) @@ -658,7 +646,7 @@ static void raise_barrier(conf_t *conf) /* block any new IO from starting */ conf->barrier++; - /* No wait for all pending IO to complete */ + /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, conf->resync_lock, @@ -735,23 +723,26 @@ static void unfreeze_array(conf_t *conf) } -/* duplicate the data pages for behind I/O */ -static struct page **alloc_behind_pages(struct bio *bio) +/* duplicate the data pages for behind I/O + * We return a list of bio_vec rather than just page pointers + * as it makes freeing easier + */ +static struct bio_vec *alloc_behind_pages(struct bio *bio) { int i; struct bio_vec *bvec; - struct page **pages = kzalloc(bio->bi_vcnt * sizeof(struct page *), + struct bio_vec *pages = kzalloc(bio->bi_vcnt * sizeof(struct bio_vec), GFP_NOIO); if (unlikely(!pages)) goto do_sync_io; bio_for_each_segment(bvec, bio, i) { - pages[i] = alloc_page(GFP_NOIO); - if (unlikely(!pages[i])) + pages[i].bv_page = alloc_page(GFP_NOIO); + if (unlikely(!pages[i].bv_page)) goto do_sync_io; - memcpy(kmap(pages[i]) + bvec->bv_offset, + memcpy(kmap(pages[i].bv_page) + bvec->bv_offset, kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len); - kunmap(pages[i]); + kunmap(pages[i].bv_page); kunmap(bvec->bv_page); } @@ -759,8 +750,8 @@ static struct page **alloc_behind_pages(struct bio *bio) do_sync_io: if (pages) - for (i = 0; i < bio->bi_vcnt && pages[i]; i++) - put_page(pages[i]); + for (i = 0; i < bio->bi_vcnt && pages[i].bv_page; i++) + put_page(pages[i].bv_page); kfree(pages); PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); return NULL; @@ -775,8 +766,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) int i, targets = 0, disks; struct bitmap *bitmap; unsigned long flags; - struct bio_list bl; - struct page **behind_pages = NULL; + struct bio_vec *behind_pages = NULL; const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); @@ -851,7 +841,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) } r1_bio->read_disk = rdisk; - read_bio = bio_clone(bio, GFP_NOIO); + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); r1_bio->bios[rdisk] = read_bio; @@ -873,13 +863,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) * bios[x] to bio */ disks = conf->raid_disks; -#if 0 - { static int first=1; - if (first) printk("First Write sector %llu disks %d\n", - (unsigned long long)r1_bio->sector, disks); - first = 0; - } -#endif retry_write: blocked_rdev = NULL; rcu_read_lock(); @@ -937,16 +920,17 @@ static int make_request(mddev_t *mddev, struct bio * bio) (behind_pages = alloc_behind_pages(bio)) != NULL) set_bit(R1BIO_BehindIO, &r1_bio->state); - atomic_set(&r1_bio->remaining, 0); + atomic_set(&r1_bio->remaining, 1); atomic_set(&r1_bio->behind_remaining, 0); - bio_list_init(&bl); + bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors, + test_bit(R1BIO_BehindIO, &r1_bio->state)); for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->bios[i]) continue; - mbio = bio_clone(bio, GFP_NOIO); + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); r1_bio->bios[i] = mbio; mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; @@ -963,39 +947,29 @@ static int make_request(mddev_t *mddev, struct bio * bio) * we clear any unused pointer in the io_vec, rather * than leave them unchanged. This is important * because when we come to free the pages, we won't - * know the originial bi_idx, so we just free + * know the original bi_idx, so we just free * them all */ __bio_for_each_segment(bvec, mbio, j, 0) - bvec->bv_page = behind_pages[j]; + bvec->bv_page = behind_pages[j].bv_page; if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags)) atomic_inc(&r1_bio->behind_remaining); } atomic_inc(&r1_bio->remaining); - - bio_list_add(&bl, mbio); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + blk_plug_device(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); } + r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL); kfree(behind_pages); /* the behind pages are attached to the bios now */ - bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors, - test_bit(R1BIO_BehindIO, &r1_bio->state)); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_merge(&conf->pending_bio_list, &bl); - bio_list_init(&bl); - - blk_plug_device(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - - /* In case raid1d snuck into freeze_array */ + /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); if (do_sync) md_wakeup_thread(mddev->thread); -#if 0 - while ((bio = bio_list_pop(&bl)) != NULL) - generic_make_request(bio); -#endif return 0; } @@ -1183,7 +1157,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } - /* Only remove non-faulty devices is recovery + /* Only remove non-faulty devices if recovery * is not possible. */ if (!test_bit(Faulty, &rdev->flags) && @@ -1245,7 +1219,7 @@ static void end_sync_write(struct bio *bio, int error) break; } if (!uptodate) { - int sync_blocks = 0; + sector_t sync_blocks = 0; sector_t s = r1_bio->sector; long sectors_to_go = r1_bio->sectors; /* make sure these bits doesn't get cleared. */ @@ -1388,7 +1362,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) * active, and resync is currently active */ rdev = conf->mirrors[d].rdev; - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1414,7 +1388,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) continue; rdev = conf->mirrors[d].rdev; atomic_add(s, &rdev->corrected_errors); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1429,7 +1403,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) if (r1_bio->bios[d]->bi_end_io != end_sync_read) continue; rdev = conf->mirrors[d].rdev; - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1513,7 +1487,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags) && - sync_page_io(rdev->bdev, + sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, READ)) @@ -1539,7 +1513,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, WRITE) == 0) @@ -1556,7 +1530,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, READ) == 0) @@ -1646,7 +1620,8 @@ static void raid1d(mddev_t *mddev) mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; bio_put(bio); - bio = bio_clone(r1_bio->master_bio, GFP_NOIO); + bio = bio_clone_mddev(r1_bio->master_bio, + GFP_NOIO, mddev); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; if (printk_ratelimit()) @@ -1705,7 +1680,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i int i; int wonly = -1; int write_targets = 0, read_targets = 0; - int sync_blocks; + sector_t sync_blocks; int still_degraded = 0; if (!conf->r1buf_pool) @@ -1755,11 +1730,11 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i msleep_interruptible(1000); bitmap_cond_end_sync(mddev->bitmap, sector_nr); + r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); raise_barrier(conf); conf->next_resync = sector_nr; - r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); rcu_read_lock(); /* * If we get a correctably read error during resync or recovery, @@ -1971,7 +1946,6 @@ static conf_t *setup_conf(mddev_t *mddev) init_waitqueue_head(&conf->wait_barrier); bio_list_init(&conf->pending_bio_list); - bio_list_init(&conf->flushing_bio_list); conf->last_used = -1; for (i = 0; i < conf->raid_disks; i++) { diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index adf8cfd73313..cbfdf1a6acd9 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -35,8 +35,6 @@ struct r1_private_data_s { struct list_head retry_list; /* queue pending writes and submit them on unplug */ struct bio_list pending_bio_list; - /* queue of writes that have been unplugged */ - struct bio_list flushing_bio_list; /* for use when syncing mirrors: */ diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f0d082f749be..c67aa54694ae 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -120,7 +120,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data) * Allocate bios. */ for (j = nalloc ; j-- ; ) { - bio = bio_alloc(gfp_flags, RESYNC_PAGES); + bio = bio_kmalloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_bio; r10_bio->devs[j].bio = bio; @@ -801,7 +801,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_fua = (bio->bi_rw & REQ_FUA); - struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; @@ -890,7 +889,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) } mirror = conf->mirrors + disk; - read_bio = bio_clone(bio, GFP_NOIO); + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); r10_bio->devs[slot].bio = read_bio; @@ -950,16 +949,16 @@ static int make_request(mddev_t *mddev, struct bio * bio) goto retry_write; } - atomic_set(&r10_bio->remaining, 0); + atomic_set(&r10_bio->remaining, 1); + bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0); - bio_list_init(&bl); for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; if (!r10_bio->devs[i].bio) continue; - mbio = bio_clone(bio, GFP_NOIO); + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); r10_bio->devs[i].bio = mbio; mbio->bi_sector = r10_bio->devs[i].addr+ @@ -970,22 +969,22 @@ static int make_request(mddev_t *mddev, struct bio * bio) mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); - bio_list_add(&bl, mbio); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + blk_plug_device(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); } - if (unlikely(!atomic_read(&r10_bio->remaining))) { - /* the array is dead */ + if (atomic_dec_and_test(&r10_bio->remaining)) { + /* This matches the end of raid10_end_write_request() */ + bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector, + r10_bio->sectors, + !test_bit(R10BIO_Degraded, &r10_bio->state), + 0); md_write_end(mddev); raid_end_bio_io(r10_bio); - return 0; } - bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_merge(&conf->pending_bio_list, &bl); - blk_plug_device(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); @@ -1558,7 +1557,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) test_bit(In_sync, &rdev->flags)) { atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - success = sync_page_io(rdev->bdev, + success = sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, @@ -1597,7 +1596,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) atomic_inc(&rdev->nr_pending); rcu_read_unlock(); atomic_add(s, &rdev->corrected_errors); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, WRITE) @@ -1634,7 +1633,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) char b[BDEVNAME_SIZE]; atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, @@ -1747,7 +1746,8 @@ static void raid10d(mddev_t *mddev) mdname(mddev), bdevname(rdev->bdev,b), (unsigned long long)r10_bio->sector); - bio = bio_clone(r10_bio->master_bio, GFP_NOIO); + bio = bio_clone_mddev(r10_bio->master_bio, + GFP_NOIO, mddev); r10_bio->devs[r10_bio->read_slot].bio = bio; bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset; @@ -1820,7 +1820,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i int disk; int i; int max_sync; - int sync_blocks; + sector_t sync_blocks; sector_t sectors_skipped = 0; int chunks_skipped = 0; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 31140d1259dc..dc574f303f8b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3876,9 +3876,9 @@ static int chunk_aligned_read(mddev_t *mddev, struct bio * raid_bio) return 0; } /* - * use bio_clone to make a copy of the bio + * use bio_clone_mddev to make a copy of the bio */ - align_bi = bio_clone(raid_bio, GFP_NOIO); + align_bi = bio_clone_mddev(raid_bio, GFP_NOIO, mddev); if (!align_bi) return 0; /* @@ -4360,7 +4360,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski raid5_conf_t *conf = mddev->private; struct stripe_head *sh; sector_t max_sector = mddev->dev_sectors; - int sync_blocks; + sector_t sync_blocks; int still_degraded = 0; int i; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 07933f3f7e4c..20895e7a99c9 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -158,6 +158,43 @@ static struct mfd_cell onkey_devs[] = { }, }; +static struct resource codec_resources[] = { + { + /* Headset microphone insertion or removal */ + .name = "micin", + .start = PM8607_IRQ_MICIN, + .end = PM8607_IRQ_MICIN, + .flags = IORESOURCE_IRQ, + }, { + /* Hook-switch press or release */ + .name = "hook", + .start = PM8607_IRQ_HOOK, + .end = PM8607_IRQ_HOOK, + .flags = IORESOURCE_IRQ, + }, { + /* Headset insertion or removal */ + .name = "headset", + .start = PM8607_IRQ_HEADSET, + .end = PM8607_IRQ_HEADSET, + .flags = IORESOURCE_IRQ, + }, { + /* Audio short */ + .name = "audio-short", + .start = PM8607_IRQ_AUDIO_SHORT, + .end = PM8607_IRQ_AUDIO_SHORT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell codec_devs[] = { + { + .name = "88pm860x-codec", + .num_resources = ARRAY_SIZE(codec_resources), + .resources = &codec_resources[0], + .id = -1, + }, +}; + static struct resource regulator_resources[] = { PM8607_REG_RESOURCE(BUCK1, BUCK1), PM8607_REG_RESOURCE(BUCK2, BUCK2), @@ -608,10 +645,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); goto out; } - if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION) + switch (ret & PM8607_VERSION_MASK) { + case 0x40: + case 0x50: dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", ret); - else { + break; + default: dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " "Chip ID: %02x\n", ret); goto out; @@ -687,6 +727,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out_dev; } + ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], + ARRAY_SIZE(codec_devs), + &codec_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add codec subdev\n"); + goto out_dev; + } return; out_dev: mfd_remove_devices(chip->dev); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index db51ea1c6082..3a1493b8b5e5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -75,7 +75,7 @@ config MFD_DAVINCI_VOICECODEC config MFD_DM355EVM_MSP bool "DaVinci DM355 EVM microcontroller" - depends on I2C && MACH_DAVINCI_DM355_EVM + depends on I2C=y && MACH_DAVINCI_DM355_EVM help This driver supports the MSP430 microcontroller used on these boards. MSP430 firmware manages resets and power sequencing, @@ -294,14 +294,15 @@ config MFD_MAX8925 to use the functionality of the device. config MFD_MAX8998 - bool "Maxim Semiconductor MAX8998 PMIC Support" - depends on I2C=y + bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE help - Say yes here to support for Maxim Semiconductor MAX8998. This is - a Power Management IC. This driver provies common support for - accessing the device, additional drivers must be enabled in order - to use the functionality of the device. + Say yes here to support for Maxim Semiconductor MAX8998 and + National Semiconductor LP3974. This is a Power Management IC. + This driver provies common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device. config MFD_WM8400 tristate "Support Wolfson Microelectronics WM8400" @@ -314,14 +315,30 @@ config MFD_WM8400 the functionality of the device. config MFD_WM831X - bool "Support Wolfson Microelectronics WM831x/2x PMICs" + bool + depends on GENERIC_HARDIRQS + +config MFD_WM831X_I2C + bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" select MFD_CORE + select MFD_WM831X depends on I2C=y && GENERIC_HARDIRQS help - Support for the Wolfson Microelecronics WM831x and WM832x PMICs. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. + Support for the Wolfson Microelecronics WM831x and WM832x PMICs + when controlled using I2C. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. + +config MFD_WM831X_SPI + bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" + select MFD_CORE + select MFD_WM831X + depends on SPI_MASTER && GENERIC_HARDIRQS + help + Support for the Wolfson Microelecronics WM831x and WM832x PMICs + when controlled using SPI. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. config MFD_WM8350 bool @@ -408,11 +425,16 @@ config MFD_PCF50633 so that function-specific drivers can bind to them. config MFD_MC13783 - tristate "Support Freescale MC13783" + tristate + +config MFD_MC13XXX + tristate "Support Freescale MC13783 and MC13892" depends on SPI_MASTER select MFD_CORE + select MFD_MC13783 help - Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC. + Support for the Freescale (Atlas) PMIC and audio CODECs + MC13783 and MC13892. This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality of the device. @@ -433,7 +455,7 @@ config PCF50633_GPIO config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U300 + default y if ARCH_U300 || ARCH_U8500 help Say yes here if you have the ABX500 Mixed Signal IC family chips. This core driver expose register access functions. @@ -444,6 +466,7 @@ config ABX500_CORE config AB3100_CORE bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" depends on I2C=y && ABX500_CORE + select MFD_CORE default y if ARCH_U300 help Select this to enable the AB3100 Mixed Signal IC core @@ -473,14 +496,33 @@ config EZX_PCAP config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on SPI=y && GENERIC_HARDIRQS + depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500 select MFD_CORE help Select this option to enable access to AB8500 power management - chip. This connects to U8500 on the SSP/SPI bus and exports - read/write functions for the devices to get access to this chip. + chip. This connects to U8500 either on the SSP/SPI bus + or the I2C bus via PRCMU. It also adds the irq_chip + parts for handling the Mixed Signal chip events. This chip embeds various other multimedia funtionalities as well. +config AB8500_I2C_CORE + bool "AB8500 register access via PRCMU I2C" + depends on AB8500_CORE && UX500_SOC_DB8500 + default y + help + This enables register access to the AB8500 chip via PRCMU I2C. + The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware + the I2C bus is connected to the Power Reset + and Mangagement Unit, PRCMU. + +config AB8500_DEBUG + bool "Enable debug info via debugfs" + depends on AB8500_CORE && DEBUG_FS + default y if DEBUG_FS + help + Select this option if you want debug information using the debug + filesystem, debugfs. + config AB3550_CORE bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" select MFD_CORE @@ -542,8 +584,8 @@ config MFD_JZ4740_ADC This driver is necessary for jz4740-battery and jz4740-hwmon driver. config MFD_TPS6586X - tristate "TPS6586x Power Management chips" - depends on I2C && GPIOLIB + bool "TPS6586x Power Management chips" + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS select MFD_CORE help If you say yes here you get support for the TPS6586X series of @@ -555,6 +597,15 @@ config MFD_TPS6586X This driver can also be built as a module. If so, the module will be called tps6586x. +config MFD_VX855 + tristate "Support for VIA VX855/VX875 integrated south bridge" + depends on PCI + select MFD_CORE + help + Say yes here to enable support for various functions of the + VIA VX855/VX875 south bridge. You will need to enable the vx855_spi + and/or vx855_gpio drivers for this to do anything useful. + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index feaeeaeeddb7..f54b3659abbb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o obj-$(CONFIG_MFD_WM831X) += wm831x.o +obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o +obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o wm8350-objs += wm8350-irq.o obj-$(CONFIG_MFD_WM8350) += wm8350.o @@ -39,7 +41,7 @@ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o -obj-$(CONFIG_MFD_MC13783) += mc13783-core.o +obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o obj-$(CONFIG_MFD_CORE) += mfd-core.o @@ -58,7 +60,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o -obj-$(CONFIG_MFD_MAX8998) += max8998.o +obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o @@ -69,6 +71,8 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB3550_CORE) += ab3550-core.o obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o +obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o +obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o obj-$(CONFIG_LPC_SCH) += lpc_sch.o @@ -76,3 +80,4 @@ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o +obj-$(CONFIG_MFD_VX855) += vx855.o diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index b048ecc56db9..4193af5f2743 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -19,6 +19,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/uaccess.h> +#include <linux/mfd/core.h> #include <linux/mfd/abx500.h> /* These are the only registers inside AB3100 used in this main file */ @@ -146,7 +147,7 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, } static int ab3100_get_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 *regval) + u8 reg, u8 *regval) { int err; @@ -202,7 +203,7 @@ static int ab3100_get_register_interruptible(struct ab3100 *ab3100, } static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, - u8 *value) + u8 *value) { struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); @@ -666,7 +667,7 @@ struct ab3100_init_setting { u8 setting; }; -static const struct ab3100_init_setting __initconst +static const struct ab3100_init_setting __devinitconst ab3100_init_settings[] = { { .abreg = AB3100_MCA, @@ -713,7 +714,7 @@ ab3100_init_settings[] = { }, }; -static int __init ab3100_setup(struct ab3100 *ab3100) +static int __devinit ab3100_setup(struct ab3100 *ab3100) { int err = 0; int i; @@ -743,52 +744,64 @@ static int __init ab3100_setup(struct ab3100 *ab3100) return err; } -/* - * Here we define all the platform devices that appear - * as children of the AB3100. These are regular platform - * devices with the IORESOURCE_IO .start and .end set - * to correspond to the internal AB3100 register range - * mapping to the corresponding subdevice. - */ - -#define AB3100_DEVICE(devname, devid) \ -static struct platform_device ab3100_##devname##_device = { \ - .name = devid, \ - .id = -1, \ -} - -/* This lists all the subdevices */ -AB3100_DEVICE(dac, "ab3100-dac"); -AB3100_DEVICE(leds, "ab3100-leds"); -AB3100_DEVICE(power, "ab3100-power"); -AB3100_DEVICE(regulators, "ab3100-regulators"); -AB3100_DEVICE(sim, "ab3100-sim"); -AB3100_DEVICE(uart, "ab3100-uart"); -AB3100_DEVICE(rtc, "ab3100-rtc"); -AB3100_DEVICE(charger, "ab3100-charger"); -AB3100_DEVICE(boost, "ab3100-boost"); -AB3100_DEVICE(adc, "ab3100-adc"); -AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge"); -AB3100_DEVICE(vibrator, "ab3100-vibrator"); -AB3100_DEVICE(otp, "ab3100-otp"); -AB3100_DEVICE(codec, "ab3100-codec"); - -static struct platform_device * -ab3100_platform_devs[] = { - &ab3100_dac_device, - &ab3100_leds_device, - &ab3100_power_device, - &ab3100_regulators_device, - &ab3100_sim_device, - &ab3100_uart_device, - &ab3100_rtc_device, - &ab3100_charger_device, - &ab3100_boost_device, - &ab3100_adc_device, - &ab3100_fuelgauge_device, - &ab3100_vibrator_device, - &ab3100_otp_device, - &ab3100_codec_device, +/* The subdevices of the AB3100 */ +static struct mfd_cell ab3100_devs[] = { + { + .name = "ab3100-dac", + .id = -1, + }, + { + .name = "ab3100-leds", + .id = -1, + }, + { + .name = "ab3100-power", + .id = -1, + }, + { + .name = "ab3100-regulators", + .id = -1, + }, + { + .name = "ab3100-sim", + .id = -1, + }, + { + .name = "ab3100-uart", + .id = -1, + }, + { + .name = "ab3100-rtc", + .id = -1, + }, + { + .name = "ab3100-charger", + .id = -1, + }, + { + .name = "ab3100-boost", + .id = -1, + }, + { + .name = "ab3100-adc", + .id = -1, + }, + { + .name = "ab3100-fuelgauge", + .id = -1, + }, + { + .name = "ab3100-vibrator", + .id = -1, + }, + { + .name = "ab3100-otp", + .id = -1, + }, + { + .name = "ab3100-codec", + .id = -1, + }, }; struct ab_family_id { @@ -796,7 +809,7 @@ struct ab_family_id { char *name; }; -static const struct ab_family_id ids[] __initdata = { +static const struct ab_family_id ids[] __devinitdata = { /* AB3100 */ { .id = 0xc0, @@ -850,8 +863,8 @@ static const struct ab_family_id ids[] __initdata = { }, }; -static int __init ab3100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int __devinit ab3100_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ab3100 *ab3100; struct ab3100_platform_data *ab3100_plf_data = @@ -935,18 +948,14 @@ static int __init ab3100_probe(struct i2c_client *client, if (err) goto exit_no_ops; - /* Set parent and a pointer back to the container in device data */ - for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) { - ab3100_platform_devs[i]->dev.parent = - &client->dev; - ab3100_platform_devs[i]->dev.platform_data = - ab3100_plf_data; - platform_set_drvdata(ab3100_platform_devs[i], ab3100); + /* Set up and register the platform devices. */ + for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { + ab3100_devs[i].platform_data = ab3100_plf_data; + ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data); } - /* Register the platform devices */ - platform_add_devices(ab3100_platform_devs, - ARRAY_SIZE(ab3100_platform_devs)); + err = mfd_add_devices(&client->dev, 0, ab3100_devs, + ARRAY_SIZE(ab3100_devs), NULL, 0); ab3100_setup_debugfs(ab3100); @@ -962,14 +971,12 @@ static int __init ab3100_probe(struct i2c_client *client, return err; } -static int __exit ab3100_remove(struct i2c_client *client) +static int __devexit ab3100_remove(struct i2c_client *client) { struct ab3100 *ab3100 = i2c_get_clientdata(client); - int i; /* Unregister subdevices */ - for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) - platform_device_unregister(ab3100_platform_devs[i]); + mfd_remove_devices(&client->dev); ab3100_remove_debugfs(); i2c_unregister_device(ab3100->testreg_client); @@ -996,7 +1003,7 @@ static struct i2c_driver ab3100_driver = { }, .id_table = ab3100_id, .probe = ab3100_probe, - .remove = __exit_p(ab3100_remove), + .remove = __devexit_p(ab3100_remove), }; static int __init ab3100_i2c_init(void) diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index b8c4b80e4c43..dbe1c93c1af3 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -4,6 +4,7 @@ * License Terms: GNU General Public License v2 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> * Author: Rabin Vincent <rabin.vincent@stericsson.com> + * Changes: Mattias Wallin <mattias.wallin@stericsson.com> */ #include <linux/kernel.h> @@ -15,6 +16,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mfd/core.h> +#include <linux/mfd/abx500.h> #include <linux/mfd/ab8500.h> #include <linux/regulator/ab8500.h> @@ -22,71 +24,71 @@ * Interrupt register offsets * Bank : 0x0E */ -#define AB8500_IT_SOURCE1_REG 0x0E00 -#define AB8500_IT_SOURCE2_REG 0x0E01 -#define AB8500_IT_SOURCE3_REG 0x0E02 -#define AB8500_IT_SOURCE4_REG 0x0E03 -#define AB8500_IT_SOURCE5_REG 0x0E04 -#define AB8500_IT_SOURCE6_REG 0x0E05 -#define AB8500_IT_SOURCE7_REG 0x0E06 -#define AB8500_IT_SOURCE8_REG 0x0E07 -#define AB8500_IT_SOURCE19_REG 0x0E12 -#define AB8500_IT_SOURCE20_REG 0x0E13 -#define AB8500_IT_SOURCE21_REG 0x0E14 -#define AB8500_IT_SOURCE22_REG 0x0E15 -#define AB8500_IT_SOURCE23_REG 0x0E16 -#define AB8500_IT_SOURCE24_REG 0x0E17 +#define AB8500_IT_SOURCE1_REG 0x00 +#define AB8500_IT_SOURCE2_REG 0x01 +#define AB8500_IT_SOURCE3_REG 0x02 +#define AB8500_IT_SOURCE4_REG 0x03 +#define AB8500_IT_SOURCE5_REG 0x04 +#define AB8500_IT_SOURCE6_REG 0x05 +#define AB8500_IT_SOURCE7_REG 0x06 +#define AB8500_IT_SOURCE8_REG 0x07 +#define AB8500_IT_SOURCE19_REG 0x12 +#define AB8500_IT_SOURCE20_REG 0x13 +#define AB8500_IT_SOURCE21_REG 0x14 +#define AB8500_IT_SOURCE22_REG 0x15 +#define AB8500_IT_SOURCE23_REG 0x16 +#define AB8500_IT_SOURCE24_REG 0x17 /* * latch registers */ -#define AB8500_IT_LATCH1_REG 0x0E20 -#define AB8500_IT_LATCH2_REG 0x0E21 -#define AB8500_IT_LATCH3_REG 0x0E22 -#define AB8500_IT_LATCH4_REG 0x0E23 -#define AB8500_IT_LATCH5_REG 0x0E24 -#define AB8500_IT_LATCH6_REG 0x0E25 -#define AB8500_IT_LATCH7_REG 0x0E26 -#define AB8500_IT_LATCH8_REG 0x0E27 -#define AB8500_IT_LATCH9_REG 0x0E28 -#define AB8500_IT_LATCH10_REG 0x0E29 -#define AB8500_IT_LATCH19_REG 0x0E32 -#define AB8500_IT_LATCH20_REG 0x0E33 -#define AB8500_IT_LATCH21_REG 0x0E34 -#define AB8500_IT_LATCH22_REG 0x0E35 -#define AB8500_IT_LATCH23_REG 0x0E36 -#define AB8500_IT_LATCH24_REG 0x0E37 +#define AB8500_IT_LATCH1_REG 0x20 +#define AB8500_IT_LATCH2_REG 0x21 +#define AB8500_IT_LATCH3_REG 0x22 +#define AB8500_IT_LATCH4_REG 0x23 +#define AB8500_IT_LATCH5_REG 0x24 +#define AB8500_IT_LATCH6_REG 0x25 +#define AB8500_IT_LATCH7_REG 0x26 +#define AB8500_IT_LATCH8_REG 0x27 +#define AB8500_IT_LATCH9_REG 0x28 +#define AB8500_IT_LATCH10_REG 0x29 +#define AB8500_IT_LATCH19_REG 0x32 +#define AB8500_IT_LATCH20_REG 0x33 +#define AB8500_IT_LATCH21_REG 0x34 +#define AB8500_IT_LATCH22_REG 0x35 +#define AB8500_IT_LATCH23_REG 0x36 +#define AB8500_IT_LATCH24_REG 0x37 /* * mask registers */ -#define AB8500_IT_MASK1_REG 0x0E40 -#define AB8500_IT_MASK2_REG 0x0E41 -#define AB8500_IT_MASK3_REG 0x0E42 -#define AB8500_IT_MASK4_REG 0x0E43 -#define AB8500_IT_MASK5_REG 0x0E44 -#define AB8500_IT_MASK6_REG 0x0E45 -#define AB8500_IT_MASK7_REG 0x0E46 -#define AB8500_IT_MASK8_REG 0x0E47 -#define AB8500_IT_MASK9_REG 0x0E48 -#define AB8500_IT_MASK10_REG 0x0E49 -#define AB8500_IT_MASK11_REG 0x0E4A -#define AB8500_IT_MASK12_REG 0x0E4B -#define AB8500_IT_MASK13_REG 0x0E4C -#define AB8500_IT_MASK14_REG 0x0E4D -#define AB8500_IT_MASK15_REG 0x0E4E -#define AB8500_IT_MASK16_REG 0x0E4F -#define AB8500_IT_MASK17_REG 0x0E50 -#define AB8500_IT_MASK18_REG 0x0E51 -#define AB8500_IT_MASK19_REG 0x0E52 -#define AB8500_IT_MASK20_REG 0x0E53 -#define AB8500_IT_MASK21_REG 0x0E54 -#define AB8500_IT_MASK22_REG 0x0E55 -#define AB8500_IT_MASK23_REG 0x0E56 -#define AB8500_IT_MASK24_REG 0x0E57 - -#define AB8500_REV_REG 0x1080 +#define AB8500_IT_MASK1_REG 0x40 +#define AB8500_IT_MASK2_REG 0x41 +#define AB8500_IT_MASK3_REG 0x42 +#define AB8500_IT_MASK4_REG 0x43 +#define AB8500_IT_MASK5_REG 0x44 +#define AB8500_IT_MASK6_REG 0x45 +#define AB8500_IT_MASK7_REG 0x46 +#define AB8500_IT_MASK8_REG 0x47 +#define AB8500_IT_MASK9_REG 0x48 +#define AB8500_IT_MASK10_REG 0x49 +#define AB8500_IT_MASK11_REG 0x4A +#define AB8500_IT_MASK12_REG 0x4B +#define AB8500_IT_MASK13_REG 0x4C +#define AB8500_IT_MASK14_REG 0x4D +#define AB8500_IT_MASK15_REG 0x4E +#define AB8500_IT_MASK16_REG 0x4F +#define AB8500_IT_MASK17_REG 0x50 +#define AB8500_IT_MASK18_REG 0x51 +#define AB8500_IT_MASK19_REG 0x52 +#define AB8500_IT_MASK20_REG 0x53 +#define AB8500_IT_MASK21_REG 0x54 +#define AB8500_IT_MASK22_REG 0x55 +#define AB8500_IT_MASK23_REG 0x56 +#define AB8500_IT_MASK24_REG 0x57 + +#define AB8500_REV_REG 0x80 /* * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt @@ -99,96 +101,132 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, }; -static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) +static int ab8500_get_chip_id(struct device *dev) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + return (int)ab8500->chip_id; +} + +static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, + u8 reg, u8 data) { int ret; + /* + * Put the u8 bank and u8 register together into a an u16. + * The bank on higher 8 bits and register in lower 8 bits. + * */ + u16 addr = ((u16)bank) << 8 | reg; dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); + ret = mutex_lock_interruptible(&ab8500->lock); + if (ret) + return ret; + ret = ab8500->write(ab8500, addr, data); if (ret < 0) dev_err(ab8500->dev, "failed to write reg %#x: %d\n", addr, ret); + mutex_unlock(&ab8500->lock); return ret; } -/** - * ab8500_write() - write an AB8500 register - * @ab8500: device to write to - * @addr: address of the register - * @data: value to write - */ -int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) +static int ab8500_set_register(struct device *dev, u8 bank, + u8 reg, u8 value) { - int ret; + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); - mutex_lock(&ab8500->lock); - ret = __ab8500_write(ab8500, addr, data); - mutex_unlock(&ab8500->lock); - - return ret; + return set_register_interruptible(ab8500, bank, reg, value); } -EXPORT_SYMBOL_GPL(ab8500_write); -static int __ab8500_read(struct ab8500 *ab8500, u16 addr) +static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, + u8 reg, u8 *value) { int ret; + /* put the u8 bank and u8 reg together into a an u16. + * bank on higher 8 bits and reg in lower */ + u16 addr = ((u16)bank) << 8 | reg; + + ret = mutex_lock_interruptible(&ab8500->lock); + if (ret) + return ret; ret = ab8500->read(ab8500, addr); if (ret < 0) dev_err(ab8500->dev, "failed to read reg %#x: %d\n", addr, ret); + else + *value = ret; + mutex_unlock(&ab8500->lock); dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); return ret; } -/** - * ab8500_read() - read an AB8500 register - * @ab8500: device to read from - * @addr: address of the register - */ -int ab8500_read(struct ab8500 *ab8500, u16 addr) +static int ab8500_get_register(struct device *dev, u8 bank, + u8 reg, u8 *value) { - int ret; - - mutex_lock(&ab8500->lock); - ret = __ab8500_read(ab8500, addr); - mutex_unlock(&ab8500->lock); + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); - return ret; + return get_register_interruptible(ab8500, bank, reg, value); } -EXPORT_SYMBOL_GPL(ab8500_read); - -/** - * ab8500_set_bits() - set a bitfield in an AB8500 register - * @ab8500: device to read from - * @addr: address of the register - * @mask: mask of the bitfield to modify - * @data: value to set to the bitfield - */ -int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data) + +static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, + u8 reg, u8 bitmask, u8 bitvalues) { int ret; + u8 data; + /* put the u8 bank and u8 reg together into a an u16. + * bank on higher 8 bits and reg in lower */ + u16 addr = ((u16)bank) << 8 | reg; - mutex_lock(&ab8500->lock); + ret = mutex_lock_interruptible(&ab8500->lock); + if (ret) + return ret; - ret = __ab8500_read(ab8500, addr); - if (ret < 0) + ret = ab8500->read(ab8500, addr); + if (ret < 0) { + dev_err(ab8500->dev, "failed to read reg %#x: %d\n", + addr, ret); goto out; + } - ret &= ~mask; - ret |= data; + data = (u8)ret; + data = (~bitmask & data) | (bitmask & bitvalues); - ret = __ab8500_write(ab8500, addr, ret); + ret = ab8500->write(ab8500, addr, data); + if (ret < 0) + dev_err(ab8500->dev, "failed to write reg %#x: %d\n", + addr, ret); + dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data); out: mutex_unlock(&ab8500->lock); return ret; } -EXPORT_SYMBOL_GPL(ab8500_set_bits); + +static int ab8500_mask_and_set_register(struct device *dev, + u8 bank, u8 reg, u8 bitmask, u8 bitvalues) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + + return mask_and_set_register_interruptible(ab8500, bank, reg, + bitmask, bitvalues); + +} + +static struct abx500_ops ab8500_ops = { + .get_chip_id = ab8500_get_chip_id, + .get_register = ab8500_get_register, + .set_register = ab8500_set_register, + .get_register_page = NULL, + .set_register_page = NULL, + .mask_and_set_register = ab8500_mask_and_set_register, + .event_registers_startup_state_get = NULL, + .startup_irq_enabled = NULL, +}; static void ab8500_irq_lock(unsigned int irq) { @@ -213,7 +251,7 @@ static void ab8500_irq_sync_unlock(unsigned int irq) ab8500->oldmask[i] = new; reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; - ab8500_write(ab8500, reg, new); + set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); } mutex_unlock(&ab8500->irq_lock); @@ -257,9 +295,11 @@ static irqreturn_t ab8500_irq(int irq, void *dev) for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { int regoffset = ab8500_irq_regoffset[i]; int status; + u8 value; - status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset); - if (status <= 0) + status = get_register_interruptible(ab8500, AB8500_INTERRUPT, + AB8500_IT_LATCH1_REG + regoffset, &value); + if (status < 0 || value == 0) continue; do { @@ -267,8 +307,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int line = i * 8 + bit; handle_nested_irq(ab8500->irq_base + line); - status &= ~(1 << bit); - } while (status); + value &= ~(1 << bit); + } while (value); } return IRQ_HANDLED; @@ -354,6 +394,11 @@ static struct resource ab8500_poweronkey_db_resources[] = { }; static struct mfd_cell ab8500_devs[] = { +#ifdef CONFIG_DEBUG_FS + { + .name = "ab8500-debug", + }, +#endif { .name = "ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), @@ -364,10 +409,21 @@ static struct mfd_cell ab8500_devs[] = { .num_resources = ARRAY_SIZE(ab8500_rtc_resources), .resources = ab8500_rtc_resources, }, + { + .name = "ab8500-pwm", + .id = 1, + }, + { + .name = "ab8500-pwm", + .id = 2, + }, + { + .name = "ab8500-pwm", + .id = 3, + }, { .name = "ab8500-charger", }, { .name = "ab8500-audio", }, { .name = "ab8500-usb", }, - { .name = "ab8500-pwm", }, { .name = "ab8500-regulator", }, { .name = "ab8500-poweron-key", @@ -381,6 +437,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500) struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); int ret; int i; + u8 value; if (plat) ab8500->irq_base = plat->irq_base; @@ -388,7 +445,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500) mutex_init(&ab8500->lock); mutex_init(&ab8500->irq_lock); - ret = ab8500_read(ab8500, AB8500_REV_REG); + ret = get_register_interruptible(ab8500, AB8500_MISC, + AB8500_REV_REG, &value); if (ret < 0) return ret; @@ -397,28 +455,37 @@ int __devinit ab8500_init(struct ab8500 *ab8500) * 0x10 - Cut 1.0 * 0x11 - Cut 1.1 */ - if (ret == 0x0 || ret == 0x10 || ret == 0x11) { - ab8500->revision = ret; - dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret); + if (value == 0x0 || value == 0x10 || value == 0x11) { + ab8500->revision = value; + dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); } else { - dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret); + dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); return -EINVAL; } + ab8500->chip_id = value; if (plat && plat->init) plat->init(ab8500); /* Clear and mask all interrupts */ for (i = 0; i < 10; i++) { - ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); - ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); + get_register_interruptible(ab8500, AB8500_INTERRUPT, + AB8500_IT_LATCH1_REG + i, &value); + set_register_interruptible(ab8500, AB8500_INTERRUPT, + AB8500_IT_MASK1_REG + i, 0xff); } for (i = 18; i < 24; i++) { - ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); - ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); + get_register_interruptible(ab8500, AB8500_INTERRUPT, + AB8500_IT_LATCH1_REG + i, &value); + set_register_interruptible(ab8500, AB8500_INTERRUPT, + AB8500_IT_MASK1_REG + i, 0xff); } + ret = abx500_register_ops(ab8500->dev, &ab8500_ops); + if (ret) + return ret; + for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) ab8500->mask[i] = ab8500->oldmask[i] = 0xff; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c new file mode 100644 index 000000000000..8d1e05a39815 --- /dev/null +++ b/drivers/mfd/ab8500-debugfs.c @@ -0,0 +1,652 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. + * License Terms: GNU General Public License v2 + */ + +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/debugfs.h> +#include <linux/platform_device.h> + +#include <linux/mfd/abx500.h> +#include <linux/mfd/ab8500.h> + +static u32 debug_bank; +static u32 debug_address; + +/** + * struct ab8500_reg_range + * @first: the first address of the range + * @last: the last address of the range + * @perm: access permissions for the range + */ +struct ab8500_reg_range { + u8 first; + u8 last; + u8 perm; +}; + +/** + * struct ab8500_i2c_ranges + * @num_ranges: the number of ranges in the list + * @bankid: bank identifier + * @range: the list of register ranges + */ +struct ab8500_i2c_ranges { + u8 num_ranges; + u8 bankid; + const struct ab8500_reg_range *range; +}; + +#define AB8500_NAME_STRING "ab8500" +#define AB8500_NUM_BANKS 22 + +#define AB8500_REV_REG 0x80 + +static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { + [0x0] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_SYS_CTRL1_BLOCK] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x02, + }, + { + .first = 0x42, + .last = 0x42, + }, + { + .first = 0x80, + .last = 0x81, + }, + }, + }, + [AB8500_SYS_CTRL2_BLOCK] = { + .num_ranges = 4, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x0D, + }, + { + .first = 0x0F, + .last = 0x17, + }, + { + .first = 0x30, + .last = 0x30, + }, + { + .first = 0x32, + .last = 0x33, + }, + }, + }, + [AB8500_REGU_CTRL1] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x00, + }, + { + .first = 0x03, + .last = 0x10, + }, + { + .first = 0x80, + .last = 0x84, + }, + }, + }, + [AB8500_REGU_CTRL2] = { + .num_ranges = 5, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x15, + }, + { + .first = 0x17, + .last = 0x19, + }, + { + .first = 0x1B, + .last = 0x1D, + }, + { + .first = 0x1F, + .last = 0x22, + }, + { + .first = 0x40, + .last = 0x44, + }, + /* 0x80-0x8B is SIM registers and should + * not be accessed from here */ + }, + }, + [AB8500_USB] = { + .num_ranges = 2, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x80, + .last = 0x83, + }, + { + .first = 0x87, + .last = 0x8A, + }, + }, + }, + [AB8500_TVOUT] = { + .num_ranges = 9, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x12, + }, + { + .first = 0x15, + .last = 0x17, + }, + { + .first = 0x19, + .last = 0x21, + }, + { + .first = 0x27, + .last = 0x2C, + }, + { + .first = 0x41, + .last = 0x41, + }, + { + .first = 0x45, + .last = 0x5B, + }, + { + .first = 0x5D, + .last = 0x5D, + }, + { + .first = 0x69, + .last = 0x69, + }, + { + .first = 0x80, + .last = 0x81, + }, + }, + }, + [AB8500_DBI] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_ECI_AV_ACC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x80, + .last = 0x82, + }, + }, + }, + [0x9] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_GPADC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x08, + }, + }, + }, + [AB8500_CHARGER] = { + .num_ranges = 8, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x03, + }, + { + .first = 0x05, + .last = 0x05, + }, + { + .first = 0x40, + .last = 0x40, + }, + { + .first = 0x42, + .last = 0x42, + }, + { + .first = 0x44, + .last = 0x44, + }, + { + .first = 0x50, + .last = 0x55, + }, + { + .first = 0x80, + .last = 0x82, + }, + { + .first = 0xC0, + .last = 0xC2, + }, + }, + }, + [AB8500_GAS_GAUGE] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x00, + }, + { + .first = 0x07, + .last = 0x0A, + }, + { + .first = 0x10, + .last = 0x14, + }, + }, + }, + [AB8500_AUDIO] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x6F, + }, + }, + }, + [AB8500_INTERRUPT] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_RTC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x0F, + }, + }, + }, + [AB8500_MISC] = { + .num_ranges = 8, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x05, + }, + { + .first = 0x10, + .last = 0x15, + }, + { + .first = 0x20, + .last = 0x25, + }, + { + .first = 0x30, + .last = 0x35, + }, + { + .first = 0x40, + .last = 0x45, + }, + { + .first = 0x50, + .last = 0x50, + }, + { + .first = 0x60, + .last = 0x67, + }, + { + .first = 0x80, + .last = 0x80, + }, + }, + }, + [0x11] = { + .num_ranges = 0, + .range = 0, + }, + [0x12] = { + .num_ranges = 0, + .range = 0, + }, + [0x13] = { + .num_ranges = 0, + .range = 0, + }, + [0x14] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_OTP_EMUL] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x01, + .last = 0x0F, + }, + }, + }, +}; + +static int ab8500_registers_print(struct seq_file *s, void *p) +{ + struct device *dev = s->private; + unsigned int i; + u32 bank = debug_bank; + + seq_printf(s, AB8500_NAME_STRING " register values:\n"); + + seq_printf(s, " bank %u:\n", bank); + for (i = 0; i < debug_ranges[bank].num_ranges; i++) { + u32 reg; + + for (reg = debug_ranges[bank].range[i].first; + reg <= debug_ranges[bank].range[i].last; + reg++) { + u8 value; + int err; + + err = abx500_get_register_interruptible(dev, + (u8)bank, (u8)reg, &value); + if (err < 0) { + dev_err(dev, "ab->read fail %d\n", err); + return err; + } + + err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, + reg, value); + if (err < 0) { + dev_err(dev, "seq_printf overflow\n"); + /* Error is not returned here since + * the output is wanted in any case */ + return 0; + } + } + } + return 0; +} + +static int ab8500_registers_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab8500_registers_print, inode->i_private); +} + +static const struct file_operations ab8500_registers_fops = { + .open = ab8500_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int ab8500_bank_print(struct seq_file *s, void *p) +{ + return seq_printf(s, "%d\n", debug_bank); +} + +static int ab8500_bank_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab8500_bank_print, inode->i_private); +} + +static ssize_t ab8500_bank_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_bank; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_bank); + if (err) + return -EINVAL; + + if (user_bank >= AB8500_NUM_BANKS) { + dev_err(dev, "debugfs error input > number of banks\n"); + return -EINVAL; + } + + debug_bank = user_bank; + + return buf_size; +} + +static int ab8500_address_print(struct seq_file *s, void *p) +{ + return seq_printf(s, "0x%02X\n", debug_address); +} + +static int ab8500_address_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab8500_address_print, inode->i_private); +} + +static ssize_t ab8500_address_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_address; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_address); + if (err) + return -EINVAL; + if (user_address > 0xff) { + dev_err(dev, "debugfs error input > 0xff\n"); + return -EINVAL; + } + debug_address = user_address; + return buf_size; +} + +static int ab8500_val_print(struct seq_file *s, void *p) +{ + struct device *dev = s->private; + int ret; + u8 regvalue; + + ret = abx500_get_register_interruptible(dev, + (u8)debug_bank, (u8)debug_address, ®value); + if (ret < 0) { + dev_err(dev, "abx500_get_reg fail %d, %d\n", + ret, __LINE__); + return -EINVAL; + } + seq_printf(s, "0x%02X\n", regvalue); + + return 0; +} + +static int ab8500_val_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab8500_val_print, inode->i_private); +} + +static ssize_t ab8500_val_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_val; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_val); + if (err) + return -EINVAL; + if (user_val > 0xff) { + dev_err(dev, "debugfs error input > 0xff\n"); + return -EINVAL; + } + err = abx500_set_register_interruptible(dev, + (u8)debug_bank, debug_address, (u8)user_val); + if (err < 0) { + printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); + return -EINVAL; + } + + return buf_size; +} + +static const struct file_operations ab8500_bank_fops = { + .open = ab8500_bank_open, + .write = ab8500_bank_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ab8500_address_fops = { + .open = ab8500_address_open, + .write = ab8500_address_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations ab8500_val_fops = { + .open = ab8500_val_open, + .write = ab8500_val_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static struct dentry *ab8500_dir; +static struct dentry *ab8500_reg_file; +static struct dentry *ab8500_bank_file; +static struct dentry *ab8500_address_file; +static struct dentry *ab8500_val_file; + +static int __devinit ab8500_debug_probe(struct platform_device *plf) +{ + debug_bank = AB8500_MISC; + debug_address = AB8500_REV_REG & 0x00FF; + + ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); + if (!ab8500_dir) + goto exit_no_debugfs; + + ab8500_reg_file = debugfs_create_file("all-bank-registers", + S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); + if (!ab8500_reg_file) + goto exit_destroy_dir; + + ab8500_bank_file = debugfs_create_file("register-bank", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); + if (!ab8500_bank_file) + goto exit_destroy_reg; + + ab8500_address_file = debugfs_create_file("register-address", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, + &ab8500_address_fops); + if (!ab8500_address_file) + goto exit_destroy_bank; + + ab8500_val_file = debugfs_create_file("register-value", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); + if (!ab8500_val_file) + goto exit_destroy_address; + + return 0; + +exit_destroy_address: + debugfs_remove(ab8500_address_file); +exit_destroy_bank: + debugfs_remove(ab8500_bank_file); +exit_destroy_reg: + debugfs_remove(ab8500_reg_file); +exit_destroy_dir: + debugfs_remove(ab8500_dir); +exit_no_debugfs: + dev_err(&plf->dev, "failed to create debugfs entries.\n"); + return -ENOMEM; +} + +static int __devexit ab8500_debug_remove(struct platform_device *plf) +{ + debugfs_remove(ab8500_val_file); + debugfs_remove(ab8500_address_file); + debugfs_remove(ab8500_bank_file); + debugfs_remove(ab8500_reg_file); + debugfs_remove(ab8500_dir); + + return 0; +} + +static struct platform_driver ab8500_debug_driver = { + .driver = { + .name = "ab8500-debug", + .owner = THIS_MODULE, + }, + .probe = ab8500_debug_probe, + .remove = __devexit_p(ab8500_debug_remove) +}; + +static int __init ab8500_debug_init(void) +{ + return platform_driver_register(&ab8500_debug_driver); +} + +static void __exit ab8500_debug_exit(void) +{ + platform_driver_unregister(&ab8500_debug_driver); +} +subsys_initcall(ab8500_debug_init); +module_exit(ab8500_debug_exit); + +MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); +MODULE_DESCRIPTION("AB8500 DEBUG"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c new file mode 100644 index 000000000000..6820327adf4a --- /dev/null +++ b/drivers/mfd/ab8500-i2c.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. + * License Terms: GNU General Public License v2 + * This file was based on drivers/mfd/ab8500-spi.c + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/ab8500.h> + +#include <mach/prcmu.h> + +static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) +{ + int ret; + + ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); + if (ret < 0) + dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); + return ret; +} + +static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) +{ + int ret; + u8 data; + + ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); + if (ret < 0) { + dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); + return ret; + } + return (int)data; +} + +static int __devinit ab8500_i2c_probe(struct platform_device *plf) +{ + struct ab8500 *ab8500; + struct resource *resource; + int ret; + + ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); + if (!ab8500) + return -ENOMEM; + + ab8500->dev = &plf->dev; + + resource = platform_get_resource(plf, IORESOURCE_IRQ, 0); + if (!resource) { + kfree(ab8500); + return -ENODEV; + } + + ab8500->irq = resource->start; + + ab8500->read = ab8500_i2c_read; + ab8500->write = ab8500_i2c_write; + + platform_set_drvdata(plf, ab8500); + + ret = ab8500_init(ab8500); + if (ret) + kfree(ab8500); + + return ret; +} + +static int __devexit ab8500_i2c_remove(struct platform_device *plf) +{ + struct ab8500 *ab8500 = platform_get_drvdata(plf); + + ab8500_exit(ab8500); + kfree(ab8500); + + return 0; +} + +static struct platform_driver ab8500_i2c_driver = { + .driver = { + .name = "ab8500-i2c", + .owner = THIS_MODULE, + }, + .probe = ab8500_i2c_probe, + .remove = __devexit_p(ab8500_i2c_remove) +}; + +static int __init ab8500_i2c_init(void) +{ + return platform_driver_register(&ab8500_i2c_driver); +} + +static void __exit ab8500_i2c_exit(void) +{ + platform_driver_unregister(&ab8500_i2c_driver); +} +subsys_initcall(ab8500_i2c_init); +module_exit(ab8500_i2c_exit); + +MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); +MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c index 01b6d584442c..b1653421edb5 100644 --- a/drivers/mfd/ab8500-spi.c +++ b/drivers/mfd/ab8500-spi.c @@ -119,7 +119,7 @@ static int __devexit ab8500_spi_remove(struct spi_device *spi) static struct spi_driver ab8500_spi_driver = { .driver = { - .name = "ab8500", + .name = "ab8500-spi", .owner = THIS_MODULE, }, .probe = ab8500_spi_probe, diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index c07aece900fb..2fadbaeb1cb1 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -470,13 +470,19 @@ static int __devinit da903x_add_subdevs(struct da903x_chip *chip, subdev = &pdata->subdevs[i]; pdev = platform_device_alloc(subdev->name, subdev->id); + if (!pdev) { + ret = -ENOMEM; + goto failed; + } pdev->dev.parent = chip->dev; pdev->dev.platform_data = subdev->platform_data; ret = platform_device_add(pdev); - if (ret) + if (ret) { + platform_device_put(pdev); goto failed; + } } return 0; diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 134c69aa4790..c2b698d69a93 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -384,12 +384,20 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, struct pcap_subdev *subdev) { struct platform_device *pdev; + int ret; pdev = platform_device_alloc(subdev->name, subdev->id); + if (!pdev) + return -ENOMEM; + pdev->dev.parent = &pcap->spi->dev; pdev->dev.platform_data = subdev->platform_data; - return platform_device_add(pdev); + ret = platform_device_add(pdev); + if (ret) + platform_device_put(pdev); + + return ret; } static int __devexit ezx_pcap_remove(struct spi_device *spi) @@ -457,6 +465,7 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) pcap->irq_base = pdata->irq_base; pcap->workqueue = create_singlethread_workqueue("pcapd"); if (!pcap->workqueue) { + ret = -ENOMEM; dev_err(&spi->dev, "cant create pcap thread\n"); goto free_pcap; } diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index f04300e05fd6..7bc752272dc1 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -138,13 +138,6 @@ static int __init pasic3_probe(struct platform_device *pdev) irq = r->start; } - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (r) { - ds1wm_resources[1].flags = IORESOURCE_IRQ | (r->flags & - (IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE)); - irq = r->start; - } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) return -ENXIO; diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 3ad492cb6c41..9dd1b33f2275 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -153,7 +153,7 @@ static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine, if (enabled) val |= BIT(engine); else - val &= BIT(engine); + val &= ~BIT(engine); writeb(val, adc->base + JZ_REG_ADC_ENABLE); spin_unlock_irqrestore(&adc->lock, flags); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 428377a5a6f5..44695f5a1800 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -93,8 +93,13 @@ static struct mfd_cell rtc_devs[] = { static struct resource onkey_resources[] = { { .name = "max8925-onkey", - .start = MAX8925_IRQ_GPM_SW_3SEC, - .end = MAX8925_IRQ_GPM_SW_3SEC, + .start = MAX8925_IRQ_GPM_SW_R, + .end = MAX8925_IRQ_GPM_SW_R, + .flags = IORESOURCE_IRQ, + }, { + .name = "max8925-onkey", + .start = MAX8925_IRQ_GPM_SW_F, + .end = MAX8925_IRQ_GPM_SW_F, .flags = IORESOURCE_IRQ, }, }; @@ -102,7 +107,7 @@ static struct resource onkey_resources[] = { static struct mfd_cell onkey_devs[] = { { .name = "max8925-onkey", - .num_resources = 1, + .num_resources = 2, .resources = &onkey_resources[0], .id = -1, }, diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c new file mode 100644 index 000000000000..45bfe77b639b --- /dev/null +++ b/drivers/mfd/max8998-irq.c @@ -0,0 +1,258 @@ +/* + * Interrupt controller support for MAX8998 + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * 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 <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/max8998-private.h> + +struct max8998_irq_data { + int reg; + int mask; +}; + +static struct max8998_irq_data max8998_irqs[] = { + [MAX8998_IRQ_DCINF] = { + .reg = 1, + .mask = MAX8998_IRQ_DCINF_MASK, + }, + [MAX8998_IRQ_DCINR] = { + .reg = 1, + .mask = MAX8998_IRQ_DCINR_MASK, + }, + [MAX8998_IRQ_JIGF] = { + .reg = 1, + .mask = MAX8998_IRQ_JIGF_MASK, + }, + [MAX8998_IRQ_JIGR] = { + .reg = 1, + .mask = MAX8998_IRQ_JIGR_MASK, + }, + [MAX8998_IRQ_PWRONF] = { + .reg = 1, + .mask = MAX8998_IRQ_PWRONF_MASK, + }, + [MAX8998_IRQ_PWRONR] = { + .reg = 1, + .mask = MAX8998_IRQ_PWRONR_MASK, + }, + [MAX8998_IRQ_WTSREVNT] = { + .reg = 2, + .mask = MAX8998_IRQ_WTSREVNT_MASK, + }, + [MAX8998_IRQ_SMPLEVNT] = { + .reg = 2, + .mask = MAX8998_IRQ_SMPLEVNT_MASK, + }, + [MAX8998_IRQ_ALARM1] = { + .reg = 2, + .mask = MAX8998_IRQ_ALARM1_MASK, + }, + [MAX8998_IRQ_ALARM0] = { + .reg = 2, + .mask = MAX8998_IRQ_ALARM0_MASK, + }, + [MAX8998_IRQ_ONKEY1S] = { + .reg = 3, + .mask = MAX8998_IRQ_ONKEY1S_MASK, + }, + [MAX8998_IRQ_TOPOFFR] = { + .reg = 3, + .mask = MAX8998_IRQ_TOPOFFR_MASK, + }, + [MAX8998_IRQ_DCINOVPR] = { + .reg = 3, + .mask = MAX8998_IRQ_DCINOVPR_MASK, + }, + [MAX8998_IRQ_CHGRSTF] = { + .reg = 3, + .mask = MAX8998_IRQ_CHGRSTF_MASK, + }, + [MAX8998_IRQ_DONER] = { + .reg = 3, + .mask = MAX8998_IRQ_DONER_MASK, + }, + [MAX8998_IRQ_CHGFAULT] = { + .reg = 3, + .mask = MAX8998_IRQ_CHGFAULT_MASK, + }, + [MAX8998_IRQ_LOBAT1] = { + .reg = 4, + .mask = MAX8998_IRQ_LOBAT1_MASK, + }, + [MAX8998_IRQ_LOBAT2] = { + .reg = 4, + .mask = MAX8998_IRQ_LOBAT2_MASK, + }, +}; + +static inline struct max8998_irq_data * +irq_to_max8998_irq(struct max8998_dev *max8998, int irq) +{ + return &max8998_irqs[irq - max8998->irq_base]; +} + +static void max8998_irq_lock(unsigned int irq) +{ + struct max8998_dev *max8998 = get_irq_chip_data(irq); + + mutex_lock(&max8998->irqlock); +} + +static void max8998_irq_sync_unlock(unsigned int irq) +{ + struct max8998_dev *max8998 = get_irq_chip_data(irq); + int i; + + for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) { + /* + * If there's been a change in the mask write it back + * to the hardware. + */ + if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) { + max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i]; + max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, + max8998->irq_masks_cur[i]); + } + } + + mutex_unlock(&max8998->irqlock); +} + +static void max8998_irq_unmask(unsigned int irq) +{ + struct max8998_dev *max8998 = get_irq_chip_data(irq); + struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); + + max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; +} + +static void max8998_irq_mask(unsigned int irq) +{ + struct max8998_dev *max8998 = get_irq_chip_data(irq); + struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); + + max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; +} + +static struct irq_chip max8998_irq_chip = { + .name = "max8998", + .bus_lock = max8998_irq_lock, + .bus_sync_unlock = max8998_irq_sync_unlock, + .mask = max8998_irq_mask, + .unmask = max8998_irq_unmask, +}; + +static irqreturn_t max8998_irq_thread(int irq, void *data) +{ + struct max8998_dev *max8998 = data; + u8 irq_reg[MAX8998_NUM_IRQ_REGS]; + int ret; + int i; + + ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1, + MAX8998_NUM_IRQ_REGS, irq_reg); + if (ret < 0) { + dev_err(max8998->dev, "Failed to read interrupt register: %d\n", + ret); + return IRQ_NONE; + } + + /* Apply masking */ + for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) + irq_reg[i] &= ~max8998->irq_masks_cur[i]; + + /* Report */ + for (i = 0; i < MAX8998_IRQ_NR; i++) { + if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) + handle_nested_irq(max8998->irq_base + i); + } + + return IRQ_HANDLED; +} + +int max8998_irq_init(struct max8998_dev *max8998) +{ + int i; + int cur_irq; + int ret; + + if (!max8998->irq) { + dev_warn(max8998->dev, + "No interrupt specified, no interrupts\n"); + max8998->irq_base = 0; + return 0; + } + + if (!max8998->irq_base) { + dev_err(max8998->dev, + "No interrupt base specified, no interrupts\n"); + return 0; + } + + mutex_init(&max8998->irqlock); + + /* Mask the individual interrupt sources */ + for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) { + max8998->irq_masks_cur[i] = 0xff; + max8998->irq_masks_cache[i] = 0xff; + max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff); + } + + max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); + max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); + + /* register with genirq */ + for (i = 0; i < MAX8998_IRQ_NR; i++) { + cur_irq = i + max8998->irq_base; + set_irq_chip_data(cur_irq, max8998); + set_irq_chip_and_handler(cur_irq, &max8998_irq_chip, + handle_edge_irq); + set_irq_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + set_irq_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max8998-irq", max8998); + if (ret) { + dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", + max8998->irq, ret); + return ret; + } + + if (!max8998->ono) + return 0; + + ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "max8998-ono", max8998); + if (ret) + dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", + max8998->ono, ret); + + return 0; +} + +void max8998_irq_exit(struct max8998_dev *max8998) +{ + if (max8998->ono) + free_irq(max8998->ono, max8998); + + if (max8998->irq) + free_irq(max8998->irq, max8998); +} diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 73e6f5c4efc9..bb9977bebe78 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -1,5 +1,5 @@ /* - * max8698.c - mfd core driver for the Maxim 8998 + * max8998.c - mfd core driver for the Maxim 8998 * * Copyright (C) 2009-2010 Samsung Electronics * Kyungmin Park <kyungmin.park@samsung.com> @@ -30,19 +30,23 @@ #include <linux/mfd/max8998.h> #include <linux/mfd/max8998-private.h> +#define RTC_I2C_ADDR (0x0c >> 1) + static struct mfd_cell max8998_devs[] = { { .name = "max8998-pmic", - } + }, { + .name = "max8998-rtc", + }, }; -static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest) +int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) { - struct i2c_client *client = max8998->i2c_client; + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); int ret; mutex_lock(&max8998->iolock); - ret = i2c_smbus_read_byte_data(client, reg); + ret = i2c_smbus_read_byte_data(i2c, reg); mutex_unlock(&max8998->iolock); if (ret < 0) return ret; @@ -51,40 +55,71 @@ static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest *dest = ret; return 0; } +EXPORT_SYMBOL(max8998_read_reg); -static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value) +int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) { - struct i2c_client *client = max8998->i2c_client; + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8998->iolock); + ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); + mutex_unlock(&max8998->iolock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(max8998_bulk_read); + +int max8998_write_reg(struct i2c_client *i2c, u8 reg, u8 value) +{ + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); int ret; mutex_lock(&max8998->iolock); - ret = i2c_smbus_write_byte_data(client, reg, value); + ret = i2c_smbus_write_byte_data(i2c, reg, value); mutex_unlock(&max8998->iolock); return ret; } +EXPORT_SYMBOL(max8998_write_reg); -static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg, - u8 val, u8 mask) +int max8998_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) { - struct i2c_client *client = max8998->i2c_client; + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8998->iolock); + ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); + mutex_unlock(&max8998->iolock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(max8998_bulk_write); + +int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) +{ + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); int ret; mutex_lock(&max8998->iolock); - ret = i2c_smbus_read_byte_data(client, reg); + ret = i2c_smbus_read_byte_data(i2c, reg); if (ret >= 0) { u8 old_val = ret & 0xff; u8 new_val = (val & mask) | (old_val & (~mask)); - ret = i2c_smbus_write_byte_data(client, reg, new_val); - if (ret >= 0) - ret = 0; + ret = i2c_smbus_write_byte_data(i2c, reg, new_val); } mutex_unlock(&max8998->iolock); return ret; } +EXPORT_SYMBOL(max8998_update_reg); static int max8998_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct max8998_platform_data *pdata = i2c->dev.platform_data; struct max8998_dev *max8998; int ret = 0; @@ -94,12 +129,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, max8998); max8998->dev = &i2c->dev; - max8998->i2c_client = i2c; - max8998->dev_read = max8998_i2c_device_read; - max8998->dev_write = max8998_i2c_device_write; - max8998->dev_update = max8998_i2c_device_update; + max8998->i2c = i2c; + max8998->irq = i2c->irq; + max8998->type = id->driver_data; + if (pdata) { + max8998->ono = pdata->ono; + max8998->irq_base = pdata->irq_base; + } mutex_init(&max8998->iolock); + max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + i2c_set_clientdata(max8998->rtc, max8998); + + max8998_irq_init(max8998); + ret = mfd_add_devices(max8998->dev, -1, max8998_devs, ARRAY_SIZE(max8998_devs), NULL, 0); @@ -110,6 +153,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, err: mfd_remove_devices(max8998->dev); + max8998_irq_exit(max8998); + i2c_unregister_device(max8998->rtc); kfree(max8998); return ret; } @@ -119,14 +164,17 @@ static int max8998_i2c_remove(struct i2c_client *i2c) struct max8998_dev *max8998 = i2c_get_clientdata(i2c); mfd_remove_devices(max8998->dev); + max8998_irq_exit(max8998); + i2c_unregister_device(max8998->rtc); kfree(max8998); return 0; } static const struct i2c_device_id max8998_i2c_id[] = { - { "max8998", 0 }, - { } + { "max8998", TYPE_MAX8998 }, + { "lp3974", TYPE_LP3974}, + { } }; MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c deleted file mode 100644 index 6df34989c1f6..000000000000 --- a/drivers/mfd/mc13783-core.c +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright 2009 Pengutronix - * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> - * - * loosely based on an earlier driver that has - * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * 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 <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/interrupt.h> -#include <linux/spi/spi.h> -#include <linux/mfd/core.h> -#include <linux/mfd/mc13783.h> - -struct mc13783 { - struct spi_device *spidev; - struct mutex lock; - int irq; - int flags; - - irq_handler_t irqhandler[MC13783_NUM_IRQ]; - void *irqdata[MC13783_NUM_IRQ]; - - /* XXX these should go as platformdata to the regulator subdevice */ - struct mc13783_regulator_init_data *regulators; - int num_regulators; -}; - -#define MC13783_REG_REVISION 7 -#define MC13783_REG_ADC_0 43 -#define MC13783_REG_ADC_1 44 -#define MC13783_REG_ADC_2 45 - -#define MC13783_IRQSTAT0 0 -#define MC13783_IRQSTAT0_ADCDONEI (1 << 0) -#define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) -#define MC13783_IRQSTAT0_TSI (1 << 2) -#define MC13783_IRQSTAT0_WHIGHI (1 << 3) -#define MC13783_IRQSTAT0_WLOWI (1 << 4) -#define MC13783_IRQSTAT0_CHGDETI (1 << 6) -#define MC13783_IRQSTAT0_CHGOVI (1 << 7) -#define MC13783_IRQSTAT0_CHGREVI (1 << 8) -#define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) -#define MC13783_IRQSTAT0_CCCVI (1 << 10) -#define MC13783_IRQSTAT0_CHGCURRI (1 << 11) -#define MC13783_IRQSTAT0_BPONI (1 << 12) -#define MC13783_IRQSTAT0_LOBATLI (1 << 13) -#define MC13783_IRQSTAT0_LOBATHI (1 << 14) -#define MC13783_IRQSTAT0_UDPI (1 << 15) -#define MC13783_IRQSTAT0_USBI (1 << 16) -#define MC13783_IRQSTAT0_IDI (1 << 19) -#define MC13783_IRQSTAT0_SE1I (1 << 21) -#define MC13783_IRQSTAT0_CKDETI (1 << 22) -#define MC13783_IRQSTAT0_UDMI (1 << 23) - -#define MC13783_IRQMASK0 1 -#define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI -#define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI -#define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI -#define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI -#define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI -#define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI -#define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI -#define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI -#define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI -#define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI -#define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI -#define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI -#define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI -#define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI -#define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI -#define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI -#define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI -#define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I -#define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI -#define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI - -#define MC13783_IRQSTAT1 3 -#define MC13783_IRQSTAT1_1HZI (1 << 0) -#define MC13783_IRQSTAT1_TODAI (1 << 1) -#define MC13783_IRQSTAT1_ONOFD1I (1 << 3) -#define MC13783_IRQSTAT1_ONOFD2I (1 << 4) -#define MC13783_IRQSTAT1_ONOFD3I (1 << 5) -#define MC13783_IRQSTAT1_SYSRSTI (1 << 6) -#define MC13783_IRQSTAT1_RTCRSTI (1 << 7) -#define MC13783_IRQSTAT1_PCI (1 << 8) -#define MC13783_IRQSTAT1_WARMI (1 << 9) -#define MC13783_IRQSTAT1_MEMHLDI (1 << 10) -#define MC13783_IRQSTAT1_PWRRDYI (1 << 11) -#define MC13783_IRQSTAT1_THWARNLI (1 << 12) -#define MC13783_IRQSTAT1_THWARNHI (1 << 13) -#define MC13783_IRQSTAT1_CLKI (1 << 14) -#define MC13783_IRQSTAT1_SEMAFI (1 << 15) -#define MC13783_IRQSTAT1_MC2BI (1 << 17) -#define MC13783_IRQSTAT1_HSDETI (1 << 18) -#define MC13783_IRQSTAT1_HSLI (1 << 19) -#define MC13783_IRQSTAT1_ALSPTHI (1 << 20) -#define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) - -#define MC13783_IRQMASK1 4 -#define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI -#define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI -#define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I -#define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I -#define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I -#define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI -#define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI -#define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI -#define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI -#define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI -#define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI -#define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI -#define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI -#define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI -#define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI -#define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI -#define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI -#define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI -#define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI -#define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI - -#define MC13783_ADC1 44 -#define MC13783_ADC1_ADEN (1 << 0) -#define MC13783_ADC1_RAND (1 << 1) -#define MC13783_ADC1_ADSEL (1 << 3) -#define MC13783_ADC1_ASC (1 << 20) -#define MC13783_ADC1_ADTRIGIGN (1 << 21) - -#define MC13783_NUMREGS 0x3f - -void mc13783_lock(struct mc13783 *mc13783) -{ - if (!mutex_trylock(&mc13783->lock)) { - dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", - __func__, __builtin_return_address(0)); - - mutex_lock(&mc13783->lock); - } - dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", - __func__, __builtin_return_address(0)); -} -EXPORT_SYMBOL(mc13783_lock); - -void mc13783_unlock(struct mc13783 *mc13783) -{ - dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", - __func__, __builtin_return_address(0)); - mutex_unlock(&mc13783->lock); -} -EXPORT_SYMBOL(mc13783_unlock); - -#define MC13783_REGOFFSET_SHIFT 25 -int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) -{ - struct spi_transfer t; - struct spi_message m; - int ret; - - BUG_ON(!mutex_is_locked(&mc13783->lock)); - - if (offset > MC13783_NUMREGS) - return -EINVAL; - - *val = offset << MC13783_REGOFFSET_SHIFT; - - memset(&t, 0, sizeof(t)); - - t.tx_buf = val; - t.rx_buf = val; - t.len = sizeof(u32); - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - ret = spi_sync(mc13783->spidev, &m); - - /* error in message.status implies error return from spi_sync */ - BUG_ON(!ret && m.status); - - if (ret) - return ret; - - *val &= 0xffffff; - - dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); - - return 0; -} -EXPORT_SYMBOL(mc13783_reg_read); - -int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) -{ - u32 buf; - struct spi_transfer t; - struct spi_message m; - int ret; - - BUG_ON(!mutex_is_locked(&mc13783->lock)); - - dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); - - if (offset > MC13783_NUMREGS || val > 0xffffff) - return -EINVAL; - - buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; - - memset(&t, 0, sizeof(t)); - - t.tx_buf = &buf; - t.rx_buf = &buf; - t.len = sizeof(u32); - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - ret = spi_sync(mc13783->spidev, &m); - - BUG_ON(!ret && m.status); - - if (ret) - return ret; - - return 0; -} -EXPORT_SYMBOL(mc13783_reg_write); - -int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, - u32 mask, u32 val) -{ - int ret; - u32 valread; - - BUG_ON(val & ~mask); - - ret = mc13783_reg_read(mc13783, offset, &valread); - if (ret) - return ret; - - valread = (valread & ~mask) | val; - - return mc13783_reg_write(mc13783, offset, valread); -} -EXPORT_SYMBOL(mc13783_reg_rmw); - -int mc13783_get_flags(struct mc13783 *mc13783) -{ - return mc13783->flags; -} -EXPORT_SYMBOL(mc13783_get_flags); - -int mc13783_irq_mask(struct mc13783 *mc13783, int irq) -{ - int ret; - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); - u32 mask; - - if (irq < 0 || irq >= MC13783_NUM_IRQ) - return -EINVAL; - - ret = mc13783_reg_read(mc13783, offmask, &mask); - if (ret) - return ret; - - if (mask & irqbit) - /* already masked */ - return 0; - - return mc13783_reg_write(mc13783, offmask, mask | irqbit); -} -EXPORT_SYMBOL(mc13783_irq_mask); - -int mc13783_irq_unmask(struct mc13783 *mc13783, int irq) -{ - int ret; - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); - u32 mask; - - if (irq < 0 || irq >= MC13783_NUM_IRQ) - return -EINVAL; - - ret = mc13783_reg_read(mc13783, offmask, &mask); - if (ret) - return ret; - - if (!(mask & irqbit)) - /* already unmasked */ - return 0; - - return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); -} -EXPORT_SYMBOL(mc13783_irq_unmask); - -int mc13783_irq_status(struct mc13783 *mc13783, int irq, - int *enabled, int *pending) -{ - int ret; - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; - unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); - - if (irq < 0 || irq >= MC13783_NUM_IRQ) - return -EINVAL; - - if (enabled) { - u32 mask; - - ret = mc13783_reg_read(mc13783, offmask, &mask); - if (ret) - return ret; - - *enabled = mask & irqbit; - } - - if (pending) { - u32 stat; - - ret = mc13783_reg_read(mc13783, offstat, &stat); - if (ret) - return ret; - - *pending = stat & irqbit; - } - - return 0; -} -EXPORT_SYMBOL(mc13783_irq_status); - -int mc13783_irq_ack(struct mc13783 *mc13783, int irq) -{ - unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; - unsigned int val = 1 << (irq < 24 ? irq : irq - 24); - - BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); - - return mc13783_reg_write(mc13783, offstat, val); -} -EXPORT_SYMBOL(mc13783_irq_ack); - -int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, - irq_handler_t handler, const char *name, void *dev) -{ - BUG_ON(!mutex_is_locked(&mc13783->lock)); - BUG_ON(!handler); - - if (irq < 0 || irq >= MC13783_NUM_IRQ) - return -EINVAL; - - if (mc13783->irqhandler[irq]) - return -EBUSY; - - mc13783->irqhandler[irq] = handler; - mc13783->irqdata[irq] = dev; - - return 0; -} -EXPORT_SYMBOL(mc13783_irq_request_nounmask); - -int mc13783_irq_request(struct mc13783 *mc13783, int irq, - irq_handler_t handler, const char *name, void *dev) -{ - int ret; - - ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); - if (ret) - return ret; - - ret = mc13783_irq_unmask(mc13783, irq); - if (ret) { - mc13783->irqhandler[irq] = NULL; - mc13783->irqdata[irq] = NULL; - return ret; - } - - return 0; -} -EXPORT_SYMBOL(mc13783_irq_request); - -int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) -{ - int ret; - BUG_ON(!mutex_is_locked(&mc13783->lock)); - - if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || - mc13783->irqdata[irq] != dev) - return -EINVAL; - - ret = mc13783_irq_mask(mc13783, irq); - if (ret) - return ret; - - mc13783->irqhandler[irq] = NULL; - mc13783->irqdata[irq] = NULL; - - return 0; -} -EXPORT_SYMBOL(mc13783_irq_free); - -static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) -{ - return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); -} - -/* - * returns: number of handled irqs or negative error - * locking: holds mc13783->lock - */ -static int mc13783_irq_handle(struct mc13783 *mc13783, - unsigned int offstat, unsigned int offmask, int baseirq) -{ - u32 stat, mask; - int ret = mc13783_reg_read(mc13783, offstat, &stat); - int num_handled = 0; - - if (ret) - return ret; - - ret = mc13783_reg_read(mc13783, offmask, &mask); - if (ret) - return ret; - - while (stat & ~mask) { - int irq = __ffs(stat & ~mask); - - stat &= ~(1 << irq); - - if (likely(mc13783->irqhandler[baseirq + irq])) { - irqreturn_t handled; - - handled = mc13783_irqhandler(mc13783, baseirq + irq); - if (handled == IRQ_HANDLED) - num_handled++; - } else { - dev_err(&mc13783->spidev->dev, - "BUG: irq %u but no handler\n", - baseirq + irq); - - mask |= 1 << irq; - - ret = mc13783_reg_write(mc13783, offmask, mask); - } - } - - return num_handled; -} - -static irqreturn_t mc13783_irq_thread(int irq, void *data) -{ - struct mc13783 *mc13783 = data; - irqreturn_t ret; - int handled = 0; - - mc13783_lock(mc13783); - - ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, - MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); - if (ret > 0) - handled = 1; - - ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, - MC13783_IRQMASK1, MC13783_IRQ_1HZ); - if (ret > 0) - handled = 1; - - mc13783_unlock(mc13783); - - return IRQ_RETVAL(handled); -} - -#define MC13783_ADC1_CHAN0_SHIFT 5 -#define MC13783_ADC1_CHAN1_SHIFT 8 - -struct mc13783_adcdone_data { - struct mc13783 *mc13783; - struct completion done; -}; - -static irqreturn_t mc13783_handler_adcdone(int irq, void *data) -{ - struct mc13783_adcdone_data *adcdone_data = data; - - mc13783_irq_ack(adcdone_data->mc13783, irq); - - complete_all(&adcdone_data->done); - - return IRQ_HANDLED; -} - -#define MC13783_ADC_WORKING (1 << 16) - -int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, - unsigned int channel, unsigned int *sample) -{ - u32 adc0, adc1, old_adc0; - int i, ret; - struct mc13783_adcdone_data adcdone_data = { - .mc13783 = mc13783, - }; - init_completion(&adcdone_data.done); - - dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); - - mc13783_lock(mc13783); - - if (mc13783->flags & MC13783_ADC_WORKING) { - ret = -EBUSY; - goto out; - } - - mc13783->flags |= MC13783_ADC_WORKING; - - mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); - - adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; - adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; - - if (channel > 7) - adc1 |= MC13783_ADC1_ADSEL; - - switch (mode) { - case MC13783_ADC_MODE_TS: - adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | - MC13783_ADC0_TSMOD1; - adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; - break; - - case MC13783_ADC_MODE_SINGLE_CHAN: - adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; - adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; - adc1 |= MC13783_ADC1_RAND; - break; - - case MC13783_ADC_MODE_MULT_CHAN: - adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; - adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; - break; - - default: - mc13783_unlock(mc13783); - return -EINVAL; - } - - dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); - mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, - mc13783_handler_adcdone, __func__, &adcdone_data); - mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE); - - mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); - mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); - - mc13783_unlock(mc13783); - - ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); - - if (!ret) - ret = -ETIMEDOUT; - - mc13783_lock(mc13783); - - mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); - - if (ret > 0) - for (i = 0; i < 4; ++i) { - ret = mc13783_reg_read(mc13783, - MC13783_REG_ADC_2, &sample[i]); - if (ret) - break; - } - - if (mode == MC13783_ADC_MODE_TS) - /* restore TSMOD */ - mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); - - mc13783->flags &= ~MC13783_ADC_WORKING; -out: - mc13783_unlock(mc13783); - - return ret; -} -EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); - -static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, - const char *name, void *pdata, size_t pdata_size) -{ - struct mfd_cell cell = { - .name = name, - .platform_data = pdata, - .data_size = pdata_size, - }; - - return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); -} - -static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) -{ - return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); -} - -static int mc13783_check_revision(struct mc13783 *mc13783) -{ - u32 rev_id, rev1, rev2, finid, icid; - - mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); - - rev1 = (rev_id & 0x018) >> 3; - rev2 = (rev_id & 0x007); - icid = (rev_id & 0x01C0) >> 6; - finid = (rev_id & 0x01E00) >> 9; - - /* Ver 0.2 is actually 3.2a. Report as 3.2 */ - if ((rev1 == 0) && (rev2 == 2)) - rev1 = 3; - - if (rev1 == 0 || icid != 2) { - dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); - return -ENODEV; - } - - dev_info(&mc13783->spidev->dev, - "MC13783 Rev %d.%d FinVer %x detected\n", - rev1, rev2, finid); - - return 0; -} - -static int mc13783_probe(struct spi_device *spi) -{ - struct mc13783 *mc13783; - struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); - int ret; - - mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); - if (!mc13783) - return -ENOMEM; - - dev_set_drvdata(&spi->dev, mc13783); - spi->mode = SPI_MODE_0 | SPI_CS_HIGH; - spi->bits_per_word = 32; - spi_setup(spi); - - mc13783->spidev = spi; - - mutex_init(&mc13783->lock); - mc13783_lock(mc13783); - - ret = mc13783_check_revision(mc13783); - if (ret) - goto err_revision; - - /* mask all irqs */ - ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); - if (ret) - goto err_mask; - - ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); - if (ret) - goto err_mask; - - ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); - - if (ret) { -err_mask: -err_revision: - mutex_unlock(&mc13783->lock); - dev_set_drvdata(&spi->dev, NULL); - kfree(mc13783); - return ret; - } - - /* This should go away (BEGIN) */ - if (pdata) { - mc13783->flags = pdata->flags; - mc13783->regulators = pdata->regulators; - mc13783->num_regulators = pdata->num_regulators; - } - /* This should go away (END) */ - - mc13783_unlock(mc13783); - - if (pdata->flags & MC13783_USE_ADC) - mc13783_add_subdevice(mc13783, "mc13783-adc"); - - if (pdata->flags & MC13783_USE_CODEC) - mc13783_add_subdevice(mc13783, "mc13783-codec"); - - if (pdata->flags & MC13783_USE_REGULATOR) { - struct mc13783_regulator_platform_data regulator_pdata = { - .num_regulators = pdata->num_regulators, - .regulators = pdata->regulators, - }; - - mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", - ®ulator_pdata, sizeof(regulator_pdata)); - } - - if (pdata->flags & MC13783_USE_RTC) - mc13783_add_subdevice(mc13783, "mc13783-rtc"); - - if (pdata->flags & MC13783_USE_TOUCHSCREEN) - mc13783_add_subdevice(mc13783, "mc13783-ts"); - - if (pdata->flags & MC13783_USE_LED) - mc13783_add_subdevice_pdata(mc13783, "mc13783-led", - pdata->leds, sizeof(*pdata->leds)); - - return 0; -} - -static int __devexit mc13783_remove(struct spi_device *spi) -{ - struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); - - free_irq(mc13783->spidev->irq, mc13783); - - mfd_remove_devices(&spi->dev); - - return 0; -} - -static struct spi_driver mc13783_driver = { - .driver = { - .name = "mc13783", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = mc13783_probe, - .remove = __devexit_p(mc13783_remove), -}; - -static int __init mc13783_init(void) -{ - return spi_register_driver(&mc13783_driver); -} -subsys_initcall(mc13783_init); - -static void __exit mc13783_exit(void) -{ - spi_unregister_driver(&mc13783_driver); -} -module_exit(mc13783_exit); - -MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); -MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c new file mode 100644 index 000000000000..a2ac2ed6d64c --- /dev/null +++ b/drivers/mfd/mc13xxx-core.c @@ -0,0 +1,840 @@ +/* + * Copyright 2009-2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * loosely based on an earlier driver that has + * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * + * 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 <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/spi/spi.h> +#include <linux/mfd/core.h> +#include <linux/mfd/mc13xxx.h> + +struct mc13xxx { + struct spi_device *spidev; + struct mutex lock; + int irq; + + irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; + void *irqdata[MC13XXX_NUM_IRQ]; +}; + +struct mc13783 { + struct mc13xxx mc13xxx; + + int adcflags; +}; + +struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783) +{ + return &mc13783->mc13xxx; +} +EXPORT_SYMBOL(mc13783_to_mc13xxx); + +#define MC13XXX_IRQSTAT0 0 +#define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) +#define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1) +#define MC13XXX_IRQSTAT0_TSI (1 << 2) +#define MC13783_IRQSTAT0_WHIGHI (1 << 3) +#define MC13783_IRQSTAT0_WLOWI (1 << 4) +#define MC13XXX_IRQSTAT0_CHGDETI (1 << 6) +#define MC13783_IRQSTAT0_CHGOVI (1 << 7) +#define MC13XXX_IRQSTAT0_CHGREVI (1 << 8) +#define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9) +#define MC13XXX_IRQSTAT0_CCCVI (1 << 10) +#define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11) +#define MC13XXX_IRQSTAT0_BPONI (1 << 12) +#define MC13XXX_IRQSTAT0_LOBATLI (1 << 13) +#define MC13XXX_IRQSTAT0_LOBATHI (1 << 14) +#define MC13783_IRQSTAT0_UDPI (1 << 15) +#define MC13783_IRQSTAT0_USBI (1 << 16) +#define MC13783_IRQSTAT0_IDI (1 << 19) +#define MC13783_IRQSTAT0_SE1I (1 << 21) +#define MC13783_IRQSTAT0_CKDETI (1 << 22) +#define MC13783_IRQSTAT0_UDMI (1 << 23) + +#define MC13XXX_IRQMASK0 1 +#define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI +#define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI +#define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI +#define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI +#define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI +#define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI +#define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI +#define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI +#define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI +#define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI +#define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI +#define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI +#define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI +#define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI +#define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI +#define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI +#define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI +#define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I +#define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI +#define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI + +#define MC13XXX_IRQSTAT1 3 +#define MC13XXX_IRQSTAT1_1HZI (1 << 0) +#define MC13XXX_IRQSTAT1_TODAI (1 << 1) +#define MC13783_IRQSTAT1_ONOFD1I (1 << 3) +#define MC13783_IRQSTAT1_ONOFD2I (1 << 4) +#define MC13783_IRQSTAT1_ONOFD3I (1 << 5) +#define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6) +#define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7) +#define MC13XXX_IRQSTAT1_PCI (1 << 8) +#define MC13XXX_IRQSTAT1_WARMI (1 << 9) +#define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10) +#define MC13783_IRQSTAT1_PWRRDYI (1 << 11) +#define MC13XXX_IRQSTAT1_THWARNLI (1 << 12) +#define MC13XXX_IRQSTAT1_THWARNHI (1 << 13) +#define MC13XXX_IRQSTAT1_CLKI (1 << 14) +#define MC13783_IRQSTAT1_SEMAFI (1 << 15) +#define MC13783_IRQSTAT1_MC2BI (1 << 17) +#define MC13783_IRQSTAT1_HSDETI (1 << 18) +#define MC13783_IRQSTAT1_HSLI (1 << 19) +#define MC13783_IRQSTAT1_ALSPTHI (1 << 20) +#define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) + +#define MC13XXX_IRQMASK1 4 +#define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI +#define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI +#define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I +#define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I +#define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I +#define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI +#define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI +#define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI +#define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI +#define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI +#define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI +#define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI +#define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI +#define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI +#define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI +#define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI +#define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI +#define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI +#define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI +#define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI + +#define MC13XXX_REVISION 7 +#define MC13XXX_REVISION_REVMETAL (0x07 << 0) +#define MC13XXX_REVISION_REVFULL (0x03 << 3) +#define MC13XXX_REVISION_ICID (0x07 << 6) +#define MC13XXX_REVISION_FIN (0x03 << 9) +#define MC13XXX_REVISION_FAB (0x03 << 11) +#define MC13XXX_REVISION_ICIDCODE (0x3f << 13) + +#define MC13783_ADC1 44 +#define MC13783_ADC1_ADEN (1 << 0) +#define MC13783_ADC1_RAND (1 << 1) +#define MC13783_ADC1_ADSEL (1 << 3) +#define MC13783_ADC1_ASC (1 << 20) +#define MC13783_ADC1_ADTRIGIGN (1 << 21) + +#define MC13783_ADC2 45 + +#define MC13XXX_NUMREGS 0x3f + +void mc13xxx_lock(struct mc13xxx *mc13xxx) +{ + if (!mutex_trylock(&mc13xxx->lock)) { + dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n", + __func__, __builtin_return_address(0)); + + mutex_lock(&mc13xxx->lock); + } + dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", + __func__, __builtin_return_address(0)); +} +EXPORT_SYMBOL(mc13xxx_lock); + +void mc13xxx_unlock(struct mc13xxx *mc13xxx) +{ + dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", + __func__, __builtin_return_address(0)); + mutex_unlock(&mc13xxx->lock); +} +EXPORT_SYMBOL(mc13xxx_unlock); + +#define MC13XXX_REGOFFSET_SHIFT 25 +int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) +{ + struct spi_transfer t; + struct spi_message m; + int ret; + + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); + + if (offset > MC13XXX_NUMREGS) + return -EINVAL; + + *val = offset << MC13XXX_REGOFFSET_SHIFT; + + memset(&t, 0, sizeof(t)); + + t.tx_buf = val; + t.rx_buf = val; + t.len = sizeof(u32); + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + ret = spi_sync(mc13xxx->spidev, &m); + + /* error in message.status implies error return from spi_sync */ + BUG_ON(!ret && m.status); + + if (ret) + return ret; + + *val &= 0xffffff; + + dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); + + return 0; +} +EXPORT_SYMBOL(mc13xxx_reg_read); + +int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) +{ + u32 buf; + struct spi_transfer t; + struct spi_message m; + int ret; + + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); + + dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); + + if (offset > MC13XXX_NUMREGS || val > 0xffffff) + return -EINVAL; + + buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val; + + memset(&t, 0, sizeof(t)); + + t.tx_buf = &buf; + t.rx_buf = &buf; + t.len = sizeof(u32); + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + ret = spi_sync(mc13xxx->spidev, &m); + + BUG_ON(!ret && m.status); + + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(mc13xxx_reg_write); + +int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, + u32 mask, u32 val) +{ + int ret; + u32 valread; + + BUG_ON(val & ~mask); + + ret = mc13xxx_reg_read(mc13xxx, offset, &valread); + if (ret) + return ret; + + valread = (valread & ~mask) | val; + + return mc13xxx_reg_write(mc13xxx, offset, valread); +} +EXPORT_SYMBOL(mc13xxx_reg_rmw); + +int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq) +{ + int ret; + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); + u32 mask; + + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) + return -EINVAL; + + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); + if (ret) + return ret; + + if (mask & irqbit) + /* already masked */ + return 0; + + return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit); +} +EXPORT_SYMBOL(mc13xxx_irq_mask); + +int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq) +{ + int ret; + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); + u32 mask; + + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) + return -EINVAL; + + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); + if (ret) + return ret; + + if (!(mask & irqbit)) + /* already unmasked */ + return 0; + + return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit); +} +EXPORT_SYMBOL(mc13xxx_irq_unmask); + +int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq, + int *enabled, int *pending) +{ + int ret; + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; + unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); + + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) + return -EINVAL; + + if (enabled) { + u32 mask; + + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); + if (ret) + return ret; + + *enabled = mask & irqbit; + } + + if (pending) { + u32 stat; + + ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); + if (ret) + return ret; + + *pending = stat & irqbit; + } + + return 0; +} +EXPORT_SYMBOL(mc13xxx_irq_status); + +int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq) +{ + unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; + unsigned int val = 1 << (irq < 24 ? irq : irq - 24); + + BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ); + + return mc13xxx_reg_write(mc13xxx, offstat, val); +} +EXPORT_SYMBOL(mc13xxx_irq_ack); + +int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, + irq_handler_t handler, const char *name, void *dev) +{ + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); + BUG_ON(!handler); + + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) + return -EINVAL; + + if (mc13xxx->irqhandler[irq]) + return -EBUSY; + + mc13xxx->irqhandler[irq] = handler; + mc13xxx->irqdata[irq] = dev; + + return 0; +} +EXPORT_SYMBOL(mc13xxx_irq_request_nounmask); + +int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, + irq_handler_t handler, const char *name, void *dev) +{ + int ret; + + ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev); + if (ret) + return ret; + + ret = mc13xxx_irq_unmask(mc13xxx, irq); + if (ret) { + mc13xxx->irqhandler[irq] = NULL; + mc13xxx->irqdata[irq] = NULL; + return ret; + } + + return 0; +} +EXPORT_SYMBOL(mc13xxx_irq_request); + +int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev) +{ + int ret; + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); + + if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] || + mc13xxx->irqdata[irq] != dev) + return -EINVAL; + + ret = mc13xxx_irq_mask(mc13xxx, irq); + if (ret) + return ret; + + mc13xxx->irqhandler[irq] = NULL; + mc13xxx->irqdata[irq] = NULL; + + return 0; +} +EXPORT_SYMBOL(mc13xxx_irq_free); + +static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq) +{ + return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]); +} + +/* + * returns: number of handled irqs or negative error + * locking: holds mc13xxx->lock + */ +static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx, + unsigned int offstat, unsigned int offmask, int baseirq) +{ + u32 stat, mask; + int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); + int num_handled = 0; + + if (ret) + return ret; + + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); + if (ret) + return ret; + + while (stat & ~mask) { + int irq = __ffs(stat & ~mask); + + stat &= ~(1 << irq); + + if (likely(mc13xxx->irqhandler[baseirq + irq])) { + irqreturn_t handled; + + handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq); + if (handled == IRQ_HANDLED) + num_handled++; + } else { + dev_err(&mc13xxx->spidev->dev, + "BUG: irq %u but no handler\n", + baseirq + irq); + + mask |= 1 << irq; + + ret = mc13xxx_reg_write(mc13xxx, offmask, mask); + } + } + + return num_handled; +} + +static irqreturn_t mc13xxx_irq_thread(int irq, void *data) +{ + struct mc13xxx *mc13xxx = data; + irqreturn_t ret; + int handled = 0; + + mc13xxx_lock(mc13xxx); + + ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0, + MC13XXX_IRQMASK0, 0); + if (ret > 0) + handled = 1; + + ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1, + MC13XXX_IRQMASK1, 24); + if (ret > 0) + handled = 1; + + mc13xxx_unlock(mc13xxx); + + return IRQ_RETVAL(handled); +} + +enum mc13xxx_id { + MC13XXX_ID_MC13783, + MC13XXX_ID_MC13892, + MC13XXX_ID_INVALID, +}; + +const char *mc13xxx_chipname[] = { + [MC13XXX_ID_MC13783] = "mc13783", + [MC13XXX_ID_MC13892] = "mc13892", +}; + +#define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) +static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id) +{ + u32 icid; + u32 revision; + const char *name; + int ret; + + ret = mc13xxx_reg_read(mc13xxx, 46, &icid); + if (ret) + return ret; + + icid = (icid >> 6) & 0x7; + + switch (icid) { + case 2: + *id = MC13XXX_ID_MC13783; + name = "mc13783"; + break; + case 7: + *id = MC13XXX_ID_MC13892; + name = "mc13892"; + break; + default: + *id = MC13XXX_ID_INVALID; + break; + } + + if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) { + ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); + if (ret) + return ret; + + dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, " + "fin: %d, fab: %d, icid: %d/%d\n", + mc13xxx_chipname[*id], + maskval(revision, MC13XXX_REVISION_REVFULL), + maskval(revision, MC13XXX_REVISION_REVMETAL), + maskval(revision, MC13XXX_REVISION_FIN), + maskval(revision, MC13XXX_REVISION_FAB), + maskval(revision, MC13XXX_REVISION_ICID), + maskval(revision, MC13XXX_REVISION_ICIDCODE)); + } + + if (*id != MC13XXX_ID_INVALID) { + const struct spi_device_id *devid = + spi_get_device_id(mc13xxx->spidev); + if (!devid || devid->driver_data != *id) + dev_warn(&mc13xxx->spidev->dev, "device id doesn't " + "match auto detection!\n"); + } + + return 0; +} + +static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) +{ + const struct spi_device_id *devid = + spi_get_device_id(mc13xxx->spidev); + + if (!devid) + return NULL; + + return mc13xxx_chipname[devid->driver_data]; +} + +#include <linux/mfd/mc13783.h> + +int mc13xxx_get_flags(struct mc13xxx *mc13xxx) +{ + struct mc13xxx_platform_data *pdata = + dev_get_platdata(&mc13xxx->spidev->dev); + + return pdata->flags; +} +EXPORT_SYMBOL(mc13xxx_get_flags); + +#define MC13783_ADC1_CHAN0_SHIFT 5 +#define MC13783_ADC1_CHAN1_SHIFT 8 + +struct mc13xxx_adcdone_data { + struct mc13xxx *mc13xxx; + struct completion done; +}; + +static irqreturn_t mc13783_handler_adcdone(int irq, void *data) +{ + struct mc13xxx_adcdone_data *adcdone_data = data; + + mc13xxx_irq_ack(adcdone_data->mc13xxx, irq); + + complete_all(&adcdone_data->done); + + return IRQ_HANDLED; +} + +#define MC13783_ADC_WORKING (1 << 0) + +int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, + unsigned int channel, unsigned int *sample) +{ + struct mc13xxx *mc13xxx = &mc13783->mc13xxx; + u32 adc0, adc1, old_adc0; + int i, ret; + struct mc13xxx_adcdone_data adcdone_data = { + .mc13xxx = mc13xxx, + }; + init_completion(&adcdone_data.done); + + dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__); + + mc13xxx_lock(mc13xxx); + + if (mc13783->adcflags & MC13783_ADC_WORKING) { + ret = -EBUSY; + goto out; + } + + mc13783->adcflags |= MC13783_ADC_WORKING; + + mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0); + + adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; + adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; + + if (channel > 7) + adc1 |= MC13783_ADC1_ADSEL; + + switch (mode) { + case MC13783_ADC_MODE_TS: + adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | + MC13783_ADC0_TSMOD1; + adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; + break; + + case MC13783_ADC_MODE_SINGLE_CHAN: + adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; + adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; + adc1 |= MC13783_ADC1_RAND; + break; + + case MC13783_ADC_MODE_MULT_CHAN: + adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; + adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; + break; + + default: + mc13783_unlock(mc13783); + return -EINVAL; + } + + dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__); + mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE, + mc13783_handler_adcdone, __func__, &adcdone_data); + mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE); + + mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0); + mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1); + + mc13xxx_unlock(mc13xxx); + + ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); + + if (!ret) + ret = -ETIMEDOUT; + + mc13xxx_lock(mc13xxx); + + mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data); + + if (ret > 0) + for (i = 0; i < 4; ++i) { + ret = mc13xxx_reg_read(mc13xxx, + MC13783_ADC2, &sample[i]); + if (ret) + break; + } + + if (mode == MC13783_ADC_MODE_TS) + /* restore TSMOD */ + mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0); + + mc13783->adcflags &= ~MC13783_ADC_WORKING; +out: + mc13xxx_unlock(mc13xxx); + + return ret; +} +EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); + +static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + const char *format, void *pdata, size_t pdata_size) +{ + char buf[30]; + const char *name = mc13xxx_get_chipname(mc13xxx); + + struct mfd_cell cell = { + .platform_data = pdata, + .data_size = pdata_size, + }; + + /* there is no asnprintf in the kernel :-( */ + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + + cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + + return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0); +} + +static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) +{ + return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); +} + +static int mc13xxx_probe(struct spi_device *spi) +{ + struct mc13xxx *mc13xxx; + struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); + enum mc13xxx_id id; + int ret; + + mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); + if (!mc13xxx) + return -ENOMEM; + + dev_set_drvdata(&spi->dev, mc13xxx); + spi->mode = SPI_MODE_0 | SPI_CS_HIGH; + spi->bits_per_word = 32; + spi_setup(spi); + + mc13xxx->spidev = spi; + + mutex_init(&mc13xxx->lock); + mc13xxx_lock(mc13xxx); + + ret = mc13xxx_identify(mc13xxx, &id); + if (ret || id == MC13XXX_ID_INVALID) + goto err_revision; + + /* mask all irqs */ + ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); + if (ret) + goto err_mask; + + ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff); + if (ret) + goto err_mask; + + ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); + + if (ret) { +err_mask: +err_revision: + mutex_unlock(&mc13xxx->lock); + dev_set_drvdata(&spi->dev, NULL); + kfree(mc13xxx); + return ret; + } + + mc13xxx_unlock(mc13xxx); + + if (pdata->flags & MC13XXX_USE_ADC) + mc13xxx_add_subdevice(mc13xxx, "%s-adc"); + + if (pdata->flags & MC13XXX_USE_CODEC) + mc13xxx_add_subdevice(mc13xxx, "%s-codec"); + + if (pdata->flags & MC13XXX_USE_REGULATOR) { + struct mc13xxx_regulator_platform_data regulator_pdata = { + .num_regulators = pdata->num_regulators, + .regulators = pdata->regulators, + }; + + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", + ®ulator_pdata, sizeof(regulator_pdata)); + } + + if (pdata->flags & MC13XXX_USE_RTC) + mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); + + if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) + mc13xxx_add_subdevice(mc13xxx, "%s-ts"); + + if (pdata->flags & MC13XXX_USE_LED) { + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", + pdata->leds, sizeof(*pdata->leds)); + } + + return 0; +} + +static int __devexit mc13xxx_remove(struct spi_device *spi) +{ + struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); + + free_irq(mc13xxx->spidev->irq, mc13xxx); + + mfd_remove_devices(&spi->dev); + + kfree(mc13xxx); + + return 0; +} + +static const struct spi_device_id mc13xxx_device_id[] = { + { + .name = "mc13783", + .driver_data = MC13XXX_ID_MC13783, + }, { + .name = "mc13892", + .driver_data = MC13XXX_ID_MC13892, + }, { + /* sentinel */ + } +}; + +static struct spi_driver mc13xxx_driver = { + .id_table = mc13xxx_device_id, + .driver = { + .name = "mc13xxx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mc13xxx_probe, + .remove = __devexit_p(mc13xxx_remove), +}; + +static int __init mc13xxx_init(void) +{ + return spi_register_driver(&mc13xxx_driver); +} +subsys_initcall(mc13xxx_init); + +static void __exit mc13xxx_exit(void) +{ + spi_unregister_driver(&mc13xxx_driver); +} +module_exit(mc13xxx_exit); + +MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); +MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 1823a57b7d8f..ec99f681e773 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -38,10 +38,12 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; platform_set_drvdata(pdev, cell->driver_data); - ret = platform_device_add_data(pdev, - cell->platform_data, cell->data_size); - if (ret) - goto fail_res; + if (cell->data_size) { + ret = platform_device_add_data(pdev, + cell->platform_data, cell->data_size); + if (ret) + goto fail_res; + } for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; @@ -65,9 +67,11 @@ static int mfd_add_device(struct device *parent, int id, res[r].end = cell->resources[r].end; } - ret = acpi_check_resource_conflict(res); - if (ret) - goto fail_res; + if (!cell->ignore_resource_conflicts) { + ret = acpi_check_resource_conflict(res); + if (ret) + goto fail_res; + } } ret = platform_device_add_resources(pdev, res, cell->num_resources); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 23e585527285..501ce13b693e 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -25,13 +25,6 @@ #include <linux/mfd/pcf50633/core.h> -int pcf50633_irq_init(struct pcf50633 *pcf, int irq); -void pcf50633_irq_free(struct pcf50633 *pcf); -#ifdef CONFIG_PM -int pcf50633_irq_suspend(struct pcf50633 *pcf); -int pcf50633_irq_resume(struct pcf50633 *pcf); -#endif - static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) { int ret; @@ -346,12 +339,14 @@ static int __devexit pcf50633_remove(struct i2c_client *client) struct pcf50633 *pcf = i2c_get_clientdata(client); int i; + sysfs_remove_group(&client->dev.kobj, &pcf_attr_group); pcf50633_irq_free(pcf); platform_device_unregister(pcf->input_pdev); platform_device_unregister(pcf->rtc_pdev); platform_device_unregister(pcf->mbc_pdev); platform_device_unregister(pcf->adc_pdev); + platform_device_unregister(pcf->bl_pdev); for (i = 0; i < PCF50633_NUM_REGULATORS; i++) platform_device_unregister(pcf->regulator_pdev[i]); diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 49b4d069cbf9..f1714f93af9d 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -65,6 +65,17 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) p->set_pwr(pdev, state); } +static int sh_mobile_sdhi_get_cd(struct platform_device *tmio) +{ + struct platform_device *pdev = to_platform_device(tmio->dev.parent); + struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + + if (p && p->get_cd) + return p->get_cd(pdev); + else + return -ENOSYS; +} + static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) { struct sh_mobile_sdhi *priv; @@ -106,12 +117,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->hclk = clk_get_rate(priv->clk); mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; + mmc_data->get_cd = sh_mobile_sdhi_get_cd; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; if (p) { mmc_data->flags = p->tmio_flags; mmc_data->ocr_mask = p->tmio_ocr_mask; + mmc_data->capabilities |= p->tmio_caps; } + /* + * All SDHI blocks support 2-byte and larger block sizes in 4-bit + * bus width mode. + */ + mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; + if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { priv->param_tx.slave_id = p->dma_slave_tx; priv->param_rx.slave_id = p->dma_slave_rx; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 0754c5e91995..b11487f1e1cb 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -873,6 +873,28 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) return ret; } +#ifdef CONFIG_PM +static int stmpe_suspend(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + + if (device_may_wakeup(&i2c->dev)) + enable_irq_wake(i2c->irq); + + return 0; +} + +static int stmpe_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + + if (device_may_wakeup(&i2c->dev)) + disable_irq_wake(i2c->irq); + + return 0; +} +#endif + static int __devinit stmpe_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -960,9 +982,19 @@ static const struct i2c_device_id stmpe_id[] = { }; MODULE_DEVICE_TABLE(i2c, stmpe_id); +#ifdef CONFIG_PM +static const struct dev_pm_ops stmpe_dev_pm_ops = { + .suspend = stmpe_suspend, + .resume = stmpe_resume, +}; +#endif + static struct i2c_driver stmpe_driver = { .driver.name = "stmpe", .driver.owner = THIS_MODULE, +#ifdef CONFIG_PM + .driver.pm = &stmpe_dev_pm_ops, +#endif .probe = stmpe_probe, .remove = __devexit_p(stmpe_remove), .id_table = stmpe_id, diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index ef6c42c8917a..1ea80d8ad915 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -155,7 +155,7 @@ static struct resource __devinitdata tc6393xb_nand_resources[] = { }, }; -static struct resource __devinitdata tc6393xb_mmc_resources[] = { +static struct resource tc6393xb_mmc_resources[] = { { .start = 0x800, .end = 0x9ff, diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index ac5995026c88..727f62c15a60 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -43,6 +43,8 @@ #include <linux/timb_dma.h> +#include <linux/ks8842.h> + #include "timberdale.h" #define DRIVER_NAME "timberdale" @@ -161,6 +163,12 @@ static const __devinitconst struct resource timberdale_spi_resources[] = { }, }; +static __devinitdata struct ks8842_platform_data + timberdale_ks8842_platform_data = { + .rx_dma_channel = DMA_ETH_RX, + .tx_dma_channel = DMA_ETH_TX +}; + static const __devinitconst struct resource timberdale_eth_resources[] = { { .start = ETHOFFSET, @@ -389,6 +397,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, + .platform_data = &timberdale_ks8842_platform_data, + .data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -447,6 +457,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, + .platform_data = &timberdale_ks8842_platform_data, + .data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -538,6 +550,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, + .platform_data = &timberdale_ks8842_platform_data, + .data_size = sizeof(timberdale_ks8842_platform_data) }, }; diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index fc0197649281..33ba7723c967 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -68,7 +68,7 @@ static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg, u8 msg[TPS6507X_MAX_REGISTER + 1]; int ret; - if (bytes > (TPS6507X_MAX_REGISTER + 1)) + if (bytes > TPS6507X_MAX_REGISTER) return -EINVAL; msg[0] = reg; diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 4cde31e6a252..b4931ab34929 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -15,6 +15,8 @@ * published by the Free Software Foundation. */ +#include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> @@ -29,9 +31,64 @@ #define TPS6586X_GPIOSET1 0x5d #define TPS6586X_GPIOSET2 0x5e +/* interrupt control registers */ +#define TPS6586X_INT_ACK1 0xb5 +#define TPS6586X_INT_ACK2 0xb6 +#define TPS6586X_INT_ACK3 0xb7 +#define TPS6586X_INT_ACK4 0xb8 + +/* interrupt mask registers */ +#define TPS6586X_INT_MASK1 0xb0 +#define TPS6586X_INT_MASK2 0xb1 +#define TPS6586X_INT_MASK3 0xb2 +#define TPS6586X_INT_MASK4 0xb3 +#define TPS6586X_INT_MASK5 0xb4 + /* device id */ #define TPS6586X_VERSIONCRC 0xcd #define TPS658621A_VERSIONCRC 0x15 +#define TPS658621C_VERSIONCRC 0x2c + +struct tps6586x_irq_data { + u8 mask_reg; + u8 mask_mask; +}; + +#define TPS6586X_IRQ(_reg, _mask) \ + { \ + .mask_reg = (_reg) - TPS6586X_INT_MASK1, \ + .mask_mask = (_mask), \ + } + +static const struct tps6586x_irq_data tps6586x_irqs[] = { + [TPS6586X_INT_PLDO_0] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0), + [TPS6586X_INT_PLDO_1] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1), + [TPS6586X_INT_PLDO_2] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2), + [TPS6586X_INT_PLDO_3] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3), + [TPS6586X_INT_PLDO_4] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4), + [TPS6586X_INT_PLDO_5] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5), + [TPS6586X_INT_PLDO_6] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6), + [TPS6586X_INT_PLDO_7] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7), + [TPS6586X_INT_COMP_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0), + [TPS6586X_INT_ADC] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1), + [TPS6586X_INT_PLDO_8] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2), + [TPS6586X_INT_PLDO_9] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3), + [TPS6586X_INT_PSM_0] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4), + [TPS6586X_INT_PSM_1] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5), + [TPS6586X_INT_PSM_2] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6), + [TPS6586X_INT_PSM_3] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7), + [TPS6586X_INT_RTC_ALM1] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4), + [TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03), + [TPS6586X_INT_USB_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2), + [TPS6586X_INT_AC_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3), + [TPS6586X_INT_BAT_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0), + [TPS6586X_INT_CHG_STAT] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc), + [TPS6586X_INT_CHG_TEMP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06), + [TPS6586X_INT_PP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0), + [TPS6586X_INT_RESUME] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5), + [TPS6586X_INT_LOW_SYS] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6), + [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), +}; struct tps6586x { struct mutex lock; @@ -39,6 +96,12 @@ struct tps6586x { struct i2c_client *client; struct gpio_chip gpio; + struct irq_chip irq_chip; + struct mutex irq_lock; + int irq_base; + u32 irq_en; + u8 mask_cache[5]; + u8 mask_reg[5]; }; static inline int __tps6586x_read(struct i2c_client *client, @@ -262,6 +325,129 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x) return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); } +static void tps6586x_irq_lock(unsigned int irq) +{ + struct tps6586x *tps6586x = get_irq_chip_data(irq); + + mutex_lock(&tps6586x->irq_lock); +} + +static void tps6586x_irq_enable(unsigned int irq) +{ + struct tps6586x *tps6586x = get_irq_chip_data(irq); + unsigned int __irq = irq - tps6586x->irq_base; + const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; + + tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; + tps6586x->irq_en |= (1 << __irq); +} + +static void tps6586x_irq_disable(unsigned int irq) +{ + struct tps6586x *tps6586x = get_irq_chip_data(irq); + + unsigned int __irq = irq - tps6586x->irq_base; + const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; + + tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; + tps6586x->irq_en &= ~(1 << __irq); +} + +static void tps6586x_irq_sync_unlock(unsigned int irq) +{ + struct tps6586x *tps6586x = get_irq_chip_data(irq); + int i; + + for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) { + if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) { + if (!WARN_ON(tps6586x_write(tps6586x->dev, + TPS6586X_INT_MASK1 + i, + tps6586x->mask_reg[i]))) + tps6586x->mask_cache[i] = tps6586x->mask_reg[i]; + } + } + + mutex_unlock(&tps6586x->irq_lock); +} + +static irqreturn_t tps6586x_irq(int irq, void *data) +{ + struct tps6586x *tps6586x = data; + u32 acks; + int ret = 0; + + ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, + sizeof(acks), (uint8_t *)&acks); + + if (ret < 0) { + dev_err(tps6586x->dev, "failed to read interrupt status\n"); + return IRQ_NONE; + } + + acks = le32_to_cpu(acks); + + while (acks) { + int i = __ffs(acks); + + if (tps6586x->irq_en & (1 << i)) + handle_nested_irq(tps6586x->irq_base + i); + + acks &= ~(1 << i); + } + + return IRQ_HANDLED; +} + +static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, + int irq_base) +{ + int i, ret; + u8 tmp[4]; + + if (!irq_base) { + dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n"); + return -EINVAL; + } + + mutex_init(&tps6586x->irq_lock); + for (i = 0; i < 5; i++) { + tps6586x->mask_cache[i] = 0xff; + tps6586x->mask_reg[i] = 0xff; + tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff); + } + + tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); + + tps6586x->irq_base = irq_base; + + tps6586x->irq_chip.name = "tps6586x"; + tps6586x->irq_chip.enable = tps6586x_irq_enable; + tps6586x->irq_chip.disable = tps6586x_irq_disable; + tps6586x->irq_chip.bus_lock = tps6586x_irq_lock; + tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock; + + for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { + int __irq = i + tps6586x->irq_base; + set_irq_chip_data(__irq, tps6586x); + set_irq_chip_and_handler(__irq, &tps6586x->irq_chip, + handle_simple_irq); + set_irq_nested_thread(__irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(__irq, IRQF_VALID); +#endif + } + + ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, + "tps6586x", tps6586x); + + if (!ret) { + device_init_wakeup(tps6586x->dev, 1); + enable_irq_wake(irq); + } + + return ret; +} + static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, struct tps6586x_platform_data *pdata) { @@ -273,13 +459,19 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, subdev = &pdata->subdevs[i]; pdev = platform_device_alloc(subdev->name, subdev->id); + if (!pdev) { + ret = -ENOMEM; + goto failed; + } pdev->dev.parent = tps6586x->dev; pdev->dev.platform_data = subdev->platform_data; ret = platform_device_add(pdev); - if (ret) + if (ret) { + platform_device_put(pdev); goto failed; + } } return 0; @@ -306,7 +498,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, return -EIO; } - if (ret != TPS658621A_VERSIONCRC) { + if ((ret != TPS658621A_VERSIONCRC) && + (ret != TPS658621C_VERSIONCRC)) { dev_err(&client->dev, "Unsupported chip ID: %x\n", ret); return -ENODEV; } @@ -321,6 +514,15 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, mutex_init(&tps6586x->lock); + if (client->irq) { + ret = tps6586x_irq_init(tps6586x, client->irq, + pdata->irq_base); + if (ret) { + dev_err(&client->dev, "IRQ init failed: %d\n", ret); + goto err_irq_init; + } + } + ret = tps6586x_add_subdevs(tps6586x, pdata); if (ret) { dev_err(&client->dev, "add devices failed: %d\n", ret); @@ -332,12 +534,31 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, return 0; err_add_devs: + if (client->irq) + free_irq(client->irq, tps6586x); +err_irq_init: kfree(tps6586x); return ret; } static int __devexit tps6586x_i2c_remove(struct i2c_client *client) { + struct tps6586x *tps6586x = i2c_get_clientdata(client); + struct tps6586x_platform_data *pdata = client->dev.platform_data; + int ret; + + if (client->irq) + free_irq(client->irq, tps6586x); + + if (pdata->gpio_base) { + ret = gpiochip_remove(&tps6586x->gpio); + if (ret) + dev_err(&client->dev, "Can't remove gpio chip: %d\n", + ret); + } + + tps6586x_remove_subdevs(tps6586x); + kfree(tps6586x); return 0; } diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 5d0fb60a4c14..35275ba7096f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -115,6 +115,12 @@ #define twl_has_codec() false #endif +#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) +#define twl_has_bci() true +#else +#define twl_has_bci() false +#endif + /* Triton Core internal information (BEGIN) */ /* Last - for index max*/ @@ -202,12 +208,6 @@ /* Few power values */ #define R_CFG_BOOT 0x05 -#define R_PROTECT_KEY 0x0E - -/* access control values for R_PROTECT_KEY */ -#define KEY_UNLOCK1 0xce -#define KEY_UNLOCK2 0xec -#define KEY_LOCK 0x00 /* some fields in R_CFG_BOOT */ #define HFCLK_FREQ_19p2_MHZ (1 << 0) @@ -255,7 +255,7 @@ struct twl_mapping { unsigned char sid; /* Slave ID */ unsigned char base; /* base address */ }; -struct twl_mapping *twl_map; +static struct twl_mapping *twl_map; static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { /* @@ -832,6 +832,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) return PTR_ERR(child); } + if (twl_has_bci() && pdata->bci && + !(features & (TPS_SUBSET | TWL5031))) { + child = add_child(3, "twl4030_bci", + pdata->bci, sizeof(*pdata->bci), false, + /* irq0 = CHG_PRES, irq1 = BCI */ + pdata->irq_base + BCI_PRES_INTR_OFFSET, + pdata->irq_base + BCI_INTR_OFFSET); + if (IS_ERR(child)) + return PTR_ERR(child); + } + return 0; } @@ -846,8 +857,8 @@ static inline int __init protect_pm_master(void) { int e = 0; - e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK, - R_PROTECT_KEY); + e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, + TWL4030_PM_MASTER_PROTECT_KEY); return e; } @@ -855,10 +866,13 @@ static inline int __init unprotect_pm_master(void) { int e = 0; - e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1, - R_PROTECT_KEY); - e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2, - R_PROTECT_KEY); + e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG1, + TWL4030_PM_MASTER_PROTECT_KEY); + e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG2, + TWL4030_PM_MASTER_PROTECT_KEY); + return e; } diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h new file mode 100644 index 000000000000..8c50a556e986 --- /dev/null +++ b/drivers/mfd/twl-core.h @@ -0,0 +1,10 @@ +#ifndef __TWL_CORE_H__ +#define __TWL_CORE_H__ + +extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); +extern int twl6030_exit_irq(void); +extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); +extern int twl4030_exit_irq(void); +extern int twl4030_init_chip_irq(const char *chip); + +#endif /* __TWL_CORE_H__ */ diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b9fda7018cef..5d3a1478004b 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -35,6 +35,7 @@ #include <linux/i2c/twl.h> +#include "twl-core.h" /* * TWL4030 IRQ handling has two stages in hardware, and thus in software. @@ -144,6 +145,7 @@ static const struct sih sih_modules_twl4030[6] = { .name = "bci", .module = TWL4030_MODULE_INTERRUPTS, .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, + .set_cor = true, .bits = 12, .bytes_ixr = 2, .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, @@ -408,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line) * set Clear-On-Read (COR) bit. * * NOTE that sometimes COR polarity is documented as being - * inverted: for MADC and BCI, COR=1 means "clear on write". + * inverted: for MADC, COR=1 means "clear on write". * And for PWR_INT it's not documented... */ if (sih->set_cor) { diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 7efa8789a3a2..16422de0823a 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -63,10 +63,6 @@ static u8 twl4030_start_script_address = 0x2b; #define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59) #define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a) -#define R_PROTECT_KEY 0x0E -#define R_KEY_1 0xC0 -#define R_KEY_2 0x0C - /* resource configuration registers <RESOURCE>_DEV_GRP at address 'n+0' <RESOURCE>_TYPE at address 'n+1' @@ -465,15 +461,17 @@ int twl4030_remove_script(u8 flags) { int err = 0; - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, - R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG1, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) { pr_err("twl4030: unable to unlock PROTECT_KEY\n"); return err; } - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, - R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG2, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) { pr_err("twl4030: unable to unlock PROTECT_KEY\n"); return err; @@ -504,7 +502,8 @@ int twl4030_remove_script(u8 flags) return err; } - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) pr_err("TWL4030 Unable to relock registers\n"); @@ -518,13 +517,15 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) struct twl4030_resconfig *resconfig; u8 address = twl4030_start_script_address; - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, - R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG1, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) goto unlock; - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, - R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG2, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) goto unlock; @@ -546,7 +547,8 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) } } - err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, + TWL4030_PM_MASTER_PROTECT_KEY); if (err) pr_err("TWL4030 Unable to relock registers\n"); return; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 10bf228ad626..aaedb11d9d2c 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -36,6 +36,9 @@ #include <linux/irq.h> #include <linux/kthread.h> #include <linux/i2c/twl.h> +#include <linux/platform_device.h> + +#include "twl-core.h" /* * TWL6030 (unlike its predecessors, which had two level interrupt handling) @@ -223,6 +226,78 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset) } EXPORT_SYMBOL(twl6030_interrupt_mask); +int twl6030_mmc_card_detect_config(void) +{ + int ret; + u8 reg_val = 0; + + /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ + twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, + REG_INT_MSK_LINE_B); + twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, + REG_INT_MSK_STS_B); + /* + * Intially Configuring MMC_CTRL for receving interrupts & + * Card status on TWL6030 for MMC1 + */ + ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); + if (ret < 0) { + pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); + return ret; + } + reg_val &= ~VMMC_AUTO_OFF; + reg_val |= SW_FC; + ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); + if (ret < 0) { + pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); + return ret; + } + + /* Configuring PullUp-PullDown register */ + ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, + TWL6030_CFG_INPUT_PUPD3); + if (ret < 0) { + pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", + ret); + return ret; + } + reg_val &= ~(MMC_PU | MMC_PD); + ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, + TWL6030_CFG_INPUT_PUPD3); + if (ret < 0) { + pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", + ret); + return ret; + } + return 0; +} +EXPORT_SYMBOL(twl6030_mmc_card_detect_config); + +int twl6030_mmc_card_detect(struct device *dev, int slot) +{ + int ret = -EIO; + u8 read_reg = 0; + struct platform_device *pdev = to_platform_device(dev); + + if (pdev->id) { + /* TWL6030 provide's Card detect support for + * only MMC1 controller. + */ + pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__); + return ret; + } + /* + * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 + * 0 - Card not present ,1 - Card present + */ + ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, + TWL6030_MMCCTRL); + if (ret >= 0) + ret = read_reg & STS_MMC; + return ret; +} +EXPORT_SYMBOL(twl6030_mmc_card_detect); + int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) { diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c new file mode 100644 index 000000000000..ebb059765edd --- /dev/null +++ b/drivers/mfd/vx855.c @@ -0,0 +1,147 @@ +/* + * Linux multi-function-device driver (MFD) for the integrated peripherals + * of the VIA VX855 chipset + * + * Copyright (C) 2009 VIA Technologies, Inc. + * Copyright (C) 2010 One Laptop per Child + * Author: Harald Welte <HaraldWelte@viatech.com> + * All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/pci.h> +#include <linux/mfd/core.h> + +/* offset into pci config space indicating the 16bit register containing + * the power management IO space base */ +#define VX855_CFG_PMIO_OFFSET 0x88 + +/* ACPI I/O Space registers */ +#define VX855_PMIO_ACPI 0x00 +#define VX855_PMIO_ACPI_LEN 0x0b + +/* Processor Power Management */ +#define VX855_PMIO_PPM 0x10 +#define VX855_PMIO_PPM_LEN 0x08 + +/* General Purpose Power Management */ +#define VX855_PMIO_GPPM 0x20 +#define VX855_PMIO_R_GPI 0x48 +#define VX855_PMIO_R_GPO 0x4c +#define VX855_PMIO_GPPM_LEN 0x33 + +#define VSPIC_MMIO_SIZE 0x1000 + +static struct resource vx855_gpio_resources[] = { + { + .flags = IORESOURCE_IO, + }, + { + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell vx855_cells[] = { + { + .name = "vx855_gpio", + .num_resources = ARRAY_SIZE(vx855_gpio_resources), + .resources = vx855_gpio_resources, + + /* we must ignore resource conflicts, for reasons outlined in + * the vx855_gpio driver */ + .ignore_resource_conflicts = true, + }, +}; + +static __devinit int vx855_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + u16 gpio_io_offset; + + ret = pci_enable_device(pdev); + if (ret) + return -ENODEV; + + pci_read_config_word(pdev, VX855_CFG_PMIO_OFFSET, &gpio_io_offset); + if (!gpio_io_offset) { + dev_warn(&pdev->dev, + "BIOS did not assign PMIO base offset?!?\n"); + ret = -ENODEV; + goto out; + } + + /* mask out the lowest seven bits, as they are always zero, but + * hardware returns them as 0x01 */ + gpio_io_offset &= 0xff80; + + /* As the region identified here includes many non-GPIO things, we + * only work with the specific registers that concern us. */ + vx855_gpio_resources[0].start = gpio_io_offset + VX855_PMIO_R_GPI; + vx855_gpio_resources[0].end = vx855_gpio_resources[0].start + 3; + vx855_gpio_resources[1].start = gpio_io_offset + VX855_PMIO_R_GPO; + vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; + + ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), + NULL, 0); + + /* we always return -ENODEV here in order to enable other + * drivers like old, not-yet-platform_device ported i2c-viapro */ + return -ENODEV; +out: + pci_disable_device(pdev); + return ret; +} + +static void vx855_remove(struct pci_dev *pdev) +{ + mfd_remove_devices(&pdev->dev); + pci_disable_device(pdev); +} + +static struct pci_device_id vx855_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, + { 0, } +}; + +static struct pci_driver vx855_pci_driver = { + .name = "vx855", + .id_table = vx855_pci_tbl, + .probe = vx855_probe, + .remove = __devexit_p(vx855_remove), +}; + +static int vx855_init(void) +{ + return pci_register_driver(&vx855_pci_driver); +} +module_init(vx855_init); + +static void vx855_exit(void) +{ + pci_unregister_driver(&vx855_pci_driver); +} +module_exit(vx855_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>"); +MODULE_DESCRIPTION("Driver for the VIA VX855 chipset"); diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 1e7aaaf6cc6f..7d2563fc15c6 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/i2c.h> #include <linux/bcd.h> #include <linux/delay.h> #include <linux/mfd/core.h> @@ -90,14 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { }; EXPORT_SYMBOL_GPL(wm831x_isinkv_values); -enum wm831x_parent { - WM8310 = 0x8310, - WM8311 = 0x8311, - WM8312 = 0x8312, - WM8320 = 0x8320, - WM8321 = 0x8321, -}; - static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) { if (!wm831x->locked) @@ -1446,7 +1437,7 @@ static struct mfd_cell backlight_devs[] = { /* * Instantiate the generic non-control parts of the device. */ -static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) +int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) { struct wm831x_pdata *pdata = wm831x->dev->platform_data; int rev; @@ -1540,6 +1531,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev); break; + case WM8325: + parent = WM8325; + wm831x->num_gpio = 12; + dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev); + break; + default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; @@ -1620,6 +1617,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) NULL, 0); break; + case WM8325: + ret = mfd_add_devices(wm831x->dev, -1, + wm8320_devs, ARRAY_SIZE(wm8320_devs), + NULL, 0); + break; + default: /* If this happens the bus probe function is buggy */ BUG(); @@ -1660,7 +1663,7 @@ err: return ret; } -static void wm831x_device_exit(struct wm831x *wm831x) +void wm831x_device_exit(struct wm831x *wm831x) { wm831x_otp_exit(wm831x); mfd_remove_devices(wm831x->dev); @@ -1670,7 +1673,7 @@ static void wm831x_device_exit(struct wm831x *wm831x) kfree(wm831x); } -static int wm831x_device_suspend(struct wm831x *wm831x) +int wm831x_device_suspend(struct wm831x *wm831x) { int reg, mask; @@ -1706,125 +1709,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x) return 0; } -static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *dest) -{ - struct i2c_client *i2c = wm831x->control_data; - int ret; - u16 r = cpu_to_be16(reg); - - ret = i2c_master_send(i2c, (unsigned char *)&r, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - if (ret != bytes) - return -EIO; - return 0; -} - -/* Currently we allocate the write buffer on the stack; this is OK for - * small writes - if we need to do large writes this will need to be - * revised. - */ -static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *src) -{ - struct i2c_client *i2c = wm831x->control_data; - unsigned char msg[bytes + 2]; - int ret; - - reg = cpu_to_be16(reg); - memcpy(&msg[0], ®, 2); - memcpy(&msg[2], src, bytes); - - ret = i2c_master_send(i2c, msg, bytes + 2); - if (ret < 0) - return ret; - if (ret < bytes + 2) - return -EIO; - - return 0; -} - -static int wm831x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm831x *wm831x; - - wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); - if (wm831x == NULL) - return -ENOMEM; - - i2c_set_clientdata(i2c, wm831x); - wm831x->dev = &i2c->dev; - wm831x->control_data = i2c; - wm831x->read_dev = wm831x_i2c_read_device; - wm831x->write_dev = wm831x_i2c_write_device; - - return wm831x_device_init(wm831x, id->driver_data, i2c->irq); -} - -static int wm831x_i2c_remove(struct i2c_client *i2c) -{ - struct wm831x *wm831x = i2c_get_clientdata(i2c); - - wm831x_device_exit(wm831x); - - return 0; -} - -static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) -{ - struct wm831x *wm831x = i2c_get_clientdata(i2c); - - return wm831x_device_suspend(wm831x); -} - -static const struct i2c_device_id wm831x_i2c_id[] = { - { "wm8310", WM8310 }, - { "wm8311", WM8311 }, - { "wm8312", WM8312 }, - { "wm8320", WM8320 }, - { "wm8321", WM8321 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); - - -static struct i2c_driver wm831x_i2c_driver = { - .driver = { - .name = "wm831x", - .owner = THIS_MODULE, - }, - .probe = wm831x_i2c_probe, - .remove = wm831x_i2c_remove, - .suspend = wm831x_i2c_suspend, - .id_table = wm831x_i2c_id, -}; - -static int __init wm831x_i2c_init(void) -{ - int ret; - - ret = i2c_add_driver(&wm831x_i2c_driver); - if (ret != 0) - pr_err("Failed to register wm831x I2C driver: %d\n", ret); - - return ret; -} -subsys_initcall(wm831x_i2c_init); - -static void __exit wm831x_i2c_exit(void) -{ - i2c_del_driver(&wm831x_i2c_driver); -} -module_exit(wm831x_i2c_exit); - -MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC"); +MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mark Brown"); diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c new file mode 100644 index 000000000000..156b19859e81 --- /dev/null +++ b/drivers/mfd/wm831x-i2c.c @@ -0,0 +1,143 @@ +/* + * wm831x-i2c.c -- I2C access for Wolfson WM831x PMICs + * + * Copyright 2009,2010 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/mfd/core.h> +#include <linux/slab.h> + +#include <linux/mfd/wm831x/core.h> +#include <linux/mfd/wm831x/pdata.h> + +static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, + int bytes, void *dest) +{ + struct i2c_client *i2c = wm831x->control_data; + int ret; + u16 r = cpu_to_be16(reg); + + ret = i2c_master_send(i2c, (unsigned char *)&r, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + ret = i2c_master_recv(i2c, dest, bytes); + if (ret < 0) + return ret; + if (ret != bytes) + return -EIO; + return 0; +} + +/* Currently we allocate the write buffer on the stack; this is OK for + * small writes - if we need to do large writes this will need to be + * revised. + */ +static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, + int bytes, void *src) +{ + struct i2c_client *i2c = wm831x->control_data; + unsigned char msg[bytes + 2]; + int ret; + + reg = cpu_to_be16(reg); + memcpy(&msg[0], ®, 2); + memcpy(&msg[2], src, bytes); + + ret = i2c_master_send(i2c, msg, bytes + 2); + if (ret < 0) + return ret; + if (ret < bytes + 2) + return -EIO; + + return 0; +} + +static int wm831x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm831x *wm831x; + + wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + if (wm831x == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, wm831x); + wm831x->dev = &i2c->dev; + wm831x->control_data = i2c; + wm831x->read_dev = wm831x_i2c_read_device; + wm831x->write_dev = wm831x_i2c_write_device; + + return wm831x_device_init(wm831x, id->driver_data, i2c->irq); +} + +static int wm831x_i2c_remove(struct i2c_client *i2c) +{ + struct wm831x *wm831x = i2c_get_clientdata(i2c); + + wm831x_device_exit(wm831x); + + return 0; +} + +static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) +{ + struct wm831x *wm831x = i2c_get_clientdata(i2c); + + return wm831x_device_suspend(wm831x); +} + +static const struct i2c_device_id wm831x_i2c_id[] = { + { "wm8310", WM8310 }, + { "wm8311", WM8311 }, + { "wm8312", WM8312 }, + { "wm8320", WM8320 }, + { "wm8321", WM8321 }, + { "wm8325", WM8325 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); + + +static struct i2c_driver wm831x_i2c_driver = { + .driver = { + .name = "wm831x", + .owner = THIS_MODULE, + }, + .probe = wm831x_i2c_probe, + .remove = wm831x_i2c_remove, + .suspend = wm831x_i2c_suspend, + .id_table = wm831x_i2c_id, +}; + +static int __init wm831x_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&wm831x_i2c_driver); + if (ret != 0) + pr_err("Failed to register wm831x I2C driver: %d\n", ret); + + return ret; +} +subsys_initcall(wm831x_i2c_init); + +static void __exit wm831x_i2c_exit(void) +{ + i2c_del_driver(&wm831x_i2c_driver); +} +module_exit(wm831x_i2c_exit); diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c new file mode 100644 index 000000000000..2789b151b0f9 --- /dev/null +++ b/drivers/mfd/wm831x-spi.c @@ -0,0 +1,232 @@ +/* + * wm831x-spi.c -- SPI access for Wolfson WM831x PMICs + * + * Copyright 2009,2010 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <linux/mfd/wm831x/core.h> + +static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, + int bytes, void *dest) +{ + u16 tx_val; + u16 *d = dest; + int r, ret; + + /* Go register at a time */ + for (r = reg; r < reg + (bytes / 2); r++) { + tx_val = r | 0x8000; + + ret = spi_write_then_read(wm831x->control_data, + (u8 *)&tx_val, 2, (u8 *)d, 2); + if (ret != 0) + return ret; + + *d = be16_to_cpu(*d); + + d++; + } + + return 0; +} + +static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, + int bytes, void *src) +{ + struct spi_device *spi = wm831x->control_data; + u16 *s = src; + u16 data[2]; + int ret, r; + + /* Go register at a time */ + for (r = reg; r < reg + (bytes / 2); r++) { + data[0] = r; + data[1] = *s++; + + ret = spi_write(spi, (char *)&data, sizeof(data)); + if (ret != 0) + return ret; + } + + return 0; +} + +static int __devinit wm831x_spi_probe(struct spi_device *spi) +{ + struct wm831x *wm831x; + enum wm831x_parent type; + + /* Currently SPI support for ID tables is unmerged, we're faking it */ + if (strcmp(spi->modalias, "wm8310") == 0) + type = WM8310; + else if (strcmp(spi->modalias, "wm8311") == 0) + type = WM8311; + else if (strcmp(spi->modalias, "wm8312") == 0) + type = WM8312; + else if (strcmp(spi->modalias, "wm8320") == 0) + type = WM8320; + else if (strcmp(spi->modalias, "wm8321") == 0) + type = WM8321; + else if (strcmp(spi->modalias, "wm8325") == 0) + type = WM8325; + else { + dev_err(&spi->dev, "Unknown device type\n"); + return -EINVAL; + } + + wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + if (wm831x == NULL) + return -ENOMEM; + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_0; + + dev_set_drvdata(&spi->dev, wm831x); + wm831x->dev = &spi->dev; + wm831x->control_data = spi; + wm831x->read_dev = wm831x_spi_read_device; + wm831x->write_dev = wm831x_spi_write_device; + + return wm831x_device_init(wm831x, type, spi->irq); +} + +static int __devexit wm831x_spi_remove(struct spi_device *spi) +{ + struct wm831x *wm831x = dev_get_drvdata(&spi->dev); + + wm831x_device_exit(wm831x); + + return 0; +} + +static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m) +{ + struct wm831x *wm831x = dev_get_drvdata(&spi->dev); + + return wm831x_device_suspend(wm831x); +} + +static struct spi_driver wm8310_spi_driver = { + .driver = { + .name = "wm8310", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static struct spi_driver wm8311_spi_driver = { + .driver = { + .name = "wm8311", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static struct spi_driver wm8312_spi_driver = { + .driver = { + .name = "wm8312", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static struct spi_driver wm8320_spi_driver = { + .driver = { + .name = "wm8320", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static struct spi_driver wm8321_spi_driver = { + .driver = { + .name = "wm8321", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static struct spi_driver wm8325_spi_driver = { + .driver = { + .name = "wm8325", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + +static int __init wm831x_spi_init(void) +{ + int ret; + + ret = spi_register_driver(&wm8310_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8310 SPI driver: %d\n", ret); + + ret = spi_register_driver(&wm8311_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8311 SPI driver: %d\n", ret); + + ret = spi_register_driver(&wm8312_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8312 SPI driver: %d\n", ret); + + ret = spi_register_driver(&wm8320_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8320 SPI driver: %d\n", ret); + + ret = spi_register_driver(&wm8321_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8321 SPI driver: %d\n", ret); + + ret = spi_register_driver(&wm8325_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8325 SPI driver: %d\n", ret); + + return 0; +} +subsys_initcall(wm831x_spi_init); + +static void __exit wm831x_spi_exit(void) +{ + spi_unregister_driver(&wm8325_spi_driver); + spi_unregister_driver(&wm8321_spi_driver); + spi_unregister_driver(&wm8320_spi_driver); + spi_unregister_driver(&wm8312_spi_driver); + spi_unregister_driver(&wm8311_spi_driver); + spi_unregister_driver(&wm8310_spi_driver); +} +module_exit(wm831x_spi_exit); + +MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Brown"); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 39a2173b4e6c..4d073f1e4502 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -62,6 +62,15 @@ config ATMEL_PWM purposes including software controlled power-efficient backlights on LCD displays, motor control, and waveform generation. +config AB8500_PWM + bool "AB8500 PWM support" + depends on AB8500_CORE + select HAVE_PWM + help + This driver exports functions to enable/disble/config/free Pulse + Width Modulation in the Analog Baseband Chip AB8500. + It is used by led and backlight driver to control the intensity. + config ATMEL_TCLIB bool "Atmel AT32/AT91 Timer/Counter Library" depends on (AVR32 || ARCH_AT91) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 47af4cd08f01..98009cc20cb9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o obj-$(CONFIG_PCH_PHUB) += pch_phub.o obj-y += ti-st/ +obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c new file mode 100644 index 000000000000..54e3d05b63cc --- /dev/null +++ b/drivers/misc/ab8500-pwm.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Arun R Murthy <arun.murthy@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pwm.h> +#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500.h> + +/* + * PWM Out generators + * Bank: 0x10 + */ +#define AB8500_PWM_OUT_CTRL1_REG 0x60 +#define AB8500_PWM_OUT_CTRL2_REG 0x61 +#define AB8500_PWM_OUT_CTRL7_REG 0x66 + +/* backlight driver constants */ +#define ENABLE_PWM 1 +#define DISABLE_PWM 0 + +struct pwm_device { + struct device *dev; + struct list_head node; + const char *label; + unsigned int pwm_id; +}; + +static LIST_HEAD(pwm_list); + +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +{ + int ret = 0; + unsigned int higher_val, lower_val; + u8 reg; + + /* + * get the first 8 bits that are be written to + * AB8500_PWM_OUT_CTRL1_REG[0:7] + */ + lower_val = duty_ns & 0x00FF; + /* + * get bits [9:10] that are to be written to + * AB8500_PWM_OUT_CTRL2_REG[0:1] + */ + higher_val = ((duty_ns & 0x0300) >> 8); + + reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2); + + ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, + reg, (u8)lower_val); + if (ret < 0) + return ret; + ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, + (reg + 1), (u8)higher_val); + + return ret; +} +EXPORT_SYMBOL(pwm_config); + +int pwm_enable(struct pwm_device *pwm) +{ + int ret; + + ret = abx500_mask_and_set_register_interruptible(pwm->dev, + AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, + 1 << (pwm->pwm_id-1), ENABLE_PWM); + if (ret < 0) + dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", + pwm->label, ret); + return ret; +} +EXPORT_SYMBOL(pwm_enable); + +void pwm_disable(struct pwm_device *pwm) +{ + int ret; + + ret = abx500_mask_and_set_register_interruptible(pwm->dev, + AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, + 1 << (pwm->pwm_id-1), DISABLE_PWM); + if (ret < 0) + dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", + pwm->label, ret); + return; +} +EXPORT_SYMBOL(pwm_disable); + +struct pwm_device *pwm_request(int pwm_id, const char *label) +{ + struct pwm_device *pwm; + + list_for_each_entry(pwm, &pwm_list, node) { + if (pwm->pwm_id == pwm_id) { + pwm->label = label; + pwm->pwm_id = pwm_id; + return pwm; + } + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(pwm_request); + +void pwm_free(struct pwm_device *pwm) +{ + pwm_disable(pwm); +} +EXPORT_SYMBOL(pwm_free); + +static int __devinit ab8500_pwm_probe(struct platform_device *pdev) +{ + struct pwm_device *pwm; + /* + * Nothing to be done in probe, this is required to get the + * device which is required for ab8500 read and write + */ + pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); + if (pwm == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + pwm->dev = &pdev->dev; + pwm->pwm_id = pdev->id; + list_add_tail(&pwm->node, &pwm_list); + platform_set_drvdata(pdev, pwm); + dev_dbg(pwm->dev, "pwm probe successful\n"); + return 0; +} + +static int __devexit ab8500_pwm_remove(struct platform_device *pdev) +{ + struct pwm_device *pwm = platform_get_drvdata(pdev); + list_del(&pwm->node); + dev_dbg(&pdev->dev, "pwm driver removed\n"); + kfree(pwm); + return 0; +} + +static struct platform_driver ab8500_pwm_driver = { + .driver = { + .name = "ab8500-pwm", + .owner = THIS_MODULE, + }, + .probe = ab8500_pwm_probe, + .remove = __devexit_p(ab8500_pwm_remove), +}; + +static int __init ab8500_pwm_init(void) +{ + return platform_driver_register(&ab8500_pwm_driver); +} + +static void __exit ab8500_pwm_exit(void) +{ + platform_driver_unregister(&ab8500_pwm_driver); +} + +subsys_initcall(ab8500_pwm_init); +module_exit(ab8500_pwm_exit); +MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>"); +MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver"); +MODULE_ALIAS("AB8500 PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 0a53500636c9..d2d5d23416dd 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -91,11 +91,10 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); -static int ibmasmfs_get_super(struct file_system_type *fst, - int flags, const char *name, void *data, - struct vfsmount *mnt) +static struct dentry *ibmasmfs_mount(struct file_system_type *fst, + int flags, const char *name, void *data) { - return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt); + return mount_single(fst, flags, data, ibmasmfs_fill_super); } static const struct super_operations ibmasmfs_s_ops = { @@ -108,7 +107,7 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations; static struct file_system_type ibmasmfs_type = { .owner = THIS_MODULE, .name = "ibmasmfs", - .get_sb = ibmasmfs_get_super, + .mount = ibmasmfs_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 72450237a0f4..59c118c19a91 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1044,12 +1044,6 @@ static int __init init_kgdbts(void) return configure_kgdbts(); } -static void cleanup_kgdbts(void) -{ - if (configured == 1) - kgdb_unregister_io_module(&kgdbts_io_ops); -} - static int kgdbts_get_char(void) { int val = 0; @@ -1081,10 +1075,8 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) return 0; } - if (kgdb_connected) { - printk(KERN_ERR - "kgdbts: Cannot reconfigure while KGDB is connected.\n"); - + if (configured == 1) { + printk(KERN_ERR "kgdbts: ERROR: Already configured and running.\n"); return -EBUSY; } @@ -1093,9 +1085,6 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) if (config[len - 1] == '\n') config[len - 1] = '\0'; - if (configured == 1) - cleanup_kgdbts(); - /* Go and configure with the new params. */ return configure_kgdbts(); } @@ -1123,7 +1112,6 @@ static struct kgdb_io kgdbts_io_ops = { }; module_init(init_kgdbts); -module_exit(cleanup_kgdbts); module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644); MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]"); MODULE_DESCRIPTION("KGDB Test Suite"); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e865032a52eb..82a1079bbdc7 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -483,8 +483,6 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) int ret; if (gpio_is_valid(pdata->slots[0].switch_pin)) { - pdata->suspend = omap_hsmmc_suspend_cdirq; - pdata->resume = omap_hsmmc_resume_cdirq; if (pdata->slots[0].cover) pdata->slots[0].get_cover_state = omap_hsmmc_get_cover_state; @@ -2218,6 +2216,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } + pdata->suspend = omap_hsmmc_suspend_cdirq; + pdata->resume = omap_hsmmc_resume_cdirq; } omap_hsmmc_disable_irq(host); diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 0f06b8002814..ddd09840520b 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -710,9 +710,21 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->bus_width = ios->bus_width; } +static int sh_mmcif_get_cd(struct mmc_host *mmc) +{ + struct sh_mmcif_host *host = mmc_priv(mmc); + struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; + + if (!p->get_cd) + return -ENOSYS; + else + return p->get_cd(host->pd); +} + static struct mmc_host_ops sh_mmcif_ops = { .request = sh_mmcif_request, .set_ios = sh_mmcif_set_ios, + .get_cd = sh_mmcif_get_cd, }; static void sh_mmcif_detect(struct mmc_host *mmc) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 69d98e3bf6ab..e7765a89593e 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -658,14 +658,21 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host) static int tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data) { + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; + pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", data->blksz, data->blocks); - /* Hardware cannot perform 1 and 2 byte requests in 4 bit mode */ - if (data->blksz < 4 && host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - pr_err("%s: %d byte block unsupported in 4 bit mode\n", - mmc_hostname(host->mmc), data->blksz); - return -EINVAL; + /* Some hardware cannot perform 2 byte requests in 4 bit mode */ + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { + int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; + + if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { + pr_err("%s: %d byte block unsupported in 4 bit mode\n", + mmc_hostname(host->mmc), data->blksz); + return -EINVAL; + } } tmio_mmc_init_sg(host, data); @@ -756,10 +763,23 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1; } +static int tmio_mmc_get_cd(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; + + if (!pdata->get_cd) + return -ENOSYS; + else + return pdata->get_cd(host->pdev); +} + static const struct mmc_host_ops tmio_mmc_ops = { .request = tmio_mmc_request, .set_ios = tmio_mmc_set_ios, .get_ro = tmio_mmc_get_ro, + .get_cd = tmio_mmc_get_cd, }; #ifdef CONFIG_PM diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 9e2b7e9e0ad9..ad9268b44416 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1496,7 +1496,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, switch (mode) { case FL_WRITING: - write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); + write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0x40) : CMD(0x41); break; case FL_OTP_WRITE: write_cmd = CMD(0xc0); @@ -1661,7 +1661,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, cmd_adr = adr & ~(wbufsize-1); /* Let's determine this according to the interleave only once */ - write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); + write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0xe8) : CMD(0xe9); mutex_lock(&chip->mutex); ret = get_chip(map, chip, cmd_adr, FL_WRITING); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index ba29d2f0ffd7..3b8e32d87977 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -291,6 +291,23 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) cfi->addr_unlock1 = 0x555; cfi->addr_unlock2 = 0x2AA; + + cfi->sector_erase_cmd = CMD(0x50); +} + +static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + + fixup_sst39vf_rev_b(mtd, param); + + /* + * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where + * it should report a size of 8KBytes (0x0020*256). + */ + cfi->cfiq->EraseRegionInfo[0] = 0x002003ff; + pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); } static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) @@ -317,14 +334,14 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) /* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { - { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, // SST39VF1602 - { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, // SST39VF1601 - { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, // SST39VF3202 - { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, // SST39VF3201 - { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, // SST39VF3202B - { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, // SST39VF3201B - { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, // SST39VF6402B - { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, // SST39VF6401B + { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ + { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ + { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ + { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ + { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ + { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ + { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ + { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ { 0, 0, NULL, NULL } }; @@ -344,6 +361,10 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, + { CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ + { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ + { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ + { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, #endif @@ -374,6 +395,13 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && extp->MajorVersion == '0') extp->MajorVersion = '1'; + /* + * SST 38VF640x chips report major=0xFF / minor=0xFF. + */ + if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) { + extp->MajorVersion = '1'; + extp->MinorVersion = '0'; + } } struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) @@ -545,15 +573,6 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); goto setup_err; } -#if 0 - // debug - for (i=0; i<mtd->numeraseregions;i++){ - printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].numblocks); - } -#endif __module_get(THIS_MODULE); register_reboot_notifier(&mtd->reboot_notifier); @@ -674,7 +693,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr * there was an error (so leave the erase * routine to recover from it) or we trying to * use the erase-in-progress sector. */ - map_write(map, CMD(0x30), chip->in_progress_block_addr); + map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); chip->state = FL_ERASING; chip->oldstate = FL_READY; printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); @@ -727,7 +746,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad switch(chip->oldstate) { case FL_ERASING: chip->state = chip->oldstate; - map_write(map, CMD(0x30), chip->in_progress_block_addr); + map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); chip->oldstate = FL_READY; chip->state = FL_ERASING; break; @@ -870,7 +889,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, local_irq_disable(); /* Resume the write or erase operation */ - map_write(map, CMD(0x30), adr); + map_write(map, cfi->sector_erase_cmd, adr); chip->state = oldstate; start = xip_currtime(); } else if (usec >= 1000000/HZ) { @@ -1025,9 +1044,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi mutex_lock(&chip->mutex); if (chip->state != FL_READY){ -#if 0 - printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state); -#endif set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); @@ -1035,10 +1051,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi schedule(); remove_wait_queue(&chip->wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; -#endif timeo = jiffies + HZ; goto retry; @@ -1246,9 +1258,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { -#if 0 - printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); -#endif set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -1256,10 +1265,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; -#endif goto retry; } @@ -1324,9 +1329,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { -#if 0 - printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); -#endif set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -1334,10 +1336,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; -#endif goto retry1; } @@ -1396,7 +1394,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); /* Write Buffer Load */ map_write(map, CMD(0x25), cmd_adr); @@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - map_write(map, CMD(0x30), adr); + map_write(map, cfi->sector_erase_cmd, adr); chip->state = FL_ERASING; chip->erase_suspended = 0; diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index 8f5b96aa87a0..d25535279404 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -177,6 +177,8 @@ static int __xipram cfi_chip_setup(struct map_info *map, cfi->cfi_mode = CFI_MODE_CFI; + cfi->sector_erase_cmd = CMD(0x30); + /* Read the CFI info structure */ xip_disable_qry(base, map, cfi); for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index e503b2ca894d..360525c637d2 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -77,6 +77,13 @@ int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); if (cfi_qry_present(map, base, cfi)) return 1; + /* SST 39VF640xB */ + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); + if (cfi_qry_present(map, base, cfi)) + return 1; /* QRY not found */ return 0; } diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 93651865ddbe..2cf0cc6a4189 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -91,7 +91,6 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) } else instr->state = MTD_ERASE_DONE; - instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return err; } diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ea22520c0406..bf5a002209bd 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -661,11 +661,14 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, + { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SECT_4K) }, { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) }, @@ -714,6 +717,7 @@ static const struct spi_device_id m25p_ids[] = { { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, @@ -924,7 +928,7 @@ static int __devinit m25p_probe(struct spi_device *spi) nr_parts = data->nr_parts; } -#ifdef CONFIG_OF +#ifdef CONFIG_MTD_OF_PARTS if (nr_parts <= 0 && spi->dev.of_node) { nr_parts = of_mtd_parse_partitions(&spi->dev, spi->dev.of_node, &parts); diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 1696bbecaa7e..52393282eaf1 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -15,7 +15,7 @@ * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi */ -#define pr_fmt(fmt) "phram: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <asm/io.h> #include <linux/init.h> diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 962212628f6e..a0dd7bba9481 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -251,6 +251,15 @@ config MTD_NETtel help Support for flash chips on NETtel/SecureEdge/SnapGear boards. +config MTD_BCM963XX + tristate "Map driver for Broadcom BCM963xx boards" + depends on BCM63XX + select MTD_MAP_BANK_WIDTH_2 + select MTD_CFI_I1 + help + Support for parsing CFE image tag and creating MTD partitions on + Broadcom BCM63xx boards. + config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index f216bb573713..c7869c7a6b18 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o obj-$(CONFIG_MTD_VMU) += vmu-flash.o obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o +obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c new file mode 100644 index 000000000000..d175c120ee84 --- /dev/null +++ b/drivers/mtd/maps/bcm963xx-flash.c @@ -0,0 +1,271 @@ +/* + * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> + * Mike Albon <malbon@openwrt.org> + * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/vmalloc.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/mach-bcm63xx/bcm963xx_tag.h> + +#define BCM63XX_BUSWIDTH 2 /* Buswidth */ +#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ + +#define PFX KBUILD_MODNAME ": " + +static struct mtd_partition *parsed_parts; + +static struct mtd_info *bcm963xx_mtd_info; + +static struct map_info bcm963xx_map = { + .name = "bcm963xx", + .bankwidth = BCM63XX_BUSWIDTH, +}; + +static int parse_cfe_partitions(struct mtd_info *master, + struct mtd_partition **pparts) +{ + /* CFE, NVRAM and global Linux are always present */ + int nrparts = 3, curpart = 0; + struct bcm_tag *buf; + struct mtd_partition *parts; + int ret; + size_t retlen; + unsigned int rootfsaddr, kerneladdr, spareaddr; + unsigned int rootfslen, kernellen, sparelen, totallen; + int namelen = 0; + int i; + char *boardid; + char *tagversion; + + /* Allocate memory for buffer */ + buf = vmalloc(sizeof(struct bcm_tag)); + if (!buf) + return -ENOMEM; + + /* Get the tag */ + ret = master->read(master, master->erasesize, sizeof(struct bcm_tag), + &retlen, (void *)buf); + if (retlen != sizeof(struct bcm_tag)) { + vfree(buf); + return -EIO; + } + + sscanf(buf->kernel_address, "%u", &kerneladdr); + sscanf(buf->kernel_length, "%u", &kernellen); + sscanf(buf->total_length, "%u", &totallen); + tagversion = &(buf->tag_version[0]); + boardid = &(buf->board_id[0]); + + printk(KERN_INFO PFX "CFE boot tag found with version %s " + "and board type %s\n", tagversion, boardid); + + kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; + rootfsaddr = kerneladdr + kernellen; + spareaddr = roundup(totallen, master->erasesize) + master->erasesize; + sparelen = master->size - spareaddr - master->erasesize; + rootfslen = spareaddr - rootfsaddr; + + /* Determine number of partitions */ + namelen = 8; + if (rootfslen > 0) { + nrparts++; + namelen += 6; + }; + if (kernellen > 0) { + nrparts++; + namelen += 6; + }; + + /* Ask kernel for more memory */ + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); + if (!parts) { + vfree(buf); + return -ENOMEM; + }; + + /* Start building partition list */ + parts[curpart].name = "CFE"; + parts[curpart].offset = 0; + parts[curpart].size = master->erasesize; + curpart++; + + if (kernellen > 0) { + parts[curpart].name = "kernel"; + parts[curpart].offset = kerneladdr; + parts[curpart].size = kernellen; + curpart++; + }; + + if (rootfslen > 0) { + parts[curpart].name = "rootfs"; + parts[curpart].offset = rootfsaddr; + parts[curpart].size = rootfslen; + if (sparelen > 0) + parts[curpart].size += sparelen; + curpart++; + }; + + parts[curpart].name = "nvram"; + parts[curpart].offset = master->size - master->erasesize; + parts[curpart].size = master->erasesize; + + /* Global partition "linux" to make easy firmware upgrade */ + curpart++; + parts[curpart].name = "linux"; + parts[curpart].offset = parts[0].size; + parts[curpart].size = master->size - parts[0].size - parts[3].size; + + for (i = 0; i < nrparts; i++) + printk(KERN_INFO PFX "Partition %d is %s offset %lx and " + "length %lx\n", i, parts[i].name, + (long unsigned int)(parts[i].offset), + (long unsigned int)(parts[i].size)); + + printk(KERN_INFO PFX "Spare partition is %x offset and length %x\n", + spareaddr, sparelen); + *pparts = parts; + vfree(buf); + + return nrparts; +}; + +static int bcm963xx_detect_cfe(struct mtd_info *master) +{ + int idoffset = 0x4e0; + static char idstring[8] = "CFE1CFE1"; + char buf[9]; + int ret; + size_t retlen; + + ret = master->read(master, idoffset, 8, &retlen, (void *)buf); + buf[retlen] = 0; + printk(KERN_INFO PFX "Read Signature value of %s\n", buf); + + return strncmp(idstring, buf, 8); +} + +static int bcm963xx_probe(struct platform_device *pdev) +{ + int err = 0; + int parsed_nr_parts = 0; + char *part_type; + struct resource *r; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no resource supplied\n"); + return -ENODEV; + } + + bcm963xx_map.phys = r->start; + bcm963xx_map.size = resource_size(r); + bcm963xx_map.virt = ioremap(r->start, resource_size(r)); + if (!bcm963xx_map.virt) { + dev_err(&pdev->dev, "failed to ioremap\n"); + return -EIO; + } + + dev_info(&pdev->dev, "0x%08lx at 0x%08x\n", + bcm963xx_map.size, bcm963xx_map.phys); + + simple_map_init(&bcm963xx_map); + + bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); + if (!bcm963xx_mtd_info) { + dev_err(&pdev->dev, "failed to probe using CFI\n"); + err = -EIO; + goto err_probe; + } + + bcm963xx_mtd_info->owner = THIS_MODULE; + + /* This is mutually exclusive */ + if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { + dev_info(&pdev->dev, "CFE bootloader detected\n"); + if (parsed_nr_parts == 0) { + int ret = parse_cfe_partitions(bcm963xx_mtd_info, + &parsed_parts); + if (ret > 0) { + part_type = "CFE"; + parsed_nr_parts = ret; + } + } + } else { + dev_info(&pdev->dev, "unsupported bootloader\n"); + err = -ENODEV; + goto err_probe; + } + + return add_mtd_partitions(bcm963xx_mtd_info, parsed_parts, + parsed_nr_parts); + +err_probe: + iounmap(bcm963xx_map.virt); + return err; +} + +static int bcm963xx_remove(struct platform_device *pdev) +{ + if (bcm963xx_mtd_info) { + del_mtd_partitions(bcm963xx_mtd_info); + map_destroy(bcm963xx_mtd_info); + } + + if (bcm963xx_map.virt) { + iounmap(bcm963xx_map.virt); + bcm963xx_map.virt = 0; + } + + return 0; +} + +static struct platform_driver bcm63xx_mtd_dev = { + .probe = bcm963xx_probe, + .remove = bcm963xx_remove, + .driver = { + .name = "bcm963xx-flash", + .owner = THIS_MODULE, + }, +}; + +static int __init bcm963xx_mtd_init(void) +{ + return platform_driver_register(&bcm63xx_mtd_dev); +} + +static void __exit bcm963xx_mtd_exit(void) +{ + platform_driver_unregister(&bcm63xx_mtd_dev); +} + +module_init(bcm963xx_mtd_init); +module_exit(bcm963xx_mtd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Broadcom BCM63xx MTD driver for CFE and RedBoot"); +MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 32e89d773b4e..af5707a80205 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -208,10 +208,14 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) if (!state) return -ENOMEM; + /* + * We cast start/end to known types in the boards file, so cast + * away their pointer types here to the known types (gpios->xxx). + */ state->gpio_count = gpios->end; - state->gpio_addrs = (void *)gpios->start; + state->gpio_addrs = (void *)(unsigned long)gpios->start; state->gpio_values = (void *)(state + 1); - state->win_size = memory->end - memory->start + 1; + state->win_size = resource_size(memory); memset(state->gpio_values, 0xff, arr_size); state->map.name = DRIVER_NAME; @@ -221,7 +225,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) state->map.copy_to = gf_copy_to; state->map.bankwidth = pdata->width; state->map.size = state->win_size * (1 << state->gpio_count); - state->map.virt = (void __iomem *)memory->start; + state->map.virt = ioremap_nocache(memory->start, state->map.size); state->map.phys = NO_XIP; state->map.map_priv_1 = (unsigned long)state; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 57a1acfe22c4..917022948399 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -640,10 +640,6 @@ static int pcmciamtd_config(struct pcmcia_device *link) } dev_info(&dev->p_dev->dev, "mtd%d: %s\n", mtd->index, mtd->name); return 0; - - dev_err(&dev->p_dev->dev, "CS Error, exiting\n"); - pcmciamtd_release(link); - return -ENODEV; } diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index ec3edf6e68b4..9861814aa027 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -50,7 +50,7 @@ static int parse_obsolete_partitions(struct platform_device *dev, { int i, plen, nr_parts; const struct { - u32 offset, len; + __be32 offset, len; } *part; const char *names; @@ -69,9 +69,9 @@ static int parse_obsolete_partitions(struct platform_device *dev, names = of_get_property(dp, "partition-names", &plen); for (i = 0; i < nr_parts; i++) { - info->parts[i].offset = part->offset; - info->parts[i].size = part->len & ~1; - if (part->len & 1) /* bit 0 set signifies read only partition */ + info->parts[i].offset = be32_to_cpu(part->offset); + info->parts[i].size = be32_to_cpu(part->len) & ~1; + if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ info->parts[i].mask_flags = MTD_WRITEABLE; if (names && (plen > 0)) { @@ -226,11 +226,11 @@ static int __devinit of_flash_probe(struct platform_device *dev, struct resource res; struct of_flash *info; const char *probe_type = match->data; - const u32 *width; + const __be32 *width; int err; int i; int count; - const u32 *p; + const __be32 *p; int reg_tuple_size; struct mtd_info **mtd_list = NULL; resource_size_t res_size; @@ -267,9 +267,11 @@ static int __devinit of_flash_probe(struct platform_device *dev, for (i = 0; i < count; i++) { err = -ENXIO; if (of_address_to_resource(dp, i, &res)) { - dev_err(&dev->dev, "Can't get IO address from device" - " tree\n"); - goto err_out; + /* + * Continue with next register tuple if this + * one is not mappable + */ + continue; } dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 50ab431b24eb..cb20c67995d8 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -37,7 +37,6 @@ #include "mtdcore.h" -static DEFINE_MUTEX(mtd_blkdevs_mutex); static LIST_HEAD(blktrans_majors); static DEFINE_MUTEX(blktrans_ref_mutex); @@ -133,6 +132,10 @@ static int mtd_blktrans_thread(void *arg) if (!req && !(req = blk_fetch_request(rq))) { set_current_state(TASK_INTERRUPTIBLE); + + if (kthread_should_stop()) + set_current_state(TASK_RUNNING); + spin_unlock_irq(rq->queue_lock); schedule(); spin_lock_irq(rq->queue_lock); @@ -176,54 +179,53 @@ static void mtd_blktrans_request(struct request_queue *rq) static int blktrans_open(struct block_device *bdev, fmode_t mode) { struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); - int ret; + int ret = 0; if (!dev) return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ - mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); - if (!dev->mtd) { - ret = -ENXIO; + if (dev->open++) goto unlock; - } - ret = !dev->open++ && dev->tr->open ? dev->tr->open(dev) : 0; + kref_get(&dev->ref); + __module_get(dev->tr->owner); + + if (dev->mtd) { + ret = dev->tr->open ? dev->tr->open(dev) : 0; + __get_mtd_device(dev->mtd); + } - /* Take another reference on the device so it won't go away till - last release */ - if (!ret) - kref_get(&dev->ref); unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); - mutex_unlock(&mtd_blkdevs_mutex); return ret; } static int blktrans_release(struct gendisk *disk, fmode_t mode) { struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); - int ret = -ENXIO; + int ret = 0; if (!dev) return ret; - mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); - /* Release one reference, we sure its not the last one here*/ - kref_put(&dev->ref, blktrans_dev_release); - - if (!dev->mtd) + if (--dev->open) goto unlock; - ret = !--dev->open && dev->tr->release ? dev->tr->release(dev) : 0; + kref_put(&dev->ref, blktrans_dev_release); + module_put(dev->tr->owner); + + if (dev->mtd) { + ret = dev->tr->release ? dev->tr->release(dev) : 0; + __put_mtd_device(dev->mtd); + } unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); - mutex_unlock(&mtd_blkdevs_mutex); return ret; } @@ -256,7 +258,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, if (!dev) return ret; - mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); if (!dev->mtd) @@ -271,7 +272,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, } unlock: mutex_unlock(&dev->lock); - mutex_unlock(&mtd_blkdevs_mutex); blktrans_dev_put(dev); return ret; } @@ -385,9 +385,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->queue = new->rq; - __get_mtd_device(new->mtd); - __module_get(tr->owner); - /* Create processing thread */ /* TODO: workqueue ? */ new->thread = kthread_run(mtd_blktrans_thread, new, @@ -410,8 +407,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) } return 0; error4: - module_put(tr->owner); - __put_mtd_device(new->mtd); blk_cleanup_queue(new->rq); error3: put_disk(new->disk); @@ -448,17 +443,15 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) blk_start_queue(old->rq); spin_unlock_irqrestore(&old->queue_lock, flags); - /* Ask trans driver for release to the mtd device */ + /* If the device is currently open, tell trans driver to close it, + then put mtd device, and don't touch it again */ mutex_lock(&old->lock); - if (old->open && old->tr->release) { - old->tr->release(old); - old->open = 0; + if (old->open) { + if (old->tr->release) + old->tr->release(old); + __put_mtd_device(old->mtd); } - __put_mtd_device(old->mtd); - module_put(old->tr->owner); - - /* At that point, we don't touch the mtd anymore */ old->mtd = NULL; mutex_unlock(&old->lock); @@ -508,13 +501,16 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) mutex_lock(&mtd_table_mutex); ret = register_blkdev(tr->major, tr->name); - if (ret) { + if (ret < 0) { printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", tr->name, tr->major, ret); mutex_unlock(&mtd_table_mutex); return ret; } + if (ret) + tr->major = ret; + tr->blkshift = ffs(tr->blksize) - 1; INIT_LIST_HEAD(&tr->devs); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5ef45487b65f..4759d827e8c7 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -30,8 +30,9 @@ #include <linux/backing-dev.h> #include <linux/compat.h> #include <linux/mount.h> - +#include <linux/blkpg.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> #include <linux/mtd/map.h> #include <asm/uaccess.h> @@ -478,6 +479,78 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, return ret; } +/* + * Copies (and truncates, if necessary) data from the larger struct, + * nand_ecclayout, to the smaller, deprecated layout struct, + * nand_ecclayout_user. This is necessary only to suppport the deprecated + * API ioctl ECCGETLAYOUT while allowing all new functionality to use + * nand_ecclayout flexibly (i.e. the struct may change size in new + * releases without requiring major rewrites). + */ +static int shrink_ecclayout(const struct nand_ecclayout *from, + struct nand_ecclayout_user *to) +{ + int i; + + if (!from || !to) + return -EINVAL; + + memset(to, 0, sizeof(*to)); + + to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES); + for (i = 0; i < to->eccbytes; i++) + to->eccpos[i] = from->eccpos[i]; + + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { + if (from->oobfree[i].length == 0 && + from->oobfree[i].offset == 0) + break; + to->oobavail += from->oobfree[i].length; + to->oobfree[i] = from->oobfree[i]; + } + + return 0; +} + +#ifdef CONFIG_MTD_PARTITIONS +static int mtd_blkpg_ioctl(struct mtd_info *mtd, + struct blkpg_ioctl_arg __user *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* Only master mtd device must be used to control partitions */ + if (!mtd_is_master(mtd)) + return -EINVAL; + + if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) + return -EFAULT; + + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + + switch (a.op) { + case BLKPG_ADD_PARTITION: + + return mtd_add_partition(mtd, p.devname, p.start, p.length); + + case BLKPG_DEL_PARTITION: + + if (p.pno < 0) + return -EINVAL; + + return mtd_del_partition(mtd, p.pno); + + default: + return -EINVAL; + } +} +#endif + + static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct mtd_file_info *mfi = file->private_data; @@ -514,6 +587,9 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (get_user(ur_idx, &(ur->regionindex))) return -EFAULT; + if (ur_idx >= mtd->numeraseregions) + return -EINVAL; + kr = &(mtd->eraseregions[ur_idx]); if (put_user(kr->offset, &(ur->offset)) @@ -813,14 +889,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } #endif + /* This ioctl is being deprecated - it truncates the ecc layout */ case ECCGETLAYOUT: { + struct nand_ecclayout_user *usrlay; + if (!mtd->ecclayout) return -EOPNOTSUPP; - if (copy_to_user(argp, mtd->ecclayout, - sizeof(struct nand_ecclayout))) - return -EFAULT; + usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL); + if (!usrlay) + return -ENOMEM; + + shrink_ecclayout(mtd->ecclayout, usrlay); + + if (copy_to_user(argp, usrlay, sizeof(*usrlay))) + ret = -EFAULT; + kfree(usrlay); break; } @@ -856,6 +941,22 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) break; } +#ifdef CONFIG_MTD_PARTITIONS + case BLKPG: + { + ret = mtd_blkpg_ioctl(mtd, + (struct blkpg_ioctl_arg __user *)arg); + break; + } + + case BLKRRPART: + { + /* No reread partition feature. Just return ok */ + ret = 0; + break; + } +#endif + default: ret = -ENOTTY; } @@ -1030,17 +1131,15 @@ static const struct file_operations mtd_fops = { #endif }; -static int mtd_inodefs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC, - mnt); + return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); } static struct file_system_type mtd_inodefs_type = { .name = "mtd_inodefs", - .get_sb = mtd_inodefs_get_sb, + .mount = mtd_inodefs_mount, .kill_sb = kill_anon_super, }; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index dc6558568876..79e3689f1e16 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -29,9 +29,11 @@ #include <linux/kmod.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/err.h> /* Our partition linked list */ static LIST_HEAD(mtd_partitions); +static DEFINE_MUTEX(mtd_partitions_mutex); /* Our partition node structure */ struct mtd_part { @@ -326,6 +328,12 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) return res; } +static inline void free_partition(struct mtd_part *p) +{ + kfree(p->mtd.name); + kfree(p); +} + /* * This function unregisters and destroy all slave MTD objects which are * attached to the given master MTD object. @@ -334,33 +342,42 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) int del_mtd_partitions(struct mtd_info *master) { struct mtd_part *slave, *next; + int ret, err = 0; + mutex_lock(&mtd_partitions_mutex); list_for_each_entry_safe(slave, next, &mtd_partitions, list) if (slave->master == master) { + ret = del_mtd_device(&slave->mtd); + if (ret < 0) { + err = ret; + continue; + } list_del(&slave->list); - del_mtd_device(&slave->mtd); - kfree(slave); + free_partition(slave); } + mutex_unlock(&mtd_partitions_mutex); - return 0; + return err; } EXPORT_SYMBOL(del_mtd_partitions); -static struct mtd_part *add_one_partition(struct mtd_info *master, - const struct mtd_partition *part, int partno, - uint64_t cur_offset) +static struct mtd_part *allocate_partition(struct mtd_info *master, + const struct mtd_partition *part, int partno, + uint64_t cur_offset) { struct mtd_part *slave; + char *name; /* allocate the partition structure */ slave = kzalloc(sizeof(*slave), GFP_KERNEL); - if (!slave) { + name = kstrdup(part->name, GFP_KERNEL); + if (!name || !slave) { printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", - master->name); - del_mtd_partitions(master); - return NULL; + master->name); + kfree(name); + kfree(slave); + return ERR_PTR(-ENOMEM); } - list_add(&slave->list, &mtd_partitions); /* set up the MTD object for this partition */ slave->mtd.type = master->type; @@ -371,7 +388,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.oobavail = master->oobavail; slave->mtd.subpage_sft = master->subpage_sft; - slave->mtd.name = part->name; + slave->mtd.name = name; slave->mtd.owner = master->owner; slave->mtd.backing_dev_info = master->backing_dev_info; @@ -518,12 +535,89 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } out_register: - /* register our partition */ - add_mtd_device(&slave->mtd); - return slave; } +int mtd_add_partition(struct mtd_info *master, char *name, + long long offset, long long length) +{ + struct mtd_partition part; + struct mtd_part *p, *new; + uint64_t start, end; + int ret = 0; + + /* the direct offset is expected */ + if (offset == MTDPART_OFS_APPEND || + offset == MTDPART_OFS_NXTBLK) + return -EINVAL; + + if (length == MTDPART_SIZ_FULL) + length = master->size - offset; + + if (length <= 0) + return -EINVAL; + + part.name = name; + part.size = length; + part.offset = offset; + part.mask_flags = 0; + part.ecclayout = NULL; + + new = allocate_partition(master, &part, -1, offset); + if (IS_ERR(new)) + return PTR_ERR(new); + + start = offset; + end = offset + length; + + mutex_lock(&mtd_partitions_mutex); + list_for_each_entry(p, &mtd_partitions, list) + if (p->master == master) { + if ((start >= p->offset) && + (start < (p->offset + p->mtd.size))) + goto err_inv; + + if ((end >= p->offset) && + (end < (p->offset + p->mtd.size))) + goto err_inv; + } + + list_add(&new->list, &mtd_partitions); + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&new->mtd); + + return ret; +err_inv: + mutex_unlock(&mtd_partitions_mutex); + free_partition(new); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mtd_add_partition); + +int mtd_del_partition(struct mtd_info *master, int partno) +{ + struct mtd_part *slave, *next; + int ret = -EINVAL; + + mutex_lock(&mtd_partitions_mutex); + list_for_each_entry_safe(slave, next, &mtd_partitions, list) + if ((slave->master == master) && + (slave->mtd.index == partno)) { + ret = del_mtd_device(&slave->mtd); + if (ret < 0) + break; + + list_del(&slave->list); + free_partition(slave); + break; + } + mutex_unlock(&mtd_partitions_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mtd_del_partition); + /* * This function, given a master MTD object and a partition table, creates * and registers slave MTD objects which are bound to the master according to @@ -544,9 +638,16 @@ int add_mtd_partitions(struct mtd_info *master, printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); for (i = 0; i < nbparts; i++) { - slave = add_one_partition(master, parts + i, i, cur_offset); - if (!slave) - return -ENOMEM; + slave = allocate_partition(master, parts + i, i, cur_offset); + if (IS_ERR(slave)) + return PTR_ERR(slave); + + mutex_lock(&mtd_partitions_mutex); + list_add(&slave->list, &mtd_partitions); + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&slave->mtd); + cur_offset = slave->offset + slave->mtd.size; } @@ -618,3 +719,20 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, return ret; } EXPORT_SYMBOL_GPL(parse_mtd_partitions); + +int mtd_is_master(struct mtd_info *mtd) +{ + struct mtd_part *part; + int nopart = 0; + + mutex_lock(&mtd_partitions_mutex); + list_for_each_entry(part, &mtd_partitions, list) + if (&part->mtd == mtd) { + nopart = 1; + break; + } + mutex_unlock(&mtd_partitions_mutex); + + return nopart; +} +EXPORT_SYMBOL_GPL(mtd_is_master); diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 38e2ab07e7a3..16b02a1fc100 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -54,11 +54,10 @@ static int get_sb_mtd_set(struct super_block *sb, void *_mtd) /* * get a superblock on an MTD-backed filesystem */ -static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, +static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct mtd_info *mtd, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct super_block *sb; int ret; @@ -79,57 +78,49 @@ static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (ret < 0) { deactivate_locked_super(sb); - return ret; + return ERR_PTR(ret); } /* go */ sb->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, sb); - - return 0; + return dget(sb->s_root); /* new mountpoint for an already mounted superblock */ already_mounted: DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); - simple_set_mnt(mnt, sb); - ret = 0; - goto out_put; + put_mtd_device(mtd); + return dget(sb->s_root); out_error: - ret = PTR_ERR(sb); -out_put: put_mtd_device(mtd); - return ret; + return ERR_CAST(sb); } /* * get a superblock on an MTD-backed filesystem by MTD device number */ -static int get_sb_mtd_nr(struct file_system_type *fs_type, int flags, +static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int mtdnr, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct mtd_info *mtd; mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) { DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); - return PTR_ERR(mtd); + return ERR_CAST(mtd); } - return get_sb_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super, - mnt); + return mount_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super); } /* * set up an MTD-based superblock */ -int get_sb_mtd(struct file_system_type *fs_type, int flags, +struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { #ifdef CONFIG_BLOCK struct block_device *bdev; @@ -138,7 +129,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, int mtdnr; if (!dev_name) - return -EINVAL; + return ERR_PTR(-EINVAL); DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); @@ -156,10 +147,10 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, mtd = get_mtd_device_nm(dev_name + 4); if (!IS_ERR(mtd)) - return get_sb_mtd_aux( + return mount_mtd_aux( fs_type, flags, dev_name, data, mtd, - fill_super, mnt); + fill_super); printk(KERN_NOTICE "MTD:" " MTD device with name \"%s\" not found.\n", @@ -174,9 +165,9 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, /* It was a valid number */ DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", mtdnr); - return get_sb_mtd_nr(fs_type, flags, + return mount_mtd_nr(fs_type, flags, dev_name, data, - mtdnr, fill_super, mnt); + mtdnr, fill_super); } } } @@ -189,7 +180,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); - return ret; + return ERR_PTR(ret); } DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); @@ -202,8 +193,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, if (major != MTD_BLOCK_MAJOR) goto not_an_MTD_device; - return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, - mnt); + return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super); not_an_MTD_device: #endif /* CONFIG_BLOCK */ @@ -212,10 +202,10 @@ not_an_MTD_device: printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); - return -EINVAL; + return ERR_PTR(-EINVAL); } -EXPORT_SYMBOL_GPL(get_sb_mtd); +EXPORT_SYMBOL_GPL(mount_mtd); /* * destroy an MTD-based superblock diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8b4b67c8a391..8229802b4346 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -400,13 +400,6 @@ config MTD_NAND_PXA3xx This enables the driver for the NAND flash device found on PXA3xx processors -config MTD_NAND_PXA3xx_BUILTIN - bool "Use builtin definitions for some NAND chips (deprecated)" - depends on MTD_NAND_PXA3xx - help - This enables builtin definitions for some NAND chips. This - is deprecated in favor of platform specific data. - config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE @@ -458,6 +451,7 @@ config MTD_NAND_ORION config MTD_NAND_FSL_ELBC tristate "NAND support for Freescale eLBC controllers" depends on PPC_OF + select FSL_LBC help Various Freescale chips, including the 8313, include a NAND Flash Controller Module with built-in hardware ECC capabilities. @@ -531,4 +525,11 @@ config MTD_NAND_JZ4740 help Enables support for NAND Flash on JZ4740 SoC based boards. +config MTD_NAND_FSMC + tristate "Support for NAND on ST Micros FSMC" + depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300 + help + Enables support for NAND Flash chips on the ST Microelectronics + Flexible Static Memory Controller (FSMC) + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index ac83dcdac5d6..8ad6faec72cb 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o +obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o obj-$(CONFIG_MTD_NAND_H1900) += h1910.o obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 6fbeefa3a766..79947bea4d57 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -110,15 +110,6 @@ static const unsigned short bfin_nfc_pin_req[] = 0}; #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC -static uint8_t bbt_pattern[] = { 0xff }; - -static struct nand_bbt_descr bootrom_bbt = { - .options = 0, - .offs = 63, - .len = 1, - .pattern = bbt_pattern, -}; - static struct nand_ecclayout bootrom_ecclayout = { .eccbytes = 24, .eccpos = { @@ -809,7 +800,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) /* setup hardware ECC data struct */ if (hardware_ecc) { #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC - chip->badblock_pattern = &bootrom_bbt; chip->ecc.layout = &bootrom_ecclayout; #endif chip->read_buf = bf5xx_nand_dma_read_buf; @@ -830,6 +820,10 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) goto out_err_nand_scan; } +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC + chip->badblockpos = 63; +#endif + /* add NAND partition */ bf5xx_nand_add_partition(info); diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8beb0d0233b5..a90fde3ede28 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -316,7 +316,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd, u32 syndrome[4]; u32 ecc_state; unsigned num_errors, corrected; - unsigned long timeo = jiffies + msecs_to_jiffies(100); + unsigned long timeo; /* All bytes 0xff? It's an erased page; ignore its ECC. */ for (i = 0; i < 10; i++) { @@ -372,9 +372,11 @@ compare: * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately * begin trying to poll for the state, you may fall right out of your * loop without any of the correction calculations having taken place. - * The recommendation from the hardware team is to wait till ECC_STATE - * reads less than 4, which means ECC HW has entered correction state. + * The recommendation from the hardware team is to initially delay as + * long as ECC_STATE reads less than 4. After that, ECC HW has entered + * correction state. */ + timeo = jiffies + usecs_to_jiffies(100); do { ecc_state = (davinci_nand_readl(info, NANDFSR_OFFSET) >> 8) & 0x0f; @@ -733,6 +735,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) * breaks userspace ioctl interface with mtd-utils. Once we * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used * for the 4KiB page chips. + * + * TODO: Note that nand_ecclayout has now been expanded and can + * hold plenty of OOB entries. */ dev_warn(&pdev->dev, "no 4-bit ECC support yet " "for 4KiB-page NAND\n"); diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 532fe07cf886..8c8d3c86c0e8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1292,6 +1292,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, read_status(denali); break; case NAND_CMD_READID: + case NAND_CMD_PARAM: reset_buf(denali); /*sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 80de0bff6c3a..c141b07b25d1 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -1,9 +1,11 @@ /* Freescale Enhanced Local Bus Controller NAND driver * - * Copyright (c) 2006-2007 Freescale Semiconductor + * Copyright © 2006-2007, 2010 Freescale Semiconductor * * Authors: Nick Spence <nick.spence@freescale.com>, * Scott Wood <scottwood@freescale.com> + * Jack Lan <jack.lan@freescale.com> + * Roy Zang <tie-fei.zang@freescale.com> * * 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 @@ -27,6 +29,7 @@ #include <linux/string.h> #include <linux/ioport.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -42,14 +45,12 @@ #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */ -struct fsl_elbc_ctrl; - /* mtd information per set */ struct fsl_elbc_mtd { struct mtd_info mtd; struct nand_chip chip; - struct fsl_elbc_ctrl *ctrl; + struct fsl_lbc_ctrl *ctrl; struct device *dev; int bank; /* Chip select bank number */ @@ -58,18 +59,12 @@ struct fsl_elbc_mtd { unsigned int fmr; /* FCM Flash Mode Register value */ }; -/* overview of the fsl elbc controller */ +/* Freescale eLBC FCM controller infomation */ -struct fsl_elbc_ctrl { +struct fsl_elbc_fcm_ctrl { struct nand_hw_control controller; struct fsl_elbc_mtd *chips[MAX_BANKS]; - /* device info */ - struct device *dev; - struct fsl_lbc_regs __iomem *regs; - int irq; - wait_queue_head_t irq_wait; - unsigned int irq_status; /* status read from LTESR by irq handler */ u8 __iomem *addr; /* Address of assigned FCM buffer */ unsigned int page; /* Last page written to / read from */ unsigned int read_bytes; /* Number of bytes read during command */ @@ -79,6 +74,7 @@ struct fsl_elbc_ctrl { unsigned int mdr; /* UPM/FCM Data Register value */ unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ + unsigned int counter; /* counter for the initializations */ char *oob_poi; /* Place to write ECC after read back */ }; @@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; int buf_num; - ctrl->page = page_addr; + elbc_fcm_ctrl->page = page_addr; out_be32(&lbc->fbar, page_addr >> (chip->phys_erase_shift - chip->page_shift)); @@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) buf_num = page_addr & 7; } - ctrl->addr = priv->vbase + buf_num * 1024; - ctrl->index = column; + elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024; + elbc_fcm_ctrl->index = column; /* for OOB data point to the second half of the buffer */ if (oob) - ctrl->index += priv->page_size ? 2048 : 512; + elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512; - dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " + dev_vdbg(priv->dev, "set_addr: bank=%d, " + "elbc_fcm_ctrl->addr=0x%p (0x%p), " "index %x, pes %d ps %d\n", - buf_num, ctrl->addr, priv->vbase, ctrl->index, + buf_num, elbc_fcm_ctrl->addr, priv->vbase, + elbc_fcm_ctrl->index, chip->phys_erase_shift, chip->page_shift); } @@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; /* Setup the FMR[OP] to execute without write protection */ out_be32(&lbc->fmr, priv->fmr | 3); - if (ctrl->use_mdr) - out_be32(&lbc->mdr, ctrl->mdr); + if (elbc_fcm_ctrl->use_mdr) + out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr); - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_run_command: fbar=%08x fpar=%08x " "fbcr=%08x bank=%d\n", in_be32(&lbc->fbar), in_be32(&lbc->fpar), @@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) /* wait for FCM complete flag or timeout */ wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, FCM_TIMEOUT_MSECS * HZ/1000); - ctrl->status = ctrl->irq_status; - + elbc_fcm_ctrl->status = ctrl->irq_status; /* store mdr value in case it was needed */ - if (ctrl->use_mdr) - ctrl->mdr = in_be32(&lbc->mdr); + if (elbc_fcm_ctrl->use_mdr) + elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr); - ctrl->use_mdr = 0; + elbc_fcm_ctrl->use_mdr = 0; - if (ctrl->status != LTESR_CC) { - dev_info(ctrl->dev, + if (elbc_fcm_ctrl->status != LTESR_CC) { + dev_info(priv->dev, "command failed: fir %x fcr %x status %x mdr %x\n", in_be32(&lbc->fir), in_be32(&lbc->fcr), - ctrl->status, ctrl->mdr); + elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr); return -EIO; } @@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) static void fsl_elbc_do_read(struct nand_chip *chip, int oob) { struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; if (priv->page_size) { @@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - ctrl->use_mdr = 0; + elbc_fcm_ctrl->use_mdr = 0; /* clear the read buffer */ - ctrl->read_bytes = 0; + elbc_fcm_ctrl->read_bytes = 0; if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; + elbc_fcm_ctrl->index = 0; switch (command) { /* READ0 and READ1 read the entire buffer to use hardware ECC. */ @@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* fall-through */ case NAND_CMD_READ0: - dev_dbg(ctrl->dev, + dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column); @@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ set_addr(mtd, 0, page_addr, 0); - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; + elbc_fcm_ctrl->index += column; fsl_elbc_do_read(chip, 0); fsl_elbc_run_command(mtd); @@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB: - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column); out_be32(&lbc->fbcr, mtd->oobsize - column); set_addr(mtd, column, page_addr, 1); - ctrl->read_bytes = mtd->writesize + mtd->oobsize; + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; fsl_elbc_do_read(chip, 1); fsl_elbc_run_command(mtd); @@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* READID must read all 5 possible bytes while CEB is active */ case NAND_CMD_READID: - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | (FIR_OP_UA << FIR_OP1_SHIFT) | @@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); /* 5 bytes for manuf, device and exts */ out_be32(&lbc->fbcr, 5); - ctrl->read_bytes = 5; - ctrl->use_mdr = 1; - ctrl->mdr = 0; + elbc_fcm_ctrl->read_bytes = 5; + elbc_fcm_ctrl->use_mdr = 1; + elbc_fcm_ctrl->mdr = 0; set_addr(mtd, 0, 0, 0); fsl_elbc_run_command(mtd); @@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* ERASE1 stores the block and page address */ case NAND_CMD_ERASE1: - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " "page_addr: 0x%x.\n", page_addr); set_addr(mtd, 0, page_addr, 0); @@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* ERASE2 uses the block and page address from ERASE1 */ case NAND_CMD_ERASE2: - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | @@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT)); out_be32(&lbc->fbcr, 0); - ctrl->read_bytes = 0; - ctrl->use_mdr = 1; + elbc_fcm_ctrl->read_bytes = 0; + elbc_fcm_ctrl->use_mdr = 1; fsl_elbc_run_command(mtd); return; @@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* SEQIN sets up the addr buffer and all registers except the length */ case NAND_CMD_SEQIN: { __be32 fcr; - dev_vdbg(ctrl->dev, - "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " + dev_vdbg(priv->dev, + "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " "page_addr: 0x%x, column: 0x%x.\n", page_addr, column); - ctrl->column = column; - ctrl->oob = 0; - ctrl->use_mdr = 1; + elbc_fcm_ctrl->use_mdr = 1; fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) | @@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* OOB area --> READOOB */ column -= mtd->writesize; fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; - ctrl->oob = 1; + elbc_fcm_ctrl->oob = 1; } else { WARN_ON(column != 0); /* First 256 bytes --> READ0 */ @@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, } out_be32(&lbc->fcr, fcr); - set_addr(mtd, column, page_addr, ctrl->oob); + set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob); return; } /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { int full_page; - dev_vdbg(ctrl->dev, + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " - "writing %d bytes.\n", ctrl->index); + "writing %d bytes.\n", elbc_fcm_ctrl->index); /* if the write did not start at 0 or is not a full page * then set the exact length, otherwise use a full page * write so the HW generates the ECC. */ - if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) { - out_be32(&lbc->fbcr, ctrl->index); + if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { + out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); full_page = 0; } else { out_be32(&lbc->fbcr, 0); @@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* Read back the page in order to fill in the ECC for the * caller. Is this really needed? */ - if (full_page && ctrl->oob_poi) { + if (full_page && elbc_fcm_ctrl->oob_poi) { out_be32(&lbc->fbcr, 3); set_addr(mtd, 6, page_addr, 1); - ctrl->read_bytes = mtd->writesize + 9; + elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; fsl_elbc_do_read(chip, 1); fsl_elbc_run_command(mtd); - memcpy_fromio(ctrl->oob_poi + 6, - &ctrl->addr[ctrl->index], 3); - ctrl->index += 3; + memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, + &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); + elbc_fcm_ctrl->index += 3; } - ctrl->oob_poi = NULL; + elbc_fcm_ctrl->oob_poi = NULL; return; } @@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); out_be32(&lbc->fbcr, 1); set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; + elbc_fcm_ctrl->read_bytes = 1; fsl_elbc_run_command(mtd); /* The chip always seems to report that it is * write-protected, even when it is not. */ - setbits8(ctrl->addr, NAND_STATUS_WP); + setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP); return; /* RESET without waiting for the ready line */ case NAND_CMD_RESET: - dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); + dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); fsl_elbc_run_command(mtd); return; default: - dev_err(ctrl->dev, + dev_err(priv->dev, "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", command); } @@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; unsigned int bufsize = mtd->writesize + mtd->oobsize; if (len <= 0) { - dev_err(ctrl->dev, "write_buf of %d bytes", len); - ctrl->status = 0; + dev_err(priv->dev, "write_buf of %d bytes", len); + elbc_fcm_ctrl->status = 0; return; } - if ((unsigned int)len > bufsize - ctrl->index) { - dev_err(ctrl->dev, + if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) { + dev_err(priv->dev, "write_buf beyond end of buffer " "(%d requested, %u available)\n", - len, bufsize - ctrl->index); - len = bufsize - ctrl->index; + len, bufsize - elbc_fcm_ctrl->index); + len = bufsize - elbc_fcm_ctrl->index; } - memcpy_toio(&ctrl->addr[ctrl->index], buf, len); + memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len); /* * This is workaround for the weird elbc hangs during nand write, * Scott Wood says: "...perhaps difference in how long it takes a @@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * is causing problems, and sync isn't helping for some reason." * Reading back the last byte helps though. */ - in_8(&ctrl->addr[ctrl->index] + len - 1); + in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1); - ctrl->index += len; + elbc_fcm_ctrl->index += len; } /* @@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; /* If there are still bytes in the FCM, then use the next byte. */ - if (ctrl->index < ctrl->read_bytes) - return in_8(&ctrl->addr[ctrl->index++]); + if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes) + return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]); - dev_err(ctrl->dev, "read_byte beyond end of buffer\n"); + dev_err(priv->dev, "read_byte beyond end of buffer\n"); return ERR_BYTE; } @@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int avail; if (len < 0) return; - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); - ctrl->index += avail; + avail = min((unsigned int)len, + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); + memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail); + elbc_fcm_ctrl->index += avail; if (len > avail) - dev_err(ctrl->dev, + dev_err(priv->dev, "read_buf beyond end of buffer " "(%d requested, %d available)\n", len, avail); @@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int i; if (len < 0) { - dev_err(ctrl->dev, "write_buf of %d bytes", len); + dev_err(priv->dev, "write_buf of %d bytes", len); return -EINVAL; } - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - dev_err(ctrl->dev, - "verify_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, ctrl->read_bytes - ctrl->index); + if ((unsigned int)len > + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) { + dev_err(priv->dev, + "verify_buf beyond end of buffer " + "(%d requested, %u available)\n", + len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); - ctrl->index = ctrl->read_bytes; + elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes; return -EINVAL; } for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) + if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i]) + != buf[i]) break; - ctrl->index += len; - return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; + elbc_fcm_ctrl->index += len; + return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO; } /* This function is called after Program and Erase Operations to @@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) { struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; - if (ctrl->status != LTESR_CC) + if (elbc_fcm_ctrl->status != LTESR_CC) return NAND_STATUS_FAIL; /* The chip always seems to report that it is * write-protected, even when it is not. */ - return (ctrl->mdr & 0xff) | NAND_STATUS_WP; + return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP; } static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; unsigned int al; @@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */ (al << FMR_AL_SHIFT); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", chip->numchips); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", chip->chipsize); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", chip->pagemask); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n", chip->chip_delay); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", chip->badblockpos); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", chip->chip_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n", chip->page_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", chip->phys_erase_shift); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n", chip->ecclayout); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", chip->ecc.mode); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", chip->ecc.steps); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", chip->ecc.bytes); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n", chip->ecc.total); - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", chip->ecc.layout); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n", mtd->erasesize); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n", mtd->writesize); - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n", + dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n", mtd->oobsize); /* adjust Option Register and ECC to match Flash page size */ @@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->badblock_pattern = &largepage_memorybased; } } else { - dev_err(ctrl->dev, + dev_err(priv->dev, "fsl_elbc_init: page size %d is not supported\n", mtd->writesize); return -1; @@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, const uint8_t *buf) { struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - ctrl->oob_poi = chip->oob_poi; + elbc_fcm_ctrl->oob_poi = chip->oob_poi; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) { - struct fsl_elbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct nand_chip *chip = &priv->chip; dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank); @@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; - chip->controller = &ctrl->controller; + chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; chip->ecc.read_page = fsl_elbc_read_page; @@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) { - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; nand_release(&priv->mtd); kfree(priv->mtd.name); @@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) if (priv->vbase) iounmap(priv->vbase); - ctrl->chips[priv->bank] = NULL; + elbc_fcm_ctrl->chips[priv->bank] = NULL; kfree(priv); - + kfree(elbc_fcm_ctrl); return 0; } -static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, - struct device_node *node) +static DEFINE_MUTEX(fsl_elbc_nand_mutex); + +static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) { - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + struct fsl_lbc_regs __iomem *lbc; struct fsl_elbc_mtd *priv; struct resource res; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; + #ifdef CONFIG_MTD_PARTITIONS static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; @@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, #endif int ret; int bank; + struct device *dev; + struct device_node *node = pdev->dev.of_node; + + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) + return -ENODEV; + lbc = fsl_lbc_ctrl_dev->regs; + dev = fsl_lbc_ctrl_dev->dev; /* get, allocate and map the memory resource */ ret = of_address_to_resource(node, 0, &res); if (ret) { - dev_err(ctrl->dev, "failed to get resource\n"); + dev_err(dev, "failed to get resource\n"); return ret; } @@ -857,11 +868,11 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && (in_be32(&lbc->bank[bank].br) & in_be32(&lbc->bank[bank].or) & BR_BA) - == res.start) + == fsl_lbc_addr(res.start)) break; if (bank >= MAX_BANKS) { - dev_err(ctrl->dev, "address did not match any chip selects\n"); + dev_err(dev, "address did not match any chip selects\n"); return -ENODEV; } @@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, if (!priv) return -ENOMEM; - ctrl->chips[bank] = priv; + mutex_lock(&fsl_elbc_nand_mutex); + if (!fsl_lbc_ctrl_dev->nand) { + elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); + if (!elbc_fcm_ctrl) { + dev_err(dev, "failed to allocate memory\n"); + mutex_unlock(&fsl_elbc_nand_mutex); + ret = -ENOMEM; + goto err; + } + elbc_fcm_ctrl->counter++; + + spin_lock_init(&elbc_fcm_ctrl->controller.lock); + init_waitqueue_head(&elbc_fcm_ctrl->controller.wq); + fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; + } else { + elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; + } + mutex_unlock(&fsl_elbc_nand_mutex); + + elbc_fcm_ctrl->chips[bank] = priv; priv->bank = bank; - priv->ctrl = ctrl; - priv->dev = ctrl->dev; + priv->ctrl = fsl_lbc_ctrl_dev; + priv->dev = dev; priv->vbase = ioremap(res.start, resource_size(&res)); if (!priv->vbase) { - dev_err(ctrl->dev, "failed to map chip region\n"); + dev_err(dev, "failed to map chip region\n"); ret = -ENOMEM; goto err; } @@ -933,171 +963,53 @@ err: return ret; } -static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) +static int fsl_elbc_nand_remove(struct platform_device *pdev) { - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - - /* - * NAND transactions can tie up the bus for a long time, so set the - * bus timeout to max by clearing LBCR[BMT] (highest base counter - * value) and setting LBCR[BMTPS] to the highest prescaler value. - */ - clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15); - - /* clear event registers */ - setbits32(&lbc->ltesr, LTESR_NAND_MASK); - out_be32(&lbc->lteatr, 0); - - /* Enable interrupts for any detected events */ - out_be32(&lbc->lteir, LTESR_NAND_MASK); - - ctrl->read_bytes = 0; - ctrl->index = 0; - ctrl->addr = NULL; - - return 0; -} - -static int fsl_elbc_ctrl_remove(struct platform_device *ofdev) -{ - struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); int i; - + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; for (i = 0; i < MAX_BANKS; i++) - if (ctrl->chips[i]) - fsl_elbc_chip_remove(ctrl->chips[i]); - - if (ctrl->irq) - free_irq(ctrl->irq, ctrl); - - if (ctrl->regs) - iounmap(ctrl->regs); - - dev_set_drvdata(&ofdev->dev, NULL); - kfree(ctrl); - return 0; -} - -/* NOTE: This interrupt is also used to report other localbus events, - * such as transaction errors on other chipselects. If we want to - * capture those, we'll need to move the IRQ code into a shared - * LBC driver. - */ - -static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data) -{ - struct fsl_elbc_ctrl *ctrl = data; - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK; - - if (status) { - out_be32(&lbc->ltesr, status); - out_be32(&lbc->lteatr, 0); - - ctrl->irq_status = status; - smp_wmb(); - wake_up(&ctrl->irq_wait); - - return IRQ_HANDLED; + if (elbc_fcm_ctrl->chips[i]) + fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]); + + mutex_lock(&fsl_elbc_nand_mutex); + elbc_fcm_ctrl->counter--; + if (!elbc_fcm_ctrl->counter) { + fsl_lbc_ctrl_dev->nand = NULL; + kfree(elbc_fcm_ctrl); } - - return IRQ_NONE; -} - -/* fsl_elbc_ctrl_probe - * - * called by device layer when it finds a device matching - * one our driver can handled. This code allocates all of - * the resources needed for the controller only. The - * resources for the NAND banks themselves are allocated - * in the chip probe function. -*/ - -static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev, - const struct of_device_id *match) -{ - struct device_node *child; - struct fsl_elbc_ctrl *ctrl; - int ret; - - ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - - dev_set_drvdata(&ofdev->dev, ctrl); - - spin_lock_init(&ctrl->controller.lock); - init_waitqueue_head(&ctrl->controller.wq); - init_waitqueue_head(&ctrl->irq_wait); - - ctrl->regs = of_iomap(ofdev->dev.of_node, 0); - if (!ctrl->regs) { - dev_err(&ofdev->dev, "failed to get memory region\n"); - ret = -ENODEV; - goto err; - } - - ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); - if (ctrl->irq == NO_IRQ) { - dev_err(&ofdev->dev, "failed to get irq resource\n"); - ret = -ENODEV; - goto err; - } - - ctrl->dev = &ofdev->dev; - - ret = fsl_elbc_ctrl_init(ctrl); - if (ret < 0) - goto err; - - ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl); - if (ret != 0) { - dev_err(&ofdev->dev, "failed to install irq (%d)\n", - ctrl->irq); - ret = ctrl->irq; - goto err; - } - - for_each_child_of_node(ofdev->dev.of_node, child) - if (of_device_is_compatible(child, "fsl,elbc-fcm-nand")) - fsl_elbc_chip_probe(ctrl, child); + mutex_unlock(&fsl_elbc_nand_mutex); return 0; -err: - fsl_elbc_ctrl_remove(ofdev); - return ret; } -static const struct of_device_id fsl_elbc_match[] = { - { - .compatible = "fsl,elbc", - }, +static const struct of_device_id fsl_elbc_nand_match[] = { + { .compatible = "fsl,elbc-fcm-nand", }, {} }; -static struct of_platform_driver fsl_elbc_ctrl_driver = { +static struct platform_driver fsl_elbc_nand_driver = { .driver = { - .name = "fsl-elbc", + .name = "fsl,elbc-fcm-nand", .owner = THIS_MODULE, - .of_match_table = fsl_elbc_match, + .of_match_table = fsl_elbc_nand_match, }, - .probe = fsl_elbc_ctrl_probe, - .remove = fsl_elbc_ctrl_remove, + .probe = fsl_elbc_nand_probe, + .remove = fsl_elbc_nand_remove, }; -static int __init fsl_elbc_init(void) +static int __init fsl_elbc_nand_init(void) { - return of_register_platform_driver(&fsl_elbc_ctrl_driver); + return platform_driver_register(&fsl_elbc_nand_driver); } -static void __exit fsl_elbc_exit(void) +static void __exit fsl_elbc_nand_exit(void) { - of_unregister_platform_driver(&fsl_elbc_ctrl_driver); + platform_driver_unregister(&fsl_elbc_nand_driver); } -module_init(fsl_elbc_init); -module_exit(fsl_elbc_exit); +module_init(fsl_elbc_nand_init); +module_exit(fsl_elbc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale"); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 4eff8b25e5af..efdcca94ce55 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -186,7 +186,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (!flash_np) return -ENODEV; - fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, + fun->mtd.name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start, flash_np->name); if (!fun->mtd.name) { ret = -ENOMEM; @@ -222,7 +222,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, { struct fsl_upm_nand *fun; struct resource io_res; - const uint32_t *prop; + const __be32 *prop; int rnb_gpio; int ret; int size; @@ -270,7 +270,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, goto err1; } for (i = 0; i < fun->mchip_count; i++) - fun->mchip_offsets[i] = prop[i]; + fun->mchip_offsets[i] = be32_to_cpu(prop[i]); } else { fun->mchip_count = 1; } @@ -295,13 +295,13 @@ static int __devinit fun_probe(struct platform_device *ofdev, prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); if (prop) - fun->chip_delay = *prop; + fun->chip_delay = be32_to_cpup(prop); else fun->chip_delay = 50; prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); if (prop && size == sizeof(uint32_t)) - fun->wait_flags = *prop; + fun->wait_flags = be32_to_cpup(prop); else fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | FSL_UPM_WAIT_WRITE_BYTE; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c new file mode 100644 index 000000000000..02edfba25b0c --- /dev/null +++ b/drivers/mtd/nand/fsmc_nand.c @@ -0,0 +1,866 @@ +/* + * drivers/mtd/nand/fsmc_nand.c + * + * ST Microelectronics + * Flexible Static Memory Controller (FSMC) + * Driver for NAND portions + * + * Copyright © 2010 ST Microelectronics + * Vipin Kumar <vipin.kumar@st.com> + * Ashish Priyadarshi + * + * Based on drivers/mtd/nand/nomadik_nand.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/resource.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/platform_device.h> +#include <linux/mtd/partitions.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/mtd/fsmc.h> +#include <mtd/mtd-abi.h> + +static struct nand_ecclayout fsmc_ecc1_layout = { + .eccbytes = 24, + .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, + 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, + .oobfree = { + {.offset = 8, .length = 8}, + {.offset = 24, .length = 8}, + {.offset = 40, .length = 8}, + {.offset = 56, .length = 8}, + {.offset = 72, .length = 8}, + {.offset = 88, .length = 8}, + {.offset = 104, .length = 8}, + {.offset = 120, .length = 8} + } +}; + +static struct nand_ecclayout fsmc_ecc4_lp_layout = { + .eccbytes = 104, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 1} + } +}; + +/* + * ECC placement definitions in oobfree type format. + * There are 13 bytes of ecc for every 512 byte block and it has to be read + * consecutively and immediately after the 512 byte data block for hardware to + * generate the error bit offsets in 512 byte data. + * Managing the ecc bytes in the following way makes it easier for software to + * read ecc bytes consecutive to data bytes. This way is similar to + * oobfree structure maintained already in generic nand driver + */ +static struct fsmc_eccplace fsmc_ecc4_lp_place = { + .eccplace = { + {.offset = 2, .length = 13}, + {.offset = 18, .length = 13}, + {.offset = 34, .length = 13}, + {.offset = 50, .length = 13}, + {.offset = 66, .length = 13}, + {.offset = 82, .length = 13}, + {.offset = 98, .length = 13}, + {.offset = 114, .length = 13} + } +}; + +static struct nand_ecclayout fsmc_ecc4_sp_layout = { + .eccbytes = 13, + .eccpos = { 0, 1, 2, 3, 6, 7, 8, + 9, 10, 11, 12, 13, 14 + }, + .oobfree = { + {.offset = 15, .length = 1}, + } +}; + +static struct fsmc_eccplace fsmc_ecc4_sp_place = { + .eccplace = { + {.offset = 0, .length = 4}, + {.offset = 6, .length = 9} + } +}; + +/* + * Default partition tables to be used if the partition information not + * provided through platform data + */ +#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} + +/* + * Default partition layout for small page(= 512 bytes) devices + * Size for "Root file system" is updated in driver based on actual device size + */ +static struct mtd_partition partition_info_16KB_blk[] = { + PARTITION("X-loader", 0, 4 * 0x4000), + PARTITION("U-Boot", 0x10000, 20 * 0x4000), + PARTITION("Kernel", 0x60000, 256 * 0x4000), + PARTITION("Root File System", 0x460000, 0), +}; + +/* + * Default partition layout for large page(> 512 bytes) devices + * Size for "Root file system" is updated in driver based on actual device size + */ +static struct mtd_partition partition_info_128KB_blk[] = { + PARTITION("X-loader", 0, 4 * 0x20000), + PARTITION("U-Boot", 0x80000, 12 * 0x20000), + PARTITION("Kernel", 0x200000, 48 * 0x20000), + PARTITION("Root File System", 0x800000, 0), +}; + +#ifdef CONFIG_MTD_CMDLINE_PARTS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/** + * struct fsmc_nand_data - atructure for FSMC NAND device state + * + * @mtd: MTD info for a NAND flash. + * @nand: Chip related info for a NAND flash. + * @partitions: Partition info for a NAND Flash. + * @nr_partitions: Total number of partition of a NAND flash. + * + * @ecc_place: ECC placing locations in oobfree type format. + * @bank: Bank number for probed device. + * @clk: Clock structure for FSMC. + * + * @data_va: NAND port for Data. + * @cmd_va: NAND port for Command. + * @addr_va: NAND port for Address. + * @regs_va: FSMC regs base address. + */ +struct fsmc_nand_data { + struct mtd_info mtd; + struct nand_chip nand; + struct mtd_partition *partitions; + unsigned int nr_partitions; + + struct fsmc_eccplace *ecc_place; + unsigned int bank; + struct clk *clk; + + struct resource *resregs; + struct resource *rescmd; + struct resource *resaddr; + struct resource *resdata; + + void __iomem *data_va; + void __iomem *cmd_va; + void __iomem *addr_va; + void __iomem *regs_va; + + void (*select_chip)(uint32_t bank, uint32_t busw); +}; + +/* Assert CS signal based on chipnr */ +static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); + + switch (chipnr) { + case -1: + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + break; + case 0: + case 1: + case 2: + case 3: + if (host->select_chip) + host->select_chip(chipnr, + chip->options & NAND_BUSWIDTH_16); + break; + + default: + BUG(); + } +} + +/* + * fsmc_cmd_ctrl - For facilitaing Hardware access + * This routine allows hardware specific access to control-lines(ALE,CLE) + */ +static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + unsigned int bank = host->bank; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_CLE) { + this->IO_ADDR_R = (void __iomem *)host->cmd_va; + this->IO_ADDR_W = (void __iomem *)host->cmd_va; + } else if (ctrl & NAND_ALE) { + this->IO_ADDR_R = (void __iomem *)host->addr_va; + this->IO_ADDR_W = (void __iomem *)host->addr_va; + } else { + this->IO_ADDR_R = (void __iomem *)host->data_va; + this->IO_ADDR_W = (void __iomem *)host->data_va; + } + + if (ctrl & NAND_NCE) { + writel(readl(®s->bank_regs[bank].pc) | FSMC_ENABLE, + ®s->bank_regs[bank].pc); + } else { + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ENABLE, + ®s->bank_regs[bank].pc); + } + } + + mb(); + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +/* + * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine + * + * This routine initializes timing parameters related to NAND memory access in + * FSMC registers + */ +static void __init fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, + uint32_t busw) +{ + uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; + + if (busw) + writel(value | FSMC_DEVWID_16, ®s->bank_regs[bank].pc); + else + writel(value | FSMC_DEVWID_8, ®s->bank_regs[bank].pc); + + writel(readl(®s->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1, + ®s->bank_regs[bank].pc); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + ®s->bank_regs[bank].comm); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + ®s->bank_regs[bank].attrib); +} + +/* + * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers + */ +static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256, + ®s->bank_regs[bank].pc); + writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCEN, + ®s->bank_regs[bank].pc); + writel(readl(®s->bank_regs[bank].pc) | FSMC_ECCEN, + ®s->bank_regs[bank].pc); +} + +/* + * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by + * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction upto + * max of 8-bits) + */ +static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, + uint8_t *ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + uint32_t ecc_tmp; + unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; + + do { + if (readl(®s->bank_regs[bank].sts) & FSMC_CODE_RDY) + break; + else + cond_resched(); + } while (!time_after_eq(jiffies, deadline)); + + ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc[0] = (uint8_t) (ecc_tmp >> 0); + ecc[1] = (uint8_t) (ecc_tmp >> 8); + ecc[2] = (uint8_t) (ecc_tmp >> 16); + ecc[3] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].ecc2); + ecc[4] = (uint8_t) (ecc_tmp >> 0); + ecc[5] = (uint8_t) (ecc_tmp >> 8); + ecc[6] = (uint8_t) (ecc_tmp >> 16); + ecc[7] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].ecc3); + ecc[8] = (uint8_t) (ecc_tmp >> 0); + ecc[9] = (uint8_t) (ecc_tmp >> 8); + ecc[10] = (uint8_t) (ecc_tmp >> 16); + ecc[11] = (uint8_t) (ecc_tmp >> 24); + + ecc_tmp = readl(®s->bank_regs[bank].sts); + ecc[12] = (uint8_t) (ecc_tmp >> 16); + + return 0; +} + +/* + * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by + * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction upto + * max of 1-bit) + */ +static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, + uint8_t *ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + uint32_t bank = host->bank; + uint32_t ecc_tmp; + + ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc[0] = (uint8_t) (ecc_tmp >> 0); + ecc[1] = (uint8_t) (ecc_tmp >> 8); + ecc[2] = (uint8_t) (ecc_tmp >> 16); + + return 0; +} + +/* + * fsmc_read_page_hwecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read + * + * This routine is needed for fsmc verison 8 as reading from NAND chip has to be + * performed in a strict sequence as follows: + * data(512 byte) -> ecc(13 byte) + * After this read, fsmc hardware generates and reports error data bits(upto a + * max of 8 bits) + */ +static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_eccplace *ecc_place = host->ecc_place; + int i, j, s, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + int off, len, group = 0; + /* + * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we + * end up reading 14 bytes (7 words) from oob. The local array is + * to maintain word alignment + */ + uint16_t ecc_oob[7]; + uint8_t *oob = (uint8_t *)&ecc_oob[0]; + + for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { + + chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + for (j = 0; j < eccbytes;) { + off = ecc_place->eccplace[group].offset; + len = ecc_place->eccplace[group].length; + group++; + + /* + * length is intentionally kept a higher multiple of 2 + * to read at least 13 bytes even in case of 16 bit NAND + * devices + */ + len = roundup(len, 2); + chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); + chip->read_buf(mtd, oob + j, len); + j += len; + } + + memcpy(&ecc_code[i], oob, 13); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + + return 0; +} + +/* + * fsmc_correct_data + * @mtd: mtd info structure + * @dat: buffer of read data + * @read_ecc: ecc read from device spare area + * @calc_ecc: ecc calculated from read data + * + * calc_ecc is a 104 bit information containing maximum of 8 error + * offset informations of 13 bits each in 512 bytes of read data. + */ +static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct fsmc_nand_data *host = container_of(mtd, + struct fsmc_nand_data, mtd); + struct fsmc_regs *regs = host->regs_va; + unsigned int bank = host->bank; + uint16_t err_idx[8]; + uint64_t ecc_data[2]; + uint32_t num_err, i; + + /* The calculated ecc is actually the correction index in data */ + memcpy(ecc_data, calc_ecc, 13); + + /* + * ------------------- calc_ecc[] bit wise -----------|--13 bits--| + * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--| + * + * calc_ecc is a 104 bit information containing maximum of 8 error + * offset informations of 13 bits each. calc_ecc is copied into a + * uint64_t array and error offset indexes are populated in err_idx + * array + */ + for (i = 0; i < 8; i++) { + if (i == 4) { + err_idx[4] = ((ecc_data[1] & 0x1) << 12) | ecc_data[0]; + ecc_data[1] >>= 1; + continue; + } + err_idx[i] = (ecc_data[i/4] & 0x1FFF); + ecc_data[i/4] >>= 13; + } + + num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; + + if (num_err == 0xF) + return -EBADMSG; + + i = 0; + while (num_err--) { + change_bit(0, (unsigned long *)&err_idx[i]); + change_bit(1, (unsigned long *)&err_idx[i]); + + if (err_idx[i] <= 512 * 8) { + change_bit(err_idx[i], (unsigned long *)dat); + i++; + } + } + return i; +} + +/* + * fsmc_nand_probe - Probe function + * @pdev: platform device structure + */ +static int __init fsmc_nand_probe(struct platform_device *pdev) +{ + struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct fsmc_nand_data *host; + struct mtd_info *mtd; + struct nand_chip *nand; + struct fsmc_regs *regs; + struct resource *res; + int nr_parts, ret = 0; + + if (!pdata) { + dev_err(&pdev->dev, "platform data is NULL\n"); + return -EINVAL; + } + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure\n"); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); + if (!res) { + ret = -EIO; + goto err_probe1; + } + + host->resdata = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!host->resdata) { + ret = -EIO; + goto err_probe1; + } + + host->data_va = ioremap(res->start, resource_size(res)); + if (!host->data_va) { + ret = -EIO; + goto err_probe1; + } + + host->resaddr = request_mem_region(res->start + PLAT_NAND_ALE, + resource_size(res), pdev->name); + if (!host->resaddr) { + ret = -EIO; + goto err_probe1; + } + + host->addr_va = ioremap(res->start + PLAT_NAND_ALE, resource_size(res)); + if (!host->addr_va) { + ret = -EIO; + goto err_probe1; + } + + host->rescmd = request_mem_region(res->start + PLAT_NAND_CLE, + resource_size(res), pdev->name); + if (!host->rescmd) { + ret = -EIO; + goto err_probe1; + } + + host->cmd_va = ioremap(res->start + PLAT_NAND_CLE, resource_size(res)); + if (!host->cmd_va) { + ret = -EIO; + goto err_probe1; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); + if (!res) { + ret = -EIO; + goto err_probe1; + } + + host->resregs = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!host->resregs) { + ret = -EIO; + goto err_probe1; + } + + host->regs_va = ioremap(res->start, resource_size(res)); + if (!host->regs_va) { + ret = -EIO; + goto err_probe1; + } + + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "failed to fetch block clock\n"); + ret = PTR_ERR(host->clk); + host->clk = NULL; + goto err_probe1; + } + + ret = clk_enable(host->clk); + if (ret) + goto err_probe1; + + host->bank = pdata->bank; + host->select_chip = pdata->select_bank; + regs = host->regs_va; + + /* Link all private pointers */ + mtd = &host->mtd; + nand = &host->nand; + mtd->priv = nand; + nand->priv = host; + + host->mtd.owner = THIS_MODULE; + nand->IO_ADDR_R = host->data_va; + nand->IO_ADDR_W = host->data_va; + nand->cmd_ctrl = fsmc_cmd_ctrl; + nand->chip_delay = 30; + + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.hwctl = fsmc_enable_hwecc; + nand->ecc.size = 512; + nand->options = pdata->options; + nand->select_chip = fsmc_select_chip; + + if (pdata->width == FSMC_NAND_BW16) + nand->options |= NAND_BUSWIDTH_16; + + fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); + + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + nand->ecc.read_page = fsmc_read_page_hwecc; + nand->ecc.calculate = fsmc_read_hwecc_ecc4; + nand->ecc.correct = fsmc_correct_data; + nand->ecc.bytes = 13; + } else { + nand->ecc.calculate = fsmc_read_hwecc_ecc1; + nand->ecc.correct = nand_correct_data; + nand->ecc.bytes = 3; + } + + /* + * Scan to find existance of the device + */ + if (nand_scan_ident(&host->mtd, 1, NULL)) { + ret = -ENXIO; + dev_err(&pdev->dev, "No NAND Device found!\n"); + goto err_probe; + } + + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + if (host->mtd.writesize == 512) { + nand->ecc.layout = &fsmc_ecc4_sp_layout; + host->ecc_place = &fsmc_ecc4_sp_place; + } else { + nand->ecc.layout = &fsmc_ecc4_lp_layout; + host->ecc_place = &fsmc_ecc4_lp_place; + } + } else { + nand->ecc.layout = &fsmc_ecc1_layout; + } + + /* Second stage of scan to fill MTD data-structures */ + if (nand_scan_tail(&host->mtd)) { + ret = -ENXIO; + goto err_probe; + } + + /* + * The partition information can is accessed by (in the same precedence) + * + * command line through Bootloader, + * platform data, + * default partition information present in driver. + */ +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + /* + * Check if partition info passed via command line + */ + host->mtd.name = "nand"; + nr_parts = parse_mtd_partitions(&host->mtd, part_probes, + &host->partitions, 0); + if (nr_parts > 0) { + host->nr_partitions = nr_parts; + } else { +#endif + /* + * Check if partition info passed via command line + */ + if (pdata->partitions) { + host->partitions = pdata->partitions; + host->nr_partitions = pdata->nr_partitions; + } else { + struct mtd_partition *partition; + int i; + + /* Select the default partitions info */ + switch (host->mtd.size) { + case 0x01000000: + case 0x02000000: + case 0x04000000: + host->partitions = partition_info_16KB_blk; + host->nr_partitions = + sizeof(partition_info_16KB_blk) / + sizeof(struct mtd_partition); + break; + case 0x08000000: + case 0x10000000: + case 0x20000000: + case 0x40000000: + host->partitions = partition_info_128KB_blk; + host->nr_partitions = + sizeof(partition_info_128KB_blk) / + sizeof(struct mtd_partition); + break; + default: + ret = -ENXIO; + pr_err("Unsupported NAND size\n"); + goto err_probe; + } + + partition = host->partitions; + for (i = 0; i < host->nr_partitions; i++, partition++) { + if (partition->size == 0) { + partition->size = host->mtd.size - + partition->offset; + break; + } + } + } +#ifdef CONFIG_MTD_CMDLINE_PARTS + } +#endif + + if (host->partitions) { + ret = add_mtd_partitions(&host->mtd, host->partitions, + host->nr_partitions); + if (ret) + goto err_probe; + } +#else + dev_info(&pdev->dev, "Registering %s as whole device\n", mtd->name); + if (!add_mtd_device(mtd)) { + ret = -ENXIO; + goto err_probe; + } +#endif + + platform_set_drvdata(pdev, host); + dev_info(&pdev->dev, "FSMC NAND driver registration successful\n"); + return 0; + +err_probe: + clk_disable(host->clk); +err_probe1: + if (host->clk) + clk_put(host->clk); + if (host->regs_va) + iounmap(host->regs_va); + if (host->resregs) + release_mem_region(host->resregs->start, + resource_size(host->resregs)); + if (host->cmd_va) + iounmap(host->cmd_va); + if (host->rescmd) + release_mem_region(host->rescmd->start, + resource_size(host->rescmd)); + if (host->addr_va) + iounmap(host->addr_va); + if (host->resaddr) + release_mem_region(host->resaddr->start, + resource_size(host->resaddr)); + if (host->data_va) + iounmap(host->data_va); + if (host->resdata) + release_mem_region(host->resdata->start, + resource_size(host->resdata)); + + kfree(host); + return ret; +} + +/* + * Clean up routine + */ +static int fsmc_nand_remove(struct platform_device *pdev) +{ + struct fsmc_nand_data *host = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (host) { +#ifdef CONFIG_MTD_PARTITIONS + del_mtd_partitions(&host->mtd); +#else + del_mtd_device(&host->mtd); +#endif + clk_disable(host->clk); + clk_put(host->clk); + + iounmap(host->regs_va); + release_mem_region(host->resregs->start, + resource_size(host->resregs)); + iounmap(host->cmd_va); + release_mem_region(host->rescmd->start, + resource_size(host->rescmd)); + iounmap(host->addr_va); + release_mem_region(host->resaddr->start, + resource_size(host->resaddr)); + iounmap(host->data_va); + release_mem_region(host->resdata->start, + resource_size(host->resdata)); + + kfree(host); + } + return 0; +} + +#ifdef CONFIG_PM +static int fsmc_nand_suspend(struct device *dev) +{ + struct fsmc_nand_data *host = dev_get_drvdata(dev); + if (host) + clk_disable(host->clk); + return 0; +} + +static int fsmc_nand_resume(struct device *dev) +{ + struct fsmc_nand_data *host = dev_get_drvdata(dev); + if (host) + clk_enable(host->clk); + return 0; +} + +static const struct dev_pm_ops fsmc_nand_pm_ops = { + .suspend = fsmc_nand_suspend, + .resume = fsmc_nand_resume, +}; +#endif + +static struct platform_driver fsmc_nand_driver = { + .remove = fsmc_nand_remove, + .driver = { + .owner = THIS_MODULE, + .name = "fsmc-nand", +#ifdef CONFIG_PM + .pm = &fsmc_nand_pm_ops, +#endif + }, +}; + +static int __init fsmc_nand_init(void) +{ + return platform_driver_probe(&fsmc_nand_driver, + fsmc_nand_probe); +} +module_init(fsmc_nand_init); + +static void __exit fsmc_nand_exit(void) +{ + platform_driver_unregister(&fsmc_nand_driver); +} +module_exit(fsmc_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi"); +MODULE_DESCRIPTION("NAND driver for SPEAr Platforms"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index df0c1da4ff49..469e649c911c 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -568,6 +568,7 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) uint rcw_width; uint rcwh; uint romloc, ps; + int ret = 0; rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); if (!rmnode) { @@ -579,7 +580,8 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) rm = of_iomap(rmnode, 0); if (!rm) { dev_err(prv->dev, "Error mapping reset module node!\n"); - return -EBUSY; + ret = -EBUSY; + goto out; } rcwh = in_be32(&rm->rcwhr); @@ -628,8 +630,9 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) rcw_width * 8, rcw_pagesize, rcw_sparesize); iounmap(rm); +out: of_node_put(rmnode); - return 0; + return ret; } /* Free driver resources */ @@ -660,7 +663,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, #endif struct nand_chip *chip; unsigned long regs_paddr, regs_size; - const uint *chips_no; + const __be32 *chips_no; int resettime = 0; int retval = 0; int rev, len; @@ -803,7 +806,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, } /* Detect NAND chips */ - if (nand_scan(mtd, *chips_no)) { + if (nand_scan(mtd, be32_to_cpup(chips_no))) { dev_err(dev, "NAND Flash not found !\n"); devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d551ddd9537a..1f75a1b1f7c3 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -45,7 +45,7 @@ #include <linux/interrupt.h> #include <linux/bitops.h> #include <linux/leds.h> -#include <asm/io.h> +#include <linux/io.h> #ifdef CONFIG_MTD_PARTITIONS #include <linux/mtd/partitions.h> @@ -59,7 +59,7 @@ static struct nand_ecclayout nand_oob_8 = { {.offset = 3, .length = 2}, {.offset = 6, - .length = 2}} + .length = 2} } }; static struct nand_ecclayout nand_oob_16 = { @@ -67,7 +67,7 @@ static struct nand_ecclayout nand_oob_16 = { .eccpos = {0, 1, 2, 3, 6, 7}, .oobfree = { {.offset = 8, - . length = 8}} + . length = 8} } }; static struct nand_ecclayout nand_oob_64 = { @@ -78,7 +78,7 @@ static struct nand_ecclayout nand_oob_64 = { 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {.offset = 2, - .length = 38}} + .length = 38} } }; static struct nand_ecclayout nand_oob_128 = { @@ -92,7 +92,7 @@ static struct nand_ecclayout nand_oob_128 = { 120, 121, 122, 123, 124, 125, 126, 127}, .oobfree = { {.offset = 2, - .length = 78}} + .length = 78} } }; static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, @@ -612,7 +612,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, NAND_CTRL_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) + ; return; /* This applies to read commands */ @@ -718,7 +719,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) + ; return; case NAND_CMD_RNDOUT: @@ -784,7 +786,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) spinlock_t *lock = &chip->controller->lock; wait_queue_head_t *wq = &chip->controller->wq; DECLARE_WAITQUEUE(wait, current); - retry: +retry: spin_lock(lock); /* Hardware controller shared among independent devices */ @@ -834,7 +836,7 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, break; } mdelay(1); - } + } } /** @@ -980,6 +982,7 @@ out: return ret; } +EXPORT_SYMBOL(nand_unlock); /** * nand_lock - [REPLACEABLE] locks all blocks present in the device @@ -1049,6 +1052,7 @@ out: return ret; } +EXPORT_SYMBOL(nand_lock); /** * nand_read_page_raw - [Intern] read raw page data without ecc @@ -1076,8 +1080,9 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * * We need a special oob layout and handling even when OOB isn't used. */ -static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) +static int nand_read_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1158,7 +1163,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @readlen: data length * @bufpoi: buffer to store read data */ -static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) +static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) { int start_step, end_step, num_steps; uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -1166,6 +1172,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 int data_col_addr, i, gaps = 0; int datafrag_len, eccfrag_len, aligned_len, aligned_pos; int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + int index = 0; /* Column address wihin the page aligned to ECC size (256bytes). */ start_step = data_offs / chip->ecc.size; @@ -1204,26 +1211,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 } else { /* send the command to read the particular ecc bytes */ /* take care about buswidth alignment in read_buf */ - aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); + index = start_step * chip->ecc.bytes; + + aligned_pos = eccpos[index] & ~(busw - 1); aligned_len = eccfrag_len; - if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) + if (eccpos[index] & (busw - 1)) aligned_len++; - if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) + if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) aligned_len++; - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + aligned_pos, -1); chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); } for (i = 0; i < eccfrag_len; i++) - chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; + chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; p = bufpoi + data_col_addr; for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { int stat; - stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); - if (stat == -1) + stat = chip->ecc.correct(mtd, p, + &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat < 0) mtd->ecc_stats.failed++; else mtd->ecc_stats.corrected += stat; @@ -1390,7 +1401,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: @@ -1402,7 +1413,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; - for(; free->length && len; free++, len -= bytes) { + for (; free->length && len; free++, len -= bytes) { /* Read request not from offset 0 ? */ if (unlikely(roffs)) { if (roffs >= free->length) { @@ -1466,7 +1477,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, buf = ops->datbuf; oob = ops->oobbuf; - while(1) { + while (1) { bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); @@ -1484,7 +1495,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); + ret = chip->ecc.read_subpage(mtd, chip, + col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); @@ -1493,7 +1505,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { - if (!NAND_SUBPAGE_READ(chip) && !oob) + if (!NAND_SUBPAGE_READ(chip) && !oob && + !(mtd->ecc_stats.failed - stats.failed)) chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -1791,7 +1804,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; - while(1) { + while (1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); @@ -1861,7 +1874,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, nand_get_device(chip, mtd, FL_READING); - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: @@ -1876,7 +1889,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, else ret = nand_do_read_ops(mtd, from, ops); - out: +out: nand_release_device(mtd); return ret; } @@ -1905,8 +1918,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * * We need a special oob layout and handling even when ECC isn't checked. */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) +static void nand_write_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2099,7 +2113,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, struct mtd_oob_ops *ops) { - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: @@ -2111,7 +2125,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; - for(; free->length && len; free++, len -= bytes) { + for (; free->length && len; free++, len -= bytes) { /* Write request not from offset 0 ? */ if (unlikely(woffs)) { if (woffs >= free->length) { @@ -2137,7 +2151,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, return NULL; } -#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0 +#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** * nand_do_write_ops - [Internal] NAND write with ECC @@ -2200,10 +2214,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); /* Don't allow multipage oob writes with offset */ - if (ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) + if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; - while(1) { + while (1) { int bytes = mtd->writesize; int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; @@ -2431,7 +2445,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, nand_get_device(chip, mtd, FL_WRITING); - switch(ops->mode) { + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: @@ -2446,7 +2460,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, else ret = nand_do_write_ops(mtd, to, ops); - out: +out: nand_release_device(mtd); return ret; } @@ -2511,7 +2525,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, { int page, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; - loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; + loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0}; unsigned int bbt_masked_page = 0xffffffff; loff_t len; @@ -2632,7 +2646,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, } instr->state = MTD_ERASE_DONE; - erase_exit: +erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; @@ -2706,7 +2720,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) struct nand_chip *chip = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { + ret = nand_block_isbad(mtd, ofs); + if (ret) { /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; @@ -2787,15 +2802,115 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } /* + * sanitize ONFI strings so we can safely print them + */ +static void sanitize_string(uint8_t *s, size_t len) +{ + ssize_t i; + + /* null terminate */ + s[len - 1] = 0; + + /* remove non printable chars */ + for (i = 0; i < len - 1; i++) { + if (s[i] < ' ' || s[i] > 127) + s[i] = '?'; + } + + /* remove trailing spaces */ + strim(s); +} + +static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + */ +static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, + int busw) +{ + struct nand_onfi_params *p = &chip->onfi_params; + int i; + int val; + + /* try ONFI for unknow chip or LP */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); + if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || + chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') + return 0; + + printk(KERN_INFO "ONFI flash detected\n"); + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + for (i = 0; i < 3; i++) { + chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == + le16_to_cpu(p->crc)) { + printk(KERN_INFO "ONFI param page %d valid\n", i); + break; + } + } + + if (i == 3) + return 0; + + /* check version */ + val = le16_to_cpu(p->revision); + if (val == 1 || val > (1 << 4)) { + printk(KERN_INFO "%s: unsupported ONFI version: %d\n", + __func__, val); + return 0; + } + + if (val & (1 << 4)) + chip->onfi_version = 22; + else if (val & (1 << 3)) + chip->onfi_version = 21; + else if (val & (1 << 2)) + chip->onfi_version = 20; + else + chip->onfi_version = 10; + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + if (!mtd->name) + mtd->name = p->model; + mtd->writesize = le32_to_cpu(p->byte_per_page); + mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; + busw = 0; + if (le16_to_cpu(p->features) & 1) + busw = NAND_BUSWIDTH_16; + + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= (NAND_NO_READRDY | + NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; + + return 1; +} + +/* * Get the flash and manufacturer id and lookup if the type is supported */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, - int busw, int *maf_id, + int busw, + int *maf_id, int *dev_id, struct nand_flash_dev *type) { - int i, dev_id, maf_idx; + int i, maf_idx; u8 id_data[8]; + int ret; /* Select the device */ chip->select_chip(mtd, 0); @@ -2811,7 +2926,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Read manufacturer and device IDs */ *maf_id = chip->read_byte(mtd); - dev_id = chip->read_byte(mtd); + *dev_id = chip->read_byte(mtd); /* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a @@ -2821,15 +2936,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - /* Read entire ID string */ - - for (i = 0; i < 8; i++) + for (i = 0; i < 2; i++) id_data[i] = chip->read_byte(mtd); - if (id_data[0] != *maf_id || id_data[1] != dev_id) { + if (id_data[0] != *maf_id || id_data[1] != *dev_id) { printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, dev_id, id_data[0], id_data[1]); + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -2837,8 +2950,23 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, type = nand_flash_ids; for (; type->name != NULL; type++) - if (dev_id == type->id) - break; + if (*dev_id == type->id) + break; + + chip->onfi_version = 0; + if (!type->name || !type->pagesize) { + /* Check is chip is ONFI compliant */ + ret = nand_flash_detect_onfi(mtd, chip, busw); + if (ret) + goto ident_done; + } + + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read entire ID string */ + + for (i = 0; i < 8; i++) + id_data[i] = chip->read_byte(mtd); if (!type->name) return ERR_PTR(-ENODEV); @@ -2848,8 +2976,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; - /* Newer devices have all the information in additional id bytes */ - if (!type->pagesize) { + if (!type->pagesize && chip->init_size) { + /* set the pagesize, oobsize, erasesize by the driver*/ + busw = chip->init_size(mtd, chip, id_data); + } else if (!type->pagesize) { int extid; /* The 3rd id byte holds MLC / multichip data */ chip->cellinfo = id_data[2]; @@ -2859,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Field definitions are in the following datasheets: * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GAG08U0D (p.40) + * New style (6 byte ID): Samsung K9GBG08U0M (p.40) * * Check for wraparound + Samsung ID + nonzero 6th byte * to decide what to do. @@ -2872,7 +3002,20 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (extid & 0x03) == 0x01 ? 128 : 218; + switch (extid & 0x03) { + case 1: + mtd->oobsize = 128; + break; + case 2: + mtd->oobsize = 218; + break; + case 3: + mtd->oobsize = 400; + break; + default: + mtd->oobsize = 436; + break; + } extid >>= 2; /* Calc blocksize */ mtd->erasesize = (128 * 1024) << @@ -2900,7 +3043,35 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, mtd->writesize = type->pagesize; mtd->oobsize = mtd->writesize / 32; busw = type->options & NAND_BUSWIDTH_16; + + /* + * Check for Spansion/AMD ID + repeating 5th, 6th byte since + * some Spansion chips have erasesize that conflicts with size + * listed in nand_ids table + * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) + */ + if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && + id_data[5] == 0x00 && id_data[6] == 0x00 && + id_data[7] == 0x00 && mtd->writesize == 512) { + mtd->erasesize = 128 * 1024; + mtd->erasesize <<= ((id_data[3] & 0x03) << 1); + } } + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + + /* Check if chip is a not a samsung device. Do not clear the + * options for chips which are not having an extended id. + */ + if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; +ident_done: + + /* + * Set chip as a default. Board drivers can override it, if necessary + */ + chip->options |= NAND_NO_AUTOINCR; /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { @@ -2915,7 +3086,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (busw != (chip->options & NAND_BUSWIDTH_16)) { printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); printk(KERN_WARNING "NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); @@ -2931,8 +3102,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ffs(mtd->erasesize) - 1; if (chip->chipsize & 0xffffffff) chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; - else - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; + else { + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift += 32 - 1; + } /* Set the bad block position */ if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) @@ -2940,27 +3113,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, else chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - - /* - * Set chip as a default. Board drivers can override it, if necessary - */ - chip->options |= NAND_NO_AUTOINCR; - - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; - /* * Bad block marker is stored in the last page of each block * on Samsung and Hynix MLC devices; stored in first two pages * of each block on Micron devices with 2KiB pages and on - * SLC Samsung, Hynix, and AMD/Spansion. All others scan only - * the first page. + * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan + * only the first page. */ if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || @@ -2969,6 +3127,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX || + *maf_id == NAND_MFR_TOSHIBA || *maf_id == NAND_MFR_AMD)) || (mtd->writesize == 2048 && *maf_id == NAND_MFR_MICRON)) @@ -2994,9 +3153,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; + /* TODO onfi flash name */ printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, + nand_manuf_ids[maf_idx].name, + chip->onfi_version ? type->name : chip->onfi_params.model); return type; } @@ -3015,7 +3176,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { - int i, busw, nand_maf_id; + int i, busw, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; @@ -3025,7 +3186,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, nand_set_defaults(chip, busw); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, table); + type = nand_get_flash_type(mtd, chip, busw, + &nand_maf_id, &nand_dev_id, table); if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) @@ -3043,7 +3205,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || - type->id != chip->read_byte(mtd)) + nand_dev_id != chip->read_byte(mtd)) break; } if (i > 1) @@ -3055,6 +3217,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return 0; } +EXPORT_SYMBOL(nand_scan_ident); /** @@ -3219,7 +3382,7 @@ int nand_scan_tail(struct mtd_info *mtd) * mode */ chip->ecc.steps = mtd->writesize / chip->ecc.size; - if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { + if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { printk(KERN_WARNING "Invalid ecc parameters\n"); BUG(); } @@ -3231,7 +3394,7 @@ int nand_scan_tail(struct mtd_info *mtd) */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { - switch(chip->ecc.steps) { + switch (chip->ecc.steps) { case 2: mtd->subpage_sft = 1; break; @@ -3283,10 +3446,11 @@ int nand_scan_tail(struct mtd_info *mtd) /* Build bad block table */ return chip->scan_bbt(mtd); } +EXPORT_SYMBOL(nand_scan_tail); /* is_module_text_address() isn't exported, and it's mostly a pointless - test if this is a module _anyway_ -- they'd have to try _really_ hard - to call us from in-kernel code if the core NAND support is modular. */ + * test if this is a module _anyway_ -- they'd have to try _really_ hard + * to call us from in-kernel code if the core NAND support is modular. */ #ifdef MODULE #define caller_is_module() (1) #else @@ -3322,6 +3486,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) ret = nand_scan_tail(mtd); return ret; } +EXPORT_SYMBOL(nand_scan); /** * nand_release - [NAND Interface] Free resources held by the NAND device @@ -3348,12 +3513,6 @@ void nand_release(struct mtd_info *mtd) & NAND_BBT_DYNAMICSTRUCT) kfree(chip->badblock_pattern); } - -EXPORT_SYMBOL_GPL(nand_lock); -EXPORT_SYMBOL_GPL(nand_unlock); -EXPORT_SYMBOL_GPL(nand_scan); -EXPORT_SYMBOL_GPL(nand_scan_ident); -EXPORT_SYMBOL_GPL(nand_scan_tail); EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void) @@ -3371,5 +3530,6 @@ module_init(nand_base_init); module_exit(nand_base_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); +MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5fedf4a74f16..586b981f0e61 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -13,28 +13,37 @@ * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a - * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number - * than the mirror bbt is used to build the memory based bbt. + * depending on the options in the BBT descriptor(s). If no flash based BBT + * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * marked good / bad blocks. This information is used to create a memory BBT. + * Once a new bad block is discovered then the "factory" information is updated + * on the device. + * If a flash based BBT is specified then the function first tries to find the + * BBT on flash. If a BBT is found then the contents are read and the memory + * based BBT is created. If a mirrored BBT is selected then the mirror is + * searched too and the versions are compared. If the mirror has a greater + * version number than the mirror BBT is used to build the memory based BBT. * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked + * If one of the BBTs is out of date or does not exist it is (re)created. + * If no BBT exists at all then the device is scanned for factory marked * good / bad blocks and the bad block tables are created. * - * For manufacturer created bbts like the one found on M-SYS DOC devices - * the bbt is searched and read but never created + * For manufacturer created BBTs like the one found on M-SYS DOC devices + * the BBT is searched and read but never created * - * The autogenerated bad block table is located in the last good blocks + * The auto generated bad block table is located in the last good blocks * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version - * number which indicates which of both tables is more up to date. + * The table is marked in the OOB area with an ident pattern and a version + * number which indicates which of both tables is more up to date. If the NAND + * controller needs the complete OOB area for the ECC information then the + * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern + * and the version byte into the data area and the OOB area will remain + * untouched. * * The table uses 2 bits per block - * 11b: block is good - * 00b: block is factory marked bad - * 01b, 10b: block is marked bad due to wear + * 11b: block is good + * 00b: block is factory marked bad + * 01b, 10b: block is marked bad due to wear * * The memory bad block table uses the following scheme: * 00b: block is good @@ -59,6 +68,16 @@ #include <linux/delay.h> #include <linux/vmalloc.h> +static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) +{ + int ret; + + ret = memcmp(buf, td->pattern, td->len); + if (!ret) + return ret; + return -1; +} + /** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search @@ -77,6 +96,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc int i, end = 0; uint8_t *p = buf; + if (td->options & NAND_BBT_NO_OOB) + return check_pattern_no_oob(buf, td); + end = paglen + td->offs; if (td->options & NAND_BBT_SCANEMPTY) { for (i = 0; i < end; i++) { @@ -156,32 +178,63 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) } /** + * add_marker_len - compute the length of the marker in data area + * @td: BBT descriptor used for computation + * + * The length will be 0 if the markeris located in OOB area. + */ +static u32 add_marker_len(struct nand_bbt_descr *td) +{ + u32 len; + + if (!(td->options & NAND_BBT_NO_OOB)) + return 0; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + return len; +} + +/** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd: MTD device structure * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read - * @bits: number of bits per block + * @td: the bbt describtion table * @offs: offset in the memory table - * @reserved_block_code: Pattern to identify reserved blocks * * Read the bad block table starting from page. * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - int bits, int offs, int reserved_block_code) + struct nand_bbt_descr *td, int offs) { int res, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; + int bits = td->options & NAND_BBT_NRBITS_MSK; uint8_t msk = (uint8_t) ((1 << bits) - 1); + u32 marker_len; + int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; + marker_len = add_marker_len(td); from = ((loff_t) page) << this->page_shift; while (totlen) { len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + if (marker_len) { + /* + * In case the BBT marker is not in the OOB area it + * will be just in the first page. + */ + len -= marker_len; + from += marker_len; + marker_len = 0; + } res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { if (retlen != len) { @@ -238,20 +291,21 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc { struct nand_chip *this = mtd->priv; int res = 0, i; - int bits; - bits = td->options & NAND_BBT_NRBITS_MSK; if (td->options & NAND_BBT_PERCHIP) { int offs = 0; for (i = 0; i < this->numchips; i++) { if (chip == -1 || chip == i) - res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); + res = read_bbt(mtd, buf, td->pages[i], + this->chipsize >> this->bbt_erase_shift, + td, offs); if (res) return res; offs += this->chipsize >> (this->bbt_erase_shift + 2); } } else { - res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); + res = read_bbt(mtd, buf, td->pages[0], + mtd->size >> this->bbt_erase_shift, td, 0); if (res) return res; } @@ -259,9 +313,25 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* + * BBT marker is in the first page, no OOB. + */ +static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + struct nand_bbt_descr *td) +{ + size_t retlen; + size_t len; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + + return mtd->read(mtd, offs, len, &retlen, buf); +} + +/* * Scan read raw data from flash */ -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { struct mtd_oob_ops ops; @@ -294,6 +364,15 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return 0; } +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + size_t len, struct nand_bbt_descr *td) +{ + if (td->options & NAND_BBT_NO_OOB) + return scan_read_raw_data(mtd, buf, offs, td); + else + return scan_read_raw_oob(mtd, buf, offs, len); +} + /* * Scan write data with oob to flash */ @@ -312,6 +391,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, return mtd->write_oob(mtd, offs, &ops); } +static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + u32 ver_offs = td->veroffs; + + if (!(td->options & NAND_BBT_NO_OOB)) + ver_offs += mtd->writesize; + return ver_offs; +} + /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd: MTD device structure @@ -331,8 +419,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize); - td->version[0] = buf[mtd->writesize + td->veroffs]; + mtd->writesize, td); + td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } @@ -340,8 +428,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize); - md->version[0] = buf[mtd->writesize + md->veroffs]; + mtd->writesize, td); + md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } @@ -357,7 +445,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, { int ret, j; - ret = scan_read_raw(mtd, buf, offs, readlen); + ret = scan_read_raw_oob(mtd, buf, offs, readlen); if (ret) return ret; @@ -464,6 +552,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, for (i = startblock; i < numblocks;) { int ret; + BUG_ON(bd->options & NAND_BBT_NO_OOB); + if (bd->options & NAND_BBT_SCANALLPAGES) ret = scan_block_full(mtd, bd, from, buf, readlen, scanlen, len); @@ -545,11 +635,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ - scan_read_raw(mtd, buf, offs, mtd->writesize); + scan_read_raw(mtd, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { - td->version[i] = buf[mtd->writesize + td->veroffs]; + offs = bbt_get_ver_offs(mtd, td); + td->version[i] = buf[offs]; } break; } @@ -733,12 +824,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); + } else if (td->options & NAND_BBT_NO_OOB) { + ooboffs = 0; + offs = td->len; + /* the version byte */ + if (td->options & NAND_BBT_VERSION) + offs++; + /* Calc length */ + len = (size_t) (numblocks >> sft); + len += offs; + /* Make it page aligned ! */ + len = ALIGN(len, mtd->writesize); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len); + /* Pattern is located at the begin of first page */ + memcpy(buf, td->pattern, td->len); } else { /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ - len = (len + (mtd->writesize - 1)) & - ~(mtd->writesize - 1); + len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + (len >> this->page_shift)* mtd->oobsize); @@ -772,7 +877,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - res = scan_write_bbt(mtd, to, len, buf, &buf[len]); + res = scan_write_bbt(mtd, to, len, buf, + td->options & NAND_BBT_NO_OOB ? NULL : + &buf[len]); if (res < 0) goto outerr; @@ -892,7 +999,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc continue; /* Create the table in memory by scanning the chip(s) */ - create_bbt(mtd, buf, bd, chipsel); + if (!(this->options & NAND_CREATE_EMPTY_BBT)) + create_bbt(mtd, buf, bd, chipsel); td->version[i] = 1; if (md) @@ -983,6 +1091,49 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) } /** + * verify_bbt_descr - verify the bad block description + * @bd: the table to verify + * + * This functions performs a few sanity checks on the bad block description + * table. + */ +static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd->priv; + u32 pattern_len = bd->len; + u32 bits = bd->options & NAND_BBT_NRBITS_MSK; + u32 table_size; + + if (!bd) + return; + BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && + !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON(!bits); + + if (bd->options & NAND_BBT_VERSION) + pattern_len++; + + if (bd->options & NAND_BBT_NO_OOB) { + BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); + BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(bd->offs); + if (bd->options & NAND_BBT_VERSION) + BUG_ON(bd->veroffs != bd->len); + BUG_ON(bd->options & NAND_BBT_SAVECONTENT); + } + + if (bd->options & NAND_BBT_PERCHIP) + table_size = this->chipsize >> this->bbt_erase_shift; + else + table_size = mtd->size >> this->bbt_erase_shift; + table_size >>= 3; + table_size *= bits; + if (bd->options & NAND_BBT_NO_OOB) + table_size += pattern_len; + BUG_ON(table_size > (1 << this->bbt_erase_shift)); +} + +/** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern @@ -1023,6 +1174,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) } return res; } + verify_bbt_descr(mtd, td); + verify_bbt_descr(mtd, md); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); @@ -1166,6 +1319,26 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern }; +static struct nand_bbt_descr bbt_main_no_bbt_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern +}; + #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ NAND_BBT_SCANBYTE1AND6) /** @@ -1236,8 +1409,13 @@ int nand_default_bbt(struct mtd_info *mtd) if (this->options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; + if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { + this->bbt_td = &bbt_main_no_bbt_descr; + this->bbt_md = &bbt_mirror_no_bbt_descr; + } else { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } } if (!this->badblock_pattern) { this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index c65f19074bc8..00cf1b0d6053 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -75,9 +75,13 @@ struct nand_flash_dev nand_flash_ids[] = { /*512 Megabit */ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16}, /* 1 Gigabit */ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, @@ -112,7 +116,34 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, /* 32 Gigabit */ + {"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS}, {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, + {"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16}, + {"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16}, + + /* 64 Gigabit */ + {"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16}, + {"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16}, + + /* 128 Gigabit */ + {"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16}, + {"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16}, + + /* 256 Gigabit */ + {"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16}, + {"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16}, + + /* 512 Gigabit */ + {"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16}, + {"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16}, /* * Renesas AND 1 Gigabit. Those chips do not support extended id and diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c25648bb5793..a6a73aab1253 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -107,6 +107,7 @@ static char *gravepages = NULL; static unsigned int rptwear = 0; static unsigned int overridesize = 0; static char *cache_file = NULL; +static unsigned int bbt; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -130,6 +131,7 @@ module_param(gravepages, charp, 0400); module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); module_param(cache_file, charp, 0400); +module_param(bbt, uint, 0400); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -162,6 +164,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); +MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 4096 @@ -2264,6 +2267,18 @@ static int __init ns_init_module(void) /* and 'badblocks' parameters to work */ chip->options |= NAND_SKIP_BBTSCAN; + switch (bbt) { + case 2: + chip->options |= NAND_USE_FLASH_BBT_NO_OOB; + case 1: + chip->options |= NAND_USE_FLASH_BBT; + case 0: + break; + default: + NS_ERR("bbt has to be 0..2\n"); + retval = -EINVAL; + goto error; + } /* * Perform minimum nandsim structure initialization to handle * the initial ID read command correctly @@ -2321,10 +2336,10 @@ static int __init ns_init_module(void) if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; - if ((retval = parse_badblocks(nand, nsmtd)) != 0) + if ((retval = nand_default_bbt(nsmtd)) != 0) goto err_exit; - if ((retval = nand_default_bbt(nsmtd)) != 0) + if ((retval = parse_badblocks(nand, nsmtd)) != 0) goto err_exit; /* Register NAND partitions */ diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 510554e6c115..c9ae0a5023b6 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -229,7 +229,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct ndfc_controller *ndfc = &ndfc_ctrl; - const u32 *reg; + const __be32 *reg; u32 ccr; int err, len; @@ -244,7 +244,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); return -ENOENT; } - ndfc->chip_select = reg[0]; + ndfc->chip_select = be32_to_cpu(reg[0]); ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); if (!ndfc->ndfcbase) { @@ -257,7 +257,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, /* It is ok if ccr does not exist - just default to 0 */ reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); if (reg) - ccr |= *reg; + ccr |= be32_to_cpup(reg); out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); @@ -265,7 +265,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); if (reg) { int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); - out_be32(ndfc->ndfcbase + offset, *reg); + out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); } err = ndfc_chip_init(ndfc, ofdev->dev.of_node); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 513e0a76a4a7..cd41c58b5bbd 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -111,11 +111,11 @@ static int use_dma = 1; module_param(use_dma, bool, 0); MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); #else -const int use_dma; +static const int use_dma; #endif #else const int use_prefetch; -const int use_dma; +static const int use_dma; #endif struct omap_nand_info { diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4d01cda68844..17f8518cc5eb 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -117,7 +117,7 @@ struct pxa3xx_nand_info { struct nand_chip nand_chip; struct platform_device *pdev; - const struct pxa3xx_nand_flash *flash_info; + struct pxa3xx_nand_cmdset *cmdset; struct clk *clk; void __iomem *mmio_base; @@ -131,6 +131,7 @@ struct pxa3xx_nand_info { int drcmr_cmd; unsigned char *data_buff; + unsigned char *oob_buff; dma_addr_t data_buff_phys; size_t data_buff_size; int data_dma_ch; @@ -149,7 +150,8 @@ struct pxa3xx_nand_info { int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ - size_t data_size; /* data size in FIFO */ + unsigned int page_size; /* page size of attached chip */ + unsigned int data_size; /* data size in FIFO */ int retcode; struct completion cmd_complete; @@ -158,6 +160,10 @@ struct pxa3xx_nand_info { uint32_t ndcb1; uint32_t ndcb2; + /* timing calcuted from setting */ + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; + /* calculated from pxa3xx_nand_flash data */ size_t oob_size; size_t read_id_bytes; @@ -174,23 +180,7 @@ MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); * Default NAND flash controller configuration setup by the * bootloader. This configuration is used only when pdata->keep_config is set */ -static struct pxa3xx_nand_timing default_timing; -static struct pxa3xx_nand_flash default_flash; - -static struct pxa3xx_nand_cmdset smallpage_cmdset = { - .read1 = 0x0000, - .read2 = 0x0050, - .program = 0x1080, - .read_status = 0x0070, - .read_id = 0x0090, - .erase = 0xD060, - .reset = 0x00FF, - .lock = 0x002A, - .unlock = 0x2423, - .lock_status = 0x007A, -}; - -static struct pxa3xx_nand_cmdset largepage_cmdset = { +static struct pxa3xx_nand_cmdset default_cmdset = { .read1 = 0x3000, .read2 = 0x0050, .program = 0x1080, @@ -203,142 +193,27 @@ static struct pxa3xx_nand_cmdset largepage_cmdset = { .lock_status = 0x007A, }; -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN -static struct pxa3xx_nand_timing samsung512MbX16_timing = { - .tCH = 10, - .tCS = 0, - .tWH = 20, - .tWP = 40, - .tRH = 30, - .tRP = 40, - .tR = 11123, - .tWHR = 110, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash samsung512MbX16 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 32, - .page_size = 512, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 4096, - .chip_id = 0x46ec, -}; - -static struct pxa3xx_nand_flash samsung2GbX8 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 2048, - .chip_id = 0xdaec, +static struct pxa3xx_nand_timing timing[] = { + { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, + { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, + { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, + { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, }; -static struct pxa3xx_nand_flash samsung32GbX8 = { - .timing = &samsung512MbX16_timing, - .cmdset = &smallpage_cmdset, - .page_per_block = 128, - .page_size = 4096, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 8192, - .chip_id = 0xd7ec, +static struct pxa3xx_nand_flash builtin_flash_types[] = { + { 0, 0, 2048, 8, 8, 0, &default_cmdset, &timing[0] }, + { 0x46ec, 32, 512, 16, 16, 4096, &default_cmdset, &timing[1] }, + { 0xdaec, 64, 2048, 8, 8, 2048, &default_cmdset, &timing[1] }, + { 0xd7ec, 128, 4096, 8, 8, 8192, &default_cmdset, &timing[1] }, + { 0xa12c, 64, 2048, 8, 8, 1024, &default_cmdset, &timing[2] }, + { 0xb12c, 64, 2048, 16, 16, 1024, &default_cmdset, &timing[2] }, + { 0xdc2c, 64, 2048, 8, 8, 4096, &default_cmdset, &timing[2] }, + { 0xcc2c, 64, 2048, 16, 16, 4096, &default_cmdset, &timing[2] }, + { 0xba20, 64, 2048, 16, 16, 2048, &default_cmdset, &timing[3] }, }; -static struct pxa3xx_nand_timing micron_timing = { - .tCH = 10, - .tCS = 25, - .tWH = 15, - .tWP = 25, - .tRH = 15, - .tRP = 30, - .tR = 25000, - .tWHR = 60, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash micron1GbX8 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 1024, - .chip_id = 0xa12c, -}; - -static struct pxa3xx_nand_flash micron1GbX16 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 1024, - .chip_id = 0xb12c, -}; - -static struct pxa3xx_nand_flash micron4GbX8 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 8, - .dfc_width = 8, - .num_blocks = 4096, - .chip_id = 0xdc2c, -}; - -static struct pxa3xx_nand_flash micron4GbX16 = { - .timing = µn_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 4096, - .chip_id = 0xcc2c, -}; - -static struct pxa3xx_nand_timing stm2GbX16_timing = { - .tCH = 10, - .tCS = 35, - .tWH = 15, - .tWP = 25, - .tRH = 15, - .tRP = 25, - .tR = 25000, - .tWHR = 60, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash stm2GbX16 = { - .timing = &stm2GbX16_timing, - .cmdset = &largepage_cmdset, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 2048, - .chip_id = 0xba20, -}; - -static struct pxa3xx_nand_flash *builtin_flash_types[] = { - &samsung512MbX16, - &samsung2GbX8, - &samsung32GbX8, - µn1GbX8, - µn1GbX16, - µn4GbX8, - µn4GbX16, - &stm2GbX16, -}; -#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */ +/* Define a default flash type setting serve as flash detecting only */ +#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -351,23 +226,9 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define NDTR1_tWHR(c) (min((c), 15) << 4) #define NDTR1_tAR(c) (min((c), 15) << 0) -#define tCH_NDTR0(r) (((r) >> 19) & 0x7) -#define tCS_NDTR0(r) (((r) >> 16) & 0x7) -#define tWH_NDTR0(r) (((r) >> 11) & 0x7) -#define tWP_NDTR0(r) (((r) >> 8) & 0x7) -#define tRH_NDTR0(r) (((r) >> 3) & 0x7) -#define tRP_NDTR0(r) (((r) >> 0) & 0x7) - -#define tR_NDTR1(r) (((r) >> 16) & 0xffff) -#define tWHR_NDTR1(r) (((r) >> 4) & 0xf) -#define tAR_NDTR1(r) (((r) >> 0) & 0xf) - /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) -/* convert nand flash controller clock cycles to nano-seconds */ -#define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) - static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_timing *t) { @@ -385,6 +246,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } @@ -408,23 +271,31 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) return -ETIMEDOUT; } -static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int column, int page_addr) +static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - /* calculate data size */ - switch (f->page_size) { + info->data_size = info->page_size; + if (!oob_enable) { + info->oob_size = 0; + return; + } + + switch (info->page_size) { case 2048: - info->data_size = (info->use_ecc) ? 2088 : 2112; + info->oob_size = (info->use_ecc) ? 40 : 64; break; case 512: - info->data_size = (info->use_ecc) ? 520 : 528; + info->oob_size = (info->use_ecc) ? 8 : 16; break; - default: - return -EINVAL; } +} + +static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, + uint16_t cmd, int column, int page_addr) +{ + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; + pxa3xx_set_datasize(info); /* generate values for NDCBx registers */ info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); @@ -463,12 +334,13 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info, static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) { - const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); info->ndcb1 = 0; info->ndcb2 = 0; + info->oob_size = 0; if (cmd == cmdset->read_id) { info->ndcb0 |= NDCB0_CMD_TYPE(3); info->data_size = 8; @@ -537,6 +409,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) case STATE_PIO_WRITING: __raw_writesl(info->mmio_base + NDDB, info->data_buff, DIV_ROUND_UP(info->data_size, 4)); + if (info->oob_size > 0) + __raw_writesl(info->mmio_base + NDDB, info->oob_buff, + DIV_ROUND_UP(info->oob_size, 4)); enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); @@ -549,6 +424,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) case STATE_PIO_READING: __raw_readsl(info->mmio_base + NDDB, info->data_buff, DIV_ROUND_UP(info->data_size, 4)); + if (info->oob_size > 0) + __raw_readsl(info->mmio_base + NDDB, info->oob_buff, + DIV_ROUND_UP(info->oob_size, 4)); break; default: printk(KERN_ERR "%s: invalid state %d\n", __func__, @@ -563,7 +441,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) { struct pxa_dma_desc *desc = info->data_desc; - int dma_len = ALIGN(info->data_size, 32); + int dma_len = ALIGN(info->data_size + info->oob_size, 32); desc->ddadr = DDADR_STOP; desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; @@ -700,8 +578,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { struct pxa3xx_nand_info *info = mtd->priv; - const struct pxa3xx_nand_flash *flash_info = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; int ret; info->use_dma = (use_dma) ? 1 : 0; @@ -925,8 +802,7 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; uint32_t ndcr; uint8_t id_buff[8]; @@ -968,7 +844,9 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, return -EINVAL; /* calculate flash information */ - info->oob_size = (f->page_size == 2048) ? 64 : 16; + info->cmdset = f->cmdset; + info->page_size = f->page_size; + info->oob_buff = info->data_buff + f->page_size; info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ @@ -992,49 +870,20 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, info->reg_ndcr = ndcr; pxa3xx_nand_set_timing(info, f->timing); - info->flash_info = f; return 0; } -static void pxa3xx_nand_detect_timing(struct pxa3xx_nand_info *info, - struct pxa3xx_nand_timing *t) -{ - unsigned long nand_clk = clk_get_rate(info->clk); - uint32_t ndtr0 = nand_readl(info, NDTR0CS0); - uint32_t ndtr1 = nand_readl(info, NDTR1CS0); - - t->tCH = cycle2ns(tCH_NDTR0(ndtr0), nand_clk); - t->tCS = cycle2ns(tCS_NDTR0(ndtr0), nand_clk); - t->tWH = cycle2ns(tWH_NDTR0(ndtr0), nand_clk); - t->tWP = cycle2ns(tWP_NDTR0(ndtr0), nand_clk); - t->tRH = cycle2ns(tRH_NDTR0(ndtr0), nand_clk); - t->tRP = cycle2ns(tRP_NDTR0(ndtr0), nand_clk); - - t->tR = cycle2ns(tR_NDTR1(ndtr1), nand_clk); - t->tWHR = cycle2ns(tWHR_NDTR1(ndtr1), nand_clk); - t->tAR = cycle2ns(tAR_NDTR1(ndtr1), nand_clk); -} - static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { uint32_t ndcr = nand_readl(info, NDCR); struct nand_flash_dev *type = NULL; - uint32_t id = -1; + uint32_t id = -1, page_per_block, num_blocks; int i; - default_flash.page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; - default_flash.page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - default_flash.flash_width = ndcr & NDCR_DWIDTH_M ? 16 : 8; - default_flash.dfc_width = ndcr & NDCR_DWIDTH_C ? 16 : 8; - - if (default_flash.page_size == 2048) - default_flash.cmdset = &largepage_cmdset; - else - default_flash.cmdset = &smallpage_cmdset; - + page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; + info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; /* set info fields needed to __readid */ - info->flash_info = &default_flash; - info->read_id_bytes = (default_flash.page_size == 2048) ? 4 : 2; + info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; if (__readid(info, &id)) @@ -1053,21 +902,20 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) return -ENODEV; /* fill the missing flash information */ - i = __ffs(default_flash.page_per_block * default_flash.page_size); - default_flash.num_blocks = type->chipsize << (20 - i); - - info->oob_size = (default_flash.page_size == 2048) ? 64 : 16; + i = __ffs(page_per_block * info->page_size); + num_blocks = type->chipsize << (20 - i); /* calculate addressing information */ - info->col_addr_cycles = (default_flash.page_size == 2048) ? 2 : 1; + info->col_addr_cycles = (info->page_size == 2048) ? 2 : 1; - if (default_flash.num_blocks * default_flash.page_per_block > 65536) + if (num_blocks * page_per_block > 65536) info->row_addr_cycles = 3; else info->row_addr_cycles = 2; - pxa3xx_nand_detect_timing(info, &default_timing); - default_flash.timing = &default_timing; + info->ndtr0cs0 = nand_readl(info, NDTR0CS0); + info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + info->cmdset = &default_cmdset; return 0; } @@ -1083,38 +931,29 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, if (pxa3xx_nand_detect_config(info) == 0) return 0; - for (i = 0; i<pdata->num_flash; ++i) { - f = pdata->flash + i; - - if (pxa3xx_nand_config_flash(info, f)) - continue; - - if (__readid(info, &id)) - continue; - - if (id == f->chip_id) - return 0; - } - -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN - for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { - - f = builtin_flash_types[i]; - - if (pxa3xx_nand_config_flash(info, f)) - continue; - - if (__readid(info, &id)) - continue; - - if (id == f->chip_id) + /* we use default timing to detect id */ + f = DEFAULT_FLASH_TYPE; + pxa3xx_nand_config_flash(info, f); + if (__readid(info, &id)) + goto fail_detect; + + for (i=0; i<ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; i++) { + /* we first choose the flash definition from platfrom */ + if (i < pdata->num_flash) + f = pdata->flash + i; + else + f = &builtin_flash_types[i - pdata->num_flash + 1]; + if (f->chip_id == id) { + dev_info(&info->pdev->dev, "detect chip id: 0x%x\n", id); + pxa3xx_nand_config_flash(info, f); return 0; + } } -#endif dev_warn(&info->pdev->dev, "failed to detect configured nand flash; found %04x instead of\n", id); +fail_detect: return -ENODEV; } @@ -1177,10 +1016,9 @@ static struct nand_ecclayout hw_largepage_ecclayout = { static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f = info->flash_info; struct nand_chip *this = &info->nand_chip; - this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; + this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; this->waitfunc = pxa3xx_nand_waitfunc; this->select_chip = pxa3xx_nand_select_chip; @@ -1196,9 +1034,9 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; this->ecc.calculate = pxa3xx_nand_ecc_calculate; this->ecc.correct = pxa3xx_nand_ecc_correct; - this->ecc.size = f->page_size; + this->ecc.size = info->page_size; - if (f->page_size == 2048) + if (info->page_size == 2048) this->ecc.layout = &hw_largepage_ecclayout; else this->ecc.layout = &hw_smallpage_ecclayout; @@ -1411,9 +1249,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); struct pxa3xx_nand_info *info = mtd->priv; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); clk_enable(info->clk); - return pxa3xx_nand_config_flash(info, info->flash_info); + return 0; } #else #define pxa3xx_nand_suspend NULL diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 5169ca6a66bc..d9d7efbc77cc 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -757,11 +757,6 @@ static irqreturn_t r852_irq(int irq, void *data) spin_lock_irqsave(&dev->irqlock, flags); - /* We can recieve shared interrupt while pci is suspended - in that case reads will return 0xFFFFFFFF.... */ - if (dev->insuspend) - goto out; - /* handle card detection interrupts first */ card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); r852_write_reg(dev, R852_CARD_IRQ_STA, card_status); @@ -1035,7 +1030,6 @@ void r852_shutdown(struct pci_dev *pci_dev) int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); - unsigned long flags; if (dev->ctlreg & R852_CTL_CARDENABLE) return -EBUSY; @@ -1047,43 +1041,22 @@ int r852_suspend(struct device *device) r852_disable_irqs(dev); r852_engine_disable(dev); - spin_lock_irqsave(&dev->irqlock, flags); - dev->insuspend = 1; - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* At that point, even if interrupt handler is running, it will quit */ - /* So wait for this to happen explictly */ - synchronize_irq(dev->irq); - /* If card was pulled off just during the suspend, which is very unlikely, we will remove it on resume, it too late now anyway... */ dev->card_unstable = 0; - - pci_save_state(to_pci_dev(device)); - return pci_prepare_to_sleep(to_pci_dev(device)); + return 0; } int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); - unsigned long flags; - - /* Turn on the hardware */ - pci_back_from_sleep(to_pci_dev(device)); - pci_restore_state(to_pci_dev(device)); r852_disable_irqs(dev); r852_card_update_present(dev); r852_engine_disable(dev); - /* Now its safe for IRQ to run */ - spin_lock_irqsave(&dev->irqlock, flags); - dev->insuspend = 0; - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* If card status changed, just do the work */ if (dev->card_detected != dev->card_registred) { dbg("card was %s during low power state", @@ -1121,7 +1094,6 @@ MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); - static struct pci_driver r852_pci_driver = { .name = DRV_NAME, .id_table = r852_pci_id_tbl, diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h index 8096cc280c73..e6a21d9d22c6 100644 --- a/drivers/mtd/nand/r852.h +++ b/drivers/mtd/nand/r852.h @@ -140,8 +140,6 @@ struct r852_device { /* interrupt handling */ spinlock_t irqlock; /* IRQ protecting lock */ int irq; /* irq num */ - int insuspend; /* device is suspended */ - /* misc */ void *tmp_buffer; /* temporary buffer */ uint8_t ctlreg; /* cached contents of control reg */ diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 7bd171eefd21..a996718fa6b0 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -44,7 +44,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev, pp = NULL; i = 0; while ((pp = of_get_next_child(node, pp))) { - const u32 *reg; + const __be32 *reg; int len; reg = of_get_property(pp, "reg", &len); diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 3f32289fdbb5..4dbd0f58eebf 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig @@ -32,10 +32,11 @@ config MTD_ONENAND_OMAP2 config MTD_ONENAND_SAMSUNG tristate "OneNAND on Samsung SOC controller support" - depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 + depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310 help - Support for a OneNAND flash device connected to an Samsung SOC - S3C64XX/S5PC1XX controller. + Support for a OneNAND flash device connected to an Samsung SOC. + S3C64XX/S5PC100 use command mapping method. + S5PC110/S5PC210 use generic OneNAND method. config MTD_ONENAND_OTP bool "OneNAND OTP Support" diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a2bb520286f8..6b3a875647c9 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3365,18 +3365,19 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, static void onenand_check_features(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - unsigned int density, process; + unsigned int density, process, numbufs; /* Lock scheme depends on density and process */ density = onenand_get_density(this->device_id); process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; + numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8; /* Lock scheme */ switch (density) { case ONENAND_DEVICE_DENSITY_4Gb: if (ONENAND_IS_DDP(this)) this->options |= ONENAND_HAS_2PLANE; - else + else if (numbufs == 1) this->options |= ONENAND_HAS_4KB_PAGE; case ONENAND_DEVICE_DENSITY_2Gb: @@ -4027,7 +4028,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->ecclayout = this->ecclayout; /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; + mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->erase = onenand_erase; mtd->point = NULL; diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index a460f1b748c2..0de7a05e6de0 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -22,6 +22,7 @@ #include <linux/mtd/onenand.h> #include <linux/mtd/partitions.h> #include <linux/dma-mapping.h> +#include <linux/interrupt.h> #include <asm/mach/flash.h> #include <plat/regs-onenand.h> @@ -58,7 +59,7 @@ enum soc_type { #define MAP_11 (0x3) #define S3C64XX_CMD_MAP_SHIFT 24 -#define S5PC1XX_CMD_MAP_SHIFT 26 +#define S5PC100_CMD_MAP_SHIFT 26 #define S3C6400_FBA_SHIFT 10 #define S3C6400_FPA_SHIFT 4 @@ -81,6 +82,17 @@ enum soc_type { #define S5PC110_DMA_TRANS_CMD 0x418 #define S5PC110_DMA_TRANS_STATUS 0x41C #define S5PC110_DMA_TRANS_DIR 0x420 +#define S5PC110_INTC_DMA_CLR 0x1004 +#define S5PC110_INTC_ONENAND_CLR 0x1008 +#define S5PC110_INTC_DMA_MASK 0x1024 +#define S5PC110_INTC_ONENAND_MASK 0x1028 +#define S5PC110_INTC_DMA_PEND 0x1044 +#define S5PC110_INTC_ONENAND_PEND 0x1048 +#define S5PC110_INTC_DMA_STATUS 0x1064 +#define S5PC110_INTC_ONENAND_STATUS 0x1068 + +#define S5PC110_INTC_DMA_TD (1 << 24) +#define S5PC110_INTC_DMA_TE (1 << 16) #define S5PC110_DMA_CFG_SINGLE (0x0 << 16) #define S5PC110_DMA_CFG_4BURST (0x2 << 16) @@ -134,6 +146,7 @@ struct s3c_onenand { void __iomem *dma_addr; struct resource *dma_res; unsigned long phys_base; + struct completion complete; #ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *parts; #endif @@ -191,7 +204,7 @@ static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val) static unsigned int s5pc1xx_cmd_map(unsigned type, unsigned val) { - return (type << S5PC1XX_CMD_MAP_SHIFT) | val; + return (type << S5PC100_CMD_MAP_SHIFT) | val; } static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa) @@ -531,10 +544,13 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, return 0; } -static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) +static int (*s5pc110_dma_ops)(void *dst, void *src, size_t count, int direction); + +static int s5pc110_dma_poll(void *dst, void *src, size_t count, int direction) { void __iomem *base = onenand->dma_addr; int status; + unsigned long timeout; writel(src, base + S5PC110_DMA_SRC_ADDR); writel(dst, base + S5PC110_DMA_DST_ADDR); @@ -552,6 +568,13 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); + /* + * There's no exact timeout values at Spec. + * In real case it takes under 1 msec. + * So 20 msecs are enough. + */ + timeout = jiffies + msecs_to_jiffies(20); + do { status = readl(base + S5PC110_DMA_TRANS_STATUS); if (status & S5PC110_DMA_TRANS_STATUS_TE) { @@ -559,13 +582,68 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) base + S5PC110_DMA_TRANS_CMD); return -EIO; } - } while (!(status & S5PC110_DMA_TRANS_STATUS_TD)); + } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) && + time_before(jiffies, timeout)); writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); return 0; } +static irqreturn_t s5pc110_onenand_irq(int irq, void *data) +{ + void __iomem *base = onenand->dma_addr; + int status, cmd = 0; + + status = readl(base + S5PC110_INTC_DMA_STATUS); + + if (likely(status & S5PC110_INTC_DMA_TD)) + cmd = S5PC110_DMA_TRANS_CMD_TDC; + + if (unlikely(status & S5PC110_INTC_DMA_TE)) + cmd = S5PC110_DMA_TRANS_CMD_TEC; + + writel(cmd, base + S5PC110_DMA_TRANS_CMD); + writel(status, base + S5PC110_INTC_DMA_CLR); + + if (!onenand->complete.done) + complete(&onenand->complete); + + return IRQ_HANDLED; +} + +static int s5pc110_dma_irq(void *dst, void *src, size_t count, int direction) +{ + void __iomem *base = onenand->dma_addr; + int status; + + status = readl(base + S5PC110_INTC_DMA_MASK); + if (status) { + status &= ~(S5PC110_INTC_DMA_TD | S5PC110_INTC_DMA_TE); + writel(status, base + S5PC110_INTC_DMA_MASK); + } + + writel(src, base + S5PC110_DMA_SRC_ADDR); + writel(dst, base + S5PC110_DMA_DST_ADDR); + + if (direction == S5PC110_DMA_DIR_READ) { + writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG); + writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG); + } else { + writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG); + writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG); + } + + writel(count, base + S5PC110_DMA_TRANS_SIZE); + writel(direction, base + S5PC110_DMA_TRANS_DIR); + + writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); + + wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20)); + + return 0; +} + static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count) { @@ -573,7 +651,8 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, void __iomem *p; void *buf = (void *) buffer; dma_addr_t dma_src, dma_dst; - int err; + int err, page_dma = 0; + struct device *dev = &onenand->pdev->dev; p = this->base + area; if (ONENAND_CURRENT_BUFFERRAM(this)) { @@ -597,21 +676,27 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, page = vmalloc_to_page(buf); if (!page) goto normal; - buf = page_address(page) + ((size_t) buf & ~PAGE_MASK); - } - /* DMA routine */ - dma_src = onenand->phys_base + (p - this->base); - dma_dst = dma_map_single(&onenand->pdev->dev, - buf, count, DMA_FROM_DEVICE); - if (dma_mapping_error(&onenand->pdev->dev, dma_dst)) { - dev_err(&onenand->pdev->dev, - "Couldn't map a %d byte buffer for DMA\n", count); + page_dma = 1; + /* DMA routine */ + dma_src = onenand->phys_base + (p - this->base); + dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); + } else { + /* DMA routine */ + dma_src = onenand->phys_base + (p - this->base); + dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE); + } + if (dma_mapping_error(dev, dma_dst)) { + dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count); goto normal; } err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src, count, S5PC110_DMA_DIR_READ); - dma_unmap_single(&onenand->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); + + if (page_dma) + dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE); + else + dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE); if (!err) return 0; @@ -759,7 +844,6 @@ static void s3c_onenand_setup(struct mtd_info *mtd) onenand->cmd_map = s5pc1xx_cmd_map; } else if (onenand->type == TYPE_S5PC110) { /* Use generic onenand functions */ - onenand->cmd_map = s5pc1xx_cmd_map; this->read_bufferram = s5pc110_read_bufferram; this->chip_probe = s5pc110_chip_probe; return; @@ -904,6 +988,20 @@ static int s3c_onenand_probe(struct platform_device *pdev) } onenand->phys_base = onenand->base_res->start; + + s5pc110_dma_ops = s5pc110_dma_poll; + /* Interrupt support */ + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (r) { + init_completion(&onenand->complete); + s5pc110_dma_ops = s5pc110_dma_irq; + err = request_irq(r->start, s5pc110_onenand_irq, + IRQF_SHARED, "onenand", &onenand); + if (err) { + dev_err(&pdev->dev, "failed to get irq\n"); + goto scan_failed; + } + } } if (onenand_scan(mtd, 1)) { @@ -1000,7 +1098,7 @@ static int s3c_pm_ops_suspend(struct device *dev) struct onenand_chip *this = mtd->priv; this->wait(mtd, FL_PM_SUSPENDED); - return mtd->suspend(mtd); + return 0; } static int s3c_pm_ops_resume(struct device *dev) @@ -1009,7 +1107,6 @@ static int s3c_pm_ops_resume(struct device *dev) struct mtd_info *mtd = platform_get_drvdata(pdev); struct onenand_chip *this = mtd->priv; - mtd->resume(mtd); this->unlock_all(mtd); return 0; } diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h index e30e48e7f63d..43bb7300785b 100644 --- a/drivers/mtd/sm_ftl.h +++ b/drivers/mtd/sm_ftl.h @@ -20,7 +20,7 @@ struct ftl_zone { - int initialized; + bool initialized; int16_t *lba_to_phys_table; /* LBA to physical table */ struct kfifo free_sectors; /* queue of free sectors */ }; @@ -37,8 +37,8 @@ struct sm_ftl { int zone_count; /* number of zones */ int max_lba; /* maximum lba in a zone */ int smallpagenand; /* 256 bytes/page nand */ - int readonly; /* is FS readonly */ - int unstable; + bool readonly; /* is FS readonly */ + bool unstable; int cis_block; /* CIS block location */ int cis_boffset; /* CIS offset in the block */ int cis_page_offset; /* CIS offset in the page */ @@ -49,7 +49,7 @@ struct sm_ftl { int cache_zone; /* zone of cached block */ unsigned char *cache_data; /* cached block data */ long unsigned int cache_data_invalid_bitmap; - int cache_clean; + bool cache_clean; struct work_struct flush_work; struct timer_list timer; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9334539ebf75..f6668cdaac85 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2541,6 +2541,7 @@ source "drivers/net/stmmac/Kconfig" config PCH_GBE tristate "PCH Gigabit Ethernet" depends on PCI + select MII ---help--- This is a gigabit ethernet driver for Topcliff PCH. Topcliff PCH is the platform controller hub that is used in Intel's diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 3134e5326231..8cb27cb7bca1 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -407,7 +407,7 @@ static noinline int __init addr_accessible(volatile void *regp, int wordflag, int writeflag) { int ret; - long flags; + unsigned long flags; long *vbr, save_berr; local_irq_save(flags); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 4e3c12371aae..407d4e272075 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -3301,7 +3301,6 @@ static int __devinit init_one(struct pci_dev *pdev, pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; @@ -3342,6 +3341,7 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->name = adapter->port[i]->name; __set_bit(i, &adapter->registered_device_map); + netif_tx_stop_all_queues(adapter->port[i]); } } if (!adapter->registered_device_map) { diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 5d72bda54389..f9f6645b2e61 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -296,8 +296,10 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, if (d->skb) { /* an SGL is present */ if (need_unmap) unmap_skb(d->skb, q, cidx, pdev); - if (d->eop) + if (d->eop) { kfree_skb(d->skb); + d->skb = NULL; + } } ++d; if (++cidx == q->size) { diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index ca663f19d7df..7236f1a53ba0 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -52,6 +52,10 @@ (ID_LED_DEF1_DEF2)) #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 +#define E1000_BASE1000T_STATUS 10 +#define E1000_IDLE_ERROR_COUNT_MASK 0xFF +#define E1000_RECEIVE_ERROR_COUNTER 21 +#define E1000_RECEIVE_ERROR_MAX 0xFFFF #define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ @@ -1243,6 +1247,39 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw) } /** + * e1000_check_phy_82574 - check 82574 phy hung state + * @hw: pointer to the HW structure + * + * Returns whether phy is hung or not + **/ +bool e1000_check_phy_82574(struct e1000_hw *hw) +{ + u16 status_1kbt = 0; + u16 receive_errors = 0; + bool phy_hung = false; + s32 ret_val = 0; + + /* + * Read PHY Receive Error counter first, if its is max - all F's then + * read the Base1000T status register If both are max then PHY is hung. + */ + ret_val = e1e_rphy(hw, E1000_RECEIVE_ERROR_COUNTER, &receive_errors); + + if (ret_val) + goto out; + if (receive_errors == E1000_RECEIVE_ERROR_MAX) { + ret_val = e1e_rphy(hw, E1000_BASE1000T_STATUS, &status_1kbt); + if (ret_val) + goto out; + if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) == + E1000_IDLE_ERROR_COUNT_MASK) + phy_hung = true; + } +out: + return phy_hung; +} + +/** * e1000_setup_link_82571 - Setup flow control and link settings * @hw: pointer to the HW structure * @@ -1859,6 +1896,7 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, + .flags2 = FLAG2_CHECK_PHY_HANG, .pba = 36, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index cee882dd67bf..fdc67fead4ea 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -397,6 +397,7 @@ struct e1000_adapter { struct work_struct print_hang_task; bool idle_check; + int phy_hang_count; }; struct e1000_info { @@ -454,6 +455,7 @@ struct e1000_info { #define FLAG2_HAS_EEE (1 << 5) #define FLAG2_DMA_BURST (1 << 6) #define FLAG2_DISABLE_AIM (1 << 8) +#define FLAG2_CHECK_PHY_HANG (1 << 9) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -631,6 +633,7 @@ extern s32 e1000_get_phy_info_ife(struct e1000_hw *hw); extern s32 e1000_check_polarity_ife(struct e1000_hw *hw); extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); extern s32 e1000_check_polarity_igp(struct e1000_hw *hw); +extern bool e1000_check_phy_82574(struct e1000_hw *hw); static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index ec8cf3f51423..c4ca1629f532 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4098,6 +4098,25 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter) } } +static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* + * With 82574 controllers, PHY needs to be checked periodically + * for hung state and reset, if two calls return true + */ + if (e1000_check_phy_82574(hw)) + adapter->phy_hang_count++; + else + adapter->phy_hang_count = 0; + + if (adapter->phy_hang_count > 1) { + adapter->phy_hang_count = 0; + schedule_work(&adapter->reset_task); + } +} + /** * e1000_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -4333,6 +4352,9 @@ link_up: if (e1000e_get_laa_state_82571(hw)) e1000e_rar_set(hw, adapter->hw.mac.addr, 0); + if (adapter->flags2 & FLAG2_CHECK_PHY_HANG) + e1000e_check_82574_phy_workaround(adapter); + /* Reset the timer */ if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, @@ -4860,8 +4882,11 @@ static void e1000_reset_task(struct work_struct *work) struct e1000_adapter *adapter; adapter = container_of(work, struct e1000_adapter, reset_task); - e1000e_dump(adapter); - e_err("Reset adapter\n"); + if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) && + (adapter->flags & FLAG_RX_RESTART_NOW))) { + e1000e_dump(adapter); + e_err("Reset adapter\n"); + } e1000e_reinit_locked(adapter); } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 14db09e2fa8b..892d196f17ac 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4107,7 +4107,6 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, int size) netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_ring *tx_ring) { - struct igb_adapter *adapter = netdev_priv(tx_ring->netdev); int tso = 0, count; u32 tx_flags = 0; u16 first; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index ebfaa68ee630..28af019c97bb 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2783,15 +2783,15 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ igbvf_reset(adapter); - /* tell the stack to leave us alone until igbvf_open() is called */ - netif_carrier_off(netdev); - netif_stop_queue(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_hw_init; + /* tell the stack to leave us alone until igbvf_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + igbvf_print_device_info(adapter); igbvf_initialize_last_counter_stats(adapter); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 666207a9c039..caa8192fff2a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -533,6 +533,7 @@ ixgb_remove(struct pci_dev *pdev) pci_release_regions(pdev); free_netdev(netdev); + pci_disable_device(pdev); } /** diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c index 8bb9ddb6dffe..0d44c6470ca3 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -43,9 +43,12 @@ * ixgbe_dcb_check_config(). */ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, - u8 direction) + int max_frame, u8 direction) { struct tc_bw_alloc *p; + int min_credit; + int min_multiplier; + int min_percent = 100; s32 ret_val = 0; /* Initialization values default for Tx settings */ u32 credit_refill = 0; @@ -59,6 +62,31 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, goto out; } + min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) / + DCB_CREDIT_QUANTUM; + + /* Find smallest link percentage */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + link_percentage = p->bwg_percent; + + link_percentage = (link_percentage * bw_percent) / 100; + + if (link_percentage && link_percentage < min_percent) + min_percent = link_percentage; + } + + /* + * The ratio between traffic classes will control the bandwidth + * percentages seen on the wire. To calculate this ratio we use + * a multiplier. It is required that the refill credits must be + * larger than the max frame size so here we find the smallest + * multiplier that will allow all bandwidth percentages to be + * greater than the max frame size. + */ + min_multiplier = (min_credit / min_percent) + 1; + /* Find out the link percentage for each TC first */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { p = &dcb_config->tc_config[i].path[direction]; @@ -73,8 +101,9 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, /* Save link_percentage for reference */ p->link_percent = (u8)link_percentage; - /* Calculate credit refill and save it */ - credit_refill = link_percentage * MINIMUM_CREDIT_REFILL; + /* Calculate credit refill ratio using multiplier */ + credit_refill = min(link_percentage * min_multiplier, + MAX_CREDIT_REFILL); p->data_credits_refill = (u16)credit_refill; /* Calculate maximum credit for the TC */ @@ -85,8 +114,8 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, * of a TC is too small, the maximum credit may not be * enough to send out a jumbo frame in data plane arbitration. */ - if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO)) - credit_max = MINIMUM_CREDIT_FOR_JUMBO; + if (credit_max && (credit_max < min_credit)) + credit_max = min_credit; if (direction == DCB_TX_CONFIG) { /* diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h index eb1059f09da0..0208a87b129e 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.h +++ b/drivers/net/ixgbe/ixgbe_dcb.h @@ -150,15 +150,14 @@ struct ixgbe_dcb_config { /* DCB driver APIs */ /* DCB credits calculation */ -s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8); +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, int, u8); /* DCB hw initialization */ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); /* DCB definitions for credit calculation */ +#define DCB_CREDIT_QUANTUM 64 /* DCB Quantum */ #define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */ -#define MINIMUM_CREDIT_REFILL 5 /* 5*64B = 320B */ -#define MINIMUM_CREDIT_FOR_JUMBO 145 /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */ #define DCB_MAX_TSO_SIZE (32*1024) /* MAX TSO packet size supported in DCB mode */ #define MINIMUM_CREDIT_FOR_TSO (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */ #define MAX_CREDIT 4095 /* Maximum credit supported: 256KB * 1204 / 64B */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 67c219f86c3a..05f224715073 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -397,6 +397,11 @@ static s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw) reg &= ~IXGBE_RTTDCS_ARBDIS; IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg); + /* Enable Security TX Buffer IFG for DCB */ + reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG); + reg |= IXGBE_SECTX_DCB; + IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg); + return 0; } diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 18d7fbf6c292..3841649fb954 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -95,6 +95,9 @@ #define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ +/* SECTXMINIFG DCB */ +#define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */ + /* DCB hardware-specific driver APIs */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f85631263af8..2bd3eb4ee5a1 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3347,6 +3347,7 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; + int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN; u32 txdctl; int i, j; @@ -3359,8 +3360,15 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) if (hw->mac.type == ixgbe_mac_82598EB) netif_set_gso_max_size(adapter->netdev, 32768); - ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG); - ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG); +#ifdef CONFIG_FCOE + if (adapter->netdev->features & NETIF_F_FCOE_MTU) + max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); +#endif + + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame, + DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame, + DCB_RX_CONFIG); /* reconfigure the hardware */ ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 316bb70775b1..e7030ceb178b 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -1077,7 +1077,6 @@ static void __NS8390_init(struct net_device *dev, int startp) ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - netif_start_queue(dev); ei_local->tx1 = ei_local->tx2 = 0; ei_local->txing = 0; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 12612127a087..f7d06cbc70ae 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -255,19 +255,6 @@ out_free_rq: } static void -nx_fw_cmd_reset_ctx(struct netxen_adapter *adapter) -{ - - netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION, - adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0, - NX_CDRP_CMD_DESTROY_RX_CTX); - - netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION, - adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0, - NX_CDRP_CMD_DESTROY_TX_CTX); -} - -static void nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter) { struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; @@ -698,8 +685,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state)) goto done; - if (reset_devices) - nx_fw_cmd_reset_ctx(adapter); err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 50820beac3aa..35ae1aa12896 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1356,6 +1356,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } + if (reset_devices) { + if (adapter->portnum == 0) { + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, 0); + adapter->need_fw_reset = 1; + } + } + err = netxen_start_firmware(adapter); if (err) goto err_out_decr_ref; diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 823b9e6431d5..06bc6034ce81 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -337,33 +337,19 @@ static int stmmac_init_phy(struct net_device *dev) return 0; } -static inline void stmmac_mac_enable_rx(void __iomem *ioaddr) +static inline void stmmac_enable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); - value |= MAC_RNABLE_RX; - /* Set the RE (receive enable bit into the MAC CTRL register). */ - writel(value, ioaddr + MAC_CTRL_REG); -} -static inline void stmmac_mac_enable_tx(void __iomem *ioaddr) -{ - u32 value = readl(ioaddr + MAC_CTRL_REG); - value |= MAC_ENABLE_TX; - /* Set the TE (transmit enable bit into the MAC CTRL register). */ + value |= MAC_RNABLE_RX | MAC_ENABLE_TX; writel(value, ioaddr + MAC_CTRL_REG); } -static inline void stmmac_mac_disable_rx(void __iomem *ioaddr) +static inline void stmmac_disable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); - value &= ~MAC_RNABLE_RX; - writel(value, ioaddr + MAC_CTRL_REG); -} -static inline void stmmac_mac_disable_tx(void __iomem *ioaddr) -{ - u32 value = readl(ioaddr + MAC_CTRL_REG); - value &= ~MAC_ENABLE_TX; + value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX); writel(value, ioaddr + MAC_CTRL_REG); } @@ -857,8 +843,7 @@ static int stmmac_open(struct net_device *dev) writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); /* Enable the MAC Rx/Tx */ - stmmac_mac_enable_rx(priv->ioaddr); - stmmac_mac_enable_tx(priv->ioaddr); + stmmac_enable_mac(priv->ioaddr); /* Set the HW DMA mode and the COE */ stmmac_dma_operation_mode(priv); @@ -928,9 +913,8 @@ static int stmmac_release(struct net_device *dev) /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv); - /* Disable the MAC core */ - stmmac_mac_disable_tx(priv->ioaddr); - stmmac_mac_disable_rx(priv->ioaddr); + /* Disable the MAC Rx/Tx */ + stmmac_disable_mac(priv->ioaddr); netif_carrier_off(dev); @@ -1787,8 +1771,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev) priv->hw->dma->stop_rx(priv->ioaddr); priv->hw->dma->stop_tx(priv->ioaddr); - stmmac_mac_disable_rx(priv->ioaddr); - stmmac_mac_disable_tx(priv->ioaddr); + stmmac_disable_mac(priv->ioaddr); netif_carrier_off(ndev); @@ -1839,13 +1822,11 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) dis_ic); priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); - stmmac_mac_disable_tx(priv->ioaddr); - /* Enable Power down mode by programming the PMT regs */ if (device_can_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); else - stmmac_mac_disable_rx(priv->ioaddr); + stmmac_disable_mac(priv->ioaddr); } else { priv->shutdown = 1; /* Although this can appear slightly redundant it actually @@ -1886,8 +1867,7 @@ static int stmmac_resume(struct platform_device *pdev) netif_device_attach(dev); /* Enable the MAC and DMA */ - stmmac_mac_enable_rx(priv->ioaddr); - stmmac_mac_enable_tx(priv->ioaddr); + stmmac_enable_mac(priv->ioaddr); priv->hw->dma->start_tx(priv->ioaddr); priv->hw->dma->start_rx(priv->ioaddr); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index cd0b14a0a93a..fbe8aca975d8 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -139,12 +139,12 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Fill the ath5k_hw struct with the needed functions */ ret = ath5k_hw_init_desc_functions(ah); if (ret) - goto err_free; + goto err; /* Bring device out of sleep and reset its units */ ret = ath5k_hw_nic_wakeup(ah, 0, true); if (ret) - goto err_free; + goto err; /* Get MAC, PHY and RADIO revisions */ ah->ah_mac_srev = srev; @@ -234,7 +234,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) } else { ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); ret = -ENODEV; - goto err_free; + goto err; } } @@ -244,7 +244,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) (srev < AR5K_SREV_AR2425)) { ATH5K_ERR(sc, "Device not yet supported.\n"); ret = -ENODEV; - goto err_free; + goto err; } /* @@ -252,7 +252,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) */ ret = ath5k_hw_post(ah); if (ret) - goto err_free; + goto err; /* Enable pci core retry fix on Hainan (5213A) and later chips */ if (srev >= AR5K_SREV_AR5213A) @@ -265,7 +265,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ret = ath5k_eeprom_init(ah); if (ret) { ATH5K_ERR(sc, "unable to init EEPROM\n"); - goto err_free; + goto err; } ee = &ah->ah_capabilities.cap_eeprom; @@ -307,7 +307,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) if (ret) { ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", sc->pdev->device); - goto err_free; + goto err; } /* Crypto settings */ @@ -341,8 +341,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); return 0; -err_free: - kfree(ah); +err: return ret; } diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 973c919fdd27..9b8e7e3fcebd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -310,7 +310,7 @@ struct ath_rx { u8 rxotherant; u32 *rxlink; unsigned int rxfilter; - spinlock_t rxflushlock; + spinlock_t pcu_lock; spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 728d904c74d7..6576f683dba0 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -801,10 +801,16 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - if ((hif_dev->device_id == 0x7010) || (hif_dev->device_id == 0x7015)) + switch (hif_dev->device_id) { + case 0x7010: + case 0x7015: + case 0x9018: firm_offset = AR7010_FIRMWARE_TEXT; - else + break; + default: firm_offset = AR9271_FIRMWARE_TEXT; + break; + } /* * Issue FW download complete command to firmware. diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c6ec800d7a6b..b52f1cf8a603 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -241,6 +241,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, */ ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); + + spin_lock_bh(&sc->rx.pcu_lock); + stopped = ath_stoprecv(sc); /* XXX: do not flush receive queue here. We don't want @@ -268,6 +271,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } spin_unlock_bh(&sc->sc_resetlock); @@ -276,9 +280,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } + spin_unlock_bh(&sc->rx.pcu_lock); + ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -613,7 +620,7 @@ void ath9k_tasklet(unsigned long data) rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); if (status & rxmask) { - spin_lock_bh(&sc->rx.rxflushlock); + spin_lock_bh(&sc->rx.pcu_lock); /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && @@ -621,7 +628,7 @@ void ath9k_tasklet(unsigned long data) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); - spin_unlock_bh(&sc->rx.rxflushlock); + spin_unlock_bh(&sc->rx.pcu_lock); } if (status & ATH9K_INT_TX) { @@ -876,6 +883,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (!ah->curchan) ah->curchan = ath_get_curchannel(sc, sc->hw); + spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -890,8 +898,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (ath_startrecv(sc) != 0) { ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); return; } + spin_unlock_bh(&sc->rx.pcu_lock); if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -930,6 +940,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); /* clear pending tx frames */ + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ @@ -947,6 +960,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); + + spin_unlock_bh(&sc->rx.pcu_lock); + ath9k_hw_configpcipowersave(ah, 1, 1); ath9k_ps_restore(sc); ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); @@ -966,6 +982,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); ath_flushrecv(sc); @@ -980,6 +999,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); + /* * We may be doing a reset in response to a request * that changes the channel so update any state that @@ -1142,6 +1163,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ + spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { @@ -1150,6 +1172,7 @@ static int ath9k_start(struct ieee80211_hw *hw) "(freq %u MHz)\n", r, curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } spin_unlock_bh(&sc->sc_resetlock); @@ -1171,8 +1194,10 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } + spin_unlock_bh(&sc->rx.pcu_lock); /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | @@ -1371,12 +1396,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) * before setting the invalid flag. */ ath9k_hw_set_interrupts(ah, 0); + spin_lock_bh(&sc->rx.pcu_lock); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.pcu_lock); /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 0cee90cf8dc9..89978d71617f 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -527,7 +527,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u16 rate_flags = rate_table->info[i].rate_flags; + u16 rate_flags = rate_table->info[j].rate_flags; u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fe73fc50082a..fddb0129bb57 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -297,19 +297,17 @@ static void ath_edma_start_recv(struct ath_softc *sc) ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); - spin_unlock_bh(&sc->rx.rxbuflock); - ath_opmode_init(sc); ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + + spin_unlock_bh(&sc->rx.rxbuflock); } static void ath_edma_stop_recv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxbuflock); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); - spin_unlock_bh(&sc->rx.rxbuflock); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -319,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) struct ath_buf *bf; int error = 0; - spin_lock_init(&sc->rx.rxflushlock); + spin_lock_init(&sc->rx.pcu_lock); sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); @@ -506,10 +504,11 @@ int ath_startrecv(struct ath_softc *sc) ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->rx.rxbuflock); ath_opmode_init(sc); ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + spin_unlock_bh(&sc->rx.rxbuflock); + return 0; } @@ -518,6 +517,7 @@ bool ath_stoprecv(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; bool stopped; + spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); @@ -526,19 +526,18 @@ bool ath_stoprecv(struct ath_softc *sc) ath_edma_stop_recv(sc); else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.rxbuflock); return stopped; } void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.rxflushlock); } static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 30ef2dfc1ed2..f2ade2402ce2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1089,15 +1089,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); - /* flush any pending frames if aggregation is enabled */ - if (sc->sc_flags & SC_OP_TXAGGR) { - if (!retry_tx) { - spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } - } - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { spin_lock_bh(&txq->axq_lock); while (!list_empty(&txq->txq_fifo_pending)) { @@ -1118,6 +1109,15 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) } spin_unlock_bh(&txq->axq_lock); } + + /* flush any pending frames if aggregation is enabled */ + if (sc->sc_flags & SC_OP_TXAGGR) { + if (!retry_tx) { + spin_lock_bh(&txq->axq_lock); + ath_txq_drain_pending_buffers(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } + } } void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 45933cf8e8c2..9a55338d957f 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -175,7 +175,9 @@ static void b43_sdio_remove(struct sdio_func *func) struct b43_sdio *sdio = sdio_get_drvdata(func); ssb_bus_unregister(&sdio->ssb); + sdio_claim_host(func); sdio_disable_func(func); + sdio_release_host(func); kfree(sdio); sdio_set_drvdata(func, NULL); } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 296fd00a5129..e5685dc317a8 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -684,18 +684,40 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) lbs_deb_enter(LBS_DEB_SDIO); + /* + * Disable interrupts + */ + sdio_claim_host(card->func); + sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret); + sdio_release_host(card->func); + sdio_claim_host(card->func); scratch = if_sdio_read_scratch(card, &ret); sdio_release_host(card->func); + lbs_deb_sdio("firmware status = %#x\n", scratch); + lbs_deb_sdio("scratch ret = %d\n", ret); + if (ret) goto out; - lbs_deb_sdio("firmware status = %#x\n", scratch); + /* + * The manual clearly describes that FEDC is the right code to use + * to detect firmware presence, but for SD8686 it is not that simple. + * Scratch is also used to store the RX packet length, so we lose + * the FEDC value early on. So we use a non-zero check in order + * to validate firmware presence. + * Additionally, the SD8686 in the Gumstix always has the high scratch + * bit set, even when the firmware is not loaded. So we have to + * exclude that from the test. + */ if (scratch == IF_SDIO_FIRMWARE_OK) { lbs_deb_sdio("firmware already loaded\n"); goto success; + } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { + lbs_deb_sdio("firmware may be running\n"); + goto success; } ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, @@ -709,10 +731,14 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) if (ret) goto out; + lbs_deb_sdio("Helper firmware loaded\n"); + ret = if_sdio_prog_real(card, mainfw); if (ret) goto out; + lbs_deb_sdio("Firmware loaded\n"); + success: sdio_claim_host(card->func); sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); @@ -1042,8 +1068,6 @@ static int if_sdio_probe(struct sdio_func *func, priv->exit_deep_sleep = if_sdio_exit_deep_sleep; priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; - priv->fw_ready = 1; - sdio_claim_host(func); /* @@ -1064,6 +1088,8 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto reclaim; + priv->fw_ready = 1; + /* * FUNC_INIT is required for SD8688 WLAN/BT multiple functions */ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 630fb8664768..458bb57914a3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1610,6 +1610,8 @@ static void netback_changed(struct xenbus_device *dev, switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: case XenbusStateConnected: case XenbusStateUnknown: case XenbusStateClosed: diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b7e755f4178a..a3984f4ef192 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -190,7 +190,7 @@ void sync_stop(void) profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); mutex_unlock(&buffer_mutex); - flush_scheduled_work(); + flush_cpu_work(); /* make sure we don't leak task structs */ process_task_mortuary(); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index f179ac2ea801..59f55441e075 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -111,14 +111,18 @@ void start_cpu_work(void) void end_cpu_work(void) { - int i; - work_enabled = 0; +} + +void flush_cpu_work(void) +{ + int i; for_each_online_cpu(i) { struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); - cancel_delayed_work(&b->work); + /* these works are per-cpu, no need for flush_sync */ + flush_delayed_work(&b->work); } } diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 68ea16ab645f..e1d097e250ae 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -25,6 +25,7 @@ void free_cpu_buffers(void); void start_cpu_work(void); void end_cpu_work(void); +void flush_cpu_work(void); /* CPU buffer is composed of such entries (which are * also used for context switch notes) diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 449de59bf35b..e9ff6f7770be 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -259,17 +259,17 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) } -static int oprofilefs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *oprofilefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, oprofilefs_fill_super, mnt); + return mount_single(fs_type, flags, data, oprofilefs_fill_super); } static struct file_system_type oprofilefs_type = { .owner = THIS_MODULE, .name = "oprofilefs", - .get_sb = oprofilefs_get_sb, + .mount = oprofilefs_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index dc0ae4d14dff..010725117dbb 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -21,6 +21,7 @@ #include "oprof.h" static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); +static int ctr_running; static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) { @@ -33,6 +34,9 @@ static void __oprofile_hrtimer_start(void *unused) { struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); + if (!ctr_running) + return; + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer->function = oprofile_hrtimer_notify; @@ -42,7 +46,10 @@ static void __oprofile_hrtimer_start(void *unused) static int oprofile_hrtimer_start(void) { + get_online_cpus(); + ctr_running = 1; on_each_cpu(__oprofile_hrtimer_start, NULL, 1); + put_online_cpus(); return 0; } @@ -50,6 +57,9 @@ static void __oprofile_hrtimer_stop(int cpu) { struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); + if (!ctr_running) + return; + hrtimer_cancel(hrtimer); } @@ -57,8 +67,11 @@ static void oprofile_hrtimer_stop(void) { int cpu; + get_online_cpus(); for_each_online_cpu(cpu) __oprofile_hrtimer_stop(cpu); + ctr_running = 0; + put_online_cpus(); } static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 34ef70d562b2..5b1630e4e9e3 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -40,6 +40,27 @@ config PCI_STUB When in doubt, say N. +config XEN_PCIDEV_FRONTEND + tristate "Xen PCI Frontend" + depends on PCI && X86 && XEN + select HOTPLUG + select PCI_XEN + default y + help + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + +config XEN_PCIDEV_FE_DEBUG + bool "Xen PCI Frontend debugging" + depends on XEN_PCIDEV_FRONTEND && PCI_DEBUG + help + Say Y here if you want the Xen PCI frontend to produce a bunch of debug + messages to the system log. Select this if you are having a + problem with Xen PCI frontend support and want to see more of what is + going on. + + When in doubt, say N. + config HT_IRQ bool "Interrupts on hypertransport devices" default y diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index dcd7ace9221e..f01e344cf4bd 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -65,4 +65,6 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o +obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o + ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 172bf26e0680..5624db8c9ad0 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -342,6 +342,7 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), } up_read(&pci_bus_sem); } +EXPORT_SYMBOL_GPL(pci_walk_bus); EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL_GPL(pci_bus_add_device); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5fcf5aec680f..7c24dcef2989 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -35,7 +35,12 @@ int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) #endif #ifndef arch_setup_msi_irqs -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +# define arch_setup_msi_irqs default_setup_msi_irqs +# define HAVE_DEFAULT_MSI_SETUP_IRQS +#endif + +#ifdef HAVE_DEFAULT_MSI_SETUP_IRQS +int default_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; int ret; @@ -60,7 +65,12 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) #endif #ifndef arch_teardown_msi_irqs -void arch_teardown_msi_irqs(struct pci_dev *dev) +# define arch_teardown_msi_irqs default_teardown_msi_irqs +# define HAVE_DEFAULT_MSI_TEARDOWN_IRQS +#endif + +#ifdef HAVE_DEFAULT_MSI_TEARDOWN_IRQS +void default_teardown_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c new file mode 100644 index 000000000000..a87c4985326e --- /dev/null +++ b/drivers/pci/xen-pcifront.c @@ -0,0 +1,1148 @@ +/* + * Xen PCI Frontend. + * + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <xen/xenbus.h> +#include <xen/events.h> +#include <xen/grant_table.h> +#include <xen/page.h> +#include <linux/spinlock.h> +#include <linux/pci.h> +#include <linux/msi.h> +#include <xen/xenbus.h> +#include <xen/interface/io/pciif.h> +#include <asm/xen/pci.h> +#include <linux/interrupt.h> +#include <asm/atomic.h> +#include <linux/workqueue.h> +#include <linux/bitops.h> +#include <linux/time.h> + +#define INVALID_GRANT_REF (0) +#define INVALID_EVTCHN (-1) + +struct pci_bus_entry { + struct list_head list; + struct pci_bus *bus; +}; + +#define _PDEVB_op_active (0) +#define PDEVB_op_active (1 << (_PDEVB_op_active)) + +struct pcifront_device { + struct xenbus_device *xdev; + struct list_head root_buses; + + int evtchn; + int gnt_ref; + + int irq; + + /* Lock this when doing any operations in sh_info */ + spinlock_t sh_info_lock; + struct xen_pci_sharedinfo *sh_info; + struct work_struct op_work; + unsigned long flags; + +}; + +struct pcifront_sd { + int domain; + struct pcifront_device *pdev; +}; + +static inline struct pcifront_device * +pcifront_get_pdev(struct pcifront_sd *sd) +{ + return sd->pdev; +} + +static inline void pcifront_init_sd(struct pcifront_sd *sd, + unsigned int domain, unsigned int bus, + struct pcifront_device *pdev) +{ + sd->domain = domain; + sd->pdev = pdev; +} + +static DEFINE_SPINLOCK(pcifront_dev_lock); +static struct pcifront_device *pcifront_dev; + +static int verbose_request; +module_param(verbose_request, int, 0644); + +static int errno_to_pcibios_err(int errno) +{ + switch (errno) { + case XEN_PCI_ERR_success: + return PCIBIOS_SUCCESSFUL; + + case XEN_PCI_ERR_dev_not_found: + return PCIBIOS_DEVICE_NOT_FOUND; + + case XEN_PCI_ERR_invalid_offset: + case XEN_PCI_ERR_op_failed: + return PCIBIOS_BAD_REGISTER_NUMBER; + + case XEN_PCI_ERR_not_implemented: + return PCIBIOS_FUNC_NOT_SUPPORTED; + + case XEN_PCI_ERR_access_denied: + return PCIBIOS_SET_FAILED; + } + return errno; +} + +static inline void schedule_pcifront_aer_op(struct pcifront_device *pdev) +{ + if (test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags) + && !test_and_set_bit(_PDEVB_op_active, &pdev->flags)) { + dev_dbg(&pdev->xdev->dev, "schedule aer frontend job\n"); + schedule_work(&pdev->op_work); + } +} + +static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) +{ + int err = 0; + struct xen_pci_op *active_op = &pdev->sh_info->op; + unsigned long irq_flags; + evtchn_port_t port = pdev->evtchn; + unsigned irq = pdev->irq; + s64 ns, ns_timeout; + struct timeval tv; + + spin_lock_irqsave(&pdev->sh_info_lock, irq_flags); + + memcpy(active_op, op, sizeof(struct xen_pci_op)); + + /* Go */ + wmb(); + set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); + notify_remote_via_evtchn(port); + + /* + * We set a poll timeout of 3 seconds but give up on return after + * 2 seconds. It is better to time out too late rather than too early + * (in the latter case we end up continually re-executing poll() with a + * timeout in the past). 1s difference gives plenty of slack for error. + */ + do_gettimeofday(&tv); + ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC; + + xen_clear_irq_pending(irq); + + while (test_bit(_XEN_PCIF_active, + (unsigned long *)&pdev->sh_info->flags)) { + xen_poll_irq_timeout(irq, jiffies + 3*HZ); + xen_clear_irq_pending(irq); + do_gettimeofday(&tv); + ns = timeval_to_ns(&tv); + if (ns > ns_timeout) { + dev_err(&pdev->xdev->dev, + "pciback not responding!!!\n"); + clear_bit(_XEN_PCIF_active, + (unsigned long *)&pdev->sh_info->flags); + err = XEN_PCI_ERR_dev_not_found; + goto out; + } + } + + /* + * We might lose backend service request since we + * reuse same evtchn with pci_conf backend response. So re-schedule + * aer pcifront service. + */ + if (test_bit(_XEN_PCIB_active, + (unsigned long *)&pdev->sh_info->flags)) { + dev_err(&pdev->xdev->dev, + "schedule aer pcifront service\n"); + schedule_pcifront_aer_op(pdev); + } + + memcpy(op, active_op, sizeof(struct xen_pci_op)); + + err = op->err; +out: + spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags); + return err; +} + +/* Access to this function is spinlocked in drivers/pci/access.c */ +static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + int err = 0; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_conf_read, + .domain = pci_domain_nr(bus), + .bus = bus->number, + .devfn = devfn, + .offset = where, + .size = size, + }; + struct pcifront_sd *sd = bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + if (verbose_request) + dev_info(&pdev->xdev->dev, + "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n", + pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size); + + err = do_pci_op(pdev, &op); + + if (likely(!err)) { + if (verbose_request) + dev_info(&pdev->xdev->dev, "read got back value %x\n", + op.value); + + *val = op.value; + } else if (err == -ENODEV) { + /* No device here, pretend that it just returned 0 */ + err = 0; + *val = 0; + } + + return errno_to_pcibios_err(err); +} + +/* Access to this function is spinlocked in drivers/pci/access.c */ +static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_conf_write, + .domain = pci_domain_nr(bus), + .bus = bus->number, + .devfn = devfn, + .offset = where, + .size = size, + .value = val, + }; + struct pcifront_sd *sd = bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + if (verbose_request) + dev_info(&pdev->xdev->dev, + "write dev=%04x:%02x:%02x.%01x - " + "offset %x size %d val %x\n", + pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); + + return errno_to_pcibios_err(do_pci_op(pdev, &op)); +} + +struct pci_ops pcifront_bus_ops = { + .read = pcifront_bus_read, + .write = pcifront_bus_write, +}; + +#ifdef CONFIG_PCI_MSI +static int pci_frontend_enable_msix(struct pci_dev *dev, + int **vector, int nvec) +{ + int err; + int i; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_enable_msix, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + .value = nvec, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + struct msi_desc *entry; + + if (nvec > SH_INFO_MAX_VEC) { + dev_err(&dev->dev, "too much vector for pci frontend: %x." + " Increase SH_INFO_MAX_VEC.\n", nvec); + return -EINVAL; + } + + i = 0; + list_for_each_entry(entry, &dev->msi_list, list) { + op.msix_entries[i].entry = entry->msi_attrib.entry_nr; + /* Vector is useless at this point. */ + op.msix_entries[i].vector = -1; + i++; + } + + err = do_pci_op(pdev, &op); + + if (likely(!err)) { + if (likely(!op.value)) { + /* we get the result */ + for (i = 0; i < nvec; i++) + *(*vector+i) = op.msix_entries[i].vector; + return 0; + } else { + printk(KERN_DEBUG "enable msix get value %x\n", + op.value); + return op.value; + } + } else { + dev_err(&dev->dev, "enable msix get err %x\n", err); + return err; + } +} + +static void pci_frontend_disable_msix(struct pci_dev *dev) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_disable_msix, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + + /* What should do for error ? */ + if (err) + dev_err(&dev->dev, "pci_disable_msix get err %x\n", err); +} + +static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_enable_msi, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + if (likely(!err)) { + *(*vector) = op.value; + } else { + dev_err(&dev->dev, "pci frontend enable msi failed for dev " + "%x:%x\n", op.bus, op.devfn); + err = -EINVAL; + } + return err; +} + +static void pci_frontend_disable_msi(struct pci_dev *dev) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_disable_msi, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + if (err == XEN_PCI_ERR_dev_not_found) { + /* XXX No response from backend, what shall we do? */ + printk(KERN_DEBUG "get no response from backend for disable MSI\n"); + return; + } + if (err) + /* how can pciback notify us fail? */ + printk(KERN_DEBUG "get fake response frombackend\n"); +} + +static struct xen_pci_frontend_ops pci_frontend_ops = { + .enable_msi = pci_frontend_enable_msi, + .disable_msi = pci_frontend_disable_msi, + .enable_msix = pci_frontend_enable_msix, + .disable_msix = pci_frontend_disable_msix, +}; + +static void pci_frontend_registrar(int enable) +{ + if (enable) + xen_pci_frontend = &pci_frontend_ops; + else + xen_pci_frontend = NULL; +}; +#else +static inline void pci_frontend_registrar(int enable) { }; +#endif /* CONFIG_PCI_MSI */ + +/* Claim resources for the PCI frontend as-is, backend won't allow changes */ +static int pcifront_claim_resource(struct pci_dev *dev, void *data) +{ + struct pcifront_device *pdev = data; + int i; + struct resource *r; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + r = &dev->resource[i]; + + if (!r->parent && r->start && r->flags) { + dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n", + pci_name(dev), i); + if (pci_claim_resource(dev, i)) { + dev_err(&pdev->xdev->dev, "Could not claim " + "resource %s/%d! Device offline. Try " + "giving less than 4GB to domain.\n", + pci_name(dev), i); + } + } + } + + return 0; +} + +static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, + unsigned int domain, unsigned int bus, + struct pci_bus *b) +{ + struct pci_dev *d; + unsigned int devfn; + + /* Scan the bus for functions and add. + * We omit handling of PCI bridge attachment because pciback prevents + * bridges from being exported. + */ + for (devfn = 0; devfn < 0x100; devfn++) { + d = pci_get_slot(b, devfn); + if (d) { + /* Device is already known. */ + pci_dev_put(d); + continue; + } + + d = pci_scan_single_device(b, devfn); + if (d) + dev_info(&pdev->xdev->dev, "New device on " + "%04x:%02x:%02x.%02x found.\n", domain, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + } + + return 0; +} + +static int __devinit pcifront_scan_root(struct pcifront_device *pdev, + unsigned int domain, unsigned int bus) +{ + struct pci_bus *b; + struct pcifront_sd *sd = NULL; + struct pci_bus_entry *bus_entry = NULL; + int err = 0; + +#ifndef CONFIG_PCI_DOMAINS + if (domain != 0) { + dev_err(&pdev->xdev->dev, + "PCI Root in non-zero PCI Domain! domain=%d\n", domain); + dev_err(&pdev->xdev->dev, + "Please compile with CONFIG_PCI_DOMAINS\n"); + err = -EINVAL; + goto err_out; + } +#endif + + dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", + domain, bus); + + bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); + sd = kmalloc(sizeof(*sd), GFP_KERNEL); + if (!bus_entry || !sd) { + err = -ENOMEM; + goto err_out; + } + pcifront_init_sd(sd, domain, bus, pdev); + + b = pci_scan_bus_parented(&pdev->xdev->dev, bus, + &pcifront_bus_ops, sd); + if (!b) { + dev_err(&pdev->xdev->dev, + "Error creating PCI Frontend Bus!\n"); + err = -ENOMEM; + goto err_out; + } + + bus_entry->bus = b; + + list_add(&bus_entry->list, &pdev->root_buses); + + /* pci_scan_bus_parented skips devices which do not have a have + * devfn==0. The pcifront_scan_bus enumerates all devfn. */ + err = pcifront_scan_bus(pdev, domain, bus, b); + + /* Claim resources before going "live" with our devices */ + pci_walk_bus(b, pcifront_claim_resource, pdev); + + /* Create SysFS and notify udev of the devices. Aka: "going live" */ + pci_bus_add_devices(b); + + return err; + +err_out: + kfree(bus_entry); + kfree(sd); + + return err; +} + +static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, + unsigned int domain, unsigned int bus) +{ + int err; + struct pci_bus *b; + +#ifndef CONFIG_PCI_DOMAINS + if (domain != 0) { + dev_err(&pdev->xdev->dev, + "PCI Root in non-zero PCI Domain! domain=%d\n", domain); + dev_err(&pdev->xdev->dev, + "Please compile with CONFIG_PCI_DOMAINS\n"); + return -EINVAL; + } +#endif + + dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n", + domain, bus); + + b = pci_find_bus(domain, bus); + if (!b) + /* If the bus is unknown, create it. */ + return pcifront_scan_root(pdev, domain, bus); + + err = pcifront_scan_bus(pdev, domain, bus, b); + + /* Claim resources before going "live" with our devices */ + pci_walk_bus(b, pcifront_claim_resource, pdev); + + /* Create SysFS and notify udev of the devices. Aka: "going live" */ + pci_bus_add_devices(b); + + return err; +} + +static void free_root_bus_devs(struct pci_bus *bus) +{ + struct pci_dev *dev; + + while (!list_empty(&bus->devices)) { + dev = container_of(bus->devices.next, struct pci_dev, + bus_list); + dev_dbg(&dev->dev, "removing device\n"); + pci_remove_bus_device(dev); + } +} + +static void pcifront_free_roots(struct pcifront_device *pdev) +{ + struct pci_bus_entry *bus_entry, *t; + + dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); + + list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { + list_del(&bus_entry->list); + + free_root_bus_devs(bus_entry->bus); + + kfree(bus_entry->bus->sysdata); + + device_unregister(bus_entry->bus->bridge); + pci_remove_bus(bus_entry->bus); + + kfree(bus_entry); + } +} + +static pci_ers_result_t pcifront_common_process(int cmd, + struct pcifront_device *pdev, + pci_channel_state_t state) +{ + pci_ers_result_t result; + struct pci_driver *pdrv; + int bus = pdev->sh_info->aer_op.bus; + int devfn = pdev->sh_info->aer_op.devfn; + struct pci_dev *pcidev; + int flag = 0; + + dev_dbg(&pdev->xdev->dev, + "pcifront AER process: cmd %x (bus:%x, devfn%x)", + cmd, bus, devfn); + result = PCI_ERS_RESULT_NONE; + + pcidev = pci_get_bus_and_slot(bus, devfn); + if (!pcidev || !pcidev->driver) { + dev_err(&pcidev->dev, + "device or driver is NULL\n"); + return result; + } + pdrv = pcidev->driver; + + if (get_driver(&pdrv->driver)) { + if (pdrv->err_handler && pdrv->err_handler->error_detected) { + dev_dbg(&pcidev->dev, + "trying to call AER service\n"); + if (pcidev) { + flag = 1; + switch (cmd) { + case XEN_PCI_OP_aer_detected: + result = pdrv->err_handler-> + error_detected(pcidev, state); + break; + case XEN_PCI_OP_aer_mmio: + result = pdrv->err_handler-> + mmio_enabled(pcidev); + break; + case XEN_PCI_OP_aer_slotreset: + result = pdrv->err_handler-> + slot_reset(pcidev); + break; + case XEN_PCI_OP_aer_resume: + pdrv->err_handler->resume(pcidev); + break; + default: + dev_err(&pdev->xdev->dev, + "bad request in aer recovery " + "operation!\n"); + + } + } + } + put_driver(&pdrv->driver); + } + if (!flag) + result = PCI_ERS_RESULT_NONE; + + return result; +} + + +static void pcifront_do_aer(struct work_struct *data) +{ + struct pcifront_device *pdev = + container_of(data, struct pcifront_device, op_work); + int cmd = pdev->sh_info->aer_op.cmd; + pci_channel_state_t state = + (pci_channel_state_t)pdev->sh_info->aer_op.err; + + /*If a pci_conf op is in progress, + we have to wait until it is done before service aer op*/ + dev_dbg(&pdev->xdev->dev, + "pcifront service aer bus %x devfn %x\n", + pdev->sh_info->aer_op.bus, pdev->sh_info->aer_op.devfn); + + pdev->sh_info->aer_op.err = pcifront_common_process(cmd, pdev, state); + + /* Post the operation to the guest. */ + wmb(); + clear_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags); + notify_remote_via_evtchn(pdev->evtchn); + + /*in case of we lost an aer request in four lines time_window*/ + smp_mb__before_clear_bit(); + clear_bit(_PDEVB_op_active, &pdev->flags); + smp_mb__after_clear_bit(); + + schedule_pcifront_aer_op(pdev); + +} + +static irqreturn_t pcifront_handler_aer(int irq, void *dev) +{ + struct pcifront_device *pdev = dev; + schedule_pcifront_aer_op(pdev); + return IRQ_HANDLED; +} +static int pcifront_connect(struct pcifront_device *pdev) +{ + int err = 0; + + spin_lock(&pcifront_dev_lock); + + if (!pcifront_dev) { + dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); + pcifront_dev = pdev; + } else { + dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); + err = -EEXIST; + } + + spin_unlock(&pcifront_dev_lock); + + return err; +} + +static void pcifront_disconnect(struct pcifront_device *pdev) +{ + spin_lock(&pcifront_dev_lock); + + if (pdev == pcifront_dev) { + dev_info(&pdev->xdev->dev, + "Disconnecting PCI Frontend Buses\n"); + pcifront_dev = NULL; + } + + spin_unlock(&pcifront_dev_lock); +} +static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) +{ + struct pcifront_device *pdev; + + pdev = kzalloc(sizeof(struct pcifront_device), GFP_KERNEL); + if (pdev == NULL) + goto out; + + pdev->sh_info = + (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); + if (pdev->sh_info == NULL) { + kfree(pdev); + pdev = NULL; + goto out; + } + pdev->sh_info->flags = 0; + + /*Flag for registering PV AER handler*/ + set_bit(_XEN_PCIB_AERHANDLER, (void *)&pdev->sh_info->flags); + + dev_set_drvdata(&xdev->dev, pdev); + pdev->xdev = xdev; + + INIT_LIST_HEAD(&pdev->root_buses); + + spin_lock_init(&pdev->sh_info_lock); + + pdev->evtchn = INVALID_EVTCHN; + pdev->gnt_ref = INVALID_GRANT_REF; + pdev->irq = -1; + + INIT_WORK(&pdev->op_work, pcifront_do_aer); + + dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n", + pdev, pdev->sh_info); +out: + return pdev; +} + +static void free_pdev(struct pcifront_device *pdev) +{ + dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); + + pcifront_free_roots(pdev); + + /*For PCIE_AER error handling job*/ + flush_scheduled_work(); + + if (pdev->irq >= 0) + unbind_from_irqhandler(pdev->irq, pdev); + + if (pdev->evtchn != INVALID_EVTCHN) + xenbus_free_evtchn(pdev->xdev, pdev->evtchn); + + if (pdev->gnt_ref != INVALID_GRANT_REF) + gnttab_end_foreign_access(pdev->gnt_ref, 0 /* r/w page */, + (unsigned long)pdev->sh_info); + else + free_page((unsigned long)pdev->sh_info); + + dev_set_drvdata(&pdev->xdev->dev, NULL); + + kfree(pdev); +} + +static int pcifront_publish_info(struct pcifront_device *pdev) +{ + int err = 0; + struct xenbus_transaction trans; + + err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); + if (err < 0) + goto out; + + pdev->gnt_ref = err; + + err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); + if (err) + goto out; + + err = bind_evtchn_to_irqhandler(pdev->evtchn, pcifront_handler_aer, + 0, "pcifront", pdev); + + if (err < 0) + return err; + + pdev->irq = err; + +do_publish: + err = xenbus_transaction_start(&trans); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error writing configuration for backend " + "(start transaction)"); + goto out; + } + + err = xenbus_printf(trans, pdev->xdev->nodename, + "pci-op-ref", "%u", pdev->gnt_ref); + if (!err) + err = xenbus_printf(trans, pdev->xdev->nodename, + "event-channel", "%u", pdev->evtchn); + if (!err) + err = xenbus_printf(trans, pdev->xdev->nodename, + "magic", XEN_PCI_MAGIC); + + if (err) { + xenbus_transaction_end(trans, 1); + xenbus_dev_fatal(pdev->xdev, err, + "Error writing configuration for backend"); + goto out; + } else { + err = xenbus_transaction_end(trans, 0); + if (err == -EAGAIN) + goto do_publish; + else if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error completing transaction " + "for backend"); + goto out; + } + } + + xenbus_switch_state(pdev->xdev, XenbusStateInitialised); + + dev_dbg(&pdev->xdev->dev, "publishing successful!\n"); + +out: + return err; +} + +static int __devinit pcifront_try_connect(struct pcifront_device *pdev) +{ + int err = -EFAULT; + int i, num_roots, len; + char str[64]; + unsigned int domain, bus; + + + /* Only connect once */ + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateInitialised) + goto out; + + err = pcifront_connect(pdev); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error connecting PCI Frontend"); + goto out; + } + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, + "root_num", "%d", &num_roots); + if (err == -ENOENT) { + xenbus_dev_error(pdev->xdev, err, + "No PCI Roots found, trying 0000:00"); + err = pcifront_scan_root(pdev, 0, 0); + num_roots = 0; + } else if (err != 1) { + if (err == 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading number of PCI roots"); + goto out; + } + + for (i = 0; i < num_roots; i++) { + len = snprintf(str, sizeof(str), "root-%d", i); + if (unlikely(len >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, + "%x:%x", &domain, &bus); + if (err != 2) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading PCI root %d", i); + goto out; + } + + err = pcifront_scan_root(pdev, domain, bus); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error scanning PCI root %04x:%02x", + domain, bus); + goto out; + } + } + + err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); + +out: + return err; +} + +static int pcifront_try_disconnect(struct pcifront_device *pdev) +{ + int err = 0; + enum xenbus_state prev_state; + + + prev_state = xenbus_read_driver_state(pdev->xdev->nodename); + + if (prev_state >= XenbusStateClosing) + goto out; + + if (prev_state == XenbusStateConnected) { + pcifront_free_roots(pdev); + pcifront_disconnect(pdev); + } + + err = xenbus_switch_state(pdev->xdev, XenbusStateClosed); + +out: + + return err; +} + +static int __devinit pcifront_attach_devices(struct pcifront_device *pdev) +{ + int err = -EFAULT; + int i, num_roots, len; + unsigned int domain, bus; + char str[64]; + + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateReconfiguring) + goto out; + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, + "root_num", "%d", &num_roots); + if (err == -ENOENT) { + xenbus_dev_error(pdev->xdev, err, + "No PCI Roots found, trying 0000:00"); + err = pcifront_rescan_root(pdev, 0, 0); + num_roots = 0; + } else if (err != 1) { + if (err == 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading number of PCI roots"); + goto out; + } + + for (i = 0; i < num_roots; i++) { + len = snprintf(str, sizeof(str), "root-%d", i); + if (unlikely(len >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, + "%x:%x", &domain, &bus); + if (err != 2) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading PCI root %d", i); + goto out; + } + + err = pcifront_rescan_root(pdev, domain, bus); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error scanning PCI root %04x:%02x", + domain, bus); + goto out; + } + } + + xenbus_switch_state(pdev->xdev, XenbusStateConnected); + +out: + return err; +} + +static int pcifront_detach_devices(struct pcifront_device *pdev) +{ + int err = 0; + int i, num_devs; + unsigned int domain, bus, slot, func; + struct pci_bus *pci_bus; + struct pci_dev *pci_dev; + char str[64]; + + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateConnected) + goto out; + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d", + &num_devs); + if (err != 1) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading number of PCI devices"); + goto out; + } + + /* Find devices being detached and remove them. */ + for (i = 0; i < num_devs; i++) { + int l, state; + l = snprintf(str, sizeof(str), "state-%d", i); + if (unlikely(l >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d", + &state); + if (err != 1) + state = XenbusStateUnknown; + + if (state != XenbusStateClosing) + continue; + + /* Remove device. */ + l = snprintf(str, sizeof(str), "vdev-%d", i); + if (unlikely(l >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, + "%x:%x:%x.%x", &domain, &bus, &slot, &func); + if (err != 4) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading PCI device %d", i); + goto out; + } + + pci_bus = pci_find_bus(domain, bus); + if (!pci_bus) { + dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n", + domain, bus); + continue; + } + pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func)); + if (!pci_dev) { + dev_dbg(&pdev->xdev->dev, + "Cannot get PCI device %04x:%02x:%02x.%02x\n", + domain, bus, slot, func); + continue; + } + pci_remove_bus_device(pci_dev); + pci_dev_put(pci_dev); + + dev_dbg(&pdev->xdev->dev, + "PCI device %04x:%02x:%02x.%02x removed.\n", + domain, bus, slot, func); + } + + err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring); + +out: + return err; +} + +static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev, + enum xenbus_state be_state) +{ + struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev); + + switch (be_state) { + case XenbusStateUnknown: + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateClosed: + break; + + case XenbusStateConnected: + pcifront_try_connect(pdev); + break; + + case XenbusStateClosing: + dev_warn(&xdev->dev, "backend going away!\n"); + pcifront_try_disconnect(pdev); + break; + + case XenbusStateReconfiguring: + pcifront_detach_devices(pdev); + break; + + case XenbusStateReconfigured: + pcifront_attach_devices(pdev); + break; + } +} + +static int pcifront_xenbus_probe(struct xenbus_device *xdev, + const struct xenbus_device_id *id) +{ + int err = 0; + struct pcifront_device *pdev = alloc_pdev(xdev); + + if (pdev == NULL) { + err = -ENOMEM; + xenbus_dev_fatal(xdev, err, + "Error allocating pcifront_device struct"); + goto out; + } + + err = pcifront_publish_info(pdev); + if (err) + free_pdev(pdev); + +out: + return err; +} + +static int pcifront_xenbus_remove(struct xenbus_device *xdev) +{ + struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev); + if (pdev) + free_pdev(pdev); + + return 0; +} + +static const struct xenbus_device_id xenpci_ids[] = { + {"pci"}, + {""}, +}; + +static struct xenbus_driver xenbus_pcifront_driver = { + .name = "pcifront", + .owner = THIS_MODULE, + .ids = xenpci_ids, + .probe = pcifront_xenbus_probe, + .remove = pcifront_xenbus_remove, + .otherend_changed = pcifront_backend_changed, +}; + +static int __init pcifront_init(void) +{ + if (!xen_pv_domain() || xen_initial_domain()) + return -ENODEV; + + pci_frontend_registrar(1 /* enable */); + + return xenbus_register_frontend(&xenbus_pcifront_driver); +} + +static void __exit pcifront_cleanup(void) +{ + xenbus_unregister_driver(&xenbus_pcifront_driver); + pci_frontend_registrar(0 /* disable */); +} +module_init(pcifront_init); +module_exit(pcifront_cleanup); + +MODULE_DESCRIPTION("Xen PCI passthrough frontend."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("xen:pci"); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index ec444774b9ee..60d83d983a36 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -182,7 +182,6 @@ config CHARGER_ISP1704 config CHARGER_TWL4030 tristate "OMAP TWL4030 BCI charger driver" depends on TWL4030_CORE - depends on BROKEN help Say Y here to enable support for TWL4030 Battery Charge Interface. diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 172951bf23a4..dd30e883d4a7 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -100,6 +100,14 @@ config REGULATOR_MAX8925 help Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. +config REGULATOR_MAX8952 + tristate "Maxim MAX8952 Power Management IC" + depends on I2C + help + This driver controls a Maxim 8952 voltage output regulator + via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS + modes ranging from 0.77V to 1.40V by 0.01V steps. + config REGULATOR_MAX8998 tristate "Maxim 8998 voltage regulator" depends on MFD_MAX8998 @@ -164,6 +172,13 @@ config REGULATOR_LP3971 Say Y here to support the voltage regulators and convertors on National Semiconductors LP3971 PMIC +config REGULATOR_LP3972 + tristate "National Semiconductors LP3972 PMIC regulator driver" + depends on I2C + help + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3972 PMIC + config REGULATOR_PCAP tristate "PCAP2 regulator driver" depends on EZX_PCAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8285fd832e16..bff815736780 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,20 +3,21 @@ # -obj-$(CONFIG_REGULATOR) += core.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o -obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o +obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o +obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 28c7ae67cec9..db6b70f20511 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -21,6 +21,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab8500.h> @@ -33,9 +34,11 @@ * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) * @fixed_uV: typical voltage (for fixed voltage supplies) + * @update_bank: bank to control on/off * @update_reg: register to control on/off * @mask: mask to enable/disable regulator * @enable: bits to enable the regulator in normal(high power) mode + * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage * @supported_voltages: supported voltage table @@ -49,11 +52,13 @@ struct ab8500_regulator_info { int max_uV; int min_uV; int fixed_uV; - int update_reg; - int mask; - int enable; - int voltage_reg; - int voltage_mask; + u8 update_bank; + u8 update_reg; + u8 mask; + u8 enable; + u8 voltage_bank; + u8 voltage_reg; + u8 voltage_mask; int const *supported_voltages; int voltages_len; }; @@ -97,8 +102,8 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_set_bits(info->ab8500, info->update_reg, - info->mask, info->enable); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, info->mask, info->enable); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); @@ -114,8 +119,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_set_bits(info->ab8500, info->update_reg, - info->mask, 0x0); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, info->mask, 0x0); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); @@ -126,19 +131,21 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 value; regulator_id = rdev_get_id(rdev); if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_read(info->ab8500, info->update_reg); + ret = abx500_get_register_interruptible(info->dev, + info->update_bank, info->update_reg, &value); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read 0x%x register\n", info->update_reg); return ret; } - if (ret & info->mask) + if (value & info->mask) return true; else return false; @@ -165,14 +172,16 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int regulator_id, ret, val; + int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 value; regulator_id = rdev_get_id(rdev); if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_read(info->ab8500, info->voltage_reg); + ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, + info->voltage_reg, &value); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); @@ -180,11 +189,11 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) } /* vintcore has a different layout */ - val = ret & info->voltage_mask; + value &= info->voltage_mask; if (regulator_id == AB8500_LDO_INTCORE) - ret = info->supported_voltages[val >> 0x3]; + ret = info->supported_voltages[value >> 0x3]; else - ret = info->supported_voltages[val]; + ret = info->supported_voltages[value]; return ret; } @@ -224,8 +233,9 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, } /* set the registers for the request */ - ret = ab8500_set_bits(info->ab8500, info->voltage_reg, - info->voltage_mask, ret); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, + info->voltage_mask, (u8)ret); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set voltage reg for regulator\n"); @@ -262,9 +272,9 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable, \ - volt_reg, volt_mask, voltages, \ - len_volts) \ +#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \ + reg_enable, volt_bank, volt_reg, volt_mask, \ + voltages, len_volts) \ { \ .desc = { \ .name = "LDO-" #_id, \ @@ -275,9 +285,11 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { }, \ .min_uV = (min) * 1000, \ .max_uV = (max) * 1000, \ + .update_bank = bank, \ .update_reg = reg, \ .mask = reg_mask, \ .enable = reg_enable, \ + .voltage_bank = volt_bank, \ .voltage_reg = volt_reg, \ .voltage_mask = volt_mask, \ .supported_voltages = voltages, \ @@ -285,8 +297,8 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .fixed_uV = 0, \ } -#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask, \ - reg_enable) \ +#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \ + reg_mask, reg_enable) \ { \ .desc = { \ .name = "LDO-" #_id, \ @@ -296,6 +308,7 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .owner = THIS_MODULE, \ }, \ .fixed_uV = fixed * 1000, \ + .update_bank = bank, \ .update_reg = reg, \ .mask = reg_mask, \ .enable = reg_enable, \ @@ -304,28 +317,29 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { static struct ab8500_regulator_info ab8500_regulator_info[] = { /* * Variable Voltage LDOs - * name, min uV, max uV, ctrl reg, reg mask, enable mask, - * volt ctrl reg, volt ctrl mask, volt table, num supported volts + * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask, + * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table, + * num supported volts */ - AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf, + AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf, + AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf, + AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38, + AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* * Fixed Voltage LDOs - * name, o/p uV, ctrl reg, enable, disable + * name, o/p uV, ctrl bank, ctrl reg, enable, disable */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x0380, 0x2, 0x2), - AB8500_FIXED_LDO(AUDIO, 2000, 0x0383, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x0383, 0x4, 0x4), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x0383, 0x8, 0x8), - AB8500_FIXED_LDO(DMIC, 1800, 0x0383, 0x10, 0x10), - AB8500_FIXED_LDO(ANA, 1200, 0x0383, 0xc, 0x4), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2), + AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4), }; static inline struct ab8500_regulator_info *find_regulator_info(int id) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index cc8b337b9119..f1d10c974cd4 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -33,6 +33,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static int has_full_constraints; +static bool board_wants_dummy_regulator; /* * struct regulator_map @@ -63,7 +64,8 @@ struct regulator { }; static int _regulator_is_enabled(struct regulator_dev *rdev); -static int _regulator_disable(struct regulator_dev *rdev); +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr); static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); @@ -1108,6 +1110,11 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, } } + if (board_wants_dummy_regulator) { + rdev = dummy_regulator_rdev; + goto found; + } + #ifdef CONFIG_REGULATOR_DUMMY if (!devname) devname = "deviceless"; @@ -1348,7 +1355,8 @@ int regulator_enable(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_enable); /* locks held by regulator_disable() */ -static int _regulator_disable(struct regulator_dev *rdev) +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; @@ -1376,8 +1384,7 @@ static int _regulator_disable(struct regulator_dev *rdev) } /* decrease our supplies ref count and disable if required */ - if (rdev->supply) - _regulator_disable(rdev->supply); + *supply_rdev_ptr = rdev->supply; rdev->use_count = 0; } else if (rdev->use_count > 1) { @@ -1407,17 +1414,29 @@ static int _regulator_disable(struct regulator_dev *rdev) int regulator_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; + struct regulator_dev *supply_rdev = NULL; int ret = 0; mutex_lock(&rdev->mutex); - ret = _regulator_disable(rdev); + ret = _regulator_disable(rdev, &supply_rdev); mutex_unlock(&rdev->mutex); + + /* decrease our supplies ref count and disable if required */ + while (supply_rdev != NULL) { + rdev = supply_rdev; + + mutex_lock(&rdev->mutex); + _regulator_disable(rdev, &supply_rdev); + mutex_unlock(&rdev->mutex); + } + return ret; } EXPORT_SYMBOL_GPL(regulator_disable); /* locks held by regulator_force_disable() */ -static int _regulator_force_disable(struct regulator_dev *rdev) +static int _regulator_force_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; @@ -1436,8 +1455,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev) } /* decrease our supplies ref count and disable if required */ - if (rdev->supply) - _regulator_disable(rdev->supply); + *supply_rdev_ptr = rdev->supply; rdev->use_count = 0; return ret; @@ -1454,12 +1472,17 @@ static int _regulator_force_disable(struct regulator_dev *rdev) */ int regulator_force_disable(struct regulator *regulator) { + struct regulator_dev *supply_rdev = NULL; int ret; mutex_lock(®ulator->rdev->mutex); regulator->uA_load = 0; - ret = _regulator_force_disable(regulator->rdev); + ret = _regulator_force_disable(regulator->rdev, &supply_rdev); mutex_unlock(®ulator->rdev->mutex); + + if (supply_rdev) + regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev))); + return ret; } EXPORT_SYMBOL_GPL(regulator_force_disable); @@ -2463,6 +2486,22 @@ void regulator_has_full_constraints(void) EXPORT_SYMBOL_GPL(regulator_has_full_constraints); /** + * regulator_use_dummy_regulator - Provide a dummy regulator when none is found + * + * Calling this function will cause the regulator API to provide a + * dummy regulator to consumers if no physical regulator is found, + * allowing most consumers to proceed as though a regulator were + * configured. This allows systems such as those with software + * controllable regulators for the CPU core only to be brought up more + * readily. + */ +void regulator_use_dummy_regulator(void) +{ + board_wants_dummy_regulator = true; +} +EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); + +/** * rdev_get_drvdata - get rdev regulator driver data * @rdev: regulator * diff --git a/drivers/regulator/dummy.h b/drivers/regulator/dummy.h index 3921c0e24249..97a11b7e8882 100644 --- a/drivers/regulator/dummy.h +++ b/drivers/regulator/dummy.h @@ -22,10 +22,6 @@ struct regulator_dev; extern struct regulator_dev *dummy_regulator_rdev; -#ifdef CONFIG_REGULATOR_DUMMY void __init regulator_dummy_init(void); -#else -static inline void regulator_dummy_init(void) { } -#endif #endif diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c new file mode 100644 index 000000000000..e07062fd0b42 --- /dev/null +++ b/drivers/regulator/lp3972.c @@ -0,0 +1,660 @@ +/* + * Regulator driver for National Semiconductors LP3972 PMIC chip + * + * Based on lp3971.c + * + * 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 <linux/bug.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/lp3972.h> +#include <linux/slab.h> + +struct lp3972 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int num_regulators; + struct regulator_dev **rdev; +}; + +/* LP3972 Control Registers */ +#define LP3972_SCR_REG 0x07 +#define LP3972_OVER1_REG 0x10 +#define LP3972_OVSR1_REG 0x11 +#define LP3972_OVER2_REG 0x12 +#define LP3972_OVSR2_REG 0x13 +#define LP3972_VCC1_REG 0x20 +#define LP3972_ADTV1_REG 0x23 +#define LP3972_ADTV2_REG 0x24 +#define LP3972_AVRC_REG 0x25 +#define LP3972_CDTC1_REG 0x26 +#define LP3972_CDTC2_REG 0x27 +#define LP3972_SDTV1_REG 0x29 +#define LP3972_SDTV2_REG 0x2A +#define LP3972_MDTV1_REG 0x32 +#define LP3972_MDTV2_REG 0x33 +#define LP3972_L2VCR_REG 0x39 +#define LP3972_L34VCR_REG 0x3A +#define LP3972_SCR1_REG 0x80 +#define LP3972_SCR2_REG 0x81 +#define LP3972_OEN3_REG 0x82 +#define LP3972_OSR3_REG 0x83 +#define LP3972_LOER4_REG 0x84 +#define LP3972_B2TV_REG 0x85 +#define LP3972_B3TV_REG 0x86 +#define LP3972_B32RC_REG 0x87 +#define LP3972_ISRA_REG 0x88 +#define LP3972_BCCR_REG 0x89 +#define LP3972_II1RR_REG 0x8E +#define LP3972_II2RR_REG 0x8F + +#define LP3972_SYS_CONTROL1_REG LP3972_SCR1_REG +/* System control register 1 initial value, + * bits 5, 6 and 7 are EPROM programmable */ +#define SYS_CONTROL1_INIT_VAL 0x02 +#define SYS_CONTROL1_INIT_MASK 0x1F + +#define LP3972_VOL_CHANGE_REG LP3972_VCC1_REG +#define LP3972_VOL_CHANGE_FLAG_GO 0x01 +#define LP3972_VOL_CHANGE_FLAG_MASK 0x03 + +/* LDO output enable mask */ +#define LP3972_OEN3_L1EN BIT(0) +#define LP3972_OVER2_LDO2_EN BIT(2) +#define LP3972_OVER2_LDO3_EN BIT(3) +#define LP3972_OVER2_LDO4_EN BIT(4) +#define LP3972_OVER1_S_EN BIT(2) + +static const int ldo1_voltage_map[] = { + 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875, + 1900, 1925, 1950, 1975, 2000, +}; + +static const int ldo23_voltage_map[] = { + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, + 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +}; + +static const int ldo4_voltage_map[] = { + 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, + 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +}; + +static const int ldo5_voltage_map[] = { + 0, 0, 0, 0, 0, 850, 875, 900, + 925, 950, 975, 1000, 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +}; + +static const int buck1_voltage_map[] = { + 725, 750, 775, 800, 825, 850, 875, 900, + 925, 950, 975, 1000, 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +}; + +static const int buck23_voltage_map[] = { + 0, 800, 850, 900, 950, 1000, 1050, 1100, + 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, + 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, + 3000, 3300, +}; + +static const int *ldo_voltage_map[] = { + ldo1_voltage_map, + ldo23_voltage_map, + ldo23_voltage_map, + ldo4_voltage_map, + ldo5_voltage_map, +}; + +static const int *buck_voltage_map[] = { + buck1_voltage_map, + buck23_voltage_map, + buck23_voltage_map, +}; + +static const int ldo_output_enable_mask[] = { + LP3972_OEN3_L1EN, + LP3972_OVER2_LDO2_EN, + LP3972_OVER2_LDO3_EN, + LP3972_OVER2_LDO4_EN, + LP3972_OVER1_S_EN, +}; + +static const int ldo_output_enable_addr[] = { + LP3972_OEN3_REG, + LP3972_OVER2_REG, + LP3972_OVER2_REG, + LP3972_OVER2_REG, + LP3972_OVER1_REG, +}; + +static const int ldo_vol_ctl_addr[] = { + LP3972_MDTV1_REG, + LP3972_L2VCR_REG, + LP3972_L34VCR_REG, + LP3972_L34VCR_REG, + LP3972_SDTV1_REG, +}; + +static const int buck_vol_enable_addr[] = { + LP3972_OVER1_REG, + LP3972_OEN3_REG, + LP3972_OEN3_REG, +}; + +static const int buck_base_addr[] = { + LP3972_ADTV1_REG, + LP3972_B2TV_REG, + LP3972_B3TV_REG, +}; + +#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x]) +#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x]) +#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x]) + +/* LDO voltage control registers shift: + LP3972_LDO1 -> 0, LP3972_LDO2 -> 4 + LP3972_LDO3 -> 0, LP3972_LDO4 -> 4 + LP3972_LDO5 -> 0 +*/ +#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2) +#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x]) +#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6) + +#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f) +#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00) +#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c) + +#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x]) +#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) +#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) +#define LP3972_BUCK_VOL_MASK 0x1f +#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00) +#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f) + +static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, + u16 *dest) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + return ret; + + *dest = ret; + return 0; +} + +static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count, + const u16 *src) +{ + if (count != 1) + return -EIO; + return i2c_smbus_write_byte_data(i2c, reg, *src); +} + +static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg) +{ + u16 val = 0; + + mutex_lock(&lp3972->io_lock); + + lp3972_i2c_read(lp3972->i2c, reg, 1, &val); + + dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val & 0xff); + + mutex_unlock(&lp3972->io_lock); + + return val & 0xff; +} + +static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) +{ + u16 tmp; + int ret; + + mutex_lock(&lp3972->io_lock); + + ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp); + tmp = (tmp & ~mask) | val; + if (ret == 0) { + ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp); + dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val & 0xff); + } + mutex_unlock(&lp3972->io_lock); + + return ret; +} + +static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int ldo = rdev_get_id(dev) - LP3972_LDO1; + return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index]; +} + +static int lp3972_ldo_is_enabled(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + u16 val; + + val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo)); + return !!(val & mask); +} + +static int lp3972_ldo_enable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + + return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), + mask, mask); +} + +static int lp3972_ldo_disable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + + return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), + mask, 0); +} + +static int lp3972_ldo_get_voltage(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_VOL_MASK(ldo); + u16 val, reg; + + reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); + val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; + + return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val]; +} + +static int lp3972_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo); + u16 val; + int shift, ret; + + if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] || + min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)]) + return -EINVAL; + + for (val = LP3972_LDO_VOL_MIN_IDX(ldo); + val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++) + if (vol_map[val] >= min_vol) + break; + + if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) + return -EINVAL; + + shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); + ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), + LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); + + if (ret) + return ret; + + /* + * LDO1 and LDO5 support voltage control by either target voltage1 + * or target voltage2 register. + * We use target voltage1 register for LDO1 and LDO5 in this driver. + * We need to update voltage change control register(0x20) to enable + * LDO1 and LDO5 to change to their programmed target values. + */ + switch (ldo) { + case LP3972_LDO1: + case LP3972_LDO5: + shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo); + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK << shift, + LP3972_VOL_CHANGE_FLAG_GO << shift); + if (ret) + return ret; + + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK << shift, 0); + break; + } + + return ret; +} + +static struct regulator_ops lp3972_ldo_ops = { + .list_voltage = lp3972_ldo_list_voltage, + .is_enabled = lp3972_ldo_is_enabled, + .enable = lp3972_ldo_enable, + .disable = lp3972_ldo_disable, + .get_voltage = lp3972_ldo_get_voltage, + .set_voltage = lp3972_ldo_set_voltage, +}; + +static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int buck = rdev_get_id(dev) - LP3972_DCDC1; + return 1000 * buck_voltage_map[buck][index]; +} + +static int lp3972_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck)); + return !!(val & mask); +} + +static int lp3972_dcdc_enable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), + mask, mask); + return val; +} + +static int lp3972_dcdc_disable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), + mask, 0); + return val; +} + +static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 reg; + int val; + + reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); + reg &= LP3972_BUCK_VOL_MASK; + if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck)) + val = 1000 * buck_voltage_map[buck][reg]; + else { + val = 0; + dev_warn(&dev->dev, "chip reported incorrect voltage value." + " reg = %d\n", reg); + } + + return val; +} + +static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = buck_voltage_map[buck]; + u16 val; + int ret; + + if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] || + min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)]) + return -EINVAL; + + for (val = LP3972_BUCK_VOL_MIN_IDX(buck); + val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++) + if (vol_map[val] >= min_vol) + break; + + if (val > LP3972_BUCK_VOL_MAX_IDX(buck) || + vol_map[val] > max_vol) + return -EINVAL; + + ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), + LP3972_BUCK_VOL_MASK, val); + if (ret) + return ret; + + if (buck != 0) + return ret; + + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO); + if (ret) + return ret; + + return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK, 0); +} + +static struct regulator_ops lp3972_dcdc_ops = { + .list_voltage = lp3972_dcdc_list_voltage, + .is_enabled = lp3972_dcdc_is_enabled, + .enable = lp3972_dcdc_enable, + .disable = lp3972_dcdc_disable, + .get_voltage = lp3972_dcdc_get_voltage, + .set_voltage = lp3972_dcdc_set_voltage, +}; + +static struct regulator_desc regulators[] = { + { + .name = "LDO1", + .id = LP3972_LDO1, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo1_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = LP3972_LDO2, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO3", + .id = LP3972_LDO3, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO4", + .id = LP3972_LDO4, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo4_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO5", + .id = LP3972_LDO5, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo5_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC1", + .id = LP3972_DCDC1, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck1_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC2", + .id = LP3972_DCDC2, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC3", + .id = LP3972_DCDC3, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, +}; + +static int __devinit setup_regulators(struct lp3972 *lp3972, + struct lp3972_platform_data *pdata) +{ + int i, err; + + lp3972->num_regulators = pdata->num_regulators; + lp3972->rdev = kcalloc(pdata->num_regulators, + sizeof(struct regulator_dev *), GFP_KERNEL); + if (!lp3972->rdev) { + err = -ENOMEM; + goto err_nomem; + } + + /* Instantiate the regulators */ + for (i = 0; i < pdata->num_regulators; i++) { + struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; + lp3972->rdev[i] = regulator_register(®ulators[reg->id], + lp3972->dev, reg->initdata, lp3972); + + if (IS_ERR(lp3972->rdev[i])) { + err = PTR_ERR(lp3972->rdev[i]); + dev_err(lp3972->dev, "regulator init failed: %d\n", + err); + goto error; + } + } + + return 0; +error: + while (--i >= 0) + regulator_unregister(lp3972->rdev[i]); + kfree(lp3972->rdev); + lp3972->rdev = NULL; +err_nomem: + return err; +} + +static int __devinit lp3972_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct lp3972 *lp3972; + struct lp3972_platform_data *pdata = i2c->dev.platform_data; + int ret; + u16 val; + + if (!pdata) { + dev_dbg(&i2c->dev, "No platform init data supplied\n"); + return -ENODEV; + } + + lp3972 = kzalloc(sizeof(struct lp3972), GFP_KERNEL); + if (!lp3972) + return -ENOMEM; + + lp3972->i2c = i2c; + lp3972->dev = &i2c->dev; + + mutex_init(&lp3972->io_lock); + + /* Detect LP3972 */ + ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val); + if (ret == 0 && + (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) { + ret = -ENODEV; + dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val); + } + if (ret < 0) { + dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret); + goto err_detect; + } + + ret = setup_regulators(lp3972, pdata); + if (ret < 0) + goto err_detect; + + i2c_set_clientdata(i2c, lp3972); + return 0; + +err_detect: + kfree(lp3972); + return ret; +} + +static int __devexit lp3972_i2c_remove(struct i2c_client *i2c) +{ + struct lp3972 *lp3972 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < lp3972->num_regulators; i++) + regulator_unregister(lp3972->rdev[i]); + kfree(lp3972->rdev); + kfree(lp3972); + + return 0; +} + +static const struct i2c_device_id lp3972_i2c_id[] = { + { "lp3972", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); + +static struct i2c_driver lp3972_i2c_driver = { + .driver = { + .name = "lp3972", + .owner = THIS_MODULE, + }, + .probe = lp3972_i2c_probe, + .remove = __devexit_p(lp3972_i2c_remove), + .id_table = lp3972_i2c_id, +}; + +static int __init lp3972_module_init(void) +{ + return i2c_add_driver(&lp3972_i2c_driver); +} +subsys_initcall(lp3972_module_init); + +static void __exit lp3972_module_exit(void) +{ + i2c_del_driver(&lp3972_i2c_driver); +} +module_exit(lp3972_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>"); +MODULE_DESCRIPTION("LP3972 PMIC driver"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c new file mode 100644 index 000000000000..0d5dda4fd911 --- /dev/null +++ b/drivers/regulator/max8952.c @@ -0,0 +1,366 @@ +/* + * max8952.c - Voltage and current regulation for the Maxim 8952 + * + * Copyright (C) 2010 Samsung Electronics + * MyungJoo Ham <myungjoo.ham@samsung.com> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/max8952.h> +#include <linux/mutex.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/slab.h> + +/* Registers */ +enum { + MAX8952_REG_MODE0, + MAX8952_REG_MODE1, + MAX8952_REG_MODE2, + MAX8952_REG_MODE3, + MAX8952_REG_CONTROL, + MAX8952_REG_SYNC, + MAX8952_REG_RAMP, + MAX8952_REG_CHIP_ID1, + MAX8952_REG_CHIP_ID2, +}; + +struct max8952_data { + struct i2c_client *client; + struct device *dev; + struct mutex mutex; + struct max8952_platform_data *pdata; + struct regulator_dev *rdev; + + bool vid0; + bool vid1; + bool en; +}; + +static int max8952_read_reg(struct max8952_data *max8952, u8 reg) +{ + int ret = i2c_smbus_read_byte_data(max8952->client, reg); + if (ret > 0) + ret &= 0xff; + + return ret; +} + +static int max8952_write_reg(struct max8952_data *max8952, + u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(max8952->client, reg, value); +} + +static int max8952_voltage(struct max8952_data *max8952, u8 mode) +{ + return (max8952->pdata->dvs_mode[mode] * 10 + 770) * 1000; +} + +static int max8952_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + if (rdev_get_id(rdev) != 0) + return -EINVAL; + + return max8952_voltage(max8952, selector); +} + +static int max8952_is_enabled(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + return max8952->en; +} + +static int max8952_enable(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + /* If not valid, assume "ALWAYS_HIGH" */ + if (gpio_is_valid(max8952->pdata->gpio_en)) + gpio_set_value(max8952->pdata->gpio_en, 1); + + max8952->en = true; + return 0; +} + +static int max8952_disable(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + /* If not valid, assume "ALWAYS_HIGH" -> not permitted */ + if (gpio_is_valid(max8952->pdata->gpio_en)) + gpio_set_value(max8952->pdata->gpio_en, 0); + else + return -EPERM; + + max8952->en = false; + return 0; +} + +static int max8952_get_voltage(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + u8 vid = 0; + + if (max8952->vid0) + vid += 1; + if (max8952->vid1) + vid += 2; + + return max8952_voltage(max8952, vid); +} + +static int max8952_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + s8 vid = -1, i; + + if (!gpio_is_valid(max8952->pdata->gpio_vid0) || + !gpio_is_valid(max8952->pdata->gpio_vid0)) { + /* DVS not supported */ + return -EPERM; + } + + for (i = 0; i < MAX8952_NUM_DVS_MODE; i++) { + int volt = max8952_voltage(max8952, i); + + /* Set the voltage as low as possible within the range */ + if (volt <= max_uV && volt >= min_uV) + if (vid == -1 || max8952_voltage(max8952, vid) > volt) + vid = i; + } + + if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { + max8952->vid0 = (vid % 2 == 1); + max8952->vid1 = (((vid >> 1) % 2) == 1); + gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); + gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); + } else + return -EINVAL; + + return 0; +} + +static struct regulator_ops max8952_ops = { + .list_voltage = max8952_list_voltage, + .is_enabled = max8952_is_enabled, + .enable = max8952_enable, + .disable = max8952_disable, + .get_voltage = max8952_get_voltage, + .set_voltage = max8952_set_voltage, + .set_suspend_disable = max8952_disable, +}; + +static struct regulator_desc regulator = { + .name = "MAX8952_VOUT", + .id = 0, + .n_voltages = MAX8952_NUM_DVS_MODE, + .ops = &max8952_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int __devinit max8952_pmic_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct max8952_platform_data *pdata = client->dev.platform_data; + struct max8952_data *max8952; + + int ret = 0, err = 0; + + if (!pdata) { + dev_err(&client->dev, "Require the platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + max8952 = kzalloc(sizeof(struct max8952_data), GFP_KERNEL); + if (!max8952) + return -ENOMEM; + + max8952->client = client; + max8952->dev = &client->dev; + max8952->pdata = pdata; + mutex_init(&max8952->mutex); + + max8952->rdev = regulator_register(®ulator, max8952->dev, + &pdata->reg_data, max8952); + + if (IS_ERR(max8952->rdev)) { + ret = PTR_ERR(max8952->rdev); + dev_err(max8952->dev, "regulator init failed (%d)\n", ret); + goto err_reg; + } + + max8952->en = !!(pdata->reg_data.constraints.boot_on); + max8952->vid0 = (pdata->default_mode % 2) == 1; + max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1; + + if (gpio_is_valid(pdata->gpio_en)) { + if (!gpio_request(pdata->gpio_en, "MAX8952 EN")) + gpio_direction_output(pdata->gpio_en, max8952->en); + else + err = 1; + } else + err = 2; + + if (err) { + dev_info(max8952->dev, "EN gpio invalid: assume that EN" + "is always High\n"); + max8952->en = 1; + pdata->gpio_en = -1; /* Mark invalid */ + } + + err = 0; + + if (gpio_is_valid(pdata->gpio_vid0) && + gpio_is_valid(pdata->gpio_vid1)) { + if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) + gpio_direction_output(pdata->gpio_vid0, + (pdata->default_mode) % 2); + else + err = 1; + + if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1")) + gpio_direction_output(pdata->gpio_vid1, + (pdata->default_mode >> 1) % 2); + else { + if (!err) + gpio_free(pdata->gpio_vid0); + err = 2; + } + + } else + err = 3; + + if (err) { + dev_warn(max8952->dev, "VID0/1 gpio invalid: " + "DVS not avilable.\n"); + max8952->vid0 = 0; + max8952->vid1 = 0; + /* Mark invalid */ + pdata->gpio_vid0 = -1; + pdata->gpio_vid1 = -1; + + /* Disable Pulldown of EN only */ + max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); + + dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1" + " do not have proper controls.\n"); + } else { + /* + * Disable Pulldown on EN, VID0, VID1 to reduce + * leakage current of MAX8952 assuming that MAX8952 + * is turned on (EN==1). Note that without having VID0/1 + * properly connected, turning pulldown off can be + * problematic. Thus, turn this off only when they are + * controllable by GPIO. + */ + max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0); + } + + max8952_write_reg(max8952, MAX8952_REG_MODE0, + (max8952_read_reg(max8952, + MAX8952_REG_MODE0) & 0xC0) | + (pdata->dvs_mode[0] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE1, + (max8952_read_reg(max8952, + MAX8952_REG_MODE1) & 0xC0) | + (pdata->dvs_mode[1] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE2, + (max8952_read_reg(max8952, + MAX8952_REG_MODE2) & 0xC0) | + (pdata->dvs_mode[2] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE3, + (max8952_read_reg(max8952, + MAX8952_REG_MODE3) & 0xC0) | + (pdata->dvs_mode[3] & 0x3F)); + + max8952_write_reg(max8952, MAX8952_REG_SYNC, + (max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) | + ((pdata->sync_freq & 0x3) << 6)); + max8952_write_reg(max8952, MAX8952_REG_RAMP, + (max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) | + ((pdata->ramp_speed & 0x7) << 5)); + + i2c_set_clientdata(client, max8952); + + return 0; + +err_reg: + kfree(max8952); + return ret; +} + +static int __devexit max8952_pmic_remove(struct i2c_client *client) +{ + struct max8952_data *max8952 = i2c_get_clientdata(client); + struct max8952_platform_data *pdata = max8952->pdata; + struct regulator_dev *rdev = max8952->rdev; + + regulator_unregister(rdev); + + gpio_free(pdata->gpio_vid0); + gpio_free(pdata->gpio_vid1); + gpio_free(pdata->gpio_en); + + kfree(max8952); + return 0; +} + +static const struct i2c_device_id max8952_ids[] = { + { "max8952", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max8952_ids); + +static struct i2c_driver max8952_pmic_driver = { + .probe = max8952_pmic_probe, + .remove = __devexit_p(max8952_pmic_remove), + .driver = { + .name = "max8952", + }, + .id_table = max8952_ids, +}; + +static int __init max8952_pmic_init(void) +{ + return i2c_add_driver(&max8952_pmic_driver); +} +subsys_initcall(max8952_pmic_init); + +static void __exit max8952_pmic_exit(void) +{ + i2c_del_driver(&max8952_pmic_driver); +} +module_exit(max8952_pmic_exit); + +MODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver"); +MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index a1baf1fbe004..5c20756db607 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -39,6 +39,11 @@ struct max8998_data { struct max8998_dev *iodev; int num_regulators; struct regulator_dev **rdev; + u8 buck1_vol[4]; /* voltages for selection */ + u8 buck2_vol[2]; + unsigned int buck1_idx; /* index to last changed voltage */ + /* value in a set */ + unsigned int buck2_idx; }; struct voltage_map_desc { @@ -173,6 +178,7 @@ static int max8998_get_enable_register(struct regulator_dev *rdev, static int max8998_ldo_is_enabled(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int ret, reg, shift = 8; u8 val; @@ -180,7 +186,7 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - ret = max8998_read_reg(max8998->iodev, reg, &val); + ret = max8998_read_reg(i2c, reg, &val); if (ret) return ret; @@ -190,31 +196,34 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev) static int max8998_ldo_enable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 8, ret; ret = max8998_get_enable_register(rdev, ®, &shift); if (ret) return ret; - return max8998_update_reg(max8998->iodev, reg, 1<<shift, 1<<shift); + return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift); } static int max8998_ldo_disable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 8, ret; ret = max8998_get_enable_register(rdev, ®, &shift); if (ret) return ret; - return max8998_update_reg(max8998->iodev, reg, 0, 1<<shift); + return max8998_update_reg(i2c, reg, 0, 1<<shift); } static int max8998_get_voltage_register(struct regulator_dev *rdev, int *_reg, int *_shift, int *_mask) { int ldo = max8998_get_ldo(rdev); + struct max8998_data *max8998 = rdev_get_drvdata(rdev); int reg, shift = 0, mask = 0xff; switch (ldo) { @@ -251,10 +260,10 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev, reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12); break; case MAX8998_BUCK1: - reg = MAX8998_REG_BUCK1_DVSARM1; + reg = MAX8998_REG_BUCK1_VOLTAGE1 + max8998->buck1_idx; break; case MAX8998_BUCK2: - reg = MAX8998_REG_BUCK2_DVSINT1; + reg = MAX8998_REG_BUCK2_VOLTAGE1 + max8998->buck2_idx; break; case MAX8998_BUCK3: reg = MAX8998_REG_BUCK3; @@ -276,6 +285,7 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev, static int max8998_get_voltage(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 0, mask, ret; u8 val; @@ -283,7 +293,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) if (ret) return ret; - ret = max8998_read_reg(max8998->iodev, reg, &val); + ret = max8998_read_reg(i2c, reg, &val); if (ret) return ret; @@ -293,18 +303,16 @@ static int max8998_get_voltage(struct regulator_dev *rdev) return max8998_list_voltage(rdev, val); } -static int max8998_set_voltage(struct regulator_dev *rdev, +static int max8998_set_voltage_ldo(struct regulator_dev *rdev, int min_uV, int max_uV) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - int previous_vol = 0; const struct voltage_map_desc *desc; int ldo = max8998_get_ldo(rdev); int reg, shift = 0, mask, ret; int i = 0; - u8 val; - bool en_ramp = false; if (ldo >= ARRAY_SIZE(ldo_voltage_map)) return -EINVAL; @@ -327,24 +335,155 @@ static int max8998_set_voltage(struct regulator_dev *rdev, if (ret) return ret; - /* wait for RAMP_UP_DELAY if rdev is BUCK1/2 and - * ENRAMP is ON */ - if (ldo == MAX8998_BUCK1 || ldo == MAX8998_BUCK2) { - max8998_read_reg(max8998->iodev, MAX8998_REG_ONOFF4, &val); - if (val & (1 << 4)) { - en_ramp = true; - previous_vol = max8998_get_voltage(rdev); - } + ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + + return ret; +} + +static inline void buck1_gpio_set(int gpio1, int gpio2, int v) +{ + gpio_set_value(gpio1, v & 0x1); + gpio_set_value(gpio2, (v >> 1) & 0x1); +} + +static inline void buck2_gpio_set(int gpio, int v) +{ + gpio_set_value(gpio, v & 0x1); +} + +static int max8998_set_voltage_buck(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct max8998_platform_data *pdata = + dev_get_platdata(max8998->iodev->dev); + struct i2c_client *i2c = max8998->iodev->i2c; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const struct voltage_map_desc *desc; + int buck = max8998_get_ldo(rdev); + int reg, shift = 0, mask, ret; + int difference = 0, i = 0, j = 0, previous_vol = 0; + u8 val = 0; + static u8 buck1_last_val; + + if (buck >= ARRAY_SIZE(ldo_voltage_map)) + return -EINVAL; + + desc = ldo_voltage_map[buck]; + + if (desc == NULL) + return -EINVAL; + + if (max_vol < desc->min || min_vol > desc->max) + return -EINVAL; + + while (desc->min + desc->step*i < min_vol && + desc->min + desc->step*i < desc->max) + i++; + + if (desc->min + desc->step*i > max_vol) + return -EINVAL; + + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + previous_vol = max8998_get_voltage(rdev); + + /* Check if voltage needs to be changed */ + /* if previous_voltage equal new voltage, return */ + if (previous_vol == max8998_list_voltage(rdev, i)) { + dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n", + previous_vol, max8998_list_voltage(rdev, i)); + return ret; } - ret = max8998_update_reg(max8998->iodev, reg, i<<shift, mask<<shift); + switch (buck) { + case MAX8998_BUCK1: + dev_dbg(max8998->dev, + "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n\ + buck1_vol3:%d, buck1_vol4:%d\n", + i, max8998->buck1_vol[0], max8998->buck1_vol[1], + max8998->buck1_vol[2], max8998->buck1_vol[3]); + + if (gpio_is_valid(pdata->buck1_set1) && + gpio_is_valid(pdata->buck1_set2)) { + + /* check if requested voltage */ + /* value is already defined */ + for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) { + if (max8998->buck1_vol[j] == i) { + max8998->buck1_idx = j; + buck1_gpio_set(pdata->buck1_set1, + pdata->buck1_set2, j); + goto buck1_exit; + } + } + + /* no predefine regulator found */ + max8998->buck1_idx = (buck1_last_val % 2) + 2; + dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n", + max8998->buck1_idx); + max8998->buck1_vol[max8998->buck1_idx] = i; + ret = max8998_get_voltage_register(rdev, ®, + &shift, + &mask); + ret = max8998_write_reg(i2c, reg, i); + buck1_gpio_set(pdata->buck1_set1, + pdata->buck1_set2, max8998->buck1_idx); + buck1_last_val++; +buck1_exit: + dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n", + i2c->name, gpio_get_value(pdata->buck1_set1), + gpio_get_value(pdata->buck1_set2)); + break; + } else { + ret = max8998_write_reg(i2c, reg, i); + } + break; + + case MAX8998_BUCK2: + dev_dbg(max8998->dev, + "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n" + , i, max8998->buck2_vol[0], max8998->buck2_vol[1]); + if (gpio_is_valid(pdata->buck2_set3)) { + if (max8998->buck2_vol[0] == i) { + max8998->buck1_idx = 0; + buck2_gpio_set(pdata->buck2_set3, 0); + } else { + max8998->buck1_idx = 1; + ret = max8998_get_voltage_register(rdev, ®, + &shift, + &mask); + ret = max8998_write_reg(i2c, reg, i); + max8998->buck2_vol[1] = i; + buck2_gpio_set(pdata->buck2_set3, 1); + } + dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, + gpio_get_value(pdata->buck2_set3)); + } else { + ret = max8998_write_reg(i2c, reg, i); + } + break; - if (en_ramp == true) { - int difference = desc->min + desc->step*i - previous_vol/1000; - if (difference > 0) - udelay(difference / ((val & 0x0f) + 1)); + case MAX8998_BUCK3: + case MAX8998_BUCK4: + ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + break; } + /* Voltage stabilization */ + max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val); + + /* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */ + /* MAX8998 has ENRAMP bit implemented, so test it*/ + if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) + return ret; + + difference = desc->min + desc->step*i - previous_vol/1000; + if (difference > 0) + udelay(difference / ((val & 0x0f) + 1)); + return ret; } @@ -354,7 +493,7 @@ static struct regulator_ops max8998_ldo_ops = { .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage = max8998_get_voltage, - .set_voltage = max8998_set_voltage, + .set_voltage = max8998_set_voltage_ldo, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, }; @@ -365,7 +504,7 @@ static struct regulator_ops max8998_buck_ops = { .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage = max8998_get_voltage, - .set_voltage = max8998_set_voltage, + .set_voltage = max8998_set_voltage_buck, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, }; @@ -538,6 +677,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct regulator_dev **rdev; struct max8998_data *max8998; + struct i2c_client *i2c; int i, ret, size; if (!pdata) { @@ -561,6 +701,86 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->iodev = iodev; max8998->num_regulators = pdata->num_regulators; platform_set_drvdata(pdev, max8998); + i2c = max8998->iodev->i2c; + + /* NOTE: */ + /* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */ + /* will be displayed */ + + /* Check if MAX8998 voltage selection GPIOs are defined */ + if (gpio_is_valid(pdata->buck1_set1) && + gpio_is_valid(pdata->buck1_set2)) { + /* Check if SET1 is not equal to 0 */ + if (!pdata->buck1_set1) { + printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck1_set1); + return -EIO; + } + /* Check if SET2 is not equal to 0 */ + if (!pdata->buck1_set2) { + printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck1_set2); + return -EIO; + } + + gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); + gpio_direction_output(pdata->buck1_set1, + max8998->buck1_idx & 0x1); + + + gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2"); + gpio_direction_output(pdata->buck1_set2, + (max8998->buck1_idx >> 1) & 0x1); + /* Set predefined value for BUCK1 register 1 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck1_max_voltage1 / 1000)) + i++; + printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); + max8998->buck1_vol[0] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); + + /* Set predefined value for BUCK1 register 2 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck1_max_voltage2 / 1000)) + i++; + + max8998->buck1_vol[1] = i; + printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i) + + ret; + if (ret) + return ret; + + } + + if (gpio_is_valid(pdata->buck2_set3)) { + /* Check if SET3 is not equal to 0 */ + if (!pdata->buck2_set3) { + printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck2_set3); + return -EIO; + } + gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); + gpio_direction_output(pdata->buck2_set3, + max8998->buck2_idx & 0x1); + + /* BUCK2 - set preset default voltage value to buck2_vol[0] */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck2_max_voltage / 1000)) + i++; + printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx); + max8998->buck2_vol[0] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); + if (ret) + return ret; + + } for (i = 0; i < pdata->num_regulators; i++) { const struct voltage_map_desc *desc; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6a77437d4f5a..2883428d5ac8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -196,6 +196,16 @@ config RTC_DRV_MAX8925 This driver can also be built as a module. If so, the module will be called rtc-max8925. +config RTC_DRV_MAX8998 + tristate "Maxim MAX8998" + depends on MFD_MAX8998 + help + If you say yes here you will get support for the + RTC of Maxim MAX8998 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8998. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help @@ -926,11 +936,12 @@ config RTC_DRV_PCAP If you say Y here you will get support for the RTC found on the PCAP2 ASIC used on some Motorola phones. -config RTC_DRV_MC13783 - depends on MFD_MC13783 - tristate "Freescale MC13783 RTC" +config RTC_DRV_MC13XXX + depends on MFD_MC13XXX + tristate "Freescale MC13xxx RTC" help - This enables support for the Freescale MC13783 PMIC RTC + This enables support for the RTCs found on Freescale's PMICs + MC13783 and MC13892. config RTC_DRV_MPC5121 tristate "Freescale MPC5121 built-in RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 7a7cb3228a1d..4c2832df4697 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -60,8 +60,9 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o +obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o -obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o +obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 2fda03125e55..e346705aae92 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -14,26 +14,26 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/rtc.h> +#include <linux/mfd/abx500.h> #include <linux/mfd/ab8500.h> #include <linux/delay.h> -#define AB8500_RTC_SOFF_STAT_REG 0x0F00 -#define AB8500_RTC_CC_CONF_REG 0x0F01 -#define AB8500_RTC_READ_REQ_REG 0x0F02 -#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03 -#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04 -#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05 -#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06 -#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07 -#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08 -#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09 -#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A -#define AB8500_RTC_STAT_REG 0x0F0B -#define AB8500_RTC_BKUP_CHG_REG 0x0F0C -#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D -#define AB8500_RTC_CALIB_REG 0x0F0E -#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F -#define AB8500_REV_REG 0x1080 +#define AB8500_RTC_SOFF_STAT_REG 0x00 +#define AB8500_RTC_CC_CONF_REG 0x01 +#define AB8500_RTC_READ_REQ_REG 0x02 +#define AB8500_RTC_WATCH_TSECMID_REG 0x03 +#define AB8500_RTC_WATCH_TSECHI_REG 0x04 +#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x05 +#define AB8500_RTC_WATCH_TMIN_MID_REG 0x06 +#define AB8500_RTC_WATCH_TMIN_HI_REG 0x07 +#define AB8500_RTC_ALRM_MIN_LOW_REG 0x08 +#define AB8500_RTC_ALRM_MIN_MID_REG 0x09 +#define AB8500_RTC_ALRM_MIN_HI_REG 0x0A +#define AB8500_RTC_STAT_REG 0x0B +#define AB8500_RTC_BKUP_CHG_REG 0x0C +#define AB8500_RTC_FORCE_BKUP_REG 0x0D +#define AB8500_RTC_CALIB_REG 0x0E +#define AB8500_RTC_SWITCH_STAT_REG 0x0F /* RtcReadRequest bits */ #define RTC_READ_REQUEST 0x01 @@ -46,13 +46,13 @@ #define COUNTS_PER_SEC (0xF000 / 60) #define AB8500_RTC_EPOCH 2000 -static const unsigned long ab8500_rtc_time_regs[] = { +static const u8 ab8500_rtc_time_regs[] = { AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG, AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG, AB8500_RTC_WATCH_TSECMID_REG }; -static const unsigned long ab8500_rtc_alarm_regs[] = { +static const u8 ab8500_rtc_alarm_regs[] = { AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG, AB8500_RTC_ALRM_MIN_LOW_REG }; @@ -76,29 +76,30 @@ static unsigned long get_elapsed_seconds(int year) static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); unsigned long timeout = jiffies + HZ; int retval, i; unsigned long mins, secs; unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; + u8 value; /* Request a data read */ - retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, - RTC_READ_REQUEST); + retval = abx500_set_register_interruptible(dev, + AB8500_RTC, AB8500_RTC_READ_REQ_REG, RTC_READ_REQUEST); if (retval < 0) return retval; /* Early AB8500 chips will not clear the rtc read request bit */ - if (ab8500->revision == 0) { + if (abx500_get_chip_id(dev) == 0) { msleep(1); } else { /* Wait for some cycles after enabling the rtc read in ab8500 */ while (time_before(jiffies, timeout)) { - retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG); + retval = abx500_get_register_interruptible(dev, + AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value); if (retval < 0) return retval; - if (!(retval & RTC_READ_REQUEST)) + if (!(value & RTC_READ_REQUEST)) break; msleep(1); @@ -107,10 +108,11 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) /* Read the Watchtime registers */ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { - retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]); + retval = abx500_get_register_interruptible(dev, + AB8500_RTC, ab8500_rtc_time_regs[i], &value); if (retval < 0) return retval; - buf[i] = retval; + buf[i] = value; } mins = (buf[0] << 16) | (buf[1] << 8) | buf[2]; @@ -128,7 +130,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; unsigned long no_secs, no_mins, secs = 0; @@ -162,27 +163,29 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[0] = (no_mins >> 16) & 0xFF; for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { - retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]); + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_time_regs[i], buf[i]); if (retval < 0) return retval; } /* Request a data write */ - return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); + return abx500_set_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); } static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; - int rtc_ctrl; + u8 rtc_ctrl, value; unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; unsigned long secs, mins; /* Check if the alarm is enabled or not */ - rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); - if (rtc_ctrl < 0) - return rtc_ctrl; + retval = abx500_get_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_STAT_REG, &rtc_ctrl); + if (retval < 0) + return retval; if (rtc_ctrl & RTC_ALARM_ENA) alarm->enabled = 1; @@ -192,10 +195,11 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) alarm->pending = 0; for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { - retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]); + retval = abx500_get_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_alarm_regs[i], &value); if (retval < 0) return retval; - buf[i] = retval; + buf[i] = value; } mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); @@ -211,15 +215,13 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); - - return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA, - enabled ? RTC_ALARM_ENA : 0); + return abx500_mask_and_set_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_STAT_REG, RTC_ALARM_ENA, + enabled ? RTC_ALARM_ENA : 0); } static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; unsigned long mins, secs = 0; @@ -247,7 +249,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* Set the alarm time */ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { - retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]); + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_alarm_regs[i], buf[i]); if (retval < 0) return retval; } @@ -276,10 +279,9 @@ static const struct rtc_class_ops ab8500_rtc_ops = { static int __devinit ab8500_rtc_probe(struct platform_device *pdev) { - struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); int err; struct rtc_device *rtc; - int rtc_ctrl; + u8 rtc_ctrl; int irq; irq = platform_get_irq_byname(pdev, "ALARM"); @@ -287,17 +289,18 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) return irq; /* For RTC supply test */ - err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA, - RTC_STATUS_DATA); + err = abx500_mask_and_set_register_interruptible(&pdev->dev, AB8500_RTC, + AB8500_RTC_STAT_REG, RTC_STATUS_DATA, RTC_STATUS_DATA); if (err < 0) return err; /* Wait for reset by the PorRtc */ msleep(1); - rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); - if (rtc_ctrl < 0) - return rtc_ctrl; + err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC, + AB8500_RTC_STAT_REG, &rtc_ctrl); + if (err < 0) + return err; /* Check if the RTC Supply fails */ if (!(rtc_ctrl & RTC_STATUS_DATA)) { diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c new file mode 100644 index 000000000000..f22dee35f330 --- /dev/null +++ b/drivers/rtc/rtc-max8998.c @@ -0,0 +1,300 @@ +/* + * RTC driver for Maxim MAX8998 + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Minkyu Kang <mk7.kang@samsung.com> + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * 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 <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/bcd.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/mfd/max8998.h> +#include <linux/mfd/max8998-private.h> + +#define MAX8998_RTC_SEC 0x00 +#define MAX8998_RTC_MIN 0x01 +#define MAX8998_RTC_HOUR 0x02 +#define MAX8998_RTC_WEEKDAY 0x03 +#define MAX8998_RTC_DATE 0x04 +#define MAX8998_RTC_MONTH 0x05 +#define MAX8998_RTC_YEAR1 0x06 +#define MAX8998_RTC_YEAR2 0x07 +#define MAX8998_ALARM0_SEC 0x08 +#define MAX8998_ALARM0_MIN 0x09 +#define MAX8998_ALARM0_HOUR 0x0a +#define MAX8998_ALARM0_WEEKDAY 0x0b +#define MAX8998_ALARM0_DATE 0x0c +#define MAX8998_ALARM0_MONTH 0x0d +#define MAX8998_ALARM0_YEAR1 0x0e +#define MAX8998_ALARM0_YEAR2 0x0f +#define MAX8998_ALARM1_SEC 0x10 +#define MAX8998_ALARM1_MIN 0x11 +#define MAX8998_ALARM1_HOUR 0x12 +#define MAX8998_ALARM1_WEEKDAY 0x13 +#define MAX8998_ALARM1_DATE 0x14 +#define MAX8998_ALARM1_MONTH 0x15 +#define MAX8998_ALARM1_YEAR1 0x16 +#define MAX8998_ALARM1_YEAR2 0x17 +#define MAX8998_ALARM0_CONF 0x18 +#define MAX8998_ALARM1_CONF 0x19 +#define MAX8998_RTC_STATUS 0x1a +#define MAX8998_WTSR_SMPL_CNTL 0x1b +#define MAX8998_TEST 0x1f + +#define HOUR_12 (1 << 7) +#define HOUR_PM (1 << 5) +#define ALARM0_STATUS (1 << 1) +#define ALARM1_STATUS (1 << 2) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +struct max8998_rtc_info { + struct device *dev; + struct max8998_dev *max8998; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + int irq; +}; + +static void max8998_data_to_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC]); + tm->tm_min = bcd2bin(data[RTC_MIN]); + if (data[RTC_HOUR] & HOUR_12) { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); + if (data[RTC_HOUR] & HOUR_PM) + tm->tm_hour += 12; + } else + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + + tm->tm_wday = data[RTC_WEEKDAY] & 0x07; + tm->tm_mday = bcd2bin(data[RTC_DATE]); + tm->tm_mon = bcd2bin(data[RTC_MONTH]); + tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; + tm->tm_year -= 1900; +} + +static void max8998_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WEEKDAY] = tm->tm_wday; + data[RTC_DATE] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon); + data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); + data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); +} + +static int max8998_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + ret = max8998_bulk_read(info->rtc, MAX8998_RTC_SEC, 8, data); + if (ret < 0) + return ret; + + max8998_data_to_tm(data, tm); + + return rtc_valid_tm(tm); +} + +static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + + max8998_tm_to_data(tm, data); + + return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data); +} + +static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + u8 val; + int ret; + + ret = max8998_bulk_read(info->rtc, MAX8998_ALARM0_SEC, 8, data); + if (ret < 0) + return ret; + + max8998_data_to_tm(data, &alrm->time); + + ret = max8998_read_reg(info->rtc, MAX8998_ALARM0_CONF, &val); + if (ret < 0) + return ret; + + alrm->enabled = !!val; + + ret = max8998_read_reg(info->rtc, MAX8998_RTC_STATUS, &val); + if (ret < 0) + return ret; + + if (val & ALARM0_STATUS) + alrm->pending = 1; + else + alrm->pending = 0; + + return 0; +} + +static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info) +{ + return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0); +} + +static int max8998_rtc_start_alarm(struct max8998_rtc_info *info) +{ + return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77); +} + +static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + max8998_tm_to_data(&alrm->time, data); + + ret = max8998_rtc_stop_alarm(info); + if (ret < 0) + return ret; + + ret = max8998_bulk_write(info->rtc, MAX8998_ALARM0_SEC, 8, data); + if (ret < 0) + return ret; + + if (alrm->enabled) + return max8998_rtc_start_alarm(info); + + return 0; +} + +static int max8998_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + return max8998_rtc_start_alarm(info); + else + return max8998_rtc_stop_alarm(info); +} + +static irqreturn_t max8998_rtc_alarm_irq(int irq, void *data) +{ + struct max8998_rtc_info *info = data; + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max8998_rtc_ops = { + .read_time = max8998_rtc_read_time, + .set_time = max8998_rtc_set_time, + .read_alarm = max8998_rtc_read_alarm, + .set_alarm = max8998_rtc_set_alarm, + .alarm_irq_enable = max8998_rtc_alarm_irq_enable, +}; + +static int __devinit max8998_rtc_probe(struct platform_device *pdev) +{ + struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent); + struct max8998_rtc_info *info; + int ret; + + info = kzalloc(sizeof(struct max8998_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + info->max8998 = max8998; + info->rtc = max8998->rtc; + info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; + + info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, + &max8998_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + goto out_rtc; + } + + platform_set_drvdata(pdev, info); + + ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->irq, ret); + + return 0; + +out_rtc: + kfree(info); + return ret; +} + +static int __devexit max8998_rtc_remove(struct platform_device *pdev) +{ + struct max8998_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->irq, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + + return 0; +} + +static struct platform_driver max8998_rtc_driver = { + .driver = { + .name = "max8998-rtc", + .owner = THIS_MODULE, + }, + .probe = max8998_rtc_probe, + .remove = __devexit_p(max8998_rtc_remove), +}; + +static int __init max8998_rtc_init(void) +{ + return platform_driver_register(&max8998_rtc_driver); +} +module_init(max8998_rtc_init); + +static void __exit max8998_rtc_exit(void) +{ + platform_driver_unregister(&max8998_rtc_driver); +} +module_exit(max8998_rtc_exit); + +MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); +MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); +MODULE_DESCRIPTION("Maxim MAX8998 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c deleted file mode 100644 index 675bfb515367..000000000000 --- a/drivers/rtc/rtc-mc13783.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Real Time Clock driver for Freescale MC13783 PMIC - * - * (C) 2009 Sascha Hauer, Pengutronix - * (C) 2009 Uwe Kleine-Koenig, Pengutronix - * - * 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 <linux/mfd/mc13783.h> -#include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/rtc.h> - -#define DRIVER_NAME "mc13783-rtc" - -#define MC13783_RTCTOD 20 -#define MC13783_RTCTODA 21 -#define MC13783_RTCDAY 22 -#define MC13783_RTCDAYA 23 - -struct mc13783_rtc { - struct rtc_device *rtc; - struct mc13783 *mc13783; - int valid; -}; - -static int mc13783_rtc_irq_enable_unlocked(struct device *dev, - unsigned int enabled, int irq) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - int (*func)(struct mc13783 *mc13783, int irq); - - if (!priv->valid) - return -ENODATA; - - func = enabled ? mc13783_irq_unmask : mc13783_irq_mask; - return func(priv->mc13783, irq); -} - -static int mc13783_rtc_irq_enable(struct device *dev, - unsigned int enabled, int irq) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - int ret; - - mc13783_lock(priv->mc13783); - - ret = mc13783_rtc_irq_enable_unlocked(dev, enabled, irq); - - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned int seconds, days1, days2; - unsigned long s1970; - int ret; - - mc13783_lock(priv->mc13783); - - if (!priv->valid) { - ret = -ENODATA; - goto out; - } - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2); -out: - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - if (days2 == days1 + 1) { - if (seconds >= 86400 / 2) - days2 = days1; - else - days1 = days2; - } - - if (days1 != days2) - return -EIO; - - s1970 = days1 * 86400 + seconds; - - rtc_time_to_tm(s1970, tm); - - return rtc_valid_tm(tm); -} - -static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned int seconds, days; - unsigned int alarmseconds; - int ret; - - seconds = secs % 86400; - days = secs / 86400; - - mc13783_lock(priv->mc13783); - - /* - * temporarily invalidate alarm to prevent triggering it when the day is - * already updated while the time isn't yet. - */ - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &alarmseconds); - if (unlikely(ret)) - goto out; - - if (alarmseconds < 86400) { - ret = mc13783_reg_write(priv->mc13783, - MC13783_RTCTODA, 0x1ffff); - if (unlikely(ret)) - goto out; - } - - /* - * write seconds=0 to prevent a day switch between writing days - * and seconds below - */ - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds); - if (unlikely(ret)) - goto out; - - /* restore alarm */ - if (alarmseconds < 86400) { - ret = mc13783_reg_write(priv->mc13783, - MC13783_RTCTODA, alarmseconds); - if (unlikely(ret)) - goto out; - } - - ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST); - if (unlikely(ret)) - goto out; - - ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST); -out: - priv->valid = !ret; - - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned seconds, days; - unsigned long s1970; - int enabled, pending; - int ret; - - mc13783_lock(priv->mc13783); - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &seconds); - if (unlikely(ret)) - goto out; - if (seconds >= 86400) { - ret = -ENODATA; - goto out; - } - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days); - if (unlikely(ret)) - goto out; - - ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_TODA, - &enabled, &pending); - -out: - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - alarm->enabled = enabled; - alarm->pending = pending; - - s1970 = days * 86400 + seconds; - - rtc_time_to_tm(s1970, &alarm->time); - dev_dbg(dev, "%s: %lu\n", __func__, s1970); - - return 0; -} - -static int mc13783_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned long s1970; - unsigned seconds, days; - int ret; - - mc13783_lock(priv->mc13783); - - /* disable alarm to prevent false triggering */ - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, 0x1ffff); - if (unlikely(ret)) - goto out; - - ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TODA); - if (unlikely(ret)) - goto out; - - ret = rtc_tm_to_time(&alarm->time, &s1970); - if (unlikely(ret)) - goto out; - - dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff", - s1970); - - ret = mc13783_rtc_irq_enable_unlocked(dev, alarm->enabled, - MC13783_IRQ_TODA); - if (unlikely(ret)) - goto out; - - seconds = s1970 % 86400; - days = s1970 / 86400; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAYA, days); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, seconds); - -out: - mc13783_unlock(priv->mc13783); - - return ret; -} - -static irqreturn_t mc13783_rtc_alarm_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "Alarm\n"); - - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); - - mc13783_irq_ack(mc13783, irq); - - return IRQ_HANDLED; -} - -static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "1HZ\n"); - - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); - - mc13783_irq_ack(mc13783, irq); - - return IRQ_HANDLED; -} - -static int mc13783_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ); -} - -static int mc13783_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) -{ - return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_TODA); -} - -static const struct rtc_class_ops mc13783_rtc_ops = { - .read_time = mc13783_rtc_read_time, - .set_mmss = mc13783_rtc_set_mmss, - .read_alarm = mc13783_rtc_read_alarm, - .set_alarm = mc13783_rtc_set_alarm, - .alarm_irq_enable = mc13783_rtc_alarm_irq_enable, - .update_irq_enable = mc13783_rtc_update_irq_enable, -}; - -static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "RTCRST\n"); - priv->valid = 0; - - mc13783_irq_mask(mc13783, irq); - - return IRQ_HANDLED; -} - -static int __devinit mc13783_rtc_probe(struct platform_device *pdev) -{ - int ret; - struct mc13783_rtc *priv; - struct mc13783 *mc13783; - int rtcrst_pending; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - mc13783 = dev_get_drvdata(pdev->dev.parent); - priv->mc13783 = mc13783; - - platform_set_drvdata(pdev, priv); - - mc13783_lock(mc13783); - - ret = mc13783_irq_request(mc13783, MC13783_IRQ_RTCRST, - mc13783_rtc_reset_handler, DRIVER_NAME, priv); - if (ret) - goto err_reset_irq_request; - - ret = mc13783_irq_status(mc13783, MC13783_IRQ_RTCRST, - NULL, &rtcrst_pending); - if (ret) - goto err_reset_irq_status; - - priv->valid = !rtcrst_pending; - - ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_1HZ, - mc13783_rtc_update_handler, DRIVER_NAME, priv); - if (ret) - goto err_update_irq_request; - - ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_TODA, - mc13783_rtc_alarm_handler, DRIVER_NAME, priv); - if (ret) - goto err_alarm_irq_request; - - priv->rtc = rtc_device_register(pdev->name, - &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) { - ret = PTR_ERR(priv->rtc); - - mc13783_irq_free(mc13783, MC13783_IRQ_TODA, priv); -err_alarm_irq_request: - - mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv); -err_update_irq_request: - -err_reset_irq_status: - - mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv); -err_reset_irq_request: - - platform_set_drvdata(pdev, NULL); - kfree(priv); - } - - mc13783_unlock(mc13783); - - return ret; -} - -static int __devexit mc13783_rtc_remove(struct platform_device *pdev) -{ - struct mc13783_rtc *priv = platform_get_drvdata(pdev); - - mc13783_lock(priv->mc13783); - - rtc_device_unregister(priv->rtc); - - mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); - - mc13783_unlock(priv->mc13783); - - platform_set_drvdata(pdev, NULL); - - kfree(priv); - - return 0; -} - -static struct platform_driver mc13783_rtc_driver = { - .remove = __devexit_p(mc13783_rtc_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mc13783_rtc_init(void) -{ - return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe); -} -module_init(mc13783_rtc_init); - -static void __exit mc13783_rtc_exit(void) -{ - platform_driver_unregister(&mc13783_rtc_driver); -} -module_exit(mc13783_rtc_exit); - -MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); -MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c new file mode 100644 index 000000000000..5314b153bfba --- /dev/null +++ b/drivers/rtc/rtc-mc13xxx.c @@ -0,0 +1,437 @@ +/* + * Real Time Clock driver for Freescale MC13XXX PMIC + * + * (C) 2009 Sascha Hauer, Pengutronix + * (C) 2009 Uwe Kleine-Koenig, Pengutronix + * + * 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 <linux/mfd/mc13xxx.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/rtc.h> + +#define DRIVER_NAME "mc13xxx-rtc" + +#define MC13XXX_RTCTOD 20 +#define MC13XXX_RTCTODA 21 +#define MC13XXX_RTCDAY 22 +#define MC13XXX_RTCDAYA 23 + +struct mc13xxx_rtc { + struct rtc_device *rtc; + struct mc13xxx *mc13xxx; + int valid; +}; + +static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + int (*func)(struct mc13xxx *mc13xxx, int irq); + + if (!priv->valid) + return -ENODATA; + + func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask; + return func(priv->mc13xxx, irq); +} + +static int mc13xxx_rtc_irq_enable(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + int ret; + + mc13xxx_lock(priv->mc13xxx); + + ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq); + + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned int seconds, days1, days2; + unsigned long s1970; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + if (!priv->valid) { + ret = -ENODATA; + goto out; + } + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); +out: + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + if (days2 == days1 + 1) { + if (seconds >= 86400 / 2) + days2 = days1; + else + days1 = days2; + } + + if (days1 != days2) + return -EIO; + + s1970 = days1 * 86400 + seconds; + + rtc_time_to_tm(s1970, tm); + + return rtc_valid_tm(tm); +} + +static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned int seconds, days; + unsigned int alarmseconds; + int ret; + + seconds = secs % 86400; + days = secs / 86400; + + mc13xxx_lock(priv->mc13xxx); + + /* + * temporarily invalidate alarm to prevent triggering it when the day is + * already updated while the time isn't yet. + */ + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds); + if (unlikely(ret)) + goto out; + + if (alarmseconds < 86400) { + ret = mc13xxx_reg_write(priv->mc13xxx, + MC13XXX_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + } + + /* + * write seconds=0 to prevent a day switch between writing days + * and seconds below + */ + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds); + if (unlikely(ret)) + goto out; + + /* restore alarm */ + if (alarmseconds < 86400) { + ret = mc13xxx_reg_write(priv->mc13xxx, + MC13XXX_RTCTODA, alarmseconds); + if (unlikely(ret)) + goto out; + } + + ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); +out: + priv->valid = !ret; + + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned seconds, days; + unsigned long s1970; + int enabled, pending; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds); + if (unlikely(ret)) + goto out; + if (seconds >= 86400) { + ret = -ENODATA; + goto out; + } + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA, + &enabled, &pending); + +out: + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + alarm->enabled = enabled; + alarm->pending = pending; + + s1970 = days * 86400 + seconds; + + rtc_time_to_tm(s1970, &alarm->time); + dev_dbg(dev, "%s: %lu\n", __func__, s1970); + + return 0; +} + +static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned long s1970; + unsigned seconds, days; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + /* disable alarm to prevent false triggering */ + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA); + if (unlikely(ret)) + goto out; + + ret = rtc_tm_to_time(&alarm->time, &s1970); + if (unlikely(ret)) + goto out; + + dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff", + s1970); + + ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled, + MC13XXX_IRQ_TODA); + if (unlikely(ret)) + goto out; + + seconds = s1970 % 86400; + days = s1970 / 86400; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds); + +out: + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "Alarm\n"); + + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); + + mc13xxx_irq_ack(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "1HZ\n"); + + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); + + mc13xxx_irq_ack(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static int mc13xxx_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) +{ + return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_1HZ); +} + +static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA); +} + +static const struct rtc_class_ops mc13xxx_rtc_ops = { + .read_time = mc13xxx_rtc_read_time, + .set_mmss = mc13xxx_rtc_set_mmss, + .read_alarm = mc13xxx_rtc_read_alarm, + .set_alarm = mc13xxx_rtc_set_alarm, + .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable, + .update_irq_enable = mc13xxx_rtc_update_irq_enable, +}; + +static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "RTCRST\n"); + priv->valid = 0; + + mc13xxx_irq_mask(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) +{ + int ret; + struct mc13xxx_rtc *priv; + struct mc13xxx *mc13xxx; + int rtcrst_pending; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mc13xxx = dev_get_drvdata(pdev->dev.parent); + priv->mc13xxx = mc13xxx; + + platform_set_drvdata(pdev, priv); + + mc13xxx_lock(mc13xxx); + + ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST, + mc13xxx_rtc_reset_handler, DRIVER_NAME, priv); + if (ret) + goto err_reset_irq_request; + + ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST, + NULL, &rtcrst_pending); + if (ret) + goto err_reset_irq_status; + + priv->valid = !rtcrst_pending; + + ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ, + mc13xxx_rtc_update_handler, DRIVER_NAME, priv); + if (ret) + goto err_update_irq_request; + + ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA, + mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv); + if (ret) + goto err_alarm_irq_request; + + priv->rtc = rtc_device_register(pdev->name, + &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); +err_alarm_irq_request: + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); +err_update_irq_request: + +err_reset_irq_status: + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); +err_reset_irq_request: + + platform_set_drvdata(pdev, NULL); + kfree(priv); + } + + mc13xxx_unlock(mc13xxx); + + return ret; +} + +static int __devexit mc13xxx_rtc_remove(struct platform_device *pdev) +{ + struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); + + mc13xxx_lock(priv->mc13xxx); + + rtc_device_unregister(priv->rtc); + + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv); + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv); + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv); + + mc13xxx_unlock(priv->mc13xxx); + + platform_set_drvdata(pdev, NULL); + + kfree(priv); + + return 0; +} + +const struct platform_device_id mc13xxx_rtc_idtable[] = { + { + .name = "mc13783-rtc", + }, { + .name = "mc13892-rtc", + }, +}; + +static struct platform_driver mc13xxx_rtc_driver = { + .id_table = mc13xxx_rtc_idtable, + .remove = __devexit_p(mc13xxx_rtc_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init mc13xxx_rtc_init(void) +{ + return platform_driver_probe(&mc13xxx_rtc_driver, &mc13xxx_rtc_probe); +} +module_init(mc13xxx_rtc_init); + +static void __exit mc13xxx_rtc_exit(void) +{ + platform_driver_unregister(&mc13xxx_rtc_driver); +} +module_exit(mc13xxx_rtc_exit); + +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 50cf96389d2c..bf61274af3bb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2802,6 +2802,73 @@ dasd_eckd_steal_lock(struct dasd_device *device) } /* + * SNID - Sense Path Group ID + * This ioctl may be used in situations where I/O is stalled due to + * a reserve, so if the normal dasd_smalloc_request fails, we use the + * preallocated dasd_reserve_req. + */ +static int dasd_eckd_snid(struct dasd_device *device, + void __user *argp) +{ + struct dasd_ccw_req *cqr; + int rc; + struct ccw1 *ccw; + int useglobal; + struct dasd_snid_ioctl_data usrparm; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (copy_from_user(&usrparm, argp, sizeof(usrparm))) + return -EFAULT; + + useglobal = 0; + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, + sizeof(struct dasd_snid_data), device); + if (IS_ERR(cqr)) { + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; + } + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SNID; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 12; + ccw->cda = (__u32)(addr_t) cqr->data; + cqr->startdev = device; + cqr->memdev = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->retries = 5; + cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->lpm = usrparm.path_mask; + + rc = dasd_sleep_on_immediatly(cqr); + /* verify that I/O processing didn't modify the path mask */ + if (!rc && usrparm.path_mask && (cqr->lpm != usrparm.path_mask)) + rc = -EIO; + if (!rc) { + usrparm.data = *((struct dasd_snid_data *)cqr->data); + if (copy_to_user(argp, &usrparm, sizeof(usrparm))) + rc = -EFAULT; + } + + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); + return rc; +} + +/* * Read performance statistics */ static int @@ -3036,6 +3103,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) return dasd_eckd_reserve(device); case BIODASDSLCK: return dasd_eckd_steal_lock(device); + case BIODASDSNID: + return dasd_eckd_snid(device, argp); case BIODASDSYMMIO: return dasd_symm_io(device, argp); default: diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 0eb49655a6cd..12097c24f2f5 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -27,6 +27,7 @@ #define DASD_ECKD_CCW_WRITE_CKD 0x1d #define DASD_ECKD_CCW_READ_CKD 0x1e #define DASD_ECKD_CCW_PSF 0x27 +#define DASD_ECKD_CCW_SNID 0x34 #define DASD_ECKD_CCW_RSSD 0x3e #define DASD_ECKD_CCW_LOCATE_RECORD 0x47 #define DASD_ECKD_CCW_SNSS 0x54 diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 29c2d73d719d..6c408670e08d 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -1077,15 +1077,14 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* FIXME: What to do with the request? */ switch (PTR_ERR(irb)) { case -ETIMEDOUT: - DBF_LH(1, "(%s): Request timed out\n", - dev_name(&cdev->dev)); + DBF_LH(1, "(%08x): Request timed out\n", + device->cdev_id); case -EIO: __tape_end_request(device, request, -EIO); break; default: - DBF_LH(1, "(%s): Unexpected i/o error %li\n", - dev_name(&cdev->dev), - PTR_ERR(irb)); + DBF_LH(1, "(%08x): Unexpected i/o error %li\n", + device->cdev_id, PTR_ERR(irb)); } return; } diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 03f07e5dd6e9..3c3f342149ec 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -47,8 +47,8 @@ tape_std_assign_timeout(unsigned long data) device->cdev_id); rc = tape_cancel_io(device, request); if(rc) - DBF_EVENT(3, "(%s): Assign timeout: Cancel failed with rc = %i\n", - dev_name(&device->cdev->dev), rc); + DBF_EVENT(3, "(%08x): Assign timeout: Cancel failed with rc = " + "%i\n", device->cdev_id, rc); } int diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index f9c9c8a397db..5eafdf435550 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -87,8 +87,6 @@ source "drivers/staging/rtl8712/Kconfig" source "drivers/staging/frontier/Kconfig" -source "drivers/staging/dream/Kconfig" - source "drivers/staging/pohmelfs/Kconfig" source "drivers/staging/autofs/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a85074f8321b..a97a955c094b 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -28,7 +28,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_SPECTRA) += spectra/ obj-$(CONFIG_TRANZPORT) += frontier/ -obj-$(CONFIG_DREAM) += dream/ obj-$(CONFIG_POHMELFS) += pohmelfs/ obj-$(CONFIG_AUTOFS_FS) += autofs/ obj-$(CONFIG_IDE_PHISON) += phison/ diff --git a/drivers/staging/autofs/init.c b/drivers/staging/autofs/init.c index 765c72f42976..5e4b372ea663 100644 --- a/drivers/staging/autofs/init.c +++ b/drivers/staging/autofs/init.c @@ -14,16 +14,16 @@ #include <linux/init.h> #include "autofs_i.h" -static int autofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *autofs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, autofs_fill_super, mnt); + return mount_nodev(fs_type, flags, data, autofs_fill_super); } static struct file_system_type autofs_fs_type = { .owner = THIS_MODULE, .name = "autofs", - .get_sb = autofs_get_sb, + .mount = autofs_mount, .kill_sb = autofs_kill_sb, }; diff --git a/drivers/staging/dream/Kconfig b/drivers/staging/dream/Kconfig deleted file mode 100644 index 0c30b19a5a7c..000000000000 --- a/drivers/staging/dream/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config DREAM - tristate "HTC Dream support" - depends on MACH_TROUT - -if DREAM - -source "drivers/staging/dream/camera/Kconfig" - -config INPUT_GPIO - tristate "GPIO driver support" - help - Say Y here if you want to support gpio based keys, wheels etc... -endif diff --git a/drivers/staging/dream/Makefile b/drivers/staging/dream/Makefile deleted file mode 100644 index 87de1a57f237..000000000000 --- a/drivers/staging/dream/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ccflags-y:=-Idrivers/staging/dream/include -obj-$(CONFIG_MSM_ADSP) += qdsp5/ -obj-$(CONFIG_MSM_CAMERA) += camera/ -obj-$(CONFIG_INPUT_GPIO) += gpio_axis.o gpio_event.o gpio_input.o gpio_matrix.o gpio_output.o - diff --git a/drivers/staging/dream/TODO b/drivers/staging/dream/TODO deleted file mode 100644 index dcd3ba808655..000000000000 --- a/drivers/staging/dream/TODO +++ /dev/null @@ -1,13 +0,0 @@ - -* camera driver uses old V4L API - -* coding style in some places is lacking - -* gpio_input.c has some features matrix_keypad lacks. They should be -merged to gpio_input, with gpio_input.c removed - -* pmem provides interface for userspace. Needs to be reviewed at least. - -* it is probably possible to simplify touchscreen driver using threaded_irq's. - -* touchscreen driver should be switched to oficial multitouch API diff --git a/drivers/staging/dream/camera/Kconfig b/drivers/staging/dream/camera/Kconfig deleted file mode 100644 index bfb6d241d807..000000000000 --- a/drivers/staging/dream/camera/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -comment "Qualcomm MSM Camera And Video" - -menuconfig MSM_CAMERA - bool "Qualcomm MSM camera and video capture support" - depends on ARCH_MSM && VIDEO_V4L2_COMMON - help - Say Y here to enable selecting the video adapters for - Qualcomm msm camera and video encoding - -config MSM_CAMERA_DEBUG - bool "Qualcomm MSM camera debugging with printk" - depends on MSM_CAMERA - help - Enable printk() debug for msm camera - -config MSM_CAMERA_FLASH - bool "Qualcomm MSM camera flash support" - depends on MSM_CAMERA && BROKEN - ---help--- - Enable support for LED flash for msm camera - - -comment "Camera Sensor Selection" -config MT9T013 - bool "Sensor mt9t013 (BAYER 3M)" - depends on MSM_CAMERA - ---help--- - MICRON 3M Bayer Sensor with AutoFocus - -config MT9D112 - bool "Sensor mt9d112 (YUV 2M)" - depends on MSM_CAMERA - ---help--- - MICRON 2M YUV Sensor - -config MT9P012 - bool "Sensor mt9p012 (BAYER 5M)" - depends on MSM_CAMERA - ---help--- - MICRON 5M Bayer Sensor with Autofocus - -config S5K3E2FX - bool "Sensor s5k3e2fx (Samsung 5M)" - depends on MSM_CAMERA - ---help--- - Samsung 5M with Autofocus diff --git a/drivers/staging/dream/camera/Makefile b/drivers/staging/dream/camera/Makefile deleted file mode 100644 index 03711dc6f482..000000000000 --- a/drivers/staging/dream/camera/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -ccflags-y:=-Idrivers/staging/dream/include -obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o -obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o -obj-$(CONFIG_MT9P012) += mt9p012_fox.o mt9p012_reg.o -obj-$(CONFIG_MSM_CAMERA) += msm_camera.o msm_v4l2.o -obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o -obj-$(CONFIG_ARCH_MSM) += msm_vfe7x.o msm_io7x.o -obj-$(CONFIG_ARCH_QSD) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o diff --git a/drivers/staging/dream/camera/msm_camera.c b/drivers/staging/dream/camera/msm_camera.c deleted file mode 100644 index de4ab61efd4b..000000000000 --- a/drivers/staging/dream/camera/msm_camera.c +++ /dev/null @@ -1,2181 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -/* FIXME: most allocations need not be GFP_ATOMIC */ -/* FIXME: management of mutexes */ -/* FIXME: msm_pmem_region_lookup return values */ -/* FIXME: way too many copy to/from user */ -/* FIXME: does region->active mean free */ -/* FIXME: check limits on command lenghts passed from userspace */ -/* FIXME: __msm_release: which queues should we flush when opencnt != 0 */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <mach/board.h> - -#include <linux/fs.h> -#include <linux/list.h> -#include <linux/uaccess.h> -#include <linux/android_pmem.h> -#include <linux/poll.h> -#include <media/msm_camera.h> -#include <mach/camera.h> - -#define MSM_MAX_CAMERA_SENSORS 5 - -#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \ - __func__, __LINE__, ((to) ? "to" : "from")) -#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) -#define ERR_COPY_TO_USER() ERR_USER_COPY(1) - -static struct class *msm_class; -static dev_t msm_devno; -static LIST_HEAD(msm_sensors); - -#define __CONTAINS(r, v, l, field) ({ \ - typeof(r) __r = r; \ - typeof(v) __v = v; \ - typeof(v) __e = __v + l; \ - int res = __v >= __r->field && \ - __e <= __r->field + __r->len; \ - res; \ -}) - -#define CONTAINS(r1, r2, field) ({ \ - typeof(r2) __r2 = r2; \ - __CONTAINS(r1, __r2->field, __r2->len, field); \ -}) - -#define IN_RANGE(r, v, field) ({ \ - typeof(r) __r = r; \ - typeof(v) __vv = v; \ - int res = ((__vv >= __r->field) && \ - (__vv < (__r->field + __r->len))); \ - res; \ -}) - -#define OVERLAPS(r1, r2, field) ({ \ - typeof(r1) __r1 = r1; \ - typeof(r2) __r2 = r2; \ - typeof(__r2->field) __v = __r2->field; \ - typeof(__v) __e = __v + __r2->len - 1; \ - int res = (IN_RANGE(__r1, __v, field) || \ - IN_RANGE(__r1, __e, field)); \ - res; \ -}) - -#define MSM_DRAIN_QUEUE_NOSYNC(sync, name) do { \ - struct msm_queue_cmd *qcmd = NULL; \ - CDBG("%s: draining queue "#name"\n", __func__); \ - while (!list_empty(&(sync)->name)) { \ - qcmd = list_first_entry(&(sync)->name, \ - struct msm_queue_cmd, list); \ - list_del_init(&qcmd->list); \ - kfree(qcmd); \ - }; \ -} while (0) - -#define MSM_DRAIN_QUEUE(sync, name) do { \ - unsigned long flags; \ - spin_lock_irqsave(&(sync)->name##_lock, flags); \ - MSM_DRAIN_QUEUE_NOSYNC(sync, name); \ - spin_unlock_irqrestore(&(sync)->name##_lock, flags); \ -} while (0) - -static int check_overlap(struct hlist_head *ptype, - unsigned long paddr, - unsigned long len) -{ - struct msm_pmem_region *region; - struct msm_pmem_region t = { .paddr = paddr, .len = len }; - struct hlist_node *node; - - hlist_for_each_entry(region, node, ptype, list) { - if (CONTAINS(region, &t, paddr) || - CONTAINS(&t, region, paddr) || - OVERLAPS(region, &t, paddr)) { - printk(KERN_ERR - " region (PHYS %p len %ld)" - " clashes with registered region" - " (paddr %p len %ld)\n", - (void *)t.paddr, t.len, - (void *)region->paddr, region->len); - return -1; - } - } - - return 0; -} - -static int msm_pmem_table_add(struct hlist_head *ptype, - struct msm_pmem_info *info) -{ - struct file *file; - unsigned long paddr; - unsigned long vstart; - unsigned long len; - int rc; - struct msm_pmem_region *region; - - rc = get_pmem_file(info->fd, &paddr, &vstart, &len, &file); - if (rc < 0) { - pr_err("msm_pmem_table_add: get_pmem_file fd %d error %d\n", - info->fd, rc); - return rc; - } - - if (check_overlap(ptype, paddr, len) < 0) - return -EINVAL; - - CDBG("%s: type = %d, paddr = 0x%lx, vaddr = 0x%lx\n", - __func__, - info->type, paddr, (unsigned long)info->vaddr); - - region = kmalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - - INIT_HLIST_NODE(®ion->list); - - region->type = info->type; - region->vaddr = info->vaddr; - region->paddr = paddr; - region->len = len; - region->file = file; - region->y_off = info->y_off; - region->cbcr_off = info->cbcr_off; - region->fd = info->fd; - region->active = info->active; - - hlist_add_head(&(region->list), ptype); - - return 0; -} - -/* return of 0 means failure */ -static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype, - int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount) -{ - struct msm_pmem_region *region; - struct msm_pmem_region *regptr; - struct hlist_node *node, *n; - - uint8_t rc = 0; - - regptr = reg; - - hlist_for_each_entry_safe(region, node, n, ptype, list) { - if (region->type == pmem_type && region->active) { - *regptr = *region; - rc += 1; - if (rc >= maxcount) - break; - regptr++; - } - } - - return rc; -} - -static unsigned long msm_pmem_frame_ptov_lookup(struct msm_sync *sync, - unsigned long pyaddr, - unsigned long pcbcraddr, - uint32_t *yoff, uint32_t *cbcroff, int *fd) -{ - struct msm_pmem_region *region; - struct hlist_node *node, *n; - - hlist_for_each_entry_safe(region, node, n, &sync->frame, list) { - if (pyaddr == (region->paddr + region->y_off) && - pcbcraddr == (region->paddr + - region->cbcr_off) && - region->active) { - /* offset since we could pass vaddr inside - * a registerd pmem buffer - */ - *yoff = region->y_off; - *cbcroff = region->cbcr_off; - *fd = region->fd; - region->active = 0; - return (unsigned long)(region->vaddr); - } - } - - return 0; -} - -static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync, - unsigned long addr, int *fd) -{ - struct msm_pmem_region *region; - struct hlist_node *node, *n; - - hlist_for_each_entry_safe(region, node, n, &sync->stats, list) { - if (addr == region->paddr && region->active) { - /* offset since we could pass vaddr inside a - * registered pmem buffer */ - *fd = region->fd; - region->active = 0; - return (unsigned long)(region->vaddr); - } - } - - return 0; -} - -static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync, - unsigned long buffer, - uint32_t yoff, uint32_t cbcroff, int fd) -{ - struct msm_pmem_region *region; - struct hlist_node *node, *n; - - hlist_for_each_entry_safe(region, - node, n, &sync->frame, list) { - if (((unsigned long)(region->vaddr) == buffer) && - (region->y_off == yoff) && - (region->cbcr_off == cbcroff) && - (region->fd == fd) && - (region->active == 0)) { - - region->active = 1; - return region->paddr; - } - } - - return 0; -} - -static unsigned long msm_pmem_stats_vtop_lookup( - struct msm_sync *sync, - unsigned long buffer, - int fd) -{ - struct msm_pmem_region *region; - struct hlist_node *node, *n; - - hlist_for_each_entry_safe(region, node, n, &sync->stats, list) { - if (((unsigned long)(region->vaddr) == buffer) && - (region->fd == fd) && region->active == 0) { - region->active = 1; - return region->paddr; - } - } - - return 0; -} - -static int __msm_pmem_table_del(struct msm_sync *sync, - struct msm_pmem_info *pinfo) -{ - int rc = 0; - struct msm_pmem_region *region; - struct hlist_node *node, *n; - - switch (pinfo->type) { - case MSM_PMEM_OUTPUT1: - case MSM_PMEM_OUTPUT2: - case MSM_PMEM_THUMBAIL: - case MSM_PMEM_MAINIMG: - case MSM_PMEM_RAW_MAINIMG: - hlist_for_each_entry_safe(region, node, n, - &sync->frame, list) { - - if (pinfo->type == region->type && - pinfo->vaddr == region->vaddr && - pinfo->fd == region->fd) { - hlist_del(node); - put_pmem_file(region->file); - kfree(region); - } - } - break; - - case MSM_PMEM_AEC_AWB: - case MSM_PMEM_AF: - hlist_for_each_entry_safe(region, node, n, - &sync->stats, list) { - - if (pinfo->type == region->type && - pinfo->vaddr == region->vaddr && - pinfo->fd == region->fd) { - hlist_del(node); - put_pmem_file(region->file); - kfree(region); - } - } - break; - - default: - rc = -EINVAL; - break; - } - - return rc; -} - -static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg) -{ - struct msm_pmem_info info; - - if (copy_from_user(&info, arg, sizeof(info))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - return __msm_pmem_table_del(sync, &info); -} - -static int __msm_get_frame(struct msm_sync *sync, - struct msm_frame *frame) -{ - unsigned long flags; - int rc = 0; - - struct msm_queue_cmd *qcmd = NULL; - struct msm_vfe_phy_info *pphy; - - spin_lock_irqsave(&sync->prev_frame_q_lock, flags); - if (!list_empty(&sync->prev_frame_q)) { - qcmd = list_first_entry(&sync->prev_frame_q, - struct msm_queue_cmd, list); - list_del_init(&qcmd->list); - } - spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags); - - if (!qcmd) { - pr_err("%s: no preview frame.\n", __func__); - return -EAGAIN; - } - - pphy = (struct msm_vfe_phy_info *)(qcmd->command); - - frame->buffer = - msm_pmem_frame_ptov_lookup(sync, - pphy->y_phy, - pphy->cbcr_phy, &(frame->y_off), - &(frame->cbcr_off), &(frame->fd)); - if (!frame->buffer) { - pr_err("%s: cannot get frame, invalid lookup address " - "y=%x cbcr=%x offset=%d\n", - __func__, - pphy->y_phy, - pphy->cbcr_phy, - frame->y_off); - rc = -EINVAL; - } - - CDBG("__msm_get_frame: y=0x%x, cbcr=0x%x, qcmd=0x%x, virt_addr=0x%x\n", - pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer); - - kfree(qcmd); - return rc; -} - -static int msm_get_frame(struct msm_sync *sync, void __user *arg) -{ - int rc = 0; - struct msm_frame frame; - - if (copy_from_user(&frame, - arg, - sizeof(struct msm_frame))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - rc = __msm_get_frame(sync, &frame); - if (rc < 0) - return rc; - - if (sync->croplen) { - if (frame.croplen > sync->croplen) { - pr_err("msm_get_frame: invalid frame croplen %d\n", - frame.croplen); - return -EINVAL; - } - - if (copy_to_user((void *)frame.cropinfo, - sync->cropinfo, - sync->croplen)) { - ERR_COPY_TO_USER(); - return -EFAULT; - } - } - - if (copy_to_user((void *)arg, - &frame, sizeof(struct msm_frame))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - } - - CDBG("Got frame!!!\n"); - - return rc; -} - -static int msm_enable_vfe(struct msm_sync *sync, void __user *arg) -{ - int rc = -EIO; - struct camera_enable_cmd cfg; - - if (copy_from_user(&cfg, - arg, - sizeof(struct camera_enable_cmd))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - if (sync->vfefn.vfe_enable) - rc = sync->vfefn.vfe_enable(&cfg); - - CDBG("msm_enable_vfe: returned rc = %d\n", rc); - return rc; -} - -static int msm_disable_vfe(struct msm_sync *sync, void __user *arg) -{ - int rc = -EIO; - struct camera_enable_cmd cfg; - - if (copy_from_user(&cfg, - arg, - sizeof(struct camera_enable_cmd))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - if (sync->vfefn.vfe_disable) - rc = sync->vfefn.vfe_disable(&cfg, NULL); - - CDBG("msm_disable_vfe: returned rc = %d\n", rc); - return rc; -} - -static struct msm_queue_cmd *__msm_control(struct msm_sync *sync, - struct msm_control_device_queue *queue, - struct msm_queue_cmd *qcmd, - int timeout) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(&sync->msg_event_q_lock, flags); - list_add_tail(&qcmd->list, &sync->msg_event_q); - /* wake up config thread */ - wake_up(&sync->msg_event_wait); - spin_unlock_irqrestore(&sync->msg_event_q_lock, flags); - - if (!queue) - return NULL; - - /* wait for config status */ - rc = wait_event_interruptible_timeout( - queue->ctrl_status_wait, - !list_empty_careful(&queue->ctrl_status_q), - timeout); - if (list_empty_careful(&queue->ctrl_status_q)) { - if (!rc) - rc = -ETIMEDOUT; - if (rc < 0) { - pr_err("msm_control: wait_event error %d\n", rc); -#if 0 - /* This is a bit scary. If we time out too early, we - * will free qcmd at the end of this function, and the - * dsp may do the same when it does respond, so we - * remove the message from the source queue. - */ - pr_err("%s: error waiting for ctrl_status_q: %d\n", - __func__, rc); - spin_lock_irqsave(&sync->msg_event_q_lock, flags); - list_del_init(&qcmd->list); - spin_unlock_irqrestore(&sync->msg_event_q_lock, flags); -#endif - return ERR_PTR(rc); - } - } - - /* control command status is ready */ - spin_lock_irqsave(&queue->ctrl_status_q_lock, flags); - BUG_ON(list_empty(&queue->ctrl_status_q)); - qcmd = list_first_entry(&queue->ctrl_status_q, - struct msm_queue_cmd, list); - list_del_init(&qcmd->list); - spin_unlock_irqrestore(&queue->ctrl_status_q_lock, flags); - - return qcmd; -} - -static int msm_control(struct msm_control_device *ctrl_pmsm, - int block, - void __user *arg) -{ - int rc = 0; - - struct msm_sync *sync = ctrl_pmsm->pmsm->sync; - struct msm_ctrl_cmd udata, *ctrlcmd; - struct msm_queue_cmd *qcmd = NULL, *qcmd_temp; - - if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - goto end; - } - - qcmd = kmalloc(sizeof(struct msm_queue_cmd) + - sizeof(struct msm_ctrl_cmd) + udata.length, - GFP_KERNEL); - if (!qcmd) { - pr_err("msm_control: cannot allocate buffer\n"); - rc = -ENOMEM; - goto end; - } - - qcmd->type = MSM_CAM_Q_CTRL; - qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1); - *ctrlcmd = udata; - ctrlcmd->value = ctrlcmd + 1; - - if (udata.length) { - if (copy_from_user(ctrlcmd->value, - udata.value, udata.length)) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - goto end; - } - } - - if (!block) { - /* qcmd will be set to NULL */ - qcmd = __msm_control(sync, NULL, qcmd, 0); - goto end; - } - - qcmd_temp = __msm_control(sync, - &ctrl_pmsm->ctrl_q, - qcmd, MAX_SCHEDULE_TIMEOUT); - - if (IS_ERR(qcmd_temp)) { - rc = PTR_ERR(qcmd_temp); - goto end; - } - qcmd = qcmd_temp; - - if (qcmd->command) { - void __user *to = udata.value; - udata = *(struct msm_ctrl_cmd *)qcmd->command; - if (udata.length > 0) { - if (copy_to_user(to, - udata.value, - udata.length)) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto end; - } - } - udata.value = to; - - if (copy_to_user((void *)arg, &udata, - sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto end; - } - } - -end: - /* Note: if we get here as a result of an error, we will free the - * qcmd that we kmalloc() in this function. When we come here as - * a result of a successful completion, we are freeing the qcmd that - * we dequeued from queue->ctrl_status_q. - */ - kfree(qcmd); - - CDBG("msm_control: end rc = %d\n", rc); - return rc; -} - -static int msm_get_stats(struct msm_sync *sync, void __user *arg) -{ - unsigned long flags; - int timeout; - int rc = 0; - - struct msm_stats_event_ctrl se; - - struct msm_queue_cmd *qcmd = NULL; - struct msm_ctrl_cmd *ctrl = NULL; - struct msm_vfe_resp *data = NULL; - struct msm_stats_buf stats; - - if (copy_from_user(&se, arg, - sizeof(struct msm_stats_event_ctrl))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - timeout = (int)se.timeout_ms; - - CDBG("msm_get_stats timeout %d\n", timeout); - rc = wait_event_interruptible_timeout( - sync->msg_event_wait, - !list_empty_careful(&sync->msg_event_q), - msecs_to_jiffies(timeout)); - if (list_empty_careful(&sync->msg_event_q)) { - if (rc == 0) - rc = -ETIMEDOUT; - if (rc < 0) { - pr_err("msm_get_stats error %d\n", rc); - return rc; - } - } - CDBG("msm_get_stats returned from wait: %d\n", rc); - - spin_lock_irqsave(&sync->msg_event_q_lock, flags); - BUG_ON(list_empty(&sync->msg_event_q)); - qcmd = list_first_entry(&sync->msg_event_q, - struct msm_queue_cmd, list); - list_del_init(&qcmd->list); - spin_unlock_irqrestore(&sync->msg_event_q_lock, flags); - - CDBG("=== received from DSP === %d\n", qcmd->type); - - switch (qcmd->type) { - case MSM_CAM_Q_VFE_EVT: - case MSM_CAM_Q_VFE_MSG: - data = (struct msm_vfe_resp *)(qcmd->command); - - /* adsp event and message */ - se.resptype = MSM_CAM_RESP_STAT_EVT_MSG; - - /* 0 - msg from aDSP, 1 - event from mARM */ - se.stats_event.type = data->evt_msg.type; - se.stats_event.msg_id = data->evt_msg.msg_id; - se.stats_event.len = data->evt_msg.len; - - CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type); - CDBG("length = %d\n", se.stats_event.len); - CDBG("msg_id = %d\n", se.stats_event.msg_id); - - if ((data->type == VFE_MSG_STATS_AF) || - (data->type == VFE_MSG_STATS_WE)) { - - stats.buffer = - msm_pmem_stats_ptov_lookup(sync, - data->phy.sbuf_phy, - &(stats.fd)); - if (!stats.buffer) { - pr_err("%s: msm_pmem_stats_ptov_lookup error\n", - __func__); - rc = -EINVAL; - goto failure; - } - - if (copy_to_user((void *)(se.stats_event.data), - &stats, - sizeof(struct msm_stats_buf))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto failure; - } - } else if ((data->evt_msg.len > 0) && - (data->type == VFE_MSG_GENERAL)) { - if (copy_to_user((void *)(se.stats_event.data), - data->evt_msg.data, - data->evt_msg.len)) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - } - } else if (data->type == VFE_MSG_OUTPUT1 || - data->type == VFE_MSG_OUTPUT2) { - if (copy_to_user((void *)(se.stats_event.data), - data->extdata, - data->extlen)) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - } - } else if (data->type == VFE_MSG_SNAPSHOT && sync->pict_pp) { - struct msm_postproc buf; - struct msm_pmem_region region; - buf.fmnum = msm_pmem_region_lookup(&sync->frame, - MSM_PMEM_MAINIMG, - ®ion, 1); - if (buf.fmnum == 1) { - buf.fmain.buffer = (unsigned long)region.vaddr; - buf.fmain.y_off = region.y_off; - buf.fmain.cbcr_off = region.cbcr_off; - buf.fmain.fd = region.fd; - } else { - buf.fmnum = msm_pmem_region_lookup(&sync->frame, - MSM_PMEM_RAW_MAINIMG, - ®ion, 1); - if (buf.fmnum == 1) { - buf.fmain.path = MSM_FRAME_PREV_2; - buf.fmain.buffer = - (unsigned long)region.vaddr; - buf.fmain.fd = region.fd; - } else { - pr_err("%s: pmem lookup failed\n", - __func__); - rc = -EINVAL; - } - } - - if (copy_to_user((void *)(se.stats_event.data), &buf, - sizeof(buf))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto failure; - } - CDBG("snapshot copy_to_user!\n"); - } - break; - - case MSM_CAM_Q_CTRL: - /* control command from control thread */ - ctrl = (struct msm_ctrl_cmd *)(qcmd->command); - - CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type); - CDBG("length = %d\n", ctrl->length); - - if (ctrl->length > 0) { - if (copy_to_user((void *)(se.ctrl_cmd.value), - ctrl->value, - ctrl->length)) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto failure; - } - } - - se.resptype = MSM_CAM_RESP_CTRL; - - /* what to control */ - se.ctrl_cmd.type = ctrl->type; - se.ctrl_cmd.length = ctrl->length; - se.ctrl_cmd.resp_fd = ctrl->resp_fd; - break; - - case MSM_CAM_Q_V4L2_REQ: - /* control command from v4l2 client */ - ctrl = (struct msm_ctrl_cmd *)(qcmd->command); - - CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type); - CDBG("length = %d\n", ctrl->length); - - if (ctrl->length > 0) { - if (copy_to_user((void *)(se.ctrl_cmd.value), - ctrl->value, ctrl->length)) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - goto failure; - } - } - - /* 2 tells config thread this is v4l2 request */ - se.resptype = MSM_CAM_RESP_V4L2; - - /* what to control */ - se.ctrl_cmd.type = ctrl->type; - se.ctrl_cmd.length = ctrl->length; - break; - - default: - rc = -EFAULT; - goto failure; - } /* switch qcmd->type */ - - if (copy_to_user((void *)arg, &se, sizeof(se))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - } - -failure: - kfree(qcmd); - - CDBG("msm_get_stats: %d\n", rc); - return rc; -} - -static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm, - void __user *arg) -{ - unsigned long flags; - int rc = 0; - - struct msm_ctrl_cmd udata, *ctrlcmd; - struct msm_queue_cmd *qcmd = NULL; - - if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - goto end; - } - - qcmd = kmalloc(sizeof(struct msm_queue_cmd) + - sizeof(struct msm_ctrl_cmd) + udata.length, - GFP_KERNEL); - if (!qcmd) { - rc = -ENOMEM; - goto end; - } - - qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1); - *ctrlcmd = udata; - if (udata.length > 0) { - ctrlcmd->value = ctrlcmd + 1; - if (copy_from_user(ctrlcmd->value, - (void *)udata.value, - udata.length)) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - kfree(qcmd); - goto end; - } - } else - ctrlcmd->value = NULL; - -end: - CDBG("msm_ctrl_cmd_done: end rc = %d\n", rc); - if (rc == 0) { - /* wake up control thread */ - spin_lock_irqsave(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags); - list_add_tail(&qcmd->list, &ctrl_pmsm->ctrl_q.ctrl_status_q); - wake_up(&ctrl_pmsm->ctrl_q.ctrl_status_wait); - spin_unlock_irqrestore(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags); - } - - return rc; -} - -static int msm_config_vfe(struct msm_sync *sync, void __user *arg) -{ - struct msm_vfe_cfg_cmd cfgcmd; - struct msm_pmem_region region[8]; - struct axidata axi_data; - void *data = NULL; - int rc = -EIO; - - memset(&axi_data, 0, sizeof(axi_data)); - - if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - switch (cfgcmd.cmd_type) { - case CMD_STATS_ENABLE: - axi_data.bufnum1 = - msm_pmem_region_lookup(&sync->stats, - MSM_PMEM_AEC_AWB, ®ion[0], - NUM_WB_EXP_STAT_OUTPUT_BUFFERS); - if (!axi_data.bufnum1) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - axi_data.region = ®ion[0]; - data = &axi_data; - break; - case CMD_STATS_AF_ENABLE: - axi_data.bufnum1 = - msm_pmem_region_lookup(&sync->stats, - MSM_PMEM_AF, ®ion[0], - NUM_AF_STAT_OUTPUT_BUFFERS); - if (!axi_data.bufnum1) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - axi_data.region = ®ion[0]; - data = &axi_data; - break; - case CMD_GENERAL: - case CMD_STATS_DISABLE: - break; - default: - pr_err("%s: unknown command type %d\n", - __func__, cfgcmd.cmd_type); - return -EINVAL; - } - - - if (sync->vfefn.vfe_config) - rc = sync->vfefn.vfe_config(&cfgcmd, data); - - return rc; -} - -static int msm_frame_axi_cfg(struct msm_sync *sync, - struct msm_vfe_cfg_cmd *cfgcmd) -{ - int rc = -EIO; - struct axidata axi_data; - void *data = &axi_data; - struct msm_pmem_region region[8]; - int pmem_type; - - memset(&axi_data, 0, sizeof(axi_data)); - - switch (cfgcmd->cmd_type) { - case CMD_AXI_CFG_OUT1: - pmem_type = MSM_PMEM_OUTPUT1; - axi_data.bufnum1 = - msm_pmem_region_lookup(&sync->frame, pmem_type, - ®ion[0], 8); - if (!axi_data.bufnum1) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - break; - - case CMD_AXI_CFG_OUT2: - pmem_type = MSM_PMEM_OUTPUT2; - axi_data.bufnum2 = - msm_pmem_region_lookup(&sync->frame, pmem_type, - ®ion[0], 8); - if (!axi_data.bufnum2) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - break; - - case CMD_AXI_CFG_SNAP_O1_AND_O2: - pmem_type = MSM_PMEM_THUMBAIL; - axi_data.bufnum1 = - msm_pmem_region_lookup(&sync->frame, pmem_type, - ®ion[0], 8); - if (!axi_data.bufnum1) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - - pmem_type = MSM_PMEM_MAINIMG; - axi_data.bufnum2 = - msm_pmem_region_lookup(&sync->frame, pmem_type, - ®ion[axi_data.bufnum1], 8); - if (!axi_data.bufnum2) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - break; - - case CMD_RAW_PICT_AXI_CFG: - pmem_type = MSM_PMEM_RAW_MAINIMG; - axi_data.bufnum2 = - msm_pmem_region_lookup(&sync->frame, pmem_type, - ®ion[0], 8); - if (!axi_data.bufnum2) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - break; - - case CMD_GENERAL: - data = NULL; - break; - - default: - pr_err("%s: unknown command type %d\n", - __func__, cfgcmd->cmd_type); - return -EINVAL; - } - - axi_data.region = ®ion[0]; - - /* send the AXI configuration command to driver */ - if (sync->vfefn.vfe_config) - rc = sync->vfefn.vfe_config(cfgcmd, data); - - return rc; -} - -static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg) -{ - int rc = 0; - struct msm_camsensor_info info; - struct msm_camera_sensor_info *sdata; - - if (copy_from_user(&info, - arg, - sizeof(struct msm_camsensor_info))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - sdata = sync->pdev->dev.platform_data; - CDBG("sensor_name %s\n", sdata->sensor_name); - - memcpy(&info.name[0], - sdata->sensor_name, - MAX_SENSOR_NAME); - info.flash_enabled = sdata->flash_type != MSM_CAMERA_FLASH_NONE; - - /* copy back to user space */ - if (copy_to_user((void *)arg, - &info, - sizeof(struct msm_camsensor_info))) { - ERR_COPY_TO_USER(); - rc = -EFAULT; - } - - return rc; -} - -static int __msm_put_frame_buf(struct msm_sync *sync, - struct msm_frame *pb) -{ - unsigned long pphy; - struct msm_vfe_cfg_cmd cfgcmd; - - int rc = -EIO; - - pphy = msm_pmem_frame_vtop_lookup(sync, - pb->buffer, - pb->y_off, pb->cbcr_off, pb->fd); - - if (pphy != 0) { - CDBG("rel: vaddr = 0x%lx, paddr = 0x%lx\n", - pb->buffer, pphy); - cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE; - cfgcmd.value = (void *)pb; - if (sync->vfefn.vfe_config) - rc = sync->vfefn.vfe_config(&cfgcmd, &pphy); - } else { - pr_err("%s: msm_pmem_frame_vtop_lookup failed\n", - __func__); - rc = -EINVAL; - } - - return rc; -} - -static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg) -{ - struct msm_frame buf_t; - - if (copy_from_user(&buf_t, - arg, - sizeof(struct msm_frame))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - return __msm_put_frame_buf(sync, &buf_t); -} - -static int __msm_register_pmem(struct msm_sync *sync, - struct msm_pmem_info *pinfo) -{ - int rc = 0; - - switch (pinfo->type) { - case MSM_PMEM_OUTPUT1: - case MSM_PMEM_OUTPUT2: - case MSM_PMEM_THUMBAIL: - case MSM_PMEM_MAINIMG: - case MSM_PMEM_RAW_MAINIMG: - rc = msm_pmem_table_add(&sync->frame, pinfo); - break; - - case MSM_PMEM_AEC_AWB: - case MSM_PMEM_AF: - rc = msm_pmem_table_add(&sync->stats, pinfo); - break; - - default: - rc = -EINVAL; - break; - } - - return rc; -} - -static int msm_register_pmem(struct msm_sync *sync, void __user *arg) -{ - struct msm_pmem_info info; - - if (copy_from_user(&info, arg, sizeof(info))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - return __msm_register_pmem(sync, &info); -} - -static int msm_stats_axi_cfg(struct msm_sync *sync, - struct msm_vfe_cfg_cmd *cfgcmd) -{ - int rc = -EIO; - struct axidata axi_data; - void *data = &axi_data; - - struct msm_pmem_region region[3]; - int pmem_type = MSM_PMEM_MAX; - - memset(&axi_data, 0, sizeof(axi_data)); - - switch (cfgcmd->cmd_type) { - case CMD_STATS_AXI_CFG: - pmem_type = MSM_PMEM_AEC_AWB; - break; - case CMD_STATS_AF_AXI_CFG: - pmem_type = MSM_PMEM_AF; - break; - case CMD_GENERAL: - data = NULL; - break; - default: - pr_err("%s: unknown command type %d\n", - __func__, cfgcmd->cmd_type); - return -EINVAL; - } - - if (cfgcmd->cmd_type != CMD_GENERAL) { - axi_data.bufnum1 = - msm_pmem_region_lookup(&sync->stats, pmem_type, - ®ion[0], NUM_WB_EXP_STAT_OUTPUT_BUFFERS); - if (!axi_data.bufnum1) { - pr_err("%s: pmem region lookup error\n", __func__); - return -EINVAL; - } - axi_data.region = ®ion[0]; - } - - /* send the AEC/AWB STATS configuration command to driver */ - if (sync->vfefn.vfe_config) - rc = sync->vfefn.vfe_config(cfgcmd, &axi_data); - - return rc; -} - -static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg) -{ - int rc = -EIO; - - struct msm_stats_buf buf; - unsigned long pphy; - struct msm_vfe_cfg_cmd cfgcmd; - - if (copy_from_user(&buf, arg, - sizeof(struct msm_stats_buf))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - CDBG("msm_put_stats_buffer\n"); - pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd); - - if (pphy != 0) { - if (buf.type == STAT_AEAW) - cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE; - else if (buf.type == STAT_AF) - cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE; - else { - pr_err("%s: invalid buf type %d\n", - __func__, - buf.type); - rc = -EINVAL; - goto put_done; - } - - cfgcmd.value = (void *)&buf; - - if (sync->vfefn.vfe_config) { - rc = sync->vfefn.vfe_config(&cfgcmd, &pphy); - if (rc < 0) - pr_err("msm_put_stats_buffer: "\ - "vfe_config err %d\n", rc); - } else - pr_err("msm_put_stats_buffer: vfe_config is NULL\n"); - } else { - pr_err("msm_put_stats_buffer: NULL physical address\n"); - rc = -EINVAL; - } - -put_done: - return rc; -} - -static int msm_axi_config(struct msm_sync *sync, void __user *arg) -{ - struct msm_vfe_cfg_cmd cfgcmd; - - if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - switch (cfgcmd.cmd_type) { - case CMD_AXI_CFG_OUT1: - case CMD_AXI_CFG_OUT2: - case CMD_AXI_CFG_SNAP_O1_AND_O2: - case CMD_RAW_PICT_AXI_CFG: - return msm_frame_axi_cfg(sync, &cfgcmd); - - case CMD_STATS_AXI_CFG: - case CMD_STATS_AF_AXI_CFG: - return msm_stats_axi_cfg(sync, &cfgcmd); - - default: - pr_err("%s: unknown command type %d\n", - __func__, - cfgcmd.cmd_type); - return -EINVAL; - } - - return 0; -} - -static int __msm_get_pic(struct msm_sync *sync, struct msm_ctrl_cmd *ctrl) -{ - unsigned long flags; - int rc = 0; - int tm; - - struct msm_queue_cmd *qcmd = NULL; - - tm = (int)ctrl->timeout_ms; - - rc = wait_event_interruptible_timeout( - sync->pict_frame_wait, - !list_empty_careful(&sync->pict_frame_q), - msecs_to_jiffies(tm)); - if (list_empty_careful(&sync->pict_frame_q)) { - if (rc == 0) - return -ETIMEDOUT; - if (rc < 0) { - pr_err("msm_camera_get_picture, rc = %d\n", rc); - return rc; - } - } - - spin_lock_irqsave(&sync->pict_frame_q_lock, flags); - BUG_ON(list_empty(&sync->pict_frame_q)); - qcmd = list_first_entry(&sync->pict_frame_q, - struct msm_queue_cmd, list); - list_del_init(&qcmd->list); - spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags); - - if (qcmd->command != NULL) { - struct msm_ctrl_cmd *q = - (struct msm_ctrl_cmd *)qcmd->command; - ctrl->type = q->type; - ctrl->status = q->status; - } else { - ctrl->type = -1; - ctrl->status = -1; - } - - kfree(qcmd); - return rc; -} - -static int msm_get_pic(struct msm_sync *sync, void __user *arg) -{ - struct msm_ctrl_cmd ctrlcmd_t; - int rc; - - if (copy_from_user(&ctrlcmd_t, - arg, - sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - rc = __msm_get_pic(sync, &ctrlcmd_t); - if (rc < 0) - return rc; - - if (sync->croplen) { - if (ctrlcmd_t.length < sync->croplen) { - pr_err("msm_get_pic: invalid len %d\n", - ctrlcmd_t.length); - return -EINVAL; - } - if (copy_to_user(ctrlcmd_t.value, - sync->cropinfo, - sync->croplen)) { - ERR_COPY_TO_USER(); - return -EFAULT; - } - } - - if (copy_to_user((void *)arg, - &ctrlcmd_t, - sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_TO_USER(); - return -EFAULT; - } - return 0; -} - -static int msm_set_crop(struct msm_sync *sync, void __user *arg) -{ - struct crop_info crop; - - if (copy_from_user(&crop, - arg, - sizeof(struct crop_info))) { - ERR_COPY_FROM_USER(); - return -EFAULT; - } - - if (!sync->croplen) { - sync->cropinfo = kmalloc(crop.len, GFP_KERNEL); - if (!sync->cropinfo) - return -ENOMEM; - } else if (sync->croplen < crop.len) - return -EINVAL; - - if (copy_from_user(sync->cropinfo, - crop.info, - crop.len)) { - ERR_COPY_FROM_USER(); - kfree(sync->cropinfo); - return -EFAULT; - } - - sync->croplen = crop.len; - - return 0; -} - -static int msm_pict_pp_done(struct msm_sync *sync, void __user *arg) -{ - struct msm_ctrl_cmd udata; - struct msm_ctrl_cmd *ctrlcmd = NULL; - struct msm_queue_cmd *qcmd = NULL; - unsigned long flags; - int rc = 0; - - if (!sync->pict_pp) - return -EINVAL; - - if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - goto pp_fail; - } - - qcmd = kmalloc(sizeof(struct msm_queue_cmd) + - sizeof(struct msm_ctrl_cmd), - GFP_KERNEL); - if (!qcmd) { - rc = -ENOMEM; - goto pp_fail; - } - - qcmd->type = MSM_CAM_Q_VFE_MSG; - qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1); - memset(ctrlcmd, 0, sizeof(struct msm_ctrl_cmd)); - ctrlcmd->type = udata.type; - ctrlcmd->status = udata.status; - - spin_lock_irqsave(&sync->pict_frame_q_lock, flags); - list_add_tail(&qcmd->list, &sync->pict_frame_q); - spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags); - wake_up(&sync->pict_frame_wait); - -pp_fail: - return rc; -} - -static long msm_ioctl_common(struct msm_device *pmsm, - unsigned int cmd, - void __user *argp) -{ - CDBG("msm_ioctl_common\n"); - switch (cmd) { - case MSM_CAM_IOCTL_REGISTER_PMEM: - return msm_register_pmem(pmsm->sync, argp); - case MSM_CAM_IOCTL_UNREGISTER_PMEM: - return msm_pmem_table_del(pmsm->sync, argp); - default: - return -EINVAL; - } -} - -static long msm_ioctl_config(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - int rc = -EINVAL; - void __user *argp = (void __user *)arg; - struct msm_device *pmsm = filep->private_data; - - CDBG("msm_ioctl_config cmd = %d\n", _IOC_NR(cmd)); - - switch (cmd) { - case MSM_CAM_IOCTL_GET_SENSOR_INFO: - rc = msm_get_sensor_info(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_CONFIG_VFE: - /* Coming from config thread for update */ - rc = msm_config_vfe(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_GET_STATS: - /* Coming from config thread wait - * for vfe statistics and control requests */ - rc = msm_get_stats(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_ENABLE_VFE: - /* This request comes from control thread: - * enable either QCAMTASK or VFETASK */ - rc = msm_enable_vfe(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_DISABLE_VFE: - /* This request comes from control thread: - * disable either QCAMTASK or VFETASK */ - rc = msm_disable_vfe(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_VFE_APPS_RESET: - msm_camio_vfe_blk_reset(); - rc = 0; - break; - - case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER: - rc = msm_put_stats_buffer(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_AXI_CONFIG: - rc = msm_axi_config(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_SET_CROP: - rc = msm_set_crop(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_PICT_PP: { - uint8_t enable; - if (copy_from_user(&enable, argp, sizeof(enable))) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - } else { - pmsm->sync->pict_pp = enable; - rc = 0; - } - break; - } - - case MSM_CAM_IOCTL_PICT_PP_DONE: - rc = msm_pict_pp_done(pmsm->sync, argp); - break; - - case MSM_CAM_IOCTL_SENSOR_IO_CFG: - rc = pmsm->sync->sctrl.s_config(argp); - break; - - case MSM_CAM_IOCTL_FLASH_LED_CFG: { - uint32_t led_state; - if (copy_from_user(&led_state, argp, sizeof(led_state))) { - ERR_COPY_FROM_USER(); - rc = -EFAULT; - } else - rc = msm_camera_flash_set_led_state(led_state); - break; - } - - default: - rc = msm_ioctl_common(pmsm, cmd, argp); - break; - } - - CDBG("msm_ioctl_config cmd = %d DONE\n", _IOC_NR(cmd)); - return rc; -} - -static int msm_unblock_poll_frame(struct msm_sync *); - -static long msm_ioctl_frame(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - int rc = -EINVAL; - void __user *argp = (void __user *)arg; - struct msm_device *pmsm = filep->private_data; - - - switch (cmd) { - case MSM_CAM_IOCTL_GETFRAME: - /* Coming from frame thread to get frame - * after SELECT is done */ - rc = msm_get_frame(pmsm->sync, argp); - break; - case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER: - rc = msm_put_frame_buffer(pmsm->sync, argp); - break; - case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME: - rc = msm_unblock_poll_frame(pmsm->sync); - break; - default: - break; - } - - return rc; -} - - -static long msm_ioctl_control(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - int rc = -EINVAL; - void __user *argp = (void __user *)arg; - struct msm_control_device *ctrl_pmsm = filep->private_data; - struct msm_device *pmsm = ctrl_pmsm->pmsm; - - switch (cmd) { - case MSM_CAM_IOCTL_CTRL_COMMAND: - /* Coming from control thread, may need to wait for - * command status */ - rc = msm_control(ctrl_pmsm, 1, argp); - break; - case MSM_CAM_IOCTL_CTRL_COMMAND_2: - /* Sends a message, returns immediately */ - rc = msm_control(ctrl_pmsm, 0, argp); - break; - case MSM_CAM_IOCTL_CTRL_CMD_DONE: - /* Config thread calls the control thread to notify it - * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND. - */ - rc = msm_ctrl_cmd_done(ctrl_pmsm, argp); - break; - case MSM_CAM_IOCTL_GET_PICTURE: - rc = msm_get_pic(pmsm->sync, argp); - break; - default: - rc = msm_ioctl_common(pmsm, cmd, argp); - break; - } - - return rc; -} - -static int __msm_release(struct msm_sync *sync) -{ - struct msm_pmem_region *region; - struct hlist_node *hnode; - struct hlist_node *n; - - mutex_lock(&sync->lock); - if (sync->opencnt) - sync->opencnt--; - - if (!sync->opencnt) { - /* need to clean up system resource */ - if (sync->vfefn.vfe_release) - sync->vfefn.vfe_release(sync->pdev); - - if (sync->cropinfo) { - kfree(sync->cropinfo); - sync->cropinfo = NULL; - sync->croplen = 0; - } - - hlist_for_each_entry_safe(region, hnode, n, - &sync->frame, list) { - hlist_del(hnode); - put_pmem_file(region->file); - kfree(region); - } - - hlist_for_each_entry_safe(region, hnode, n, - &sync->stats, list) { - hlist_del(hnode); - put_pmem_file(region->file); - kfree(region); - } - - MSM_DRAIN_QUEUE(sync, msg_event_q); - MSM_DRAIN_QUEUE(sync, prev_frame_q); - MSM_DRAIN_QUEUE(sync, pict_frame_q); - - sync->sctrl.s_release(); - - sync->apps_id = NULL; - CDBG("msm_release completed!\n"); - } - mutex_unlock(&sync->lock); - - return 0; -} - -static int msm_release_config(struct inode *node, struct file *filep) -{ - int rc; - struct msm_device *pmsm = filep->private_data; - printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name); - rc = __msm_release(pmsm->sync); - atomic_set(&pmsm->opened, 0); - return rc; -} - -static int msm_release_control(struct inode *node, struct file *filep) -{ - int rc; - struct msm_control_device *ctrl_pmsm = filep->private_data; - struct msm_device *pmsm = ctrl_pmsm->pmsm; - printk(KERN_INFO "msm_camera: RELEASE %s\n", - filep->f_path.dentry->d_name.name); - rc = __msm_release(pmsm->sync); - if (!rc) { - MSM_DRAIN_QUEUE(&ctrl_pmsm->ctrl_q, ctrl_status_q); - MSM_DRAIN_QUEUE(pmsm->sync, pict_frame_q); - } - kfree(ctrl_pmsm); - return rc; -} - -static int msm_release_frame(struct inode *node, struct file *filep) -{ - int rc; - struct msm_device *pmsm = filep->private_data; - printk(KERN_INFO "msm_camera: RELEASE %s\n", - filep->f_path.dentry->d_name.name); - rc = __msm_release(pmsm->sync); - if (!rc) { - MSM_DRAIN_QUEUE(pmsm->sync, prev_frame_q); - atomic_set(&pmsm->opened, 0); - } - return rc; -} - -static int msm_unblock_poll_frame(struct msm_sync *sync) -{ - unsigned long flags; - CDBG("msm_unblock_poll_frame\n"); - spin_lock_irqsave(&sync->prev_frame_q_lock, flags); - sync->unblock_poll_frame = 1; - wake_up(&sync->prev_frame_wait); - spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags); - return 0; -} - -static unsigned int __msm_poll_frame(struct msm_sync *sync, - struct file *filep, - struct poll_table_struct *pll_table) -{ - int rc = 0; - unsigned long flags; - - poll_wait(filep, &sync->prev_frame_wait, pll_table); - - spin_lock_irqsave(&sync->prev_frame_q_lock, flags); - if (!list_empty_careful(&sync->prev_frame_q)) - /* frame ready */ - rc = POLLIN | POLLRDNORM; - if (sync->unblock_poll_frame) { - CDBG("%s: sync->unblock_poll_frame is true\n", __func__); - rc |= POLLPRI; - sync->unblock_poll_frame = 0; - } - spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags); - - return rc; -} - -static unsigned int msm_poll_frame(struct file *filep, - struct poll_table_struct *pll_table) -{ - struct msm_device *pmsm = filep->private_data; - return __msm_poll_frame(pmsm->sync, filep, pll_table); -} - -/* - * This function executes in interrupt context. - */ - -static void *msm_vfe_sync_alloc(int size, - void *syncdata __attribute__((unused))) -{ - struct msm_queue_cmd *qcmd = - kmalloc(sizeof(struct msm_queue_cmd) + size, GFP_ATOMIC); - return qcmd ? qcmd + 1 : NULL; -} - -/* - * This function executes in interrupt context. - */ - -static void msm_vfe_sync(struct msm_vfe_resp *vdata, - enum msm_queue qtype, void *syncdata) -{ - struct msm_queue_cmd *qcmd = NULL; - struct msm_queue_cmd *qcmd_frame = NULL; - struct msm_vfe_phy_info *fphy; - - unsigned long flags; - struct msm_sync *sync = (struct msm_sync *)syncdata; - if (!sync) { - pr_err("msm_camera: no context in dsp callback.\n"); - return; - } - - qcmd = ((struct msm_queue_cmd *)vdata) - 1; - qcmd->type = qtype; - - if (qtype == MSM_CAM_Q_VFE_MSG) { - switch (vdata->type) { - case VFE_MSG_OUTPUT1: - case VFE_MSG_OUTPUT2: - qcmd_frame = - kmalloc(sizeof(struct msm_queue_cmd) + - sizeof(struct msm_vfe_phy_info), - GFP_ATOMIC); - if (!qcmd_frame) - goto mem_fail; - fphy = (struct msm_vfe_phy_info *)(qcmd_frame + 1); - *fphy = vdata->phy; - - qcmd_frame->type = MSM_CAM_Q_VFE_MSG; - qcmd_frame->command = fphy; - - CDBG("qcmd_frame= 0x%x phy_y= 0x%x, phy_cbcr= 0x%x\n", - (int) qcmd_frame, fphy->y_phy, fphy->cbcr_phy); - - spin_lock_irqsave(&sync->prev_frame_q_lock, flags); - list_add_tail(&qcmd_frame->list, &sync->prev_frame_q); - wake_up(&sync->prev_frame_wait); - spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags); - CDBG("woke up frame thread\n"); - break; - case VFE_MSG_SNAPSHOT: - if (sync->pict_pp) - break; - - CDBG("snapshot pp = %d\n", sync->pict_pp); - qcmd_frame = - kmalloc(sizeof(struct msm_queue_cmd), - GFP_ATOMIC); - if (!qcmd_frame) - goto mem_fail; - qcmd_frame->type = MSM_CAM_Q_VFE_MSG; - qcmd_frame->command = NULL; - spin_lock_irqsave(&sync->pict_frame_q_lock, - flags); - list_add_tail(&qcmd_frame->list, &sync->pict_frame_q); - wake_up(&sync->pict_frame_wait); - spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags); - CDBG("woke up picture thread\n"); - break; - default: - CDBG("%s: qtype = %d not handled\n", - __func__, vdata->type); - break; - } - } - - qcmd->command = (void *)vdata; - CDBG("vdata->type = %d\n", vdata->type); - - spin_lock_irqsave(&sync->msg_event_q_lock, flags); - list_add_tail(&qcmd->list, &sync->msg_event_q); - wake_up(&sync->msg_event_wait); - spin_unlock_irqrestore(&sync->msg_event_q_lock, flags); - CDBG("woke up config thread\n"); - return; - -mem_fail: - kfree(qcmd); -} - -static struct msm_vfe_callback msm_vfe_s = { - .vfe_resp = msm_vfe_sync, - .vfe_alloc = msm_vfe_sync_alloc, -}; - -static int __msm_open(struct msm_sync *sync, const char *const apps_id) -{ - int rc = 0; - - mutex_lock(&sync->lock); - if (sync->apps_id && strcmp(sync->apps_id, apps_id)) { - pr_err("msm_camera(%s): sensor %s is already opened for %s\n", - apps_id, - sync->sdata->sensor_name, - sync->apps_id); - rc = -EBUSY; - goto msm_open_done; - } - - sync->apps_id = apps_id; - - if (!sync->opencnt) { - - msm_camvfe_fn_init(&sync->vfefn, sync); - if (sync->vfefn.vfe_init) { - rc = sync->vfefn.vfe_init(&msm_vfe_s, - sync->pdev); - if (rc < 0) { - pr_err("vfe_init failed at %d\n", rc); - goto msm_open_done; - } - rc = sync->sctrl.s_init(sync->sdata); - if (rc < 0) { - pr_err("sensor init failed: %d\n", rc); - goto msm_open_done; - } - } else { - pr_err("no sensor init func\n"); - rc = -ENODEV; - goto msm_open_done; - } - - if (rc >= 0) { - INIT_HLIST_HEAD(&sync->frame); - INIT_HLIST_HEAD(&sync->stats); - sync->unblock_poll_frame = 0; - } - } - sync->opencnt++; - -msm_open_done: - mutex_unlock(&sync->lock); - return rc; -} - -static int msm_open_common(struct inode *inode, struct file *filep, - int once) -{ - int rc; - struct msm_device *pmsm = - container_of(inode->i_cdev, struct msm_device, cdev); - - CDBG("msm_camera: open %s\n", filep->f_path.dentry->d_name.name); - - if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) { - pr_err("msm_camera: %s is already opened.\n", - filep->f_path.dentry->d_name.name); - return -EBUSY; - } - - rc = nonseekable_open(inode, filep); - if (rc < 0) { - pr_err("msm_open: nonseekable_open error %d\n", rc); - return rc; - } - - rc = __msm_open(pmsm->sync, MSM_APPS_ID_PROP); - if (rc < 0) - return rc; - - filep->private_data = pmsm; - - CDBG("msm_open() open: rc = %d\n", rc); - return rc; -} - -static int msm_open(struct inode *inode, struct file *filep) -{ - return msm_open_common(inode, filep, 1); -} - -static int msm_open_control(struct inode *inode, struct file *filep) -{ - int rc; - - struct msm_control_device *ctrl_pmsm = - kmalloc(sizeof(struct msm_control_device), GFP_KERNEL); - if (!ctrl_pmsm) - return -ENOMEM; - - rc = msm_open_common(inode, filep, 0); - if (rc < 0) { - kfree(ctrl_pmsm); - return rc; - } - - ctrl_pmsm->pmsm = filep->private_data; - filep->private_data = ctrl_pmsm; - spin_lock_init(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock); - INIT_LIST_HEAD(&ctrl_pmsm->ctrl_q.ctrl_status_q); - init_waitqueue_head(&ctrl_pmsm->ctrl_q.ctrl_status_wait); - - CDBG("msm_open() open: rc = %d\n", rc); - return rc; -} - -static int __msm_v4l2_control(struct msm_sync *sync, - struct msm_ctrl_cmd *out) -{ - int rc = 0; - - struct msm_queue_cmd *qcmd = NULL, *rcmd = NULL; - struct msm_ctrl_cmd *ctrl; - struct msm_control_device_queue FIXME; - - /* wake up config thread, 4 is for V4L2 application */ - qcmd = kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); - if (!qcmd) { - pr_err("msm_control: cannot allocate buffer\n"); - rc = -ENOMEM; - goto end; - } - qcmd->type = MSM_CAM_Q_V4L2_REQ; - qcmd->command = out; - - rcmd = __msm_control(sync, &FIXME, qcmd, out->timeout_ms); - if (IS_ERR(rcmd)) { - rc = PTR_ERR(rcmd); - goto end; - } - - ctrl = (struct msm_ctrl_cmd *)(rcmd->command); - /* FIXME: we should just set out->length = ctrl->length; */ - BUG_ON(out->length < ctrl->length); - memcpy(out->value, ctrl->value, ctrl->length); - -end: - kfree(rcmd); - CDBG("__msm_v4l2_control: end rc = %d\n", rc); - return rc; -} - -static const struct file_operations msm_fops_config = { - .owner = THIS_MODULE, - .open = msm_open, - .unlocked_ioctl = msm_ioctl_config, - .release = msm_release_config, - .llseek = no_llseek, -}; - -static const struct file_operations msm_fops_control = { - .owner = THIS_MODULE, - .open = msm_open_control, - .unlocked_ioctl = msm_ioctl_control, - .release = msm_release_control, - .llseek = no_llseek, -}; - -static const struct file_operations msm_fops_frame = { - .owner = THIS_MODULE, - .open = msm_open, - .unlocked_ioctl = msm_ioctl_frame, - .release = msm_release_frame, - .poll = msm_poll_frame, - .llseek = no_llseek, -}; - -static int msm_setup_cdev(struct msm_device *msm, - int node, - dev_t devno, - const char *suffix, - const struct file_operations *fops) -{ - int rc = -ENODEV; - - struct device *device = - device_create(msm_class, NULL, - devno, NULL, - "%s%d", suffix, node); - - if (IS_ERR(device)) { - rc = PTR_ERR(device); - pr_err("msm_camera: error creating device: %d\n", rc); - return rc; - } - - cdev_init(&msm->cdev, fops); - msm->cdev.owner = THIS_MODULE; - - rc = cdev_add(&msm->cdev, devno, 1); - if (rc < 0) { - pr_err("msm_camera: error adding cdev: %d\n", rc); - device_destroy(msm_class, devno); - return rc; - } - - return rc; -} - -static int msm_tear_down_cdev(struct msm_device *msm, dev_t devno) -{ - cdev_del(&msm->cdev); - device_destroy(msm_class, devno); - return 0; -} - -int msm_v4l2_register(struct msm_v4l2_driver *drv) -{ - /* FIXME: support multiple sensors */ - if (list_empty(&msm_sensors)) - return -ENODEV; - - drv->sync = list_first_entry(&msm_sensors, struct msm_sync, list); - drv->open = __msm_open; - drv->release = __msm_release; - drv->ctrl = __msm_v4l2_control; - drv->reg_pmem = __msm_register_pmem; - drv->get_frame = __msm_get_frame; - drv->put_frame = __msm_put_frame_buf; - drv->get_pict = __msm_get_pic; - drv->drv_poll = __msm_poll_frame; - - return 0; -} -EXPORT_SYMBOL(msm_v4l2_register); - -int msm_v4l2_unregister(struct msm_v4l2_driver *drv) -{ - drv->sync = NULL; - return 0; -} -EXPORT_SYMBOL(msm_v4l2_unregister); - -static int msm_sync_init(struct msm_sync *sync, - struct platform_device *pdev, - int (*sensor_probe)(const struct msm_camera_sensor_info *, - struct msm_sensor_ctrl *)) -{ - int rc = 0; - struct msm_sensor_ctrl sctrl; - sync->sdata = pdev->dev.platform_data; - - spin_lock_init(&sync->msg_event_q_lock); - INIT_LIST_HEAD(&sync->msg_event_q); - init_waitqueue_head(&sync->msg_event_wait); - - spin_lock_init(&sync->prev_frame_q_lock); - INIT_LIST_HEAD(&sync->prev_frame_q); - init_waitqueue_head(&sync->prev_frame_wait); - - spin_lock_init(&sync->pict_frame_q_lock); - INIT_LIST_HEAD(&sync->pict_frame_q); - init_waitqueue_head(&sync->pict_frame_wait); - - rc = msm_camio_probe_on(pdev); - if (rc < 0) - return rc; - rc = sensor_probe(sync->sdata, &sctrl); - if (rc >= 0) { - sync->pdev = pdev; - sync->sctrl = sctrl; - } - msm_camio_probe_off(pdev); - if (rc < 0) { - pr_err("msm_camera: failed to initialize %s\n", - sync->sdata->sensor_name); - return rc; - } - - sync->opencnt = 0; - mutex_init(&sync->lock); - CDBG("initialized %s\n", sync->sdata->sensor_name); - return rc; -} - -static int msm_sync_destroy(struct msm_sync *sync) -{ - return 0; -} - -static int msm_device_init(struct msm_device *pmsm, - struct msm_sync *sync, - int node) -{ - int dev_num = 3 * node; - int rc = msm_setup_cdev(pmsm, node, - MKDEV(MAJOR(msm_devno), dev_num), - "control", &msm_fops_control); - if (rc < 0) { - pr_err("error creating control node: %d\n", rc); - return rc; - } - - rc = msm_setup_cdev(pmsm + 1, node, - MKDEV(MAJOR(msm_devno), dev_num + 1), - "config", &msm_fops_config); - if (rc < 0) { - pr_err("error creating config node: %d\n", rc); - msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno), - dev_num)); - return rc; - } - - rc = msm_setup_cdev(pmsm + 2, node, - MKDEV(MAJOR(msm_devno), dev_num + 2), - "frame", &msm_fops_frame); - if (rc < 0) { - pr_err("error creating frame node: %d\n", rc); - msm_tear_down_cdev(pmsm, - MKDEV(MAJOR(msm_devno), dev_num)); - msm_tear_down_cdev(pmsm + 1, - MKDEV(MAJOR(msm_devno), dev_num + 1)); - return rc; - } - - atomic_set(&pmsm[0].opened, 0); - atomic_set(&pmsm[1].opened, 0); - atomic_set(&pmsm[2].opened, 0); - - pmsm[0].sync = sync; - pmsm[1].sync = sync; - pmsm[2].sync = sync; - - return rc; -} - -int msm_camera_drv_start(struct platform_device *dev, - int (*sensor_probe)(const struct msm_camera_sensor_info *, - struct msm_sensor_ctrl *)) -{ - struct msm_device *pmsm = NULL; - struct msm_sync *sync; - int rc = -ENODEV; - static int camera_node; - - if (camera_node >= MSM_MAX_CAMERA_SENSORS) { - pr_err("msm_camera: too many camera sensors\n"); - return rc; - } - - if (!msm_class) { - /* There are three device nodes per sensor */ - rc = alloc_chrdev_region(&msm_devno, 0, - 3 * MSM_MAX_CAMERA_SENSORS, - "msm_camera"); - if (rc < 0) { - pr_err("msm_camera: failed to allocate chrdev: %d\n", - rc); - return rc; - } - - msm_class = class_create(THIS_MODULE, "msm_camera"); - if (IS_ERR(msm_class)) { - rc = PTR_ERR(msm_class); - pr_err("msm_camera: create device class failed: %d\n", - rc); - return rc; - } - } - - pmsm = kzalloc(sizeof(struct msm_device) * 3 + - sizeof(struct msm_sync), GFP_ATOMIC); - if (!pmsm) - return -ENOMEM; - sync = (struct msm_sync *)(pmsm + 3); - - rc = msm_sync_init(sync, dev, sensor_probe); - if (rc < 0) { - kfree(pmsm); - return rc; - } - - CDBG("setting camera node %d\n", camera_node); - rc = msm_device_init(pmsm, sync, camera_node); - if (rc < 0) { - msm_sync_destroy(sync); - kfree(pmsm); - return rc; - } - - camera_node++; - list_add(&sync->list, &msm_sensors); - return rc; -} -EXPORT_SYMBOL(msm_camera_drv_start); diff --git a/drivers/staging/dream/camera/msm_io7x.c b/drivers/staging/dream/camera/msm_io7x.c deleted file mode 100644 index 55c020bb7afa..000000000000 --- a/drivers/staging/dream/camera/msm_io7x.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2008-2009 QUALCOMM Incorporated - */ - -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <mach/gpio.h> -#include <mach/board.h> -#include <mach/camera.h> - -#define CAMIF_CFG_RMSK 0x1fffff -#define CAM_SEL_BMSK 0x2 -#define CAM_PCLK_SRC_SEL_BMSK 0x60000 -#define CAM_PCLK_INVERT_BMSK 0x80000 -#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 - -#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 -#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 -#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 - -#define CAM_SEL_SHFT 0x1 -#define CAM_PCLK_SRC_SEL_SHFT 0x11 -#define CAM_PCLK_INVERT_SHFT 0x13 -#define CAM_PAD_REG_SW_RESET_SHFT 0x14 - -#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 -#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF -#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 -#define APPS_RESET_OFFSET 0x00000210 - -static struct clk *camio_vfe_mdc_clk; -static struct clk *camio_mdc_clk; -static struct clk *camio_vfe_clk; - -static struct msm_camera_io_ext camio_ext; -static struct resource *appio, *mdcio; -void __iomem *appbase, *mdcbase; - -static struct msm_camera_io_ext camio_ext; -static struct resource *appio, *mdcio; -void __iomem *appbase, *mdcbase; - -extern int clk_set_flags(struct clk *clk, unsigned long flags); - -int msm_camio_clk_enable(enum msm_camio_clk_type clktype) -{ - int rc = -1; - struct clk *clk = NULL; - - switch (clktype) { - case CAMIO_VFE_MDC_CLK: - clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk"); - break; - - case CAMIO_MDC_CLK: - clk = camio_mdc_clk = clk_get(NULL, "mdc_clk"); - break; - - case CAMIO_VFE_CLK: - clk = camio_vfe_clk = clk_get(NULL, "vfe_clk"); - break; - - default: - break; - } - - if (!IS_ERR(clk)) { - clk_enable(clk); - rc = 0; - } - - return rc; -} - -int msm_camio_clk_disable(enum msm_camio_clk_type clktype) -{ - int rc = -1; - struct clk *clk = NULL; - - switch (clktype) { - case CAMIO_VFE_MDC_CLK: - clk = camio_vfe_mdc_clk; - break; - - case CAMIO_MDC_CLK: - clk = camio_mdc_clk; - break; - - case CAMIO_VFE_CLK: - clk = camio_vfe_clk; - break; - - default: - break; - } - - if (!IS_ERR(clk)) { - clk_disable(clk); - clk_put(clk); - rc = 0; - } - - return rc; -} - -void msm_camio_clk_rate_set(int rate) -{ - struct clk *clk = camio_vfe_clk; - - if (clk != ERR_PTR(-ENOENT)) - clk_set_rate(clk, rate); -} - -int msm_camio_enable(struct platform_device *pdev) -{ - int rc = 0; - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - camio_ext = camdev->ioext; - - appio = request_mem_region(camio_ext.appphy, - camio_ext.appsz, pdev->name); - if (!appio) { - rc = -EBUSY; - goto enable_fail; - } - - appbase = ioremap(camio_ext.appphy, - camio_ext.appsz); - if (!appbase) { - rc = -ENOMEM; - goto apps_no_mem; - } - - mdcio = request_mem_region(camio_ext.mdcphy, - camio_ext.mdcsz, pdev->name); - if (!mdcio) { - rc = -EBUSY; - goto mdc_busy; - } - - mdcbase = ioremap(camio_ext.mdcphy, - camio_ext.mdcsz); - if (!mdcbase) { - rc = -ENOMEM; - goto mdc_no_mem; - } - - camdev->camera_gpio_on(); - - msm_camio_clk_enable(CAMIO_VFE_CLK); - msm_camio_clk_enable(CAMIO_MDC_CLK); - msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); - return 0; - -mdc_no_mem: - release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); -mdc_busy: - iounmap(appbase); -apps_no_mem: - release_mem_region(camio_ext.appphy, camio_ext.appsz); -enable_fail: - return rc; -} - -void msm_camio_disable(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - iounmap(mdcbase); - release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); - iounmap(appbase); - release_mem_region(camio_ext.appphy, camio_ext.appsz); - - camdev->camera_gpio_off(); - - msm_camio_clk_disable(CAMIO_VFE_CLK); - msm_camio_clk_disable(CAMIO_MDC_CLK); - msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); -} - -void msm_camio_camif_pad_reg_reset(void) -{ - uint32_t reg; - uint32_t mask, value; - - /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ - msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - - mask = CAM_SEL_BMSK | - CAM_PCLK_SRC_SEL_BMSK | - CAM_PCLK_INVERT_BMSK; - - value = 1 << CAM_SEL_SHFT | - 3 << CAM_PCLK_SRC_SEL_SHFT | - 0 << CAM_PCLK_INVERT_SHFT; - - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 1 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 0 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); - mdelay(10); -} - -void msm_camio_vfe_blk_reset(void) -{ - uint32_t val; - - val = readl(appbase + 0x00000210); - val |= 0x1; - writel(val, appbase + 0x00000210); - mdelay(10); - - val = readl(appbase + 0x00000210); - val &= ~0x1; - writel(val, appbase + 0x00000210); - mdelay(10); -} - -void msm_camio_camif_pad_reg_reset_2(void) -{ - uint32_t reg; - uint32_t mask, value; - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 1 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 0 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); -} - -void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) -{ - struct clk *clk = NULL; - - clk = camio_vfe_clk; - - if (clk != NULL && clk != ERR_PTR(-ENOENT)) { - switch (srctype) { - case MSM_CAMIO_CLK_SRC_INTERNAL: - clk_set_flags(clk, 0x00000100 << 1); - break; - - case MSM_CAMIO_CLK_SRC_EXTERNAL: - clk_set_flags(clk, 0x00000100); - break; - - default: - break; - } - } -} - -int msm_camio_probe_on(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - camdev->camera_gpio_on(); - return msm_camio_clk_enable(CAMIO_VFE_CLK); -} - -int msm_camio_probe_off(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - camdev->camera_gpio_off(); - return msm_camio_clk_disable(CAMIO_VFE_CLK); -} diff --git a/drivers/staging/dream/camera/msm_io8x.c b/drivers/staging/dream/camera/msm_io8x.c deleted file mode 100644 index 895161ae2e14..000000000000 --- a/drivers/staging/dream/camera/msm_io8x.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2008-2009 QUALCOMM Incorporated - */ - -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <mach/gpio.h> -#include <mach/board.h> -#include <mach/camera.h> - -#define CAMIF_CFG_RMSK 0x1fffff -#define CAM_SEL_BMSK 0x2 -#define CAM_PCLK_SRC_SEL_BMSK 0x60000 -#define CAM_PCLK_INVERT_BMSK 0x80000 -#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 - -#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 -#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 -#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 - -#define CAM_SEL_SHFT 0x1 -#define CAM_PCLK_SRC_SEL_SHFT 0x11 -#define CAM_PCLK_INVERT_SHFT 0x13 -#define CAM_PAD_REG_SW_RESET_SHFT 0x14 - -#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 -#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF -#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 -#define APPS_RESET_OFFSET 0x00000210 - -static struct clk *camio_vfe_mdc_clk; -static struct clk *camio_mdc_clk; -static struct clk *camio_vfe_clk; -static struct clk *camio_vfe_axi_clk; -static struct msm_camera_io_ext camio_ext; -static struct resource *appio, *mdcio; -void __iomem *appbase, *mdcbase; - -extern int clk_set_flags(struct clk *clk, unsigned long flags); - -int msm_camio_clk_enable(enum msm_camio_clk_type clktype) -{ - int rc = 0; - struct clk *clk = NULL; - - switch (clktype) { - case CAMIO_VFE_MDC_CLK: - camio_vfe_mdc_clk = - clk = clk_get(NULL, "vfe_mdc_clk"); - break; - - case CAMIO_MDC_CLK: - camio_mdc_clk = - clk = clk_get(NULL, "mdc_clk"); - break; - - case CAMIO_VFE_CLK: - camio_vfe_clk = - clk = clk_get(NULL, "vfe_clk"); - break; - - case CAMIO_VFE_AXI_CLK: - camio_vfe_axi_clk = - clk = clk_get(NULL, "vfe_axi_clk"); - break; - - default: - break; - } - - if (!IS_ERR(clk)) - clk_enable(clk); - else - rc = -1; - - return rc; -} - -int msm_camio_clk_disable(enum msm_camio_clk_type clktype) -{ - int rc = 0; - struct clk *clk = NULL; - - switch (clktype) { - case CAMIO_VFE_MDC_CLK: - clk = camio_vfe_mdc_clk; - break; - - case CAMIO_MDC_CLK: - clk = camio_mdc_clk; - break; - - case CAMIO_VFE_CLK: - clk = camio_vfe_clk; - break; - - case CAMIO_VFE_AXI_CLK: - clk = camio_vfe_axi_clk; - break; - - default: - break; - } - - if (!IS_ERR(clk)) { - clk_disable(clk); - clk_put(clk); - } else - rc = -1; - - return rc; -} - -void msm_camio_clk_rate_set(int rate) -{ - struct clk *clk = camio_vfe_mdc_clk; - - /* TODO: check return */ - clk_set_rate(clk, rate); -} - -int msm_camio_enable(struct platform_device *pdev) -{ - int rc = 0; - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - camio_ext = camdev->ioext; - - appio = request_mem_region(camio_ext.appphy, - camio_ext.appsz, pdev->name); - if (!appio) { - rc = -EBUSY; - goto enable_fail; - } - - appbase = ioremap(camio_ext.appphy, - camio_ext.appsz); - if (!appbase) { - rc = -ENOMEM; - goto apps_no_mem; - } - - mdcio = request_mem_region(camio_ext.mdcphy, - camio_ext.mdcsz, pdev->name); - if (!mdcio) { - rc = -EBUSY; - goto mdc_busy; - } - - mdcbase = ioremap(camio_ext.mdcphy, - camio_ext.mdcsz); - if (!mdcbase) { - rc = -ENOMEM; - goto mdc_no_mem; - } - - camdev->camera_gpio_on(); - - msm_camio_clk_enable(CAMIO_VFE_CLK); - msm_camio_clk_enable(CAMIO_MDC_CLK); - msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); - msm_camio_clk_enable(CAMIO_VFE_AXI_CLK); - return 0; - -mdc_no_mem: - release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); -mdc_busy: - iounmap(appbase); -apps_no_mem: - release_mem_region(camio_ext.appphy, camio_ext.appsz); -enable_fail: - return rc; -} - -void msm_camio_disable(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - iounmap(mdcbase); - release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); - iounmap(appbase); - release_mem_region(camio_ext.appphy, camio_ext.appsz); - - camdev->camera_gpio_off(); - - msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); - msm_camio_clk_disable(CAMIO_MDC_CLK); - msm_camio_clk_disable(CAMIO_VFE_CLK); - msm_camio_clk_disable(CAMIO_VFE_AXI_CLK); -} - -void msm_camio_camif_pad_reg_reset(void) -{ - uint32_t reg; - uint32_t mask, value; - - /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ - msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - - mask = CAM_SEL_BMSK | - CAM_PCLK_SRC_SEL_BMSK | - CAM_PCLK_INVERT_BMSK | - EXT_CAM_HSYNC_POL_SEL_BMSK | - EXT_CAM_VSYNC_POL_SEL_BMSK | - MDDI_CLK_CHICKEN_BIT_BMSK; - - value = 1 << CAM_SEL_SHFT | - 3 << CAM_PCLK_SRC_SEL_SHFT | - 0 << CAM_PCLK_INVERT_SHFT | - 0 << EXT_CAM_HSYNC_POL_SEL_SHFT | - 0 << EXT_CAM_VSYNC_POL_SEL_SHFT | - 0 << MDDI_CLK_CHICKEN_BIT_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 1 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 0 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); - - mdelay(10); - - /* todo: check return */ - if (camio_vfe_clk) - clk_set_rate(camio_vfe_clk, 96000000); -} - -void msm_camio_vfe_blk_reset(void) -{ - uint32_t val; - - val = readl(appbase + 0x00000210); - val |= 0x1; - writel(val, appbase + 0x00000210); - mdelay(10); - - val = readl(appbase + 0x00000210); - val &= ~0x1; - writel(val, appbase + 0x00000210); - mdelay(10); -} - -void msm_camio_camif_pad_reg_reset_2(void) -{ - uint32_t reg; - uint32_t mask, value; - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 1 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); - - reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; - mask = CAM_PAD_REG_SW_RESET_BMSK; - value = 0 << CAM_PAD_REG_SW_RESET_SHFT; - writel((reg & (~mask)) | (value & mask), mdcbase); - mdelay(10); -} - -void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) -{ - struct clk *clk = NULL; - - clk = camio_vfe_clk; - - if (clk != NULL) { - switch (srctype) { - case MSM_CAMIO_CLK_SRC_INTERNAL: - clk_set_flags(clk, 0x00000100 << 1); - break; - - case MSM_CAMIO_CLK_SRC_EXTERNAL: - clk_set_flags(clk, 0x00000100); - break; - - default: - break; - } - } -} - -void msm_camio_clk_axi_rate_set(int rate) -{ - struct clk *clk = camio_vfe_axi_clk; - /* todo: check return */ - clk_set_rate(clk, rate); -} - -int msm_camio_probe_on(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - camdev->camera_gpio_on(); - return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); -} - -int msm_camio_probe_off(struct platform_device *pdev) -{ - struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; - struct msm_camera_device_platform_data *camdev = sinfo->pdata; - - camdev->camera_gpio_off(); - return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); -} diff --git a/drivers/staging/dream/camera/msm_v4l2.c b/drivers/staging/dream/camera/msm_v4l2.c deleted file mode 100644 index c276f2f7583a..000000000000 --- a/drivers/staging/dream/camera/msm_v4l2.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - * - */ - -#include <linux/workqueue.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/list.h> -#include <linux/ioctl.h> -#include <linux/spinlock.h> -#include <linux/videodev2.h> -#include <linux/proc_fs.h> -#include <linux/slab.h> -#include <media/v4l2-dev.h> -#include <media/msm_camera.h> -#include <mach/camera.h> -#include <media/v4l2-ioctl.h> -/*#include <linux/platform_device.h>*/ - -#define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \ - struct v4l2_buffer) - -#define MSM_V4L2_GET_PICTURE _IOWR('V', BASE_VIDIOC_PRIVATE+2, \ - struct v4l2_buffer) - -#define MSM_V4L2_DEVICE_NAME "msm_v4l2" - -#define MSM_V4L2_PROC_NAME "msm_v4l2" - -#define MSM_V4L2_DEVNUM_MPEG2 0 -#define MSM_V4L2_DEVNUM_YUV 20 - -/* HVGA-P (portrait) and HVGA-L (landscape) */ -#define MSM_V4L2_WIDTH 480 -#define MSM_V4L2_HEIGHT 320 - -#if 1 -#define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args) -#else -#define D(fmt, args...) do {} while (0) -#endif - -#define PREVIEW_FRAMES_NUM 4 - -struct msm_v4l2_device { - struct list_head read_queue; - struct v4l2_format current_cap_format; - struct v4l2_format current_pix_format; - struct video_device *pvdev; - struct msm_v4l2_driver *drv; - uint8_t opencnt; - - spinlock_t read_queue_lock; -}; - -static struct msm_v4l2_device *g_pmsm_v4l2_dev; - - -static DEFINE_MUTEX(msm_v4l2_opencnt_lock); - -static int msm_v4l2_open(struct file *f) -{ - int rc = 0; - D("%s\n", __func__); - mutex_lock(&msm_v4l2_opencnt_lock); - if (!g_pmsm_v4l2_dev->opencnt) { - rc = g_pmsm_v4l2_dev->drv->open( - g_pmsm_v4l2_dev->drv->sync, - MSM_APPS_ID_V4L2); - } - g_pmsm_v4l2_dev->opencnt++; - mutex_unlock(&msm_v4l2_opencnt_lock); - return rc; -} - -static int msm_v4l2_release(struct file *f) -{ - int rc = 0; - D("%s\n", __func__); - mutex_lock(&msm_v4l2_opencnt_lock); - if (!g_pmsm_v4l2_dev->opencnt) { - g_pmsm_v4l2_dev->opencnt--; - if (!g_pmsm_v4l2_dev->opencnt) { - rc = g_pmsm_v4l2_dev->drv->release( - g_pmsm_v4l2_dev->drv->sync); - } - } - mutex_unlock(&msm_v4l2_opencnt_lock); - return rc; -} - -static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w) -{ - return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w); -} - -static long msm_v4l2_ioctl(struct file *filep, - unsigned int cmd, unsigned long arg) -{ - struct msm_ctrl_cmd *ctrlcmd; - - D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__); - - switch (cmd) { - case MSM_V4L2_START_SNAPSHOT: - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_ioctl: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->length = 0; - ctrlcmd->value = NULL; - ctrlcmd->timeout_ms = 10000; - - D("msm_v4l2_ioctl, MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n", - cmd); - ctrlcmd->type = MSM_V4L2_SNAPSHOT; - return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, - ctrlcmd); - - case MSM_V4L2_GET_PICTURE: - D("msm_v4l2_ioctl, MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd); - ctrlcmd = (struct msm_ctrl_cmd *)arg; - return g_pmsm_v4l2_dev->drv->get_pict( - g_pmsm_v4l2_dev->drv->sync, ctrlcmd); - - default: - D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd); - return video_ioctl2(filep, cmd, arg); - } -} - -static void msm_v4l2_release_dev(struct video_device *d) -{ - D("%s\n", __func__); -} - -static int msm_v4l2_querycap(struct file *f, - void *pctx, struct v4l2_capability *pcaps) -{ - D("%s\n", __func__); - strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver)); - strncpy(pcaps->card, - MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card)); - pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - return 0; -} - -static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id *pnorm) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_queryctrl(struct file *f, - void *pctx, struct v4l2_queryctrl *pqctrl) -{ - int rc = 0; - struct msm_ctrl_cmd *ctrlcmd; - - D("%s\n", __func__); - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_QUERY_CTRL; - ctrlcmd->length = sizeof(struct v4l2_queryctrl); - ctrlcmd->value = pqctrl; - ctrlcmd->timeout_ms = 10000; - - rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); - if (rc < 0) - return -1; - - return ctrlcmd->status; -} - -static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c) -{ - int rc = 0; - struct msm_ctrl_cmd *ctrlcmd; - - D("%s\n", __func__); - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_GET_CTRL; - ctrlcmd->length = sizeof(struct v4l2_control); - ctrlcmd->value = c; - ctrlcmd->timeout_ms = 10000; - - rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); - if (rc < 0) - return -1; - - return ctrlcmd->status; -} - -static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c) -{ - int rc = 0; - struct msm_ctrl_cmd *ctrlcmd; - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_SET_CTRL; - ctrlcmd->length = sizeof(struct v4l2_control); - ctrlcmd->value = c; - ctrlcmd->timeout_ms = 10000; - - D("%s\n", __func__); - - rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); - if (rc < 0) - return -1; - - return ctrlcmd->status; -} - -static int msm_v4l2_reqbufs(struct file *f, - void *pctx, struct v4l2_requestbuffers *b) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb) -{ - struct msm_pmem_info pmem_buf; -#if 0 - __u32 width = 0; - __u32 height = 0; - __u32 y_size = 0; - __u32 y_pad = 0; - - /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */ - width = 640; - /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */ - height = 480; - - D("%s: width = %d, height = %d\n", __func__, width, height); - - y_size = width * height; - y_pad = y_size % 4; -#endif - - __u32 y_pad = pb->bytesused % 4; - - /* V4L2 videodev will do the copy_from_user. */ - - memset(&pmem_buf, 0, sizeof(struct msm_pmem_info)); - pmem_buf.type = MSM_PMEM_OUTPUT2; - pmem_buf.vaddr = (void *)pb->m.userptr; - pmem_buf.y_off = 0; - pmem_buf.fd = (int)pb->reserved; - /* pmem_buf.cbcr_off = (y_size + y_pad); */ - pmem_buf.cbcr_off = (pb->bytesused + y_pad); - - g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf); - - return 0; -} - -static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb) -{ - /* - __u32 y_size = 0; - __u32 y_pad = 0; - __u32 width = 0; - __u32 height = 0; - */ - - __u32 y_pad = 0; - - struct msm_pmem_info meminfo; - struct msm_frame frame; - static int cnt; - - if ((pb->flags >> 16) & 0x0001) { - /* this is for previwe */ -#if 0 - width = 640; - height = 480; - - /* V4L2 videodev will do the copy_from_user. */ - D("%s: width = %d, height = %d\n", __func__, width, height); - y_size = width * height; - y_pad = y_size % 4; -#endif - - y_pad = pb->bytesused % 4; - - if (pb->type == V4L2_BUF_TYPE_PRIVATE) { - /* this qbuf is actually for releasing */ - - frame.buffer = pb->m.userptr; - frame.y_off = 0; - /* frame.cbcr_off = (y_size + y_pad); */ - frame.cbcr_off = (pb->bytesused + y_pad); - frame.fd = pb->reserved; - - D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n", - pb->bytesused); - - g_pmsm_v4l2_dev->drv->put_frame( - g_pmsm_v4l2_dev->drv->sync, - &frame); - - return 0; - } - - D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n", - pb->bytesused); - - meminfo.type = MSM_PMEM_OUTPUT2; - meminfo.fd = (int)pb->reserved; - meminfo.vaddr = (void *)pb->m.userptr; - meminfo.y_off = 0; - /* meminfo.cbcr_off = (y_size + y_pad); */ - meminfo.cbcr_off = (pb->bytesused + y_pad); - if (cnt == PREVIEW_FRAMES_NUM - 1) - meminfo.active = 0; - else - meminfo.active = 1; - cnt++; - g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, - &meminfo); - } else if ((pb->flags) & 0x0001) { - /* this is for snapshot */ - - __u32 y_size = 0; - - if ((pb->flags >> 8) & 0x01) { - - y_size = pb->bytesused; - - meminfo.type = MSM_PMEM_THUMBAIL; - } else if ((pb->flags >> 9) & 0x01) { - - y_size = pb->bytesused; - - meminfo.type = MSM_PMEM_MAINIMG; - } - - y_pad = y_size % 4; - - meminfo.fd = (int)pb->reserved; - meminfo.vaddr = (void *)pb->m.userptr; - meminfo.y_off = 0; - /* meminfo.cbcr_off = (y_size + y_pad); */ - meminfo.cbcr_off = (y_size + y_pad); - meminfo.active = 1; - g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, - &meminfo); - } - - return 0; -} - -static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb) -{ - struct msm_frame frame; - D("%s\n", __func__); - - /* V4L2 videodev will do the copy_to_user. */ - if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - - D("%s, %d\n", __func__, __LINE__); - - g_pmsm_v4l2_dev->drv->get_frame( - g_pmsm_v4l2_dev->drv->sync, - &frame); - - pb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pb->m.userptr = (unsigned long)frame.buffer; /* FIXME */ - pb->reserved = (int)frame.fd; - /* pb->length = (int)frame.cbcr_off; */ - - pb->bytesused = frame.cbcr_off; - - } else if (pb->type == V4L2_BUF_TYPE_PRIVATE) { - __u32 y_pad = pb->bytesused % 4; - - frame.buffer = pb->m.userptr; - frame.y_off = 0; - /* frame.cbcr_off = (y_size + y_pad); */ - frame.cbcr_off = (pb->bytesused + y_pad); - frame.fd = pb->reserved; - - g_pmsm_v4l2_dev->drv->put_frame( - g_pmsm_v4l2_dev->drv->sync, - &frame); - } - - return 0; -} - -static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i) -{ - struct msm_ctrl_cmd *ctrlcmd; - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_STREAM_ON; - ctrlcmd->timeout_ms = 10000; - ctrlcmd->length = 0; - ctrlcmd->value = NULL; - - D("%s\n", __func__); - - g_pmsm_v4l2_dev->drv->ctrl( - g_pmsm_v4l2_dev->drv->sync, - ctrlcmd); - - D("%s after drv->ctrl \n", __func__); - - return 0; -} - -static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i) -{ - struct msm_ctrl_cmd *ctrlcmd; - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_STREAM_OFF; - ctrlcmd->timeout_ms = 10000; - ctrlcmd->length = 0; - ctrlcmd->value = NULL; - - - D("%s\n", __func__); - - g_pmsm_v4l2_dev->drv->ctrl( - g_pmsm_v4l2_dev->drv->sync, - ctrlcmd); - - return 0; -} - -static int msm_v4l2_enum_fmt_overlay(struct file *f, - void *pctx, struct v4l2_fmtdesc *pfmtdesc) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_enum_fmt_cap(struct file *f, - void *pctx, struct v4l2_fmtdesc *pfmtdesc) -{ - D("%s\n", __func__); - - switch (pfmtdesc->index) { - case 0: - pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pfmtdesc->flags = 0; - strncpy(pfmtdesc->description, "YUV 4:2:0", - sizeof(pfmtdesc->description)); - pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int msm_v4l2_g_fmt_cap(struct file *f, - void *pctx, struct v4l2_format *pfmt) -{ - D("%s\n", __func__); - pfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pfmt->fmt.pix.width = MSM_V4L2_WIDTH; - pfmt->fmt.pix.height = MSM_V4L2_HEIGHT; - pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420; - pfmt->fmt.pix.field = V4L2_FIELD_ANY; - pfmt->fmt.pix.bytesperline = 0; - pfmt->fmt.pix.sizeimage = 0; - pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - pfmt->fmt.pix.priv = 0; - return 0; -} - -static int msm_v4l2_s_fmt_cap(struct file *f, - void *pctx, struct v4l2_format *pfmt) -{ - struct msm_ctrl_cmd *ctrlcmd; - - D("%s\n", __func__); - - ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); - if (!ctrlcmd) { - CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); - return -ENOMEM; - } - - ctrlcmd->type = MSM_V4L2_VID_CAP_TYPE; - ctrlcmd->length = sizeof(struct v4l2_format); - ctrlcmd->value = pfmt; - ctrlcmd->timeout_ms = 10000; - - if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - kfree(ctrlcmd); - return -1; - } - -#if 0 - /* FIXEME */ - if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420) { - kfree(ctrlcmd); - return -EINVAL; - } -#endif - - /* Ok, but check other params, too. */ - -#if 0 - memcpy(&g_pmsm_v4l2_dev->current_pix_format.fmt.pix, pfmt, - sizeof(struct v4l2_format)); -#endif - - g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); - - return 0; -} - -static int msm_v4l2_g_fmt_overlay(struct file *f, - void *pctx, struct v4l2_format *pfmt) -{ - D("%s\n", __func__); - pfmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; - pfmt->fmt.pix.width = MSM_V4L2_WIDTH; - pfmt->fmt.pix.height = MSM_V4L2_HEIGHT; - pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420; - pfmt->fmt.pix.field = V4L2_FIELD_ANY; - pfmt->fmt.pix.bytesperline = 0; - pfmt->fmt.pix.sizeimage = 0; - pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - pfmt->fmt.pix.priv = 0; - return 0; -} - -static int msm_v4l2_s_fmt_overlay(struct file *f, - void *pctx, struct v4l2_format *pfmt) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_g_jpegcomp(struct file *f, - void *pctx, struct v4l2_jpegcompression *pcomp) -{ - D("%s\n", __func__); - return 0; -} - -static int msm_v4l2_s_jpegcomp(struct file *f, - void *pctx, struct v4l2_jpegcompression *pcomp) -{ - D("%s\n", __func__); - return 0; -} - -#ifdef CONFIG_PROC_FS -int msm_v4l2_read_proc(char *pbuf, char **start, off_t offset, - int count, int *eof, void *data) -{ - int len = 0; - len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n"); - - if (g_pmsm_v4l2_dev) { - len += snprintf(pbuf, strlen("mode: ") + 1, "mode: "); - - if (g_pmsm_v4l2_dev->current_cap_format.type - == V4L2_BUF_TYPE_VIDEO_CAPTURE) - len += snprintf(pbuf, strlen("capture\n") + 1, - "capture\n"); - else - len += snprintf(pbuf, strlen("unknown\n") + 1, - "unknown\n"); - - len += snprintf(pbuf, 21, "resolution: %dx%d\n", - g_pmsm_v4l2_dev->current_cap_format.fmt.pix. - width, - g_pmsm_v4l2_dev->current_cap_format.fmt.pix. - height); - - len += snprintf(pbuf, - strlen("pixel format: ") + 1, "pixel format: "); - if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.pixelformat - == V4L2_PIX_FMT_YVU420) - len += snprintf(pbuf, strlen("yvu420\n") + 1, - "yvu420\n"); - else - len += snprintf(pbuf, strlen("unknown\n") + 1, - "unknown\n"); - - len += snprintf(pbuf, strlen("colorspace: ") + 1, - "colorspace: "); - if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.colorspace - == V4L2_COLORSPACE_JPEG) - len += snprintf(pbuf, strlen("jpeg\n") + 1, "jpeg\n"); - else - len += snprintf(pbuf, strlen("unknown\n") + 1, - "unknown\n"); - } - - *eof = 1; - return len; -} -#endif - -static const struct v4l2_file_operations msm_v4l2_fops = { - .owner = THIS_MODULE, - .open = msm_v4l2_open, - .poll = msm_v4l2_poll, - .release = msm_v4l2_release, - .ioctl = msm_v4l2_ioctl, -}; - -static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev) -{ - pmsm_v4l2_dev->read_queue_lock = - __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev->read_queue_lock); - INIT_LIST_HEAD(&pmsm_v4l2_dev->read_queue); -} - -static int msm_v4l2_try_fmt_cap(struct file *file, - void *fh, struct v4l2_format *f) -{ - /* FIXME */ - return 0; -} - -static int mm_v4l2_try_fmt_type_private(struct file *file, - void *fh, struct v4l2_format *f) -{ - /* FIXME */ - return 0; -} - -/* - * should the following structure be used instead of the code in the function? - * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = { - * .vidioc_querycap = .... - * } - */ -static const struct v4l2_ioctl_ops msm_ioctl_ops = { - .vidioc_querycap = msm_v4l2_querycap, - .vidioc_s_std = msm_v4l2_s_std, - - .vidioc_queryctrl = msm_v4l2_queryctrl, - .vidioc_g_ctrl = msm_v4l2_g_ctrl, - .vidioc_s_ctrl = msm_v4l2_s_ctrl, - - .vidioc_reqbufs = msm_v4l2_reqbufs, - .vidioc_querybuf = msm_v4l2_querybuf, - .vidioc_qbuf = msm_v4l2_qbuf, - .vidioc_dqbuf = msm_v4l2_dqbuf, - - .vidioc_streamon = msm_v4l2_streamon, - .vidioc_streamoff = msm_v4l2_streamoff, - - .vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay, - .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap, - - .vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap, - .vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private, - - .vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt_cap, - .vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt_cap, - .vidioc_g_fmt_vid_overlay = msm_v4l2_g_fmt_overlay, - .vidioc_s_fmt_vid_overlay = msm_v4l2_s_fmt_overlay, - .vidioc_overlay = msm_v4l2_overlay, - - .vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp, - .vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp, -}; - -static int msm_v4l2_video_dev_init(struct video_device *pvd) -{ - strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name)); - pvd->vfl_type = 1; - pvd->fops = &msm_v4l2_fops; - pvd->release = msm_v4l2_release_dev; - pvd->minor = -1; - pvd->ioctl_ops = &msm_ioctl_ops; - return msm_v4l2_register(g_pmsm_v4l2_dev->drv); -} - -static int __init msm_v4l2_init(void) -{ - int rc = -ENOMEM; - struct video_device *pvdev = NULL; - struct msm_v4l2_device *pmsm_v4l2_dev = NULL; - D("%s\n", __func__); - - pvdev = video_device_alloc(); - if (pvdev == NULL) - return rc; - - pmsm_v4l2_dev = - kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL); - if (pmsm_v4l2_dev == NULL) { - video_device_release(pvdev); - return rc; - } - - msm_v4l2_dev_init(pmsm_v4l2_dev); - - g_pmsm_v4l2_dev = pmsm_v4l2_dev; - g_pmsm_v4l2_dev->pvdev = pvdev; - - g_pmsm_v4l2_dev->drv = - kzalloc(sizeof(struct msm_v4l2_driver), GFP_KERNEL); - if (!g_pmsm_v4l2_dev->drv) { - video_device_release(pvdev); - kfree(pmsm_v4l2_dev); - return rc; - } - - rc = msm_v4l2_video_dev_init(pvdev); - if (rc < 0) { - video_device_release(pvdev); - kfree(g_pmsm_v4l2_dev->drv); - kfree(pmsm_v4l2_dev); - return rc; - } - - if (video_register_device(pvdev, VFL_TYPE_GRABBER, - MSM_V4L2_DEVNUM_YUV)) { - D("failed to register device\n"); - video_device_release(pvdev); - kfree(g_pmsm_v4l2_dev); - g_pmsm_v4l2_dev = NULL; - return -ENOENT; - } -#ifdef CONFIG_PROC_FS - create_proc_read_entry(MSM_V4L2_PROC_NAME, - 0, NULL, msm_v4l2_read_proc, NULL); -#endif - - return 0; -} - -static void __exit msm_v4l2_exit(void) -{ - struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev; - D("%s\n", __func__); -#ifdef CONFIG_PROC_FS - remove_proc_entry(MSM_V4L2_PROC_NAME, NULL); -#endif - video_unregister_device(pvdev); - video_device_release(pvdev); - - msm_v4l2_unregister(g_pmsm_v4l2_dev->drv); - - kfree(g_pmsm_v4l2_dev->drv); - g_pmsm_v4l2_dev->drv = NULL; - - kfree(g_pmsm_v4l2_dev); - g_pmsm_v4l2_dev = NULL; -} - -module_init(msm_v4l2_init); -module_exit(msm_v4l2_exit); - -MODULE_DESCRIPTION("MSM V4L2 driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/dream/camera/msm_vfe7x.c b/drivers/staging/dream/camera/msm_vfe7x.c deleted file mode 100644 index 198656ac3de5..000000000000 --- a/drivers/staging/dream/camera/msm_vfe7x.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include <linux/msm_adsp.h> -#include <linux/uaccess.h> -#include <linux/fs.h> -#include <linux/sched.h> -#include <linux/android_pmem.h> -#include <linux/slab.h> -#include <mach/msm_adsp.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include "msm_vfe7x.h" - -#define QDSP_CMDQUEUE QDSP_vfeCommandQueue - -#define VFE_RESET_CMD 0 -#define VFE_START_CMD 1 -#define VFE_STOP_CMD 2 -#define VFE_FRAME_ACK 20 -#define STATS_AF_ACK 21 -#define STATS_WE_ACK 22 - -#define MSG_STOP_ACK 1 -#define MSG_SNAPSHOT 2 -#define MSG_OUTPUT1 6 -#define MSG_OUTPUT2 7 -#define MSG_STATS_AF 8 -#define MSG_STATS_WE 9 - -static struct msm_adsp_module *qcam_mod; -static struct msm_adsp_module *vfe_mod; -static struct msm_vfe_callback *resp; -static void *extdata; -static uint32_t extlen; - -struct mutex vfe_lock; -static void *vfe_syncdata; -static uint8_t vfestopped; - -static struct stop_event stopevent; - -static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo, - enum vfe_resp_msg type, - void *data, void **ext, int32_t *elen) -{ - switch (type) { - case VFE_MSG_OUTPUT1: - case VFE_MSG_OUTPUT2: { - pinfo->y_phy = ((struct vfe_endframe *)data)->y_address; - pinfo->cbcr_phy = - ((struct vfe_endframe *)data)->cbcr_address; - - CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n", - pinfo->y_phy, pinfo->cbcr_phy); - - ((struct vfe_frame_extra *)extdata)->bl_evencol = - ((struct vfe_endframe *)data)->blacklevelevencolumn; - - ((struct vfe_frame_extra *)extdata)->bl_oddcol = - ((struct vfe_endframe *)data)->blackleveloddcolumn; - - ((struct vfe_frame_extra *)extdata)->g_def_p_cnt = - ((struct vfe_endframe *)data)->greendefectpixelcount; - - ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt = - ((struct vfe_endframe *)data)->redbluedefectpixelcount; - - *ext = extdata; - *elen = extlen; - } - break; - - case VFE_MSG_STATS_AF: - case VFE_MSG_STATS_WE: - pinfo->sbuf_phy = *(uint32_t *)data; - break; - - default: - break; - } /* switch */ -} - -static void vfe_7x_ops(void *driver_data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)) -{ - uint32_t evt_buf[3]; - struct msm_vfe_resp *rp; - void *data; - - len = (id == (uint16_t)-1) ? 0 : len; - data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata); - - if (!data) { - pr_err("rp: cannot allocate buffer\n"); - return; - } - rp = (struct msm_vfe_resp *)data; - rp->evt_msg.len = len; - - if (id == ((uint16_t)-1)) { - /* event */ - rp->type = VFE_EVENT; - rp->evt_msg.type = MSM_CAMERA_EVT; - getevent(evt_buf, sizeof(evt_buf)); - rp->evt_msg.msg_id = evt_buf[0]; - resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata); - } else { - /* messages */ - rp->evt_msg.type = MSM_CAMERA_MSG; - rp->evt_msg.msg_id = id; - rp->evt_msg.data = rp + 1; - getevent(rp->evt_msg.data, len); - - switch (rp->evt_msg.msg_id) { - case MSG_SNAPSHOT: - rp->type = VFE_MSG_SNAPSHOT; - break; - - case MSG_OUTPUT1: - rp->type = VFE_MSG_OUTPUT1; - vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1, - rp->evt_msg.data, &(rp->extdata), - &(rp->extlen)); - break; - - case MSG_OUTPUT2: - rp->type = VFE_MSG_OUTPUT2; - vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2, - rp->evt_msg.data, &(rp->extdata), - &(rp->extlen)); - break; - - case MSG_STATS_AF: - rp->type = VFE_MSG_STATS_AF; - vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF, - rp->evt_msg.data, NULL, NULL); - break; - - case MSG_STATS_WE: - rp->type = VFE_MSG_STATS_WE; - vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE, - rp->evt_msg.data, NULL, NULL); - - CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy); - break; - - case MSG_STOP_ACK: - rp->type = VFE_MSG_GENERAL; - stopevent.state = 1; - wake_up(&stopevent.wait); - break; - - - default: - rp->type = VFE_MSG_GENERAL; - break; - } - resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata); - } -} - -static struct msm_adsp_ops vfe_7x_sync = { - .event = vfe_7x_ops, -}; - -static int vfe_7x_enable(struct camera_enable_cmd *enable) -{ - int rc = -EFAULT; - - if (!strcmp(enable->name, "QCAMTASK")) - rc = msm_adsp_enable(qcam_mod); - else if (!strcmp(enable->name, "VFETASK")) - rc = msm_adsp_enable(vfe_mod); - - return rc; -} - -static int vfe_7x_disable(struct camera_enable_cmd *enable, - struct platform_device *dev __attribute__((unused))) -{ - int rc = -EFAULT; - - if (!strcmp(enable->name, "QCAMTASK")) - rc = msm_adsp_disable(qcam_mod); - else if (!strcmp(enable->name, "VFETASK")) - rc = msm_adsp_disable(vfe_mod); - - return rc; -} - -static int vfe_7x_stop(void) -{ - int rc = 0; - uint32_t stopcmd = VFE_STOP_CMD; - rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE, - &stopcmd, sizeof(uint32_t)); - if (rc < 0) { - CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc); - return rc; - } - - stopevent.state = 0; - rc = wait_event_timeout(stopevent.wait, - stopevent.state != 0, - msecs_to_jiffies(stopevent.timeout)); - - return rc; -} - -static void vfe_7x_release(struct platform_device *pdev) -{ - mutex_lock(&vfe_lock); - vfe_syncdata = NULL; - mutex_unlock(&vfe_lock); - - if (!vfestopped) { - CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__); - vfe_7x_stop(); - } else - vfestopped = 0; - - msm_adsp_disable(qcam_mod); - msm_adsp_disable(vfe_mod); - - msm_adsp_put(qcam_mod); - msm_adsp_put(vfe_mod); - - msm_camio_disable(pdev); - - kfree(extdata); - extlen = 0; -} - -static int vfe_7x_init(struct msm_vfe_callback *presp, - struct platform_device *dev) -{ - int rc = 0; - - init_waitqueue_head(&stopevent.wait); - stopevent.timeout = 200; - stopevent.state = 0; - - if (presp && presp->vfe_resp) - resp = presp; - else - return -EFAULT; - - /* Bring up all the required GPIOs and Clocks */ - rc = msm_camio_enable(dev); - if (rc < 0) - return rc; - - msm_camio_camif_pad_reg_reset(); - - extlen = sizeof(struct vfe_frame_extra); - - extdata = kmalloc(extlen, GFP_ATOMIC); - if (!extdata) { - rc = -ENOMEM; - goto init_fail; - } - - rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL); - if (rc) { - rc = -EBUSY; - goto get_qcam_fail; - } - - rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL); - if (rc) { - rc = -EBUSY; - goto get_vfe_fail; - } - - return 0; - -get_vfe_fail: - msm_adsp_put(qcam_mod); -get_qcam_fail: - kfree(extdata); -init_fail: - extlen = 0; - return rc; -} - -static int vfe_7x_config_axi(int mode, - struct axidata *ad, struct axiout *ao) -{ - struct msm_pmem_region *regptr; - unsigned long *bptr; - int cnt; - - int rc = 0; - - if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) { - regptr = ad->region; - - CDBG("bufnum1 = %d\n", ad->bufnum1); - CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", - regptr->paddr, regptr->y_off, regptr->cbcr_off); - - bptr = &ao->output1buffer1_y_phy; - for (cnt = 0; cnt < ad->bufnum1; cnt++) { - *bptr = regptr->paddr + regptr->y_off; - bptr++; - *bptr = regptr->paddr + regptr->cbcr_off; - - bptr++; - regptr++; - } - - regptr--; - for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) { - *bptr = regptr->paddr + regptr->y_off; - bptr++; - *bptr = regptr->paddr + regptr->cbcr_off; - bptr++; - } - } /* if OUTPUT1 or Both */ - - if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) { - regptr = &(ad->region[ad->bufnum1]); - - CDBG("bufnum2 = %d\n", ad->bufnum2); - CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n", - regptr->paddr, regptr->y_off, regptr->cbcr_off); - - bptr = &ao->output2buffer1_y_phy; - for (cnt = 0; cnt < ad->bufnum2; cnt++) { - *bptr = regptr->paddr + regptr->y_off; - bptr++; - *bptr = regptr->paddr + regptr->cbcr_off; - - bptr++; - regptr++; - } - - regptr--; - for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) { - *bptr = regptr->paddr + regptr->y_off; - bptr++; - *bptr = regptr->paddr + regptr->cbcr_off; - bptr++; - } - } - - return rc; -} - -static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data) -{ - struct msm_pmem_region *regptr; - unsigned char buf[256]; - - struct vfe_stats_ack sack; - struct axidata *axid; - uint32_t i; - - struct vfe_stats_we_cfg *scfg = NULL; - struct vfe_stats_af_cfg *sfcfg = NULL; - - struct axiout *axio = NULL; - void *cmd_data = NULL; - void *cmd_data_alloc = NULL; - long rc = 0; - struct msm_vfe_command_7k *vfecmd; - - vfecmd = - kmalloc(sizeof(struct msm_vfe_command_7k), - GFP_ATOMIC); - if (!vfecmd) { - pr_err("vfecmd alloc failed!\n"); - return -ENOMEM; - } - - if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && - cmd->cmd_type != CMD_STATS_BUF_RELEASE && - cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) { - if (copy_from_user(vfecmd, - (void __user *)(cmd->value), - sizeof(struct msm_vfe_command_7k))) { - rc = -EFAULT; - goto config_failure; - } - } - - switch (cmd->cmd_type) { - case CMD_STATS_ENABLE: - case CMD_STATS_AXI_CFG: { - axid = data; - if (!axid) { - rc = -EFAULT; - goto config_failure; - } - - scfg = - kmalloc(sizeof(struct vfe_stats_we_cfg), - GFP_ATOMIC); - if (!scfg) { - rc = -ENOMEM; - goto config_failure; - } - - if (copy_from_user(scfg, - (void __user *)(vfecmd->value), - vfecmd->length)) { - - rc = -EFAULT; - goto config_done; - } - - CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n", - axid->bufnum1, scfg->wb_expstatsenable); - - if (axid->bufnum1 > 0) { - regptr = axid->region; - - for (i = 0; i < axid->bufnum1; i++) { - - CDBG("STATS_ENABLE, phy = 0x%lx\n", - regptr->paddr); - - scfg->wb_expstatoutputbuffer[i] = - (void *)regptr->paddr; - regptr++; - } - - cmd_data = scfg; - - } else { - rc = -EINVAL; - goto config_done; - } - } - break; - - case CMD_STATS_AF_ENABLE: - case CMD_STATS_AF_AXI_CFG: { - axid = data; - if (!axid) { - rc = -EFAULT; - goto config_failure; - } - - sfcfg = - kmalloc(sizeof(struct vfe_stats_af_cfg), - GFP_ATOMIC); - - if (!sfcfg) { - rc = -ENOMEM; - goto config_failure; - } - - if (copy_from_user(sfcfg, - (void __user *)(vfecmd->value), - vfecmd->length)) { - - rc = -EFAULT; - goto config_done; - } - - CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n", - axid->bufnum1, sfcfg->af_enable); - - if (axid->bufnum1 > 0) { - regptr = axid->region; - - for (i = 0; i < axid->bufnum1; i++) { - - CDBG("STATS_ENABLE, phy = 0x%lx\n", - regptr->paddr); - - sfcfg->af_outbuf[i] = - (void *)regptr->paddr; - - regptr++; - } - - cmd_data = sfcfg; - - } else { - rc = -EINVAL; - goto config_done; - } - } - break; - - case CMD_FRAME_BUF_RELEASE: { - struct msm_frame *b; - unsigned long p; - struct vfe_outputack fack; - if (!data) { - rc = -EFAULT; - goto config_failure; - } - - b = (struct msm_frame *)(cmd->value); - p = *(unsigned long *)data; - - fack.header = VFE_FRAME_ACK; - - fack.output2newybufferaddress = - (void *)(p + b->y_off); - - fack.output2newcbcrbufferaddress = - (void *)(p + b->cbcr_off); - - vfecmd->queue = QDSP_CMDQUEUE; - vfecmd->length = sizeof(struct vfe_outputack); - cmd_data = &fack; - } - break; - - case CMD_SNAP_BUF_RELEASE: - break; - - case CMD_STATS_BUF_RELEASE: { - CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n"); - if (!data) { - rc = -EFAULT; - goto config_failure; - } - - sack.header = STATS_WE_ACK; - sack.bufaddr = (void *)*(uint32_t *)data; - - vfecmd->queue = QDSP_CMDQUEUE; - vfecmd->length = sizeof(struct vfe_stats_ack); - cmd_data = &sack; - } - break; - - case CMD_STATS_AF_BUF_RELEASE: { - CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n"); - if (!data) { - rc = -EFAULT; - goto config_failure; - } - - sack.header = STATS_AF_ACK; - sack.bufaddr = (void *)*(uint32_t *)data; - - vfecmd->queue = QDSP_CMDQUEUE; - vfecmd->length = sizeof(struct vfe_stats_ack); - cmd_data = &sack; - } - break; - - case CMD_GENERAL: - case CMD_STATS_DISABLE: { - if (vfecmd->length > 256) { - cmd_data_alloc = - cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC); - if (!cmd_data) { - rc = -ENOMEM; - goto config_failure; - } - } else - cmd_data = buf; - - if (copy_from_user(cmd_data, - (void __user *)(vfecmd->value), - vfecmd->length)) { - - rc = -EFAULT; - goto config_done; - } - - if (vfecmd->queue == QDSP_CMDQUEUE) { - switch (*(uint32_t *)cmd_data) { - case VFE_RESET_CMD: - msm_camio_vfe_blk_reset(); - msm_camio_camif_pad_reg_reset_2(); - vfestopped = 0; - break; - - case VFE_START_CMD: - msm_camio_camif_pad_reg_reset_2(); - vfestopped = 0; - break; - - case VFE_STOP_CMD: - vfestopped = 1; - goto config_send; - - default: - break; - } - } /* QDSP_CMDQUEUE */ - } - break; - - case CMD_AXI_CFG_OUT1: { - axid = data; - if (!axid) { - rc = -EFAULT; - goto config_failure; - } - - axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); - if (!axio) { - rc = -ENOMEM; - goto config_failure; - } - - if (copy_from_user(axio, (void *)(vfecmd->value), - sizeof(struct axiout))) { - rc = -EFAULT; - goto config_done; - } - - vfe_7x_config_axi(OUTPUT_1, axid, axio); - - cmd_data = axio; - } - break; - - case CMD_AXI_CFG_OUT2: - case CMD_RAW_PICT_AXI_CFG: { - axid = data; - if (!axid) { - rc = -EFAULT; - goto config_failure; - } - - axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); - if (!axio) { - rc = -ENOMEM; - goto config_failure; - } - - if (copy_from_user(axio, (void __user *)(vfecmd->value), - sizeof(struct axiout))) { - rc = -EFAULT; - goto config_done; - } - - vfe_7x_config_axi(OUTPUT_2, axid, axio); - cmd_data = axio; - } - break; - - case CMD_AXI_CFG_SNAP_O1_AND_O2: { - axid = data; - if (!axid) { - rc = -EFAULT; - goto config_failure; - } - - axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC); - if (!axio) { - rc = -ENOMEM; - goto config_failure; - } - - if (copy_from_user(axio, (void __user *)(vfecmd->value), - sizeof(struct axiout))) { - rc = -EFAULT; - goto config_done; - } - - vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio); - - cmd_data = axio; - } - break; - - default: - break; - } /* switch */ - - if (vfestopped) - goto config_done; - -config_send: - CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data); - rc = msm_adsp_write(vfe_mod, vfecmd->queue, - cmd_data, vfecmd->length); - -config_done: - if (cmd_data_alloc != NULL) - kfree(cmd_data_alloc); - -config_failure: - kfree(scfg); - kfree(axio); - kfree(vfecmd); - return rc; -} - -void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) -{ - mutex_init(&vfe_lock); - fptr->vfe_init = vfe_7x_init; - fptr->vfe_enable = vfe_7x_enable; - fptr->vfe_config = vfe_7x_config; - fptr->vfe_disable = vfe_7x_disable; - fptr->vfe_release = vfe_7x_release; - vfe_syncdata = data; -} diff --git a/drivers/staging/dream/camera/msm_vfe7x.h b/drivers/staging/dream/camera/msm_vfe7x.h deleted file mode 100644 index be3e9ad8f524..000000000000 --- a/drivers/staging/dream/camera/msm_vfe7x.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ -#ifndef __MSM_VFE7X_H__ -#define __MSM_VFE7X_H__ -#include <media/msm_camera.h> -#include <mach/camera.h> - -struct vfe_frame_extra { - uint32_t bl_evencol; - uint32_t bl_oddcol; - uint16_t g_def_p_cnt; - uint16_t r_b_def_p_cnt; -}; - -struct vfe_endframe { - uint32_t y_address; - uint32_t cbcr_address; - - unsigned int blacklevelevencolumn:23; - uint16_t reserved1:9; - unsigned int blackleveloddcolumn:23; - uint16_t reserved2:9; - - uint16_t greendefectpixelcount:8; - uint16_t reserved3:8; - uint16_t redbluedefectpixelcount:8; - uint16_t reserved4:8; -} __attribute__((packed, aligned(4))); - -struct vfe_outputack { - uint32_t header; - void *output2newybufferaddress; - void *output2newcbcrbufferaddress; -} __attribute__((packed, aligned(4))); - -struct vfe_stats_ack { - uint32_t header; - /* MUST BE 64 bit ALIGNED */ - void *bufaddr; -} __attribute__((packed, aligned(4))); - -/* AXI Output Config Command sent to DSP */ -struct axiout { - uint32_t cmdheader:32; - int outputmode:3; - uint8_t format:2; - uint32_t /* reserved */ : 27; - - /* AXI Output 1 Y Configuration, Part 1 */ - uint32_t out1yimageheight:12; - uint32_t /* reserved */ : 4; - uint32_t out1yimagewidthin64bitwords:10; - uint32_t /* reserved */ : 6; - - /* AXI Output 1 Y Configuration, Part 2 */ - uint8_t out1yburstlen:2; - uint32_t out1ynumrows:12; - uint32_t out1yrowincin64bitincs:12; - uint32_t /* reserved */ : 6; - - /* AXI Output 1 CbCr Configuration, Part 1 */ - uint32_t out1cbcrimageheight:12; - uint32_t /* reserved */ : 4; - uint32_t out1cbcrimagewidthin64bitwords:10; - uint32_t /* reserved */ : 6; - - /* AXI Output 1 CbCr Configuration, Part 2 */ - uint8_t out1cbcrburstlen:2; - uint32_t out1cbcrnumrows:12; - uint32_t out1cbcrrowincin64bitincs:12; - uint32_t /* reserved */ : 6; - - /* AXI Output 2 Y Configuration, Part 1 */ - uint32_t out2yimageheight:12; - uint32_t /* reserved */ : 4; - uint32_t out2yimagewidthin64bitwords:10; - uint32_t /* reserved */ : 6; - - /* AXI Output 2 Y Configuration, Part 2 */ - uint8_t out2yburstlen:2; - uint32_t out2ynumrows:12; - uint32_t out2yrowincin64bitincs:12; - uint32_t /* reserved */ : 6; - - /* AXI Output 2 CbCr Configuration, Part 1 */ - uint32_t out2cbcrimageheight:12; - uint32_t /* reserved */ : 4; - uint32_t out2cbcrimagewidtein64bitwords:10; - uint32_t /* reserved */ : 6; - - /* AXI Output 2 CbCr Configuration, Part 2 */ - uint8_t out2cbcrburstlen:2; - uint32_t out2cbcrnumrows:12; - uint32_t out2cbcrrowincin64bitincs:12; - uint32_t /* reserved */ : 6; - - /* Address configuration: - * output1 phisycal address */ - unsigned long output1buffer1_y_phy; - unsigned long output1buffer1_cbcr_phy; - unsigned long output1buffer2_y_phy; - unsigned long output1buffer2_cbcr_phy; - unsigned long output1buffer3_y_phy; - unsigned long output1buffer3_cbcr_phy; - unsigned long output1buffer4_y_phy; - unsigned long output1buffer4_cbcr_phy; - unsigned long output1buffer5_y_phy; - unsigned long output1buffer5_cbcr_phy; - unsigned long output1buffer6_y_phy; - unsigned long output1buffer6_cbcr_phy; - unsigned long output1buffer7_y_phy; - unsigned long output1buffer7_cbcr_phy; - unsigned long output1buffer8_y_phy; - unsigned long output1buffer8_cbcr_phy; - - /* output2 phisycal address */ - unsigned long output2buffer1_y_phy; - unsigned long output2buffer1_cbcr_phy; - unsigned long output2buffer2_y_phy; - unsigned long output2buffer2_cbcr_phy; - unsigned long output2buffer3_y_phy; - unsigned long output2buffer3_cbcr_phy; - unsigned long output2buffer4_y_phy; - unsigned long output2buffer4_cbcr_phy; - unsigned long output2buffer5_y_phy; - unsigned long output2buffer5_cbcr_phy; - unsigned long output2buffer6_y_phy; - unsigned long output2buffer6_cbcr_phy; - unsigned long output2buffer7_y_phy; - unsigned long output2buffer7_cbcr_phy; - unsigned long output2buffer8_y_phy; - unsigned long output2buffer8_cbcr_phy; -} __attribute__((packed, aligned(4))); - -struct vfe_stats_we_cfg { - uint32_t header; - - /* White Balance/Exposure Statistic Selection */ - uint8_t wb_expstatsenable:1; - uint8_t wb_expstatbuspriorityselection:1; - unsigned int wb_expstatbuspriorityvalue:4; - unsigned int /* reserved */ : 26; - - /* White Balance/Exposure Statistic Configuration, Part 1 */ - uint8_t exposurestatregions:1; - uint8_t exposurestatsubregions:1; - unsigned int /* reserved */ : 14; - - unsigned int whitebalanceminimumy:8; - unsigned int whitebalancemaximumy:8; - - /* White Balance/Exposure Statistic Configuration, Part 2 */ - uint8_t wb_expstatslopeofneutralregionline[ - NUM_WB_EXP_NEUTRAL_REGION_LINES]; - - /* White Balance/Exposure Statistic Configuration, Part 3 */ - unsigned int wb_expstatcrinterceptofneutralregionline2:12; - unsigned int /* reserved */ : 4; - unsigned int wb_expstatcbinterceptofneutralreginnline1:12; - unsigned int /* reserved */ : 4; - - /* White Balance/Exposure Statistic Configuration, Part 4 */ - unsigned int wb_expstatcrinterceptofneutralregionline4:12; - unsigned int /* reserved */ : 4; - unsigned int wb_expstatcbinterceptofneutralregionline3:12; - unsigned int /* reserved */ : 4; - - /* White Balance/Exposure Statistic Output Buffer Header */ - unsigned int wb_expmetricheaderpattern:8; - unsigned int /* reserved */ : 24; - - /* White Balance/Exposure Statistic Output Buffers-MUST - * BE 64 bit ALIGNED */ - void *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS]; -} __attribute__((packed, aligned(4))); - -struct vfe_stats_af_cfg { - uint32_t header; - - /* Autofocus Statistic Selection */ - uint8_t af_enable:1; - uint8_t af_busprioritysel:1; - unsigned int af_buspriorityval:4; - unsigned int /* reserved */ : 26; - - /* Autofocus Statistic Configuration, Part 1 */ - unsigned int af_singlewinvoffset:12; - unsigned int /* reserved */ : 4; - unsigned int af_singlewinhoffset:12; - unsigned int /* reserved */ : 3; - uint8_t af_winmode:1; - - /* Autofocus Statistic Configuration, Part 2 */ - unsigned int af_singglewinvh:11; - unsigned int /* reserved */ : 5; - unsigned int af_singlewinhw:11; - unsigned int /* reserved */ : 5; - - /* Autofocus Statistic Configuration, Parts 3-6 */ - uint8_t af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS]; - - /* Autofocus Statistic Configuration, Part 7 */ - signed int af_metrichpfcoefa00:5; - signed int af_metrichpfcoefa04:5; - unsigned int af_metricmaxval:11; - uint8_t af_metricsel:1; - unsigned int /* reserved */ : 10; - - /* Autofocus Statistic Configuration, Part 8 */ - signed int af_metrichpfcoefa20:5; - signed int af_metrichpfcoefa21:5; - signed int af_metrichpfcoefa22:5; - signed int af_metrichpfcoefa23:5; - signed int af_metrichpfcoefa24:5; - unsigned int /* reserved */ : 7; - - /* Autofocus Statistic Output Buffer Header */ - unsigned int af_metrichp:8; - unsigned int /* reserved */ : 24; - - /* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */ - void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS]; -} __attribute__((packed, aligned(4))); /* VFE_StatsAutofocusConfigCmdType */ - -struct msm_camera_frame_msg { - unsigned long output_y_address; - unsigned long output_cbcr_address; - - unsigned int blacklevelevenColumn:23; - uint16_t reserved1:9; - unsigned int blackleveloddColumn:23; - uint16_t reserved2:9; - - uint16_t greendefectpixelcount:8; - uint16_t reserved3:8; - uint16_t redbluedefectpixelcount:8; - uint16_t reserved4:8; -} __attribute__((packed, aligned(4))); - -/* New one for 7k */ -struct msm_vfe_command_7k { - uint16_t queue; - uint16_t length; - void *value; -}; - -struct stop_event { - wait_queue_head_t wait; - int state; - int timeout; -}; - - -#endif /* __MSM_VFE7X_H__ */ diff --git a/drivers/staging/dream/camera/msm_vfe8x.c b/drivers/staging/dream/camera/msm_vfe8x.c deleted file mode 100644 index d87d56f914de..000000000000 --- a/drivers/staging/dream/camera/msm_vfe8x.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/interrupt.h> -#include <mach/irqs.h> -#include "msm_vfe8x_proc.h" - -#define ON 1 -#define OFF 0 - -struct mutex vfe_lock; -static void *vfe_syncdata; - -static int vfe_enable(struct camera_enable_cmd *enable) -{ - int rc = 0; - return rc; -} - -static int vfe_disable(struct camera_enable_cmd *enable, - struct platform_device *dev) -{ - int rc = 0; - - vfe_stop(); - - msm_camio_disable(dev); - return rc; -} - -static void vfe_release(struct platform_device *dev) -{ - msm_camio_disable(dev); - vfe_cmd_release(dev); - - mutex_lock(&vfe_lock); - vfe_syncdata = NULL; - mutex_unlock(&vfe_lock); -} - -static void vfe_config_axi(int mode, - struct axidata *ad, struct vfe_cmd_axi_output_config *ao) -{ - struct msm_pmem_region *regptr; - int i, j; - uint32_t *p1, *p2; - - if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) { - regptr = ad->region; - for (i = 0; - i < ad->bufnum1; i++) { - - p1 = &(ao->output1.outputY.outFragments[i][0]); - p2 = &(ao->output1.outputCbcr.outFragments[i][0]); - - for (j = 0; - j < ao->output1.fragmentCount; j++) { - - *p1 = regptr->paddr + regptr->y_off; - p1++; - - *p2 = regptr->paddr + regptr->cbcr_off; - p2++; - } - regptr++; - } - } /* if OUTPUT1 or Both */ - - if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) { - - regptr = &(ad->region[ad->bufnum1]); - CDBG("bufnum2 = %d\n", ad->bufnum2); - - for (i = 0; - i < ad->bufnum2; i++) { - - p1 = &(ao->output2.outputY.outFragments[i][0]); - p2 = &(ao->output2.outputCbcr.outFragments[i][0]); - - CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, cbcr_off = %d\n", - regptr->paddr, regptr->y_off, regptr->cbcr_off); - - for (j = 0; - j < ao->output2.fragmentCount; j++) { - - *p1 = regptr->paddr + regptr->y_off; - CDBG("vfe_config_axi: p1 = 0x%x\n", *p1); - p1++; - - *p2 = regptr->paddr + regptr->cbcr_off; - CDBG("vfe_config_axi: p2 = 0x%x\n", *p2); - p2++; - } - regptr++; - } - } -} - -static int vfe_proc_general(struct msm_vfe_command_8k *cmd) -{ - int rc = 0; - - CDBG("vfe_proc_general: cmdID = %d\n", cmd->id); - - switch (cmd->id) { - case VFE_CMD_ID_RESET: - msm_camio_vfe_blk_reset(); - msm_camio_camif_pad_reg_reset_2(); - vfe_reset(); - break; - - case VFE_CMD_ID_START: { - struct vfe_cmd_start start; - if (copy_from_user(&start, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - /* msm_camio_camif_pad_reg_reset_2(); */ - msm_camio_camif_pad_reg_reset(); - vfe_start(&start); - } - break; - - case VFE_CMD_ID_CAMIF_CONFIG: { - struct vfe_cmd_camif_config camif; - if (copy_from_user(&camif, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_camif_config(&camif); - } - break; - - case VFE_CMD_ID_BLACK_LEVEL_CONFIG: { - struct vfe_cmd_black_level_config bl; - if (copy_from_user(&bl, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_black_level_config(&bl); - } - break; - - case VFE_CMD_ID_ROLL_OFF_CONFIG: { - struct vfe_cmd_roll_off_config rolloff; - if (copy_from_user(&rolloff, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_roll_off_config(&rolloff); - } - break; - - case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG: { - struct vfe_cmd_demux_channel_gain_config demuxc; - if (copy_from_user(&demuxc, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - /* demux is always enabled. */ - vfe_demux_channel_gain_config(&demuxc); - } - break; - - case VFE_CMD_ID_DEMOSAIC_CONFIG: { - struct vfe_cmd_demosaic_config demosaic; - if (copy_from_user(&demosaic, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_demosaic_config(&demosaic); - } - break; - - case VFE_CMD_ID_FOV_CROP_CONFIG: - case VFE_CMD_ID_FOV_CROP_UPDATE: { - struct vfe_cmd_fov_crop_config fov; - if (copy_from_user(&fov, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_fov_crop_config(&fov); - } - break; - - case VFE_CMD_ID_MAIN_SCALER_CONFIG: - case VFE_CMD_ID_MAIN_SCALER_UPDATE: { - struct vfe_cmd_main_scaler_config mainds; - if (copy_from_user(&mainds, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_main_scaler_config(&mainds); - } - break; - - case VFE_CMD_ID_WHITE_BALANCE_CONFIG: - case VFE_CMD_ID_WHITE_BALANCE_UPDATE: { - struct vfe_cmd_white_balance_config wb; - if (copy_from_user(&wb, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_white_balance_config(&wb); - } - break; - - case VFE_CMD_ID_COLOR_CORRECTION_CONFIG: - case VFE_CMD_ID_COLOR_CORRECTION_UPDATE: { - struct vfe_cmd_color_correction_config cc; - if (copy_from_user(&cc, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_color_correction_config(&cc); - } - break; - - case VFE_CMD_ID_LA_CONFIG: { - struct vfe_cmd_la_config la; - if (copy_from_user(&la, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_la_config(&la); - } - break; - - case VFE_CMD_ID_RGB_GAMMA_CONFIG: { - struct vfe_cmd_rgb_gamma_config rgb; - if (copy_from_user(&rgb, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - rc = vfe_rgb_gamma_config(&rgb); - } - break; - - case VFE_CMD_ID_CHROMA_ENHAN_CONFIG: - case VFE_CMD_ID_CHROMA_ENHAN_UPDATE: { - struct vfe_cmd_chroma_enhan_config chrom; - if (copy_from_user(&chrom, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_chroma_enhan_config(&chrom); - } - break; - - case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG: - case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE: { - struct vfe_cmd_chroma_suppression_config chromsup; - if (copy_from_user(&chromsup, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_chroma_sup_config(&chromsup); - } - break; - - case VFE_CMD_ID_ASF_CONFIG: { - struct vfe_cmd_asf_config asf; - if (copy_from_user(&asf, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_asf_config(&asf); - } - break; - - case VFE_CMD_ID_SCALER2Y_CONFIG: - case VFE_CMD_ID_SCALER2Y_UPDATE: { - struct vfe_cmd_scaler2_config ds2y; - if (copy_from_user(&ds2y, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_scaler2y_config(&ds2y); - } - break; - - case VFE_CMD_ID_SCALER2CbCr_CONFIG: - case VFE_CMD_ID_SCALER2CbCr_UPDATE: { - struct vfe_cmd_scaler2_config ds2cbcr; - if (copy_from_user(&ds2cbcr, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_scaler2cbcr_config(&ds2cbcr); - } - break; - - case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG: { - struct vfe_cmd_chroma_subsample_config sub; - if (copy_from_user(&sub, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_chroma_subsample_config(&sub); - } - break; - - case VFE_CMD_ID_FRAME_SKIP_CONFIG: { - struct vfe_cmd_frame_skip_config fskip; - if (copy_from_user(&fskip, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_frame_skip_config(&fskip); - } - break; - - case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG: { - struct vfe_cmd_output_clamp_config clamp; - if (copy_from_user(&clamp, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_output_clamp_config(&clamp); - } - break; - - /* module update commands */ - case VFE_CMD_ID_BLACK_LEVEL_UPDATE: { - struct vfe_cmd_black_level_config blk; - if (copy_from_user(&blk, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_black_level_update(&blk); - } - break; - - case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE: { - struct vfe_cmd_demux_channel_gain_config dmu; - if (copy_from_user(&dmu, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_demux_channel_gain_update(&dmu); - } - break; - - case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE: { - struct vfe_cmd_demosaic_bpc_update demo_bpc; - if (copy_from_user(&demo_bpc, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_demosaic_bpc_update(&demo_bpc); - } - break; - - case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE: { - struct vfe_cmd_demosaic_abf_update demo_abf; - if (copy_from_user(&demo_abf, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_demosaic_abf_update(&demo_abf); - } - break; - - case VFE_CMD_ID_LA_UPDATE: { - struct vfe_cmd_la_config la; - if (copy_from_user(&la, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_la_update(&la); - } - break; - - case VFE_CMD_ID_RGB_GAMMA_UPDATE: { - struct vfe_cmd_rgb_gamma_config rgb; - if (copy_from_user(&rgb, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - rc = vfe_rgb_gamma_update(&rgb); - } - break; - - case VFE_CMD_ID_ASF_UPDATE: { - struct vfe_cmd_asf_update asf; - if (copy_from_user(&asf, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_asf_update(&asf); - } - break; - - case VFE_CMD_ID_FRAME_SKIP_UPDATE: { - struct vfe_cmd_frame_skip_update fskip; - if (copy_from_user(&fskip, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_frame_skip_update(&fskip); - } - break; - - case VFE_CMD_ID_CAMIF_FRAME_UPDATE: { - struct vfe_cmds_camif_frame fup; - if (copy_from_user(&fup, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_camif_frame_update(&fup); - } - break; - - /* stats update commands */ - case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE: { - struct vfe_cmd_stats_af_update afup; - if (copy_from_user(&afup, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_stats_update_af(&afup); - } - break; - - case VFE_CMD_ID_STATS_WB_EXP_UPDATE: { - struct vfe_cmd_stats_wb_exp_update wbexp; - if (copy_from_user(&wbexp, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_stats_update_wb_exp(&wbexp); - } - break; - - /* control of start, stop, update, etc... */ - case VFE_CMD_ID_STOP: - vfe_stop(); - break; - - case VFE_CMD_ID_GET_HW_VERSION: - break; - - /* stats */ - case VFE_CMD_ID_STATS_SETTING: { - struct vfe_cmd_stats_setting stats; - if (copy_from_user(&stats, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_stats_setting(&stats); - } - break; - - case VFE_CMD_ID_STATS_AUTOFOCUS_START: { - struct vfe_cmd_stats_af_start af; - if (copy_from_user(&af, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_stats_start_af(&af); - } - break; - - case VFE_CMD_ID_STATS_AUTOFOCUS_STOP: - vfe_stats_af_stop(); - break; - - case VFE_CMD_ID_STATS_WB_EXP_START: { - struct vfe_cmd_stats_wb_exp_start awexp; - if (copy_from_user(&awexp, - (void __user *) cmd->value, cmd->length)) - rc = -EFAULT; - - vfe_stats_start_wb_exp(&awexp); - } - break; - - case VFE_CMD_ID_STATS_WB_EXP_STOP: - vfe_stats_wb_exp_stop(); - break; - - case VFE_CMD_ID_ASYNC_TIMER_SETTING: - break; - - case VFE_CMD_ID_UPDATE: - vfe_update(); - break; - - /* test gen */ - case VFE_CMD_ID_TEST_GEN_START: - break; - -/* - acknowledge from upper layer - these are not in general command. - - case VFE_CMD_ID_OUTPUT1_ACK: - break; - case VFE_CMD_ID_OUTPUT2_ACK: - break; - case VFE_CMD_ID_EPOCH1_ACK: - break; - case VFE_CMD_ID_EPOCH2_ACK: - break; - case VFE_CMD_ID_STATS_AUTOFOCUS_ACK: - break; - case VFE_CMD_ID_STATS_WB_EXP_ACK: - break; -*/ - - default: - break; - } /* switch */ - - return rc; -} - -static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data) -{ - struct msm_pmem_region *regptr; - struct msm_vfe_command_8k vfecmd; - - uint32_t i; - - void *cmd_data = NULL; - long rc = 0; - - struct vfe_cmd_axi_output_config *axio = NULL; - struct vfe_cmd_stats_setting *scfg = NULL; - - if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && - cmd->cmd_type != CMD_STATS_BUF_RELEASE) { - - if (copy_from_user(&vfecmd, - (void __user *)(cmd->value), - sizeof(struct msm_vfe_command_8k))) - return -EFAULT; - } - - CDBG("vfe_config: cmdType = %d\n", cmd->cmd_type); - - switch (cmd->cmd_type) { - case CMD_GENERAL: - rc = vfe_proc_general(&vfecmd); - break; - - case CMD_STATS_ENABLE: - case CMD_STATS_AXI_CFG: { - struct axidata *axid; - - axid = data; - if (!axid) - return -EFAULT; - - scfg = - kmalloc(sizeof(struct vfe_cmd_stats_setting), - GFP_ATOMIC); - if (!scfg) - return -ENOMEM; - - if (copy_from_user(scfg, - (void __user *)(vfecmd.value), - vfecmd.length)) { - - kfree(scfg); - return -EFAULT; - } - - regptr = axid->region; - if (axid->bufnum1 > 0) { - for (i = 0; i < axid->bufnum1; i++) { - scfg->awbBuffer[i] = - (uint32_t)(regptr->paddr); - regptr++; - } - } - - if (axid->bufnum2 > 0) { - for (i = 0; i < axid->bufnum2; i++) { - scfg->afBuffer[i] = - (uint32_t)(regptr->paddr); - regptr++; - } - } - - vfe_stats_config(scfg); - } - break; - - case CMD_STATS_AF_AXI_CFG: { - } - break; - - case CMD_FRAME_BUF_RELEASE: { - /* preview buffer release */ - struct msm_frame *b; - unsigned long p; - struct vfe_cmd_output_ack fack; - - if (!data) - return -EFAULT; - - b = (struct msm_frame *)(cmd->value); - p = *(unsigned long *)data; - - b->path = MSM_FRAME_ENC; - - fack.ybufaddr[0] = - (uint32_t)(p + b->y_off); - - fack.chromabufaddr[0] = - (uint32_t)(p + b->cbcr_off); - - if (b->path == MSM_FRAME_PREV_1) - vfe_output1_ack(&fack); - - if (b->path == MSM_FRAME_ENC || - b->path == MSM_FRAME_PREV_2) - vfe_output2_ack(&fack); - } - break; - - case CMD_SNAP_BUF_RELEASE: { - } - break; - - case CMD_STATS_BUF_RELEASE: { - struct vfe_cmd_stats_wb_exp_ack sack; - - if (!data) - return -EFAULT; - - sack.nextWbExpOutputBufferAddr = *(uint32_t *)data; - vfe_stats_wb_exp_ack(&sack); - } - break; - - case CMD_AXI_CFG_OUT1: { - struct axidata *axid; - - axid = data; - if (!axid) - return -EFAULT; - - axio = memdup_user((void __user *)(vfecmd.value), - sizeof(struct vfe_cmd_axi_output_config)); - if (IS_ERR(axio)) - return PTR_ERR(axio); - - vfe_config_axi(OUTPUT_1, axid, axio); - vfe_axi_output_config(axio); - } - break; - - case CMD_AXI_CFG_OUT2: - case CMD_RAW_PICT_AXI_CFG: { - struct axidata *axid; - - axid = data; - if (!axid) - return -EFAULT; - - axio = memdup_user((void __user *)(vfecmd.value), - sizeof(struct vfe_cmd_axi_output_config)); - if (IS_ERR(axio)) - return PTR_ERR(axio); - - vfe_config_axi(OUTPUT_2, axid, axio); - - axio->outputDataSize = 0; - vfe_axi_output_config(axio); - } - break; - - case CMD_AXI_CFG_SNAP_O1_AND_O2: { - struct axidata *axid; - axid = data; - if (!axid) - return -EFAULT; - - axio = memdup_user((void __user *)(vfecmd.value), - sizeof(struct vfe_cmd_axi_output_config)); - if (IS_ERR(axio)) - return PTR_ERR(axio); - - vfe_config_axi(OUTPUT_1_AND_2, - axid, axio); - vfe_axi_output_config(axio); - cmd_data = axio; - } - break; - - default: - break; - } /* switch */ - - kfree(scfg); - - kfree(axio); - -/* - if (cmd->length > 256 && - cmd_data && - (cmd->cmd_type == CMD_GENERAL || - cmd->cmd_type == CMD_STATS_DISABLE)) { - kfree(cmd_data); - } -*/ - return rc; -} - -static int vfe_init(struct msm_vfe_callback *presp, - struct platform_device *dev) -{ - int rc = 0; - - rc = vfe_cmd_init(presp, dev, vfe_syncdata); - if (rc < 0) - return rc; - - /* Bring up all the required GPIOs and Clocks */ - return msm_camio_enable(dev); -} - -void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data) -{ - mutex_init(&vfe_lock); - fptr->vfe_init = vfe_init; - fptr->vfe_enable = vfe_enable; - fptr->vfe_config = vfe_config; - fptr->vfe_disable = vfe_disable; - fptr->vfe_release = vfe_release; - vfe_syncdata = data; -} diff --git a/drivers/staging/dream/camera/msm_vfe8x.h b/drivers/staging/dream/camera/msm_vfe8x.h deleted file mode 100644 index 28a70a9e5ed7..000000000000 --- a/drivers/staging/dream/camera/msm_vfe8x.h +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ -#ifndef __MSM_VFE8X_H__ -#define __MSM_VFE8X_H__ - -#define TRUE 1 -#define FALSE 0 -#define boolean uint8_t - -enum VFE_STATE { - VFE_STATE_IDLE, - VFE_STATE_ACTIVE -}; - -enum vfe_cmd_id { - /* - *Important! Command_ID are arranged in order. - *Don't change!*/ - VFE_CMD_ID_START, - VFE_CMD_ID_RESET, - - /* bus and camif config */ - VFE_CMD_ID_AXI_INPUT_CONFIG, - VFE_CMD_ID_CAMIF_CONFIG, - VFE_CMD_ID_AXI_OUTPUT_CONFIG, - - /* module config */ - VFE_CMD_ID_BLACK_LEVEL_CONFIG, - VFE_CMD_ID_ROLL_OFF_CONFIG, - VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG, - VFE_CMD_ID_DEMOSAIC_CONFIG, - VFE_CMD_ID_FOV_CROP_CONFIG, - VFE_CMD_ID_MAIN_SCALER_CONFIG, - VFE_CMD_ID_WHITE_BALANCE_CONFIG, - VFE_CMD_ID_COLOR_CORRECTION_CONFIG, - VFE_CMD_ID_LA_CONFIG, - VFE_CMD_ID_RGB_GAMMA_CONFIG, - VFE_CMD_ID_CHROMA_ENHAN_CONFIG, - VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG, - VFE_CMD_ID_ASF_CONFIG, - VFE_CMD_ID_SCALER2Y_CONFIG, - VFE_CMD_ID_SCALER2CbCr_CONFIG, - VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG, - VFE_CMD_ID_FRAME_SKIP_CONFIG, - VFE_CMD_ID_OUTPUT_CLAMP_CONFIG, - - /* test gen */ - VFE_CMD_ID_TEST_GEN_START, - - VFE_CMD_ID_UPDATE, - - /* ackownledge from upper layer */ - VFE_CMD_ID_OUTPUT1_ACK, - VFE_CMD_ID_OUTPUT2_ACK, - VFE_CMD_ID_EPOCH1_ACK, - VFE_CMD_ID_EPOCH2_ACK, - VFE_CMD_ID_STATS_AUTOFOCUS_ACK, - VFE_CMD_ID_STATS_WB_EXP_ACK, - - /* module update commands */ - VFE_CMD_ID_BLACK_LEVEL_UPDATE, - VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE, - VFE_CMD_ID_DEMOSAIC_BPC_UPDATE, - VFE_CMD_ID_DEMOSAIC_ABF_UPDATE, - VFE_CMD_ID_FOV_CROP_UPDATE, - VFE_CMD_ID_WHITE_BALANCE_UPDATE, - VFE_CMD_ID_COLOR_CORRECTION_UPDATE, - VFE_CMD_ID_LA_UPDATE, - VFE_CMD_ID_RGB_GAMMA_UPDATE, - VFE_CMD_ID_CHROMA_ENHAN_UPDATE, - VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE, - VFE_CMD_ID_MAIN_SCALER_UPDATE, - VFE_CMD_ID_SCALER2CbCr_UPDATE, - VFE_CMD_ID_SCALER2Y_UPDATE, - VFE_CMD_ID_ASF_UPDATE, - VFE_CMD_ID_FRAME_SKIP_UPDATE, - VFE_CMD_ID_CAMIF_FRAME_UPDATE, - - /* stats update commands */ - VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE, - VFE_CMD_ID_STATS_WB_EXP_UPDATE, - - /* control of start, stop, update, etc... */ - VFE_CMD_ID_STOP, - VFE_CMD_ID_GET_HW_VERSION, - - /* stats */ - VFE_CMD_ID_STATS_SETTING, - VFE_CMD_ID_STATS_AUTOFOCUS_START, - VFE_CMD_ID_STATS_AUTOFOCUS_STOP, - VFE_CMD_ID_STATS_WB_EXP_START, - VFE_CMD_ID_STATS_WB_EXP_STOP, - - VFE_CMD_ID_ASYNC_TIMER_SETTING, - - /* max id */ - VFE_CMD_ID_MAX -}; - -struct vfe_cmd_hw_version { - uint32_t minorVersion; - uint32_t majorVersion; - uint32_t coreVersion; -}; - -enum VFE_CAMIF_SYNC_EDGE { - VFE_CAMIF_SYNC_EDGE_ActiveHigh, - VFE_CAMIF_SYNC_EDGE_ActiveLow -}; - -enum VFE_CAMIF_SYNC_MODE { - VFE_CAMIF_SYNC_MODE_APS, - VFE_CAMIF_SYNC_MODE_EFS, - VFE_CAMIF_SYNC_MODE_ELS, - VFE_CAMIF_SYNC_MODE_ILLEGAL -}; - -struct vfe_cmds_camif_efs { - uint8_t efsendofline; - uint8_t efsstartofline; - uint8_t efsendofframe; - uint8_t efsstartofframe; -}; - -struct vfe_cmds_camif_frame { - uint16_t pixelsPerLine; - uint16_t linesPerFrame; -}; - -struct vfe_cmds_camif_window { - uint16_t firstpixel; - uint16_t lastpixel; - uint16_t firstline; - uint16_t lastline; -}; - -enum CAMIF_SUBSAMPLE_FRAME_SKIP { - CAMIF_SUBSAMPLE_FRAME_SKIP_0, - CAMIF_SUBSAMPLE_FRAME_SKIP_AllFrames, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_2Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_3Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_4Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_5Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_6Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_7Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_8Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_9Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_10Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_11Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_12Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_13Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_14Frame, - CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_15Frame -}; - -struct vfe_cmds_camif_subsample { - uint16_t pixelskipmask; - uint16_t lineskipmask; - enum CAMIF_SUBSAMPLE_FRAME_SKIP frameskip; - uint8_t frameskipmode; - uint8_t pixelskipwrap; -}; - -struct vfe_cmds_camif_epoch { - uint8_t enable; - uint16_t lineindex; -}; - -struct vfe_cmds_camif_cfg { - enum VFE_CAMIF_SYNC_EDGE vSyncEdge; - enum VFE_CAMIF_SYNC_EDGE hSyncEdge; - enum VFE_CAMIF_SYNC_MODE syncMode; - uint8_t vfeSubSampleEnable; - uint8_t busSubSampleEnable; - uint8_t irqSubSampleEnable; - uint8_t binningEnable; - uint8_t misrEnable; -}; - -struct vfe_cmd_camif_config { - struct vfe_cmds_camif_cfg camifConfig; - struct vfe_cmds_camif_efs EFS; - struct vfe_cmds_camif_frame frame; - struct vfe_cmds_camif_window window; - struct vfe_cmds_camif_subsample subsample; - struct vfe_cmds_camif_epoch epoch1; - struct vfe_cmds_camif_epoch epoch2; -}; - -enum VFE_AXI_OUTPUT_MODE { - VFE_AXI_OUTPUT_MODE_Output1, - VFE_AXI_OUTPUT_MODE_Output2, - VFE_AXI_OUTPUT_MODE_Output1AndOutput2, - VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2, - VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1, - VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2, - VFE_AXI_LAST_OUTPUT_MODE_ENUM -}; - -enum VFE_RAW_WR_PATH_SEL { - VFE_RAW_OUTPUT_DISABLED, - VFE_RAW_OUTPUT_ENC_CBCR_PATH, - VFE_RAW_OUTPUT_VIEW_CBCR_PATH, - VFE_RAW_OUTPUT_PATH_INVALID -}; - -enum VFE_RAW_PIXEL_DATA_SIZE { - VFE_RAW_PIXEL_DATA_SIZE_8BIT, - VFE_RAW_PIXEL_DATA_SIZE_10BIT, - VFE_RAW_PIXEL_DATA_SIZE_12BIT, -}; - -#define VFE_AXI_OUTPUT_BURST_LENGTH 4 -#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4 -#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3 - -struct vfe_cmds_axi_out_per_component { - uint16_t imageWidth; - uint16_t imageHeight; - uint16_t outRowCount; - uint16_t outRowIncrement; - uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT] - [VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; -}; - -struct vfe_cmds_axi_per_output_path { - uint8_t fragmentCount; - struct vfe_cmds_axi_out_per_component outputY; - struct vfe_cmds_axi_out_per_component outputCbcr; -}; - -enum VFE_AXI_BURST_LENGTH { - VFE_AXI_BURST_LENGTH_IS_2 = 2, - VFE_AXI_BURST_LENGTH_IS_4 = 4, - VFE_AXI_BURST_LENGTH_IS_8 = 8, - VFE_AXI_BURST_LENGTH_IS_16 = 16 -}; - -struct vfe_cmd_axi_output_config { - enum VFE_AXI_BURST_LENGTH burstLength; - enum VFE_AXI_OUTPUT_MODE outputMode; - enum VFE_RAW_PIXEL_DATA_SIZE outputDataSize; - struct vfe_cmds_axi_per_output_path output1; - struct vfe_cmds_axi_per_output_path output2; -}; - -struct vfe_cmd_fov_crop_config { - uint8_t enable; - uint16_t firstPixel; - uint16_t lastPixel; - uint16_t firstLine; - uint16_t lastLine; -}; - -struct vfe_cmds_main_scaler_stripe_init { - uint16_t MNCounterInit; - uint16_t phaseInit; -}; - -struct vfe_cmds_scaler_one_dimension { - uint8_t enable; - uint16_t inputSize; - uint16_t outputSize; - uint32_t phaseMultiplicationFactor; - uint8_t interpolationResolution; -}; - -struct vfe_cmd_main_scaler_config { - uint8_t enable; - struct vfe_cmds_scaler_one_dimension hconfig; - struct vfe_cmds_scaler_one_dimension vconfig; - struct vfe_cmds_main_scaler_stripe_init MNInitH; - struct vfe_cmds_main_scaler_stripe_init MNInitV; -}; - -struct vfe_cmd_scaler2_config { - uint8_t enable; - struct vfe_cmds_scaler_one_dimension hconfig; - struct vfe_cmds_scaler_one_dimension vconfig; -}; - -struct vfe_cmd_frame_skip_config { - uint8_t output1Period; - uint32_t output1Pattern; - uint8_t output2Period; - uint32_t output2Pattern; -}; - -struct vfe_cmd_frame_skip_update { - uint32_t output1Pattern; - uint32_t output2Pattern; -}; - -struct vfe_cmd_output_clamp_config { - uint8_t minCh0; - uint8_t minCh1; - uint8_t minCh2; - uint8_t maxCh0; - uint8_t maxCh1; - uint8_t maxCh2; -}; - -struct vfe_cmd_chroma_subsample_config { - uint8_t enable; - uint8_t cropEnable; - uint8_t vsubSampleEnable; - uint8_t hsubSampleEnable; - uint8_t vCosited; - uint8_t hCosited; - uint8_t vCositedPhase; - uint8_t hCositedPhase; - uint16_t cropWidthFirstPixel; - uint16_t cropWidthLastPixel; - uint16_t cropHeightFirstLine; - uint16_t cropHeightLastLine; -}; - -enum VFE_START_INPUT_SOURCE { - VFE_START_INPUT_SOURCE_CAMIF, - VFE_START_INPUT_SOURCE_TESTGEN, - VFE_START_INPUT_SOURCE_AXI, - VFE_START_INPUT_SOURCE_INVALID -}; - -enum VFE_START_OPERATION_MODE { - VFE_START_OPERATION_MODE_CONTINUOUS, - VFE_START_OPERATION_MODE_SNAPSHOT -}; - -enum VFE_START_PIXEL_PATTERN { - VFE_BAYER_RGRGRG, - VFE_BAYER_GRGRGR, - VFE_BAYER_BGBGBG, - VFE_BAYER_GBGBGB, - VFE_YUV_YCbYCr, - VFE_YUV_YCrYCb, - VFE_YUV_CbYCrY, - VFE_YUV_CrYCbY -}; - -enum VFE_BUS_RD_INPUT_PIXEL_PATTERN { - VFE_BAYER_RAW, - VFE_YUV_INTERLEAVED, - VFE_YUV_PSEUDO_PLANAR_Y, - VFE_YUV_PSEUDO_PLANAR_CBCR -}; - -enum VFE_YUV_INPUT_COSITING_MODE { - VFE_YUV_COSITED, - VFE_YUV_INTERPOLATED -}; - -struct vfe_cmd_start { - enum VFE_START_INPUT_SOURCE inputSource; - enum VFE_START_OPERATION_MODE operationMode; - uint8_t snapshotCount; - enum VFE_START_PIXEL_PATTERN pixel; - enum VFE_YUV_INPUT_COSITING_MODE yuvInputCositingMode; -}; - -struct vfe_cmd_output_ack { - uint32_t ybufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; - uint32_t chromabufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; -}; - -#define VFE_STATS_BUFFER_COUNT 3 - -struct vfe_cmd_stats_setting { - uint16_t frameHDimension; - uint16_t frameVDimension; - uint8_t afBusPrioritySelection; - uint8_t afBusPriority; - uint8_t awbBusPrioritySelection; - uint8_t awbBusPriority; - uint8_t histBusPrioritySelection; - uint8_t histBusPriority; - uint32_t afBuffer[VFE_STATS_BUFFER_COUNT]; - uint32_t awbBuffer[VFE_STATS_BUFFER_COUNT]; - uint32_t histBuffer[VFE_STATS_BUFFER_COUNT]; -}; - -struct vfe_cmd_stats_af_start { - uint8_t enable; - uint8_t windowMode; - uint16_t windowHOffset; - uint16_t windowVOffset; - uint16_t windowWidth; - uint16_t windowHeight; - uint8_t gridForMultiWindows[16]; - uint8_t metricSelection; - int16_t metricMax; - int8_t highPassCoef[7]; - int8_t bufferHeader; -}; - -struct vfe_cmd_stats_af_update { - uint8_t windowMode; - uint16_t windowHOffset; - uint16_t windowVOffset; - uint16_t windowWidth; - uint16_t windowHeight; -}; - -struct vfe_cmd_stats_wb_exp_start { - uint8_t enable; - uint8_t wbExpRegions; - uint8_t wbExpSubRegion; - uint8_t awbYMin; - uint8_t awbYMax; - int8_t awbMCFG[4]; - int16_t awbCCFG[4]; - int8_t axwHeader; -}; - -struct vfe_cmd_stats_wb_exp_update { - uint8_t wbExpRegions; - uint8_t wbExpSubRegion; - int8_t awbYMin; - int8_t awbYMax; - int8_t awbMCFG[4]; - int16_t awbCCFG[4]; -}; - -struct vfe_cmd_stats_af_ack { - uint32_t nextAFOutputBufferAddr; -}; - -struct vfe_cmd_stats_wb_exp_ack { - uint32_t nextWbExpOutputBufferAddr; -}; - -struct vfe_cmd_black_level_config { - uint8_t enable; - uint16_t evenEvenAdjustment; - uint16_t evenOddAdjustment; - uint16_t oddEvenAdjustment; - uint16_t oddOddAdjustment; -}; - -/* 13*1 */ -#define VFE_ROLL_OFF_INIT_TABLE_SIZE 13 -/* 13*16 */ -#define VFE_ROLL_OFF_DELTA_TABLE_SIZE 208 - -struct vfe_cmd_roll_off_config { - uint8_t enable; - uint16_t gridWidth; - uint16_t gridHeight; - uint16_t yDelta; - uint8_t gridXIndex; - uint8_t gridYIndex; - uint16_t gridPixelXIndex; - uint16_t gridPixelYIndex; - uint16_t yDeltaAccum; - uint16_t initTableR[VFE_ROLL_OFF_INIT_TABLE_SIZE]; - uint16_t initTableGr[VFE_ROLL_OFF_INIT_TABLE_SIZE]; - uint16_t initTableB[VFE_ROLL_OFF_INIT_TABLE_SIZE]; - uint16_t initTableGb[VFE_ROLL_OFF_INIT_TABLE_SIZE]; - int16_t deltaTableR[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; - int16_t deltaTableGr[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; - int16_t deltaTableB[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; - int16_t deltaTableGb[VFE_ROLL_OFF_DELTA_TABLE_SIZE]; -}; - -struct vfe_cmd_demux_channel_gain_config { - uint16_t ch0EvenGain; - uint16_t ch0OddGain; - uint16_t ch1Gain; - uint16_t ch2Gain; -}; - -struct vfe_cmds_demosaic_abf { - uint8_t enable; - uint8_t forceOn; - uint8_t shift; - uint16_t lpThreshold; - uint16_t max; - uint16_t min; - uint8_t ratio; -}; - -struct vfe_cmds_demosaic_bpc { - uint8_t enable; - uint16_t fmaxThreshold; - uint16_t fminThreshold; - uint16_t redDiffThreshold; - uint16_t blueDiffThreshold; - uint16_t greenDiffThreshold; -}; - -struct vfe_cmd_demosaic_config { - uint8_t enable; - uint8_t slopeShift; - struct vfe_cmds_demosaic_abf abfConfig; - struct vfe_cmds_demosaic_bpc bpcConfig; -}; - -struct vfe_cmd_demosaic_bpc_update { - struct vfe_cmds_demosaic_bpc bpcUpdate; -}; - -struct vfe_cmd_demosaic_abf_update { - struct vfe_cmds_demosaic_abf abfUpdate; -}; - -struct vfe_cmd_white_balance_config { - uint8_t enable; - uint16_t ch2Gain; - uint16_t ch1Gain; - uint16_t ch0Gain; -}; - -enum VFE_COLOR_CORRECTION_COEF_QFACTOR { - COEF_IS_Q7_SIGNED, - COEF_IS_Q8_SIGNED, - COEF_IS_Q9_SIGNED, - COEF_IS_Q10_SIGNED -}; - -struct vfe_cmd_color_correction_config { - uint8_t enable; - enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor; - int16_t C0; - int16_t C1; - int16_t C2; - int16_t C3; - int16_t C4; - int16_t C5; - int16_t C6; - int16_t C7; - int16_t C8; - int16_t K0; - int16_t K1; - int16_t K2; -}; - -#define VFE_LA_TABLE_LENGTH 256 -struct vfe_cmd_la_config { - uint8_t enable; - int16_t table[VFE_LA_TABLE_LENGTH]; -}; - -#define VFE_GAMMA_TABLE_LENGTH 256 -enum VFE_RGB_GAMMA_TABLE_SELECT { - RGB_GAMMA_CH0_SELECTED, - RGB_GAMMA_CH1_SELECTED, - RGB_GAMMA_CH2_SELECTED, - RGB_GAMMA_CH0_CH1_SELECTED, - RGB_GAMMA_CH0_CH2_SELECTED, - RGB_GAMMA_CH1_CH2_SELECTED, - RGB_GAMMA_CH0_CH1_CH2_SELECTED -}; - -struct vfe_cmd_rgb_gamma_config { - uint8_t enable; - enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect; - int16_t table[VFE_GAMMA_TABLE_LENGTH]; -}; - -struct vfe_cmd_chroma_enhan_config { - uint8_t enable; - int16_t am; - int16_t ap; - int16_t bm; - int16_t bp; - int16_t cm; - int16_t cp; - int16_t dm; - int16_t dp; - int16_t kcr; - int16_t kcb; - int16_t RGBtoYConversionV0; - int16_t RGBtoYConversionV1; - int16_t RGBtoYConversionV2; - uint8_t RGBtoYConversionOffset; -}; - -struct vfe_cmd_chroma_suppression_config { - uint8_t enable; - uint8_t m1; - uint8_t m3; - uint8_t n1; - uint8_t n3; - uint8_t nn1; - uint8_t mm1; -}; - -struct vfe_cmd_asf_config { - uint8_t enable; - uint8_t smoothFilterEnabled; - uint8_t sharpMode; - uint8_t smoothCoefCenter; - uint8_t smoothCoefSurr; - uint8_t normalizeFactor; - uint8_t sharpK1; - uint8_t sharpK2; - uint8_t sharpThreshE1; - int8_t sharpThreshE2; - int8_t sharpThreshE3; - int8_t sharpThreshE4; - int8_t sharpThreshE5; - int8_t filter1Coefficients[9]; - int8_t filter2Coefficients[9]; - uint8_t cropEnable; - uint16_t cropFirstPixel; - uint16_t cropLastPixel; - uint16_t cropFirstLine; - uint16_t cropLastLine; -}; - -struct vfe_cmd_asf_update { - uint8_t enable; - uint8_t smoothFilterEnabled; - uint8_t sharpMode; - uint8_t smoothCoefCenter; - uint8_t smoothCoefSurr; - uint8_t normalizeFactor; - uint8_t sharpK1; - uint8_t sharpK2; - uint8_t sharpThreshE1; - int8_t sharpThreshE2; - int8_t sharpThreshE3; - int8_t sharpThreshE4; - int8_t sharpThreshE5; - int8_t filter1Coefficients[9]; - int8_t filter2Coefficients[9]; - uint8_t cropEnable; -}; - -enum VFE_TEST_GEN_SYNC_EDGE { - VFE_TEST_GEN_SYNC_EDGE_ActiveHigh, - VFE_TEST_GEN_SYNC_EDGE_ActiveLow -}; - -struct vfe_cmd_test_gen_start { - uint8_t pixelDataSelect; - uint8_t systematicDataSelect; - enum VFE_TEST_GEN_SYNC_EDGE hsyncEdge; - enum VFE_TEST_GEN_SYNC_EDGE vsyncEdge; - uint16_t numFrame; - enum VFE_RAW_PIXEL_DATA_SIZE pixelDataSize; - uint16_t imageWidth; - uint16_t imageHeight; - uint32_t startOfFrameOffset; - uint32_t endOfFrameNOffset; - uint16_t startOfLineOffset; - uint16_t endOfLineNOffset; - uint16_t hbi; - uint8_t vblEnable; - uint16_t vbl; - uint8_t startOfFrameDummyLine; - uint8_t endOfFrameDummyLine; - uint8_t unicolorBarEnable; - uint8_t colorBarsSplitEnable; - uint8_t unicolorBarSelect; - enum VFE_START_PIXEL_PATTERN colorBarsPixelPattern; - uint8_t colorBarsRotatePeriod; - uint16_t testGenRandomSeed; -}; - -struct vfe_cmd_bus_pm_start { - uint8_t output2YWrPmEnable; - uint8_t output2CbcrWrPmEnable; - uint8_t output1YWrPmEnable; - uint8_t output1CbcrWrPmEnable; -}; - -struct vfe_cmd_camif_frame_update { - struct vfe_cmds_camif_frame camifFrame; -}; - -struct vfe_cmd_sync_timer_setting { - uint8_t whichSyncTimer; - uint8_t operation; - uint8_t polarity; - uint16_t repeatCount; - uint16_t hsyncCount; - uint32_t pclkCount; - uint32_t outputDuration; -}; - -struct vfe_cmd_async_timer_setting { - uint8_t whichAsyncTimer; - uint8_t operation; - uint8_t polarity; - uint16_t repeatCount; - uint16_t inactiveCount; - uint32_t activeCount; -}; - -struct vfe_frame_skip_counts { - uint32_t totalFrameCount; - uint32_t output1Count; - uint32_t output2Count; -}; - -enum VFE_AXI_RD_UNPACK_HBI_SEL { - VFE_AXI_RD_HBI_32_CLOCK_CYCLES, - VFE_AXI_RD_HBI_64_CLOCK_CYCLES, - VFE_AXI_RD_HBI_128_CLOCK_CYCLES, - VFE_AXI_RD_HBI_256_CLOCK_CYCLES, - VFE_AXI_RD_HBI_512_CLOCK_CYCLES, - VFE_AXI_RD_HBI_1024_CLOCK_CYCLES, - VFE_AXI_RD_HBI_2048_CLOCK_CYCLES, - VFE_AXI_RD_HBI_4096_CLOCK_CYCLES -}; - -struct vfe_cmd_axi_input_config { - uint32_t fragAddr[4]; - uint8_t totalFragmentCount; - uint16_t ySize; - uint16_t xOffset; - uint16_t xSize; - uint16_t rowIncrement; - uint16_t numOfRows; - enum VFE_AXI_BURST_LENGTH burstLength; - uint8_t unpackPhase; - enum VFE_AXI_RD_UNPACK_HBI_SEL unpackHbi; - enum VFE_RAW_PIXEL_DATA_SIZE pixelSize; - uint8_t padRepeatCountLeft; - uint8_t padRepeatCountRight; - uint8_t padRepeatCountTop; - uint8_t padRepeatCountBottom; - uint8_t padLeftComponentSelectCycle0; - uint8_t padLeftComponentSelectCycle1; - uint8_t padLeftComponentSelectCycle2; - uint8_t padLeftComponentSelectCycle3; - uint8_t padLeftStopCycle0; - uint8_t padLeftStopCycle1; - uint8_t padLeftStopCycle2; - uint8_t padLeftStopCycle3; - uint8_t padRightComponentSelectCycle0; - uint8_t padRightComponentSelectCycle1; - uint8_t padRightComponentSelectCycle2; - uint8_t padRightComponentSelectCycle3; - uint8_t padRightStopCycle0; - uint8_t padRightStopCycle1; - uint8_t padRightStopCycle2; - uint8_t padRightStopCycle3; - uint8_t padTopLineCount; - uint8_t padBottomLineCount; -}; - -struct vfe_interrupt_status { - uint8_t camifErrorIrq; - uint8_t camifSofIrq; - uint8_t camifEolIrq; - uint8_t camifEofIrq; - uint8_t camifEpoch1Irq; - uint8_t camifEpoch2Irq; - uint8_t camifOverflowIrq; - uint8_t ceIrq; - uint8_t regUpdateIrq; - uint8_t resetAckIrq; - uint8_t encYPingpongIrq; - uint8_t encCbcrPingpongIrq; - uint8_t viewYPingpongIrq; - uint8_t viewCbcrPingpongIrq; - uint8_t rdPingpongIrq; - uint8_t afPingpongIrq; - uint8_t awbPingpongIrq; - uint8_t histPingpongIrq; - uint8_t encIrq; - uint8_t viewIrq; - uint8_t busOverflowIrq; - uint8_t afOverflowIrq; - uint8_t awbOverflowIrq; - uint8_t syncTimer0Irq; - uint8_t syncTimer1Irq; - uint8_t syncTimer2Irq; - uint8_t asyncTimer0Irq; - uint8_t asyncTimer1Irq; - uint8_t asyncTimer2Irq; - uint8_t asyncTimer3Irq; - uint8_t axiErrorIrq; - uint8_t violationIrq; - uint8_t anyErrorIrqs; - uint8_t anyOutput1PathIrqs; - uint8_t anyOutput2PathIrqs; - uint8_t anyOutputPathIrqs; - uint8_t anyAsyncTimerIrqs; - uint8_t anySyncTimerIrqs; - uint8_t anyIrqForActiveStatesOnly; -}; - -enum VFE_MESSAGE_ID { - VFE_MSG_ID_RESET_ACK, - VFE_MSG_ID_START_ACK, - VFE_MSG_ID_STOP_ACK, - VFE_MSG_ID_UPDATE_ACK, - VFE_MSG_ID_OUTPUT1, - VFE_MSG_ID_OUTPUT2, - VFE_MSG_ID_SNAPSHOT_DONE, - VFE_MSG_ID_STATS_AUTOFOCUS, - VFE_MSG_ID_STATS_WB_EXP, - VFE_MSG_ID_EPOCH1, - VFE_MSG_ID_EPOCH2, - VFE_MSG_ID_SYNC_TIMER0_DONE, - VFE_MSG_ID_SYNC_TIMER1_DONE, - VFE_MSG_ID_SYNC_TIMER2_DONE, - VFE_MSG_ID_ASYNC_TIMER0_DONE, - VFE_MSG_ID_ASYNC_TIMER1_DONE, - VFE_MSG_ID_ASYNC_TIMER2_DONE, - VFE_MSG_ID_ASYNC_TIMER3_DONE, - VFE_MSG_ID_AF_OVERFLOW, - VFE_MSG_ID_AWB_OVERFLOW, - VFE_MSG_ID_AXI_ERROR, - VFE_MSG_ID_CAMIF_OVERFLOW, - VFE_MSG_ID_VIOLATION, - VFE_MSG_ID_CAMIF_ERROR, - VFE_MSG_ID_BUS_OVERFLOW, -}; - -struct vfe_msg_stats_autofocus { - uint32_t afBuffer; - uint32_t frameCounter; -}; - -struct vfe_msg_stats_wb_exp { - uint32_t awbBuffer; - uint32_t frameCounter; -}; - -struct vfe_frame_bpc_info { - uint32_t greenDefectPixelCount; - uint32_t redBlueDefectPixelCount; -}; - -struct vfe_frame_asf_info { - uint32_t asfMaxEdge; - uint32_t asfHbiCount; -}; - -struct vfe_msg_camif_status { - uint8_t camifState; - uint32_t pixelCount; - uint32_t lineCount; -}; - -struct vfe_bus_pm_per_path { - uint32_t yWrPmStats0; - uint32_t yWrPmStats1; - uint32_t cbcrWrPmStats0; - uint32_t cbcrWrPmStats1; -}; - -struct vfe_bus_performance_monitor { - struct vfe_bus_pm_per_path encPathPmInfo; - struct vfe_bus_pm_per_path viewPathPmInfo; -}; - -struct vfe_irq_thread_msg { - uint32_t vfeIrqStatus; - uint32_t camifStatus; - uint32_t demosaicStatus; - uint32_t asfMaxEdge; - struct vfe_bus_performance_monitor pmInfo; -}; - -struct vfe_msg_output { - uint32_t yBuffer; - uint32_t cbcrBuffer; - struct vfe_frame_bpc_info bpcInfo; - struct vfe_frame_asf_info asfInfo; - uint32_t frameCounter; - struct vfe_bus_pm_per_path pmData; -}; - -struct vfe_message { - enum VFE_MESSAGE_ID _d; - union { - struct vfe_msg_output msgOutput1; - struct vfe_msg_output msgOutput2; - struct vfe_msg_stats_autofocus msgStatsAf; - struct vfe_msg_stats_wb_exp msgStatsWbExp; - struct vfe_msg_camif_status msgCamifError; - struct vfe_bus_performance_monitor msgBusOverflow; - } _u; -}; - -/* New one for 8k */ -struct msm_vfe_command_8k { - int32_t id; - uint16_t length; - void *value; -}; - -struct vfe_frame_extra { - struct vfe_frame_bpc_info bpcInfo; - struct vfe_frame_asf_info asfInfo; - uint32_t frameCounter; - struct vfe_bus_pm_per_path pmData; -}; -#endif /* __MSM_VFE8X_H__ */ diff --git a/drivers/staging/dream/camera/msm_vfe8x_proc.c b/drivers/staging/dream/camera/msm_vfe8x_proc.c deleted file mode 100644 index f80ef967ba87..000000000000 --- a/drivers/staging/dream/camera/msm_vfe8x_proc.c +++ /dev/null @@ -1,4003 +0,0 @@ -/* -* Copyright (C) 2008-2009 QUALCOMM Incorporated. -*/ -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include "msm_vfe8x_proc.h" -#include <media/msm_camera.h> - -struct msm_vfe8x_ctrl { - /* bit 1:0 ENC_IRQ_MASK = 0x11: - * generate IRQ when both y and cbcr frame is ready. */ - - /* bit 1:0 VIEW_IRQ_MASK= 0x11: - * generate IRQ when both y and cbcr frame is ready. */ - struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal; - struct vfe_module_enable vfeModuleEnableLocal; - struct vfe_camif_cfg_data vfeCamifConfigLocal; - struct vfe_interrupt_mask vfeImaskLocal; - struct vfe_stats_cmd_data vfeStatsCmdLocal; - struct vfe_bus_cfg_data vfeBusConfigLocal; - struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal; - struct vfe_bus_cmd_data vfeBusCmdLocal; - enum vfe_interrupt_name vfeInterruptNameLocal; - uint32_t vfeLaBankSel; - struct vfe_gamma_lut_sel vfeGammaLutSel; - - boolean vfeStartAckPendingFlag; - boolean vfeStopAckPending; - boolean vfeResetAckPending; - boolean vfeUpdateAckPending; - - enum VFE_AXI_OUTPUT_MODE axiOutputMode; - enum VFE_START_OPERATION_MODE vfeOperationMode; - - uint32_t vfeSnapShotCount; - uint32_t vfeRequestedSnapShotCount; - boolean vfeStatsPingPongReloadFlag; - uint32_t vfeFrameId; - - struct vfe_cmd_frame_skip_config vfeFrameSkip; - uint32_t vfeFrameSkipPattern; - uint8_t vfeFrameSkipCount; - uint8_t vfeFrameSkipPeriod; - - boolean vfeTestGenStartFlag; - uint32_t vfeImaskPacked; - uint32_t vfeImaskCompositePacked; - enum VFE_RAW_PIXEL_DATA_SIZE axiInputDataSize; - struct vfe_irq_thread_msg vfeIrqThreadMsgLocal; - - struct vfe_output_path_combo viewPath; - struct vfe_output_path_combo encPath; - struct vfe_frame_skip_counts vfeDroppedFrameCounts; - struct vfe_stats_control afStatsControl; - struct vfe_stats_control awbStatsControl; - - enum VFE_STATE vstate; - - spinlock_t ack_lock; - spinlock_t state_lock; - spinlock_t io_lock; - - struct msm_vfe_callback *resp; - uint32_t extlen; - void *extdata; - - spinlock_t tasklet_lock; - struct list_head tasklet_q; - - int vfeirq; - void __iomem *vfebase; - - void *syncdata; -}; -static struct msm_vfe8x_ctrl *ctrl; -static irqreturn_t vfe_parse_irq(int irq_num, void *data); - -struct isr_queue_cmd { - struct list_head list; - struct vfe_interrupt_status vfeInterruptStatus; - struct vfe_frame_asf_info vfeAsfFrameInfo; - struct vfe_frame_bpc_info vfeBpcFrameInfo; - struct vfe_msg_camif_status vfeCamifStatusLocal; - struct vfe_bus_performance_monitor vfePmData; -}; - -static void vfe_prog_hw(uint8_t *hwreg, - uint32_t *inptr, uint32_t regcnt) -{ - /* unsigned long flags; */ - uint32_t i; - uint32_t *p; - - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->io_lock, flags); */ - - p = (uint32_t *)(hwreg); - for (i = 0; i < (regcnt >> 2); i++) - writel(*inptr++, p++); - /* *p++ = *inptr++; */ - - /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */ -} - -static void vfe_read_reg_values(uint8_t *hwreg, - uint32_t *dest, uint32_t count) -{ - /* unsigned long flags; */ - uint32_t *temp; - uint32_t i; - - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->io_lock, flags); */ - - temp = (uint32_t *)(hwreg); - for (i = 0; i < count; i++) - *dest++ = *temp++; - - /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */ -} - -static struct vfe_irqenable vfe_read_irq_mask(void) -{ - /* unsigned long flags; */ - uint32_t *temp; - struct vfe_irqenable rc; - - memset(&rc, 0, sizeof(rc)); - - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->io_lock, flags); */ - temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_MASK); - - rc = *((struct vfe_irqenable *)temp); - /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */ - - return rc; -} - -static void -vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath, - struct vfe_output_path_combo *epath) -{ - vpath->yPath.hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR); - vpath->yPath.hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR); - vpath->cbcrPath.hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR); - vpath->cbcrPath.hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR); - - epath->yPath.hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR); - epath->yPath.hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR); - epath->cbcrPath.hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR); - epath->cbcrPath.hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR); -} - -static void vfe_axi_output(struct vfe_cmd_axi_output_config *in, - struct vfe_output_path_combo *out1, - struct vfe_output_path_combo *out2, uint16_t out) -{ - struct vfe_axi_out_cfg cmd; - - uint16_t temp; - uint32_t burstLength; - - /* force it to burst length 4, hardware does not support it. */ - burstLength = 1; - - /* AXI Output 2 Y Configuration*/ - /* VFE_BUS_ENC_Y_WR_PING_ADDR */ - cmd.out2YPingAddr = out2->yPath.addressBuffer[0]; - - /* VFE_BUS_ENC_Y_WR_PONG_ADDR */ - cmd.out2YPongAddr = out2->yPath.addressBuffer[1]; - - /* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */ - cmd.out2YImageHeight = in->output2.outputY.imageHeight; - /* convert the image width and row increment to be in - * unit of 64bit (8 bytes) */ - temp = (in->output2.outputY.imageWidth + (out - 1)) / - out; - cmd.out2YImageWidthin64bit = temp; - - /* VFE_BUS_ENC_Y_WR_BUFFER_CFG */ - cmd.out2YBurstLength = burstLength; - cmd.out2YNumRows = in->output2.outputY.outRowCount; - temp = (in->output2.outputY.outRowIncrement + (out - 1)) / - out; - cmd.out2YRowIncrementIn64bit = temp; - - /* AXI Output 2 Cbcr Configuration*/ - /* VFE_BUS_ENC_Cbcr_WR_PING_ADDR */ - cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0]; - - /* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR */ - cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1]; - - /* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */ - cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight; - temp = (in->output2.outputCbcr.imageWidth + (out - 1)) / - out; - cmd.out2CbcrImageWidthIn64bit = temp; - - /* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */ - cmd.out2CbcrBurstLength = burstLength; - cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount; - temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) / - out; - cmd.out2CbcrRowIncrementIn64bit = temp; - - /* AXI Output 1 Y Configuration */ - /* VFE_BUS_VIEW_Y_WR_PING_ADDR */ - cmd.out1YPingAddr = out1->yPath.addressBuffer[0]; - - /* VFE_BUS_VIEW_Y_WR_PONG_ADDR */ - cmd.out1YPongAddr = out1->yPath.addressBuffer[1]; - - /* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */ - cmd.out1YImageHeight = in->output1.outputY.imageHeight; - temp = (in->output1.outputY.imageWidth + (out - 1)) / - out; - cmd.out1YImageWidthin64bit = temp; - - /* VFE_BUS_VIEW_Y_WR_BUFFER_CFG */ - cmd.out1YBurstLength = burstLength; - cmd.out1YNumRows = in->output1.outputY.outRowCount; - - temp = - (in->output1.outputY.outRowIncrement + - (out - 1)) / out; - cmd.out1YRowIncrementIn64bit = temp; - - /* AXI Output 1 Cbcr Configuration*/ - cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0]; - - /* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR */ - cmd.out1CbcrPongAddr = - out1->cbcrPath.addressBuffer[1]; - - /* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */ - cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight; - temp = (in->output1.outputCbcr.imageWidth + - (out - 1)) / out; - cmd.out1CbcrImageWidthIn64bit = temp; - - cmd.out1CbcrBurstLength = burstLength; - cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount; - temp = - (in->output1.outputCbcr.outRowIncrement + - (out - 1)) / out; - - cmd.out1CbcrRowIncrementIn64bit = temp; - - vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR, - (uint32_t *)&cmd, sizeof(cmd)); -} - -static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in) -{ - struct vfe_axi_bus_cfg cmd; - - cmd.stripeRdPathEn = in->stripeRdPathEn; - cmd.encYWrPathEn = in->encYWrPathEn; - cmd.encCbcrWrPathEn = in->encCbcrWrPathEn; - cmd.viewYWrPathEn = in->viewYWrPathEn; - cmd.viewCbcrWrPathEn = in->viewCbcrWrPathEn; - cmd.rawPixelDataSize = (uint32_t)in->rawPixelDataSize; - cmd.rawWritePathSelect = (uint32_t)in->rawWritePathSelect; - - /* program vfe_bus_cfg */ - writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG); -} - -static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in) -{ - struct VFE_CAMIFConfigType cfg; - - memset(&cfg, 0, sizeof(cfg)); - - cfg.VSyncEdge = - in->camifCfgFromCmd.vSyncEdge; - - cfg.HSyncEdge = - in->camifCfgFromCmd.hSyncEdge; - - cfg.syncMode = - in->camifCfgFromCmd.syncMode; - - cfg.vfeSubsampleEnable = - in->camifCfgFromCmd.vfeSubSampleEnable; - - cfg.busSubsampleEnable = - in->camifCfgFromCmd.busSubSampleEnable; - - cfg.camif2vfeEnable = - in->camif2OutputEnable; - - cfg.camif2busEnable = - in->camif2BusEnable; - - cfg.irqSubsampleEnable = - in->camifCfgFromCmd.irqSubSampleEnable; - - cfg.binningEnable = - in->camifCfgFromCmd.binningEnable; - - cfg.misrEnable = - in->camifCfgFromCmd.misrEnable; - - /* program camif_config */ - writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG); -} - -static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in) -{ - struct vfe_buscmd cmd; - memset(&cmd, 0, sizeof(cmd)); - - cmd.stripeReload = in->stripeReload; - cmd.busPingpongReload = in->busPingpongReload; - cmd.statsPingpongReload = in->statsPingpongReload; - - writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD); - - CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd))); - - /* this is needed, as the control bits are pulse based. - * Don't want to reload bus pingpong again. */ - in->busPingpongReload = 0; - in->statsPingpongReload = 0; - in->stripeReload = 0; -} - -static void vfe_reg_module_cfg(struct vfe_module_enable *in) -{ - struct vfe_mod_enable ena; - - memset(&ena, 0, sizeof(ena)); - - ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable; - ena.lensRollOffEnable = in->lensRollOffEnable; - ena.demuxEnable = in->demuxEnable; - ena.chromaUpsampleEnable = in->chromaUpsampleEnable; - ena.demosaicEnable = in->demosaicEnable; - ena.statsEnable = in->statsEnable; - ena.cropEnable = in->cropEnable; - ena.mainScalerEnable = in->mainScalerEnable; - ena.whiteBalanceEnable = in->whiteBalanceEnable; - ena.colorCorrectionEnable = in->colorCorrectionEnable; - ena.yHistEnable = in->yHistEnable; - ena.skinToneEnable = in->skinToneEnable; - ena.lumaAdaptationEnable = in->lumaAdaptationEnable; - ena.rgbLUTEnable = in->rgbLUTEnable; - ena.chromaEnhanEnable = in->chromaEnhanEnable; - ena.asfEnable = in->asfEnable; - ena.chromaSuppressionEnable = in->chromaSuppressionEnable; - ena.chromaSubsampleEnable = in->chromaSubsampleEnable; - ena.scaler2YEnable = in->scaler2YEnable; - ena.scaler2CbcrEnable = in->scaler2CbcrEnable; - - writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG); -} - -static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel) -{ - /* set bit 8 for auto increment. */ - uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT; - - value += (uint32_t)bankSel; - /* CDBG("dmi cfg input bank is 0x%x\n", bankSel); */ - - writel(value, ctrl->vfebase + VFE_DMI_CFG); - writel(0, ctrl->vfebase + VFE_DMI_ADDR); -} - -static void vfe_write_lens_roll_off_table( - struct vfe_cmd_roll_off_config *in) -{ - uint16_t i; - uint32_t data; - - uint16_t *initGr = in->initTableGr; - uint16_t *initGb = in->initTableGb; - uint16_t *initB = in->initTableB; - uint16_t *initR = in->initTableR; - - int16_t *pDeltaGr = in->deltaTableGr; - int16_t *pDeltaGb = in->deltaTableGb; - int16_t *pDeltaB = in->deltaTableB; - int16_t *pDeltaR = in->deltaTableR; - - vfe_program_dmi_cfg(ROLLOFF_RAM); - - /* first pack and write init table */ - for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) { - data = (((uint32_t)(*initR)) & 0x0000FFFF) | - (((uint32_t)(*initGr)) << 16); - initR++; - initGr++; - - writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); - - data = (((uint32_t)(*initB)) & 0x0000FFFF) | - (((uint32_t)(*initGr))<<16); - initB++; - initGb++; - - writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); - } - - /* there are gaps between the init table and delta table, - * set the offset for delta table. */ - writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, - ctrl->vfebase + VFE_DMI_ADDR); - - /* pack and write delta table */ - for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) { - data = (((int32_t)(*pDeltaR)) & 0x0000FFFF) | - (((int32_t)(*pDeltaGr))<<16); - pDeltaR++; - pDeltaGr++; - - writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); - - data = (((int32_t)(*pDeltaB)) & 0x0000FFFF) | - (((int32_t)(*pDeltaGb))<<16); - pDeltaB++; - pDeltaGb++; - - writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); - } - - /* After DMI transfer, to make it safe, need to set the - * DMI_CFG to unselect any SRAM - */ - /* unselect the SRAM Bank. */ - writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); -} - -static void vfe_set_default_reg_values(void) -{ - writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0); - writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1); - writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE); - - /* default frame drop period and pattern */ - writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG); - writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG); - writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN); - writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN); - writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG); - writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG); - writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN); - writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN); - writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG); - writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG); -} - -static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd) -{ - writel(period, ctrl->vfebase + VFE_DEMUX_CFG); - writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG); - writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG); -} - -static void vfe_pm_stop(void) -{ - writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD); -} - -static void vfe_program_bus_rd_irq_en(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN); -} - -static void vfe_camif_go(void) -{ - writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND); -} - -static void vfe_camif_stop_immediately(void) -{ - writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND); - writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE); -} - -static void vfe_program_reg_update_cmd(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD); -} - -static void vfe_program_bus_cmd(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_BUS_CMD); -} - -static void vfe_program_global_reset_cmd(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD); -} - -static void vfe_program_axi_cmd(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_AXI_CMD); -} - -static void vfe_program_irq_composite_mask(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK); -} - -static inline void vfe_program_irq_mask(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_IRQ_MASK); -} - -static void vfe_program_chroma_upsample_cfg(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG); -} - -static uint32_t vfe_read_axi_status(void) -{ - return readl(ctrl->vfebase + VFE_AXI_STATUS); -} - -static uint32_t vfe_read_pm_status_in_raw_capture(void) -{ - return readl(ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PM_STATS_1); -} - -static void -vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl, - struct vfe_stats_control *awbControl) -{ - afControl->hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); - afControl->hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); - - awbControl->hwRegPingAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); - awbControl->hwRegPongAddress = (uint8_t *) - (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); -} - -static uint32_t vfe_read_camif_status(void) -{ - return readl(ctrl->vfebase + CAMIF_STATUS); -} - -static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in) -{ - struct VFE_GammaLutSelect_ConfigCmdType cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.ch0BankSelect = in->ch0BankSelect; - cmd.ch1BankSelect = in->ch1BankSelect; - cmd.ch2BankSelect = in->ch2BankSelect; - CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd)); - vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL, - (uint32_t *)&cmd, sizeof(cmd)); -} - -static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in) -{ - struct VFE_StatsCmdType stats; - memset(&stats, 0, sizeof(stats)); - - stats.autoFocusEnable = in->autoFocusEnable; - stats.axwEnable = in->axwEnable; - stats.histEnable = in->histEnable; - stats.clearHistEnable = in->clearHistEnable; - stats.histAutoClearEnable = in->histAutoClearEnable; - stats.colorConversionEnable = in->colorConversionEnable; - - writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD); -} - -static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in) -{ - struct VFE_Bus_Pm_ConfigCmdType cmd; - memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType)); - - cmd.output2YWrPmEnable = in->output2YWrPmEnable; - cmd.output2CbcrWrPmEnable = in->output2CbcrWrPmEnable; - cmd.output1YWrPmEnable = in->output1YWrPmEnable; - cmd.output1CbcrWrPmEnable = in->output1CbcrWrPmEnable; - - vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in) -{ - in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn; - in->output1YWrPmEnable = ctrl->vfeBusConfigLocal.viewYWrPathEn; - in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn; - in->output2YWrPmEnable = ctrl->vfeBusConfigLocal.encYWrPathEn; - - if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable) - ctrl->viewPath.pmEnabled = TRUE; - - if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable) - ctrl->encPath.pmEnabled = TRUE; - - vfe_pm_start(in); - - writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD); -} - -static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data) -{ - struct vfe_irqenable packedData; - - memset(&packedData, 0, sizeof(packedData)); - - packedData.camifErrorIrq = data.camifErrorIrq; - packedData.camifSofIrq = data.camifSofIrq; - packedData.camifEolIrq = data.camifEolIrq; - packedData.camifEofIrq = data.camifEofIrq; - packedData.camifEpoch1Irq = data.camifEpoch1Irq; - packedData.camifEpoch2Irq = data.camifEpoch2Irq; - packedData.camifOverflowIrq = data.camifOverflowIrq; - packedData.ceIrq = data.ceIrq; - packedData.regUpdateIrq = data.regUpdateIrq; - packedData.resetAckIrq = data.resetAckIrq; - packedData.encYPingpongIrq = data.encYPingpongIrq; - packedData.encCbcrPingpongIrq = data.encCbcrPingpongIrq; - packedData.viewYPingpongIrq = data.viewYPingpongIrq; - packedData.viewCbcrPingpongIrq = data.viewCbcrPingpongIrq; - packedData.rdPingpongIrq = data.rdPingpongIrq; - packedData.afPingpongIrq = data.afPingpongIrq; - packedData.awbPingpongIrq = data.awbPingpongIrq; - packedData.histPingpongIrq = data.histPingpongIrq; - packedData.encIrq = data.encIrq; - packedData.viewIrq = data.viewIrq; - packedData.busOverflowIrq = data.busOverflowIrq; - packedData.afOverflowIrq = data.afOverflowIrq; - packedData.awbOverflowIrq = data.awbOverflowIrq; - packedData.syncTimer0Irq = data.syncTimer0Irq; - packedData.syncTimer1Irq = data.syncTimer1Irq; - packedData.syncTimer2Irq = data.syncTimer2Irq; - packedData.asyncTimer0Irq = data.asyncTimer0Irq; - packedData.asyncTimer1Irq = data.asyncTimer1Irq; - packedData.asyncTimer2Irq = data.asyncTimer2Irq; - packedData.asyncTimer3Irq = data.asyncTimer3Irq; - packedData.axiErrorIrq = data.axiErrorIrq; - packedData.violationIrq = data.violationIrq; - - return *((uint32_t *)&packedData); -} - -static uint32_t -vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data) -{ - struct VFE_Irq_Composite_MaskType packedData; - - memset(&packedData, 0, sizeof(packedData)); - - packedData.encIrqComMaskBits = data.encIrqComMask; - packedData.viewIrqComMaskBits = data.viewIrqComMask; - packedData.ceDoneSelBits = data.ceDoneSel; - - return *((uint32_t *)&packedData); -} - -static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo, - enum vfe_resp_msg type, void *data, void **ext, int32_t *elen) -{ - switch (type) { - case VFE_MSG_OUTPUT1: { - pinfo->y_phy = - ((struct vfe_message *)data)->_u.msgOutput1.yBuffer; - pinfo->cbcr_phy = - ((struct vfe_message *)data)->_u.msgOutput1.cbcrBuffer; - - ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo = - ((struct vfe_message *)data)->_u.msgOutput1.bpcInfo; - - ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo = - ((struct vfe_message *)data)->_u.msgOutput1.asfInfo; - - ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter = - ((struct vfe_message *)data)->_u.msgOutput1.frameCounter; - - ((struct vfe_frame_extra *)ctrl->extdata)->pmData = - ((struct vfe_message *)data)->_u.msgOutput1.pmData; - - *ext = ctrl->extdata; - *elen = ctrl->extlen; - } - break; - - case VFE_MSG_OUTPUT2: { - pinfo->y_phy = - ((struct vfe_message *)data)->_u.msgOutput2.yBuffer; - pinfo->cbcr_phy = - ((struct vfe_message *)data)->_u.msgOutput2.cbcrBuffer; - - CDBG("vfe_addr_convert, pinfo->y_phy = 0x%x\n", pinfo->y_phy); - CDBG("vfe_addr_convert, pinfo->cbcr_phy = 0x%x\n", - pinfo->cbcr_phy); - - ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo = - ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo; - - ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo = - ((struct vfe_message *)data)->_u.msgOutput2.asfInfo; - - ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter = - ((struct vfe_message *)data)->_u.msgOutput2.frameCounter; - - ((struct vfe_frame_extra *)ctrl->extdata)->pmData = - ((struct vfe_message *)data)->_u.msgOutput2.pmData; - - *ext = ctrl->extdata; - *elen = ctrl->extlen; - } - break; - - case VFE_MSG_STATS_AF: - pinfo->sbuf_phy = - ((struct vfe_message *)data)->_u.msgStatsAf.afBuffer; - break; - - case VFE_MSG_STATS_WE: - pinfo->sbuf_phy = - ((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer; - break; - - default: - break; - } /* switch */ -} - -static void -vfe_proc_ops(enum VFE_MESSAGE_ID id, void *msg, size_t len) -{ - struct msm_vfe_resp *rp; - - /* In 8k, OUTPUT1 & OUTPUT2 messages arrive before - * SNAPSHOT_DONE. We don't send such messages to user */ - - CDBG("ctrl->vfeOperationMode = %d, msgId = %d\n", - ctrl->vfeOperationMode, id); - - if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) && - (id == VFE_MSG_ID_OUTPUT1 || id == VFE_MSG_ID_OUTPUT2)) { - return; - } - - rp = ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp), ctrl->syncdata); - if (!rp) { - CDBG("rp: cannot allocate buffer\n"); - return; - } - - CDBG("vfe_proc_ops, msgId = %d\n", id); - - rp->evt_msg.type = MSM_CAMERA_MSG; - rp->evt_msg.msg_id = id; - rp->evt_msg.len = len; - rp->evt_msg.data = msg; - - switch (rp->evt_msg.msg_id) { - case VFE_MSG_ID_SNAPSHOT_DONE: - rp->type = VFE_MSG_SNAPSHOT; - break; - - case VFE_MSG_ID_OUTPUT1: - rp->type = VFE_MSG_OUTPUT1; - vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT1, - rp->evt_msg.data, &(rp->extdata), - &(rp->extlen)); - break; - - case VFE_MSG_ID_OUTPUT2: - rp->type = VFE_MSG_OUTPUT2; - vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT2, - rp->evt_msg.data, &(rp->extdata), - &(rp->extlen)); - break; - - case VFE_MSG_ID_STATS_AUTOFOCUS: - rp->type = VFE_MSG_STATS_AF; - vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AF, - rp->evt_msg.data, NULL, NULL); - break; - - case VFE_MSG_ID_STATS_WB_EXP: - rp->type = VFE_MSG_STATS_WE; - vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_WE, - rp->evt_msg.data, NULL, NULL); - break; - - default: - rp->type = VFE_MSG_GENERAL; - break; - } - - ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata); -} - -static void vfe_send_msg_no_payload(enum VFE_MESSAGE_ID id) -{ - struct vfe_message *msg; - - msg = kzalloc(sizeof(*msg), GFP_ATOMIC); - if (!msg) - return; - - msg->_d = id; - vfe_proc_ops(id, msg, 0); -} - -static void vfe_send_bus_overflow_msg(void) -{ - struct vfe_message *msg; - msg = - kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - msg->_d = VFE_MSG_ID_BUS_OVERFLOW; -#if 0 - memcpy(&(msg->_u.msgBusOverflow), - &ctrl->vfePmData, sizeof(ctrl->vfePmData)); -#endif - - vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW, - msg, sizeof(struct vfe_message)); -} - -static void vfe_send_camif_error_msg(void) -{ -#if 0 - struct vfe_message *msg; - msg = - kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - msg->_d = VFE_MSG_ID_CAMIF_ERROR; - memcpy(&(msg->_u.msgCamifError), - &ctrl->vfeCamifStatusLocal, sizeof(ctrl->vfeCamifStatusLocal)); - - vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR, - msg, sizeof(struct vfe_message)); -#endif -} - -static void vfe_process_error_irq( - struct vfe_interrupt_status *irqstatus) -{ - /* all possible error irq. Note error irqs are not enabled, it is - * checked only when other interrupts are present. */ - if (irqstatus->afOverflowIrq) - vfe_send_msg_no_payload(VFE_MSG_ID_AF_OVERFLOW); - - if (irqstatus->awbOverflowIrq) - vfe_send_msg_no_payload(VFE_MSG_ID_AWB_OVERFLOW); - - if (irqstatus->axiErrorIrq) - vfe_send_msg_no_payload(VFE_MSG_ID_AXI_ERROR); - - if (irqstatus->busOverflowIrq) - vfe_send_bus_overflow_msg(); - - if (irqstatus->camifErrorIrq) - vfe_send_camif_error_msg(); - - if (irqstatus->camifOverflowIrq) - vfe_send_msg_no_payload(VFE_MSG_ID_CAMIF_OVERFLOW); - - if (irqstatus->violationIrq) - ; -} - -static void vfe_process_camif_sof_irq(void) -{ - /* increment the frame id number. */ - ctrl->vfeFrameId++; - - CDBG("camif_sof_irq, frameId = %d\n", - ctrl->vfeFrameId); - - /* In snapshot mode, if frame skip is programmed, - * need to check it accordingly to stop camif at - * correct frame boundary. For the dropped frames, - * there won't be any output path irqs, but there is - * still SOF irq, which can help us determine when - * to stop the camif. - */ - if (ctrl->vfeOperationMode) { - if ((1 << ctrl->vfeFrameSkipCount) & - ctrl->vfeFrameSkipPattern) { - - ctrl->vfeSnapShotCount--; - if (ctrl->vfeSnapShotCount == 0) - /* terminate vfe pipeline at frame boundary. */ - writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, - ctrl->vfebase + CAMIF_COMMAND); - } - - /* update frame skip counter for bit checking. */ - ctrl->vfeFrameSkipCount++; - if (ctrl->vfeFrameSkipCount == - (ctrl->vfeFrameSkipPeriod + 1)) - ctrl->vfeFrameSkipCount = 0; - } -} - -static int vfe_get_af_pingpong_status(void) -{ - uint32_t busPingPongStatus; - int rc = 0; - - busPingPongStatus = - readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); - - if ((busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT) == 0) - return -EFAULT; - - return rc; -} - -static uint32_t vfe_read_af_buf_addr(boolean pipo) -{ - if (pipo == FALSE) - return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); - else - return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); -} - -static void -vfe_update_af_buf_addr(boolean pipo, uint32_t addr) -{ - if (pipo == FALSE) - writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); - else - writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); -} - -static void -vfe_send_af_stats_msg(uint32_t afBufAddress) -{ - /* unsigned long flags; */ - struct vfe_message *msg; - msg = - kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - /* fill message with right content. */ - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - if (ctrl->vstate != VFE_STATE_ACTIVE) { - kfree(msg); - goto af_stats_done; - } - - msg->_d = VFE_MSG_ID_STATS_AUTOFOCUS; - msg->_u.msgStatsAf.afBuffer = afBufAddress; - msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId; - - vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS, - msg, sizeof(struct vfe_message)); - - ctrl->afStatsControl.ackPending = TRUE; - -af_stats_done: - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - return; -} - -static void vfe_process_stats_af_irq(void) -{ - boolean bufferAvailable; - - if (!(ctrl->afStatsControl.ackPending)) { - - /* read hardware status. */ - ctrl->afStatsControl.pingPongStatus = - vfe_get_af_pingpong_status(); - - bufferAvailable = - (ctrl->afStatsControl.pingPongStatus) ^ 1; - - ctrl->afStatsControl.bufToRender = - vfe_read_af_buf_addr(bufferAvailable); - - /* update the same buffer address (ping or pong) */ - vfe_update_af_buf_addr(bufferAvailable, - ctrl->afStatsControl.nextFrameAddrBuf); - - vfe_send_af_stats_msg(ctrl->afStatsControl.bufToRender); - } else - ctrl->afStatsControl.droppedStatsFrameCount++; -} - -static boolean vfe_get_awb_pingpong_status(void) -{ - uint32_t busPingPongStatus; - - busPingPongStatus = - readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); - - if ((busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT) == 0) - return FALSE; - - return TRUE; -} - -static uint32_t -vfe_read_awb_buf_addr(boolean pingpong) -{ - if (pingpong == FALSE) - return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); - else - return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); -} - -static void vfe_update_awb_buf_addr( - boolean pingpong, uint32_t addr) -{ - if (pingpong == FALSE) - writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); - else - writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); -} - -static void vfe_send_awb_stats_msg(uint32_t awbBufAddress) -{ - /* unsigned long flags; */ - struct vfe_message *msg; - - msg = - kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - /* fill message with right content. */ - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - if (ctrl->vstate != VFE_STATE_ACTIVE) { - kfree(msg); - goto awb_stats_done; - } - - msg->_d = VFE_MSG_ID_STATS_WB_EXP; - msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress; - msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId; - - vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP, - msg, sizeof(struct vfe_message)); - - ctrl->awbStatsControl.ackPending = TRUE; - -awb_stats_done: - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - return; -} - -static void vfe_process_stats_awb_irq(void) -{ - boolean bufferAvailable; - - if (!(ctrl->awbStatsControl.ackPending)) { - - ctrl->awbStatsControl.pingPongStatus = - vfe_get_awb_pingpong_status(); - - bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1; - - ctrl->awbStatsControl.bufToRender = - vfe_read_awb_buf_addr(bufferAvailable); - - vfe_update_awb_buf_addr(bufferAvailable, - ctrl->awbStatsControl.nextFrameAddrBuf); - - vfe_send_awb_stats_msg(ctrl->awbStatsControl.bufToRender); - - } else - ctrl->awbStatsControl.droppedStatsFrameCount++; -} - -static void vfe_process_sync_timer_irq( - struct vfe_interrupt_status *irqstatus) -{ - if (irqstatus->syncTimer0Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER0_DONE); - - if (irqstatus->syncTimer1Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER1_DONE); - - if (irqstatus->syncTimer2Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER2_DONE); -} - -static void vfe_process_async_timer_irq( - struct vfe_interrupt_status *irqstatus) -{ - - if (irqstatus->asyncTimer0Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE); - - if (irqstatus->asyncTimer1Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER1_DONE); - - if (irqstatus->asyncTimer2Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER2_DONE); - - if (irqstatus->asyncTimer3Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER3_DONE); -} - -static void vfe_send_violation_msg(void) -{ - vfe_send_msg_no_payload(VFE_MSG_ID_VIOLATION); -} - -static void vfe_send_async_timer_msg(void) -{ - vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE); -} - -static void vfe_write_gamma_table(uint8_t channel, - boolean bank, int16_t *pTable) -{ - uint16_t i; - - enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED; - - switch (channel) { - case 0: - if (bank == 0) - dmiRamSel = RGBLUT_RAM_CH0_BANK0; - else - dmiRamSel = RGBLUT_RAM_CH0_BANK1; - break; - - case 1: - if (bank == 0) - dmiRamSel = RGBLUT_RAM_CH1_BANK0; - else - dmiRamSel = RGBLUT_RAM_CH1_BANK1; - break; - - case 2: - if (bank == 0) - dmiRamSel = RGBLUT_RAM_CH2_BANK0; - else - dmiRamSel = RGBLUT_RAM_CH2_BANK1; - break; - - default: - break; - } - - vfe_program_dmi_cfg(dmiRamSel); - - for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) { - writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); - pTable++; - } - - /* After DMI transfer, need to set the DMI_CFG to unselect any SRAM - unselect the SRAM Bank. */ - writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); -} - -static void vfe_prog_hw_testgen_cmd(uint32_t value) -{ - writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD); -} - -static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out) -{ - uint32_t *temp; - - memset(out, 0, sizeof(struct vfe_irq_thread_msg)); - - temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_STATUS); - out->vfeIrqStatus = readl(temp); - - temp = (uint32_t *)(ctrl->vfebase + CAMIF_STATUS); - out->camifStatus = readl(temp); - writel(0x7, ctrl->vfebase + CAMIF_COMMAND); - writel(0x3, ctrl->vfebase + CAMIF_COMMAND); - CDBG("camifStatus = 0x%x\n", out->camifStatus); - -/* - temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS); - out->demosaicStatus = readl(temp); - - temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE); - out->asfMaxEdge = readl(temp); - - temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0); -*/ - -#if 0 - out->pmInfo.encPathPmInfo.yWrPmStats0 = readl(temp++); - out->pmInfo.encPathPmInfo.yWrPmStats1 = readl(temp++); - out->pmInfo.encPathPmInfo.cbcrWrPmStats0 = readl(temp++); - out->pmInfo.encPathPmInfo.cbcrWrPmStats1 = readl(temp++); - out->pmInfo.viewPathPmInfo.yWrPmStats0 = readl(temp++); - out->pmInfo.viewPathPmInfo.yWrPmStats1 = readl(temp++); - out->pmInfo.viewPathPmInfo.cbcrWrPmStats0 = readl(temp++); - out->pmInfo.viewPathPmInfo.cbcrWrPmStats1 = readl(temp); -#endif /* if 0 Jeff */ -} - -static struct vfe_interrupt_status -vfe_parse_interrupt_status(uint32_t irqStatusIn) -{ - struct vfe_irqenable hwstat; - struct vfe_interrupt_status ret; - boolean temp; - - memset(&hwstat, 0, sizeof(hwstat)); - memset(&ret, 0, sizeof(ret)); - - hwstat = *((struct vfe_irqenable *)(&irqStatusIn)); - - ret.camifErrorIrq = hwstat.camifErrorIrq; - ret.camifSofIrq = hwstat.camifSofIrq; - ret.camifEolIrq = hwstat.camifEolIrq; - ret.camifEofIrq = hwstat.camifEofIrq; - ret.camifEpoch1Irq = hwstat.camifEpoch1Irq; - ret.camifEpoch2Irq = hwstat.camifEpoch2Irq; - ret.camifOverflowIrq = hwstat.camifOverflowIrq; - ret.ceIrq = hwstat.ceIrq; - ret.regUpdateIrq = hwstat.regUpdateIrq; - ret.resetAckIrq = hwstat.resetAckIrq; - ret.encYPingpongIrq = hwstat.encYPingpongIrq; - ret.encCbcrPingpongIrq = hwstat.encCbcrPingpongIrq; - ret.viewYPingpongIrq = hwstat.viewYPingpongIrq; - ret.viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq; - ret.rdPingpongIrq = hwstat.rdPingpongIrq; - ret.afPingpongIrq = hwstat.afPingpongIrq; - ret.awbPingpongIrq = hwstat.awbPingpongIrq; - ret.histPingpongIrq = hwstat.histPingpongIrq; - ret.encIrq = hwstat.encIrq; - ret.viewIrq = hwstat.viewIrq; - ret.busOverflowIrq = hwstat.busOverflowIrq; - ret.afOverflowIrq = hwstat.afOverflowIrq; - ret.awbOverflowIrq = hwstat.awbOverflowIrq; - ret.syncTimer0Irq = hwstat.syncTimer0Irq; - ret.syncTimer1Irq = hwstat.syncTimer1Irq; - ret.syncTimer2Irq = hwstat.syncTimer2Irq; - ret.asyncTimer0Irq = hwstat.asyncTimer0Irq; - ret.asyncTimer1Irq = hwstat.asyncTimer1Irq; - ret.asyncTimer2Irq = hwstat.asyncTimer2Irq; - ret.asyncTimer3Irq = hwstat.asyncTimer3Irq; - ret.axiErrorIrq = hwstat.axiErrorIrq; - ret.violationIrq = hwstat.violationIrq; - - /* logic OR of any error bits - * although each irq corresponds to a bit, the data type here is a - * boolean already. hence use logic operation. - */ - temp = - ret.camifErrorIrq || - ret.camifOverflowIrq || - ret.afOverflowIrq || - ret.awbPingpongIrq || - ret.busOverflowIrq || - ret.axiErrorIrq || - ret.violationIrq; - - ret.anyErrorIrqs = temp; - - /* logic OR of any output path bits*/ - temp = - ret.encYPingpongIrq || - ret.encCbcrPingpongIrq || - ret.encIrq; - - ret.anyOutput2PathIrqs = temp; - - temp = - ret.viewYPingpongIrq || - ret.viewCbcrPingpongIrq || - ret.viewIrq; - - ret.anyOutput1PathIrqs = temp; - - ret.anyOutputPathIrqs = - ret.anyOutput1PathIrqs || - ret.anyOutput2PathIrqs; - - /* logic OR of any sync timer bits*/ - temp = - ret.syncTimer0Irq || - ret.syncTimer1Irq || - ret.syncTimer2Irq; - - ret.anySyncTimerIrqs = temp; - - /* logic OR of any async timer bits*/ - temp = - ret.asyncTimer0Irq || - ret.asyncTimer1Irq || - ret.asyncTimer2Irq || - ret.asyncTimer3Irq; - - ret.anyAsyncTimerIrqs = temp; - - /* bool for all interrupts that are not allowed in idle state */ - temp = - ret.anyErrorIrqs || - ret.anyOutputPathIrqs || - ret.anySyncTimerIrqs || - ret.regUpdateIrq || - ret.awbPingpongIrq || - ret.afPingpongIrq || - ret.camifSofIrq || - ret.camifEpoch2Irq || - ret.camifEpoch1Irq; - - ret.anyIrqForActiveStatesOnly = - temp; - - return ret; -} - -static struct vfe_frame_asf_info -vfe_get_asf_frame_info(struct vfe_irq_thread_msg *in) -{ - struct vfe_asf_info asfInfoTemp; - struct vfe_frame_asf_info rc; - - memset(&rc, 0, sizeof(rc)); - memset(&asfInfoTemp, 0, sizeof(asfInfoTemp)); - - asfInfoTemp = - *((struct vfe_asf_info *)(&(in->asfMaxEdge))); - - rc.asfHbiCount = asfInfoTemp.HBICount; - rc.asfMaxEdge = asfInfoTemp.maxEdge; - - return rc; -} - -static struct vfe_frame_bpc_info -vfe_get_demosaic_frame_info(struct vfe_irq_thread_msg *in) -{ - struct vfe_bps_info bpcInfoTemp; - struct vfe_frame_bpc_info rc; - - memset(&rc, 0, sizeof(rc)); - memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp)); - - bpcInfoTemp = - *((struct vfe_bps_info *)(&(in->demosaicStatus))); - - rc.greenDefectPixelCount = - bpcInfoTemp.greenBadPixelCount; - - rc.redBlueDefectPixelCount = - bpcInfoTemp.RedBlueBadPixelCount; - - return rc; -} - -static struct vfe_msg_camif_status -vfe_get_camif_status(struct vfe_irq_thread_msg *in) -{ - struct vfe_camif_stats camifStatusTemp; - struct vfe_msg_camif_status rc; - - memset(&rc, 0, sizeof(rc)); - memset(&camifStatusTemp, 0, sizeof(camifStatusTemp)); - - camifStatusTemp = - *((struct vfe_camif_stats *)(&(in->camifStatus))); - - rc.camifState = (boolean)camifStatusTemp.camifHalt; - rc.lineCount = camifStatusTemp.lineCount; - rc.pixelCount = camifStatusTemp.pixelCount; - - return rc; -} - -static struct vfe_bus_performance_monitor -vfe_get_performance_monitor_data(struct vfe_irq_thread_msg *in) -{ - struct vfe_bus_performance_monitor rc; - memset(&rc, 0, sizeof(rc)); - - rc.encPathPmInfo.yWrPmStats0 = - in->pmInfo.encPathPmInfo.yWrPmStats0; - rc.encPathPmInfo.yWrPmStats1 = - in->pmInfo.encPathPmInfo.yWrPmStats1; - rc.encPathPmInfo.cbcrWrPmStats0 = - in->pmInfo.encPathPmInfo.cbcrWrPmStats0; - rc.encPathPmInfo.cbcrWrPmStats1 = - in->pmInfo.encPathPmInfo.cbcrWrPmStats1; - rc.viewPathPmInfo.yWrPmStats0 = - in->pmInfo.viewPathPmInfo.yWrPmStats0; - rc.viewPathPmInfo.yWrPmStats1 = - in->pmInfo.viewPathPmInfo.yWrPmStats1; - rc.viewPathPmInfo.cbcrWrPmStats0 = - in->pmInfo.viewPathPmInfo.cbcrWrPmStats0; - rc.viewPathPmInfo.cbcrWrPmStats1 = - in->pmInfo.viewPathPmInfo.cbcrWrPmStats1; - - return rc; -} - -static void vfe_process_reg_update_irq(void) -{ - CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n", - ctrl->vfeStartAckPendingFlag); - if (ctrl->vfeStartAckPendingFlag == TRUE) { - vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK); - ctrl->vfeStartAckPendingFlag = FALSE; - } else - vfe_send_msg_no_payload(VFE_MSG_ID_UPDATE_ACK); -} - -static void vfe_process_reset_irq(void) -{ - /* unsigned long flags; */ - - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - ctrl->vstate = VFE_STATE_IDLE; - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - - if (ctrl->vfeStopAckPending == TRUE) { - ctrl->vfeStopAckPending = FALSE; - vfe_send_msg_no_payload(VFE_MSG_ID_STOP_ACK); - } else { - vfe_set_default_reg_values(); - vfe_send_msg_no_payload(VFE_MSG_ID_RESET_ACK); - } -} - -static void vfe_process_pingpong_irq(struct vfe_output_path *in, - uint8_t fragmentCount) -{ - uint16_t circularIndex; - uint32_t nextFragmentAddr; - - /* get next fragment address from circular buffer */ - circularIndex = (in->fragIndex) % (2 * fragmentCount); - nextFragmentAddr = in->addressBuffer[circularIndex]; - - in->fragIndex = circularIndex + 1; - - /* use next fragment to program hardware ping/pong address. */ - if (in->hwCurrentFlag == ping) { - writel(nextFragmentAddr, in->hwRegPingAddress); - in->hwCurrentFlag = pong; - - } else { - writel(nextFragmentAddr, in->hwRegPongAddress); - in->hwCurrentFlag = ping; - } -} - -static void vfe_send_output2_msg( - struct vfe_msg_output *pPayload) -{ - /* unsigned long flags; */ - struct vfe_message *msg; - - msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - /* fill message with right content. */ - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - if (ctrl->vstate != VFE_STATE_ACTIVE) { - kfree(msg); - goto output2_msg_done; - } - - msg->_d = VFE_MSG_ID_OUTPUT2; - - memcpy(&(msg->_u.msgOutput2), - (void *)pPayload, sizeof(struct vfe_msg_output)); - - vfe_proc_ops(VFE_MSG_ID_OUTPUT2, - msg, sizeof(struct vfe_message)); - - ctrl->encPath.ackPending = TRUE; - - if (!(ctrl->vfeRequestedSnapShotCount <= 3) && - (ctrl->vfeOperationMode == - VFE_START_OPERATION_MODE_SNAPSHOT)) - ctrl->encPath.ackPending = TRUE; - -output2_msg_done: - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - return; -} - -static void vfe_send_output1_msg( - struct vfe_msg_output *pPayload) -{ - /* unsigned long flags; */ - struct vfe_message *msg; - - msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC); - if (!msg) - return; - - /* @todo This is causing issues, need further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - if (ctrl->vstate != VFE_STATE_ACTIVE) { - kfree(msg); - goto output1_msg_done; - } - - msg->_d = VFE_MSG_ID_OUTPUT1; - memmove(&(msg->_u), - (void *)pPayload, sizeof(struct vfe_msg_output)); - - vfe_proc_ops(VFE_MSG_ID_OUTPUT1, - msg, sizeof(struct vfe_message)); - - ctrl->viewPath.ackPending = TRUE; - - if (!(ctrl->vfeRequestedSnapShotCount <= 3) && - (ctrl->vfeOperationMode == - VFE_START_OPERATION_MODE_SNAPSHOT)) - ctrl->viewPath.ackPending = TRUE; - -output1_msg_done: - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - return; -} - -static void vfe_send_output_msg(boolean whichOutputPath, - uint32_t yPathAddr, uint32_t cbcrPathAddr) -{ - struct vfe_msg_output msgPayload; - - msgPayload.yBuffer = yPathAddr; - msgPayload.cbcrBuffer = cbcrPathAddr; - - /* asf info is common for both output1 and output2 */ -#if 0 - msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount; - msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge; - - /* demosaic info is common for both output1 and output2 */ - msgPayload.bpcInfo.greenDefectPixelCount = - ctrl->vfeBpcFrameInfo.greenDefectPixelCount; - msgPayload.bpcInfo.redBlueDefectPixelCount = - ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount; -#endif /* if 0 */ - - /* frame ID is common for both paths. */ - msgPayload.frameCounter = ctrl->vfeFrameId; - - if (whichOutputPath) { - /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */ - vfe_send_output2_msg(&msgPayload); - } else { - /* msgPayload.pmData = ctrl->vfePmData.viewPathPmInfo; */ - vfe_send_output1_msg(&msgPayload); - } -} - -static void vfe_process_frame_done_irq_multi_frag( - struct vfe_output_path_combo *in) -{ - uint32_t yAddress, cbcrAddress; - uint16_t idx; - uint32_t *ptrY; - uint32_t *ptrCbcr; - const uint32_t *ptrSrc; - uint8_t i; - - if (!in->ackPending) { - - idx = (in->currentFrame) * (in->fragCount); - - /* Send output message. */ - yAddress = in->yPath.addressBuffer[idx]; - cbcrAddress = in->cbcrPath.addressBuffer[idx]; - - /* copy next frame to current frame. */ - ptrSrc = in->nextFrameAddrBuf; - ptrY = (uint32_t *)&(in->yPath.addressBuffer[idx]); - ptrCbcr = (uint32_t *)&(in->cbcrPath.addressBuffer[idx]); - - /* Copy Y address */ - for (i = 0; i < in->fragCount; i++) - *ptrY++ = *ptrSrc++; - - /* Copy Cbcr address */ - for (i = 0; i < in->fragCount; i++) - *ptrCbcr++ = *ptrSrc++; - - vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress); - - } else { - if (in->whichOutputPath == 0) - ctrl->vfeDroppedFrameCounts.output1Count++; - - if (in->whichOutputPath == 1) - ctrl->vfeDroppedFrameCounts.output2Count++; - } - - /* toggle current frame. */ - in->currentFrame = in->currentFrame^1; - - if (ctrl->vfeOperationMode) - in->snapshotPendingCount--; -} - -static void vfe_process_frame_done_irq_no_frag_io( - struct vfe_output_path_combo *in, uint32_t *pNextAddr, - uint32_t *pdestRenderAddr) -{ - uint32_t busPingPongStatus; - uint32_t tempAddress; - - /* 1. read hw status register. */ - busPingPongStatus = - readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); - - CDBG("hardware status is 0x%x\n", busPingPongStatus); - - /* 2. determine ping or pong */ - /* use cbcr status */ - busPingPongStatus = busPingPongStatus & (1<<(in->cbcrStatusBit)); - - /* 3. read out address and update address */ - if (busPingPongStatus == 0) { - /* hw is working on ping, render pong buffer */ - /* a. read out pong address */ - /* read out y address. */ - tempAddress = readl(in->yPath.hwRegPongAddress); - - CDBG("pong 1 addr = 0x%x\n", tempAddress); - *pdestRenderAddr++ = tempAddress; - /* read out cbcr address. */ - tempAddress = readl(in->cbcrPath.hwRegPongAddress); - - CDBG("pong 2 addr = 0x%x\n", tempAddress); - *pdestRenderAddr = tempAddress; - - /* b. update pong address */ - writel(*pNextAddr++, in->yPath.hwRegPongAddress); - writel(*pNextAddr, in->cbcrPath.hwRegPongAddress); - } else { - /* hw is working on pong, render ping buffer */ - - /* a. read out ping address */ - tempAddress = readl(in->yPath.hwRegPingAddress); - CDBG("ping 1 addr = 0x%x\n", tempAddress); - *pdestRenderAddr++ = tempAddress; - tempAddress = readl(in->cbcrPath.hwRegPingAddress); - - CDBG("ping 2 addr = 0x%x\n", tempAddress); - *pdestRenderAddr = tempAddress; - - /* b. update ping address */ - writel(*pNextAddr++, in->yPath.hwRegPingAddress); - CDBG("NextAddress = 0x%x\n", *pNextAddr); - writel(*pNextAddr, in->cbcrPath.hwRegPingAddress); - } -} - -static void vfe_process_frame_done_irq_no_frag( - struct vfe_output_path_combo *in) -{ - uint32_t addressToRender[2]; - static uint32_t fcnt; - - if (fcnt++ < 3) - return; - - if (!in->ackPending) { - vfe_process_frame_done_irq_no_frag_io(in, - in->nextFrameAddrBuf, addressToRender); - - /* use addressToRender to send out message. */ - vfe_send_output_msg(in->whichOutputPath, - addressToRender[0], addressToRender[1]); - - } else { - /* ackPending is still there, accumulate dropped frame count. - * These count can be read through ioctrl command. */ - CDBG("waiting frame ACK\n"); - - if (in->whichOutputPath == 0) - ctrl->vfeDroppedFrameCounts.output1Count++; - - if (in->whichOutputPath == 1) - ctrl->vfeDroppedFrameCounts.output2Count++; - } - - /* in case of multishot when upper layer did not ack, there will still - * be a snapshot done msg sent out, even though the number of frames - * sent out may be less than the desired number of frames. snapshot - * done msg would be helpful to indicate that vfe pipeline has stop, - * and in good known state. - */ - if (ctrl->vfeOperationMode) - in->snapshotPendingCount--; -} - -static void vfe_process_output_path_irq( - struct vfe_interrupt_status *irqstatus) -{ - /* unsigned long flags; */ - - /* process the view path interrupts */ - if (irqstatus->anyOutput1PathIrqs) { - if (ctrl->viewPath.multiFrag) { - - if (irqstatus->viewCbcrPingpongIrq) - vfe_process_pingpong_irq( - &(ctrl->viewPath.cbcrPath), - ctrl->viewPath.fragCount); - - if (irqstatus->viewYPingpongIrq) - vfe_process_pingpong_irq( - &(ctrl->viewPath.yPath), - ctrl->viewPath.fragCount); - - if (irqstatus->viewIrq) - vfe_process_frame_done_irq_multi_frag( - &ctrl->viewPath); - - } else { - /* typical case for no fragment, - only frame done irq is enabled. */ - if (irqstatus->viewIrq) - vfe_process_frame_done_irq_no_frag( - &ctrl->viewPath); - } - } - - /* process the encoder path interrupts */ - if (irqstatus->anyOutput2PathIrqs) { - if (ctrl->encPath.multiFrag) { - if (irqstatus->encCbcrPingpongIrq) - vfe_process_pingpong_irq( - &(ctrl->encPath.cbcrPath), - ctrl->encPath.fragCount); - - if (irqstatus->encYPingpongIrq) - vfe_process_pingpong_irq(&(ctrl->encPath.yPath), - ctrl->encPath.fragCount); - - if (irqstatus->encIrq) - vfe_process_frame_done_irq_multi_frag( - &ctrl->encPath); - - } else { - if (irqstatus->encIrq) - vfe_process_frame_done_irq_no_frag( - &ctrl->encPath); - } - } - - if (ctrl->vfeOperationMode) { - if ((ctrl->encPath.snapshotPendingCount == 0) && - (ctrl->viewPath.snapshotPendingCount == 0)) { - - /* @todo This is causing issues, further investigate */ - /* spin_lock_irqsave(&ctrl->state_lock, flags); */ - ctrl->vstate = VFE_STATE_IDLE; - /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */ - - vfe_send_msg_no_payload(VFE_MSG_ID_SNAPSHOT_DONE); - vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP); - vfe_pm_stop(); - } - } -} - -static void vfe_do_tasklet(unsigned long data) -{ - unsigned long flags; - - struct isr_queue_cmd *qcmd = NULL; - - CDBG("=== vfe_do_tasklet start === \n"); - - spin_lock_irqsave(&ctrl->tasklet_lock, flags); - qcmd = list_first_entry(&ctrl->tasklet_q, - struct isr_queue_cmd, list); - - if (!qcmd) { - spin_unlock_irqrestore(&ctrl->tasklet_lock, flags); - return; - } - - list_del(&qcmd->list); - spin_unlock_irqrestore(&ctrl->tasklet_lock, flags); - - if (qcmd->vfeInterruptStatus.regUpdateIrq) { - CDBG("irq regUpdateIrq\n"); - vfe_process_reg_update_irq(); - } - - if (qcmd->vfeInterruptStatus.resetAckIrq) { - CDBG("irq resetAckIrq\n"); - vfe_process_reset_irq(); - } - - spin_lock_irqsave(&ctrl->state_lock, flags); - if (ctrl->vstate != VFE_STATE_ACTIVE) { - spin_unlock_irqrestore(&ctrl->state_lock, flags); - return; - } - spin_unlock_irqrestore(&ctrl->state_lock, flags); - -#if 0 - if (qcmd->vfeInterruptStatus.camifEpoch1Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH1); - - if (qcmd->vfeInterruptStatus.camifEpoch2Irq) - vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH2); -#endif /* Jeff */ - - /* next, check output path related interrupts. */ - if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) { - CDBG("irq anyOutputPathIrqs\n"); - vfe_process_output_path_irq(&qcmd->vfeInterruptStatus); - } - - if (qcmd->vfeInterruptStatus.afPingpongIrq) - vfe_process_stats_af_irq(); - - if (qcmd->vfeInterruptStatus.awbPingpongIrq) - vfe_process_stats_awb_irq(); - - /* any error irqs*/ - if (qcmd->vfeInterruptStatus.anyErrorIrqs) - vfe_process_error_irq(&qcmd->vfeInterruptStatus); - -#if 0 - if (qcmd->vfeInterruptStatus.anySyncTimerIrqs) - vfe_process_sync_timer_irq(); - - if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs) - vfe_process_async_timer_irq(); -#endif /* Jeff */ - - if (qcmd->vfeInterruptStatus.camifSofIrq) { - CDBG("irq camifSofIrq\n"); - vfe_process_camif_sof_irq(); - } - - kfree(qcmd); - CDBG("=== vfe_do_tasklet end === \n"); -} - -DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0); - -static irqreturn_t vfe_parse_irq(int irq_num, void *data) -{ - unsigned long flags; - uint32_t irqStatusLocal; - struct vfe_irq_thread_msg irq; - struct isr_queue_cmd *qcmd; - - CDBG("vfe_parse_irq\n"); - - vfe_read_irq_status(&irq); - - if (irq.vfeIrqStatus == 0) { - CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n"); - return IRQ_HANDLED; - } - - qcmd = kzalloc(sizeof(struct isr_queue_cmd), - GFP_ATOMIC); - if (!qcmd) { - CDBG("vfe_parse_irq: qcmd malloc failed!\n"); - return IRQ_HANDLED; - } - - spin_lock_irqsave(&ctrl->ack_lock, flags); - - if (ctrl->vfeStopAckPending) - irqStatusLocal = - (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus); - else - irqStatusLocal = - ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) & - irq.vfeIrqStatus); - - spin_unlock_irqrestore(&ctrl->ack_lock, flags); - - /* first parse the interrupt status to local data structures. */ - qcmd->vfeInterruptStatus = vfe_parse_interrupt_status(irqStatusLocal); - qcmd->vfeAsfFrameInfo = vfe_get_asf_frame_info(&irq); - qcmd->vfeBpcFrameInfo = vfe_get_demosaic_frame_info(&irq); - qcmd->vfeCamifStatusLocal = vfe_get_camif_status(&irq); - qcmd->vfePmData = vfe_get_performance_monitor_data(&irq); - - spin_lock_irqsave(&ctrl->tasklet_lock, flags); - list_add_tail(&qcmd->list, &ctrl->tasklet_q); - spin_unlock_irqrestore(&ctrl->tasklet_lock, flags); - tasklet_schedule(&vfe_tasklet); - - /* clear the pending interrupt of the same kind.*/ - writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR); - - return IRQ_HANDLED; -} - -int vfe_cmd_init(struct msm_vfe_callback *presp, - struct platform_device *pdev, void *sdata) -{ - struct resource *vfemem, *vfeirq, *vfeio; - int rc; - - vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!vfemem) { - CDBG("no mem resource?\n"); - return -ENODEV; - } - - vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!vfeirq) { - CDBG("no irq resource?\n"); - return -ENODEV; - } - - vfeio = request_mem_region(vfemem->start, - resource_size(vfemem), pdev->name); - if (!vfeio) { - CDBG("VFE region already claimed\n"); - return -EBUSY; - } - - ctrl = - kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL); - if (!ctrl) { - rc = -ENOMEM; - goto cmd_init_failed1; - } - - ctrl->vfeirq = vfeirq->start; - - ctrl->vfebase = - ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1); - if (!ctrl->vfebase) { - rc = -ENOMEM; - goto cmd_init_failed2; - } - - rc = request_irq(ctrl->vfeirq, vfe_parse_irq, - IRQF_TRIGGER_RISING, "vfe", 0); - if (rc < 0) - goto cmd_init_failed2; - - if (presp && presp->vfe_resp) - ctrl->resp = presp; - else { - rc = -EINVAL; - goto cmd_init_failed3; - } - - ctrl->extdata = - kmalloc(sizeof(struct vfe_frame_extra), GFP_KERNEL); - if (!ctrl->extdata) { - rc = -ENOMEM; - goto cmd_init_failed3; - } - - spin_lock_init(&ctrl->ack_lock); - spin_lock_init(&ctrl->state_lock); - spin_lock_init(&ctrl->io_lock); - - ctrl->extlen = sizeof(struct vfe_frame_extra); - - spin_lock_init(&ctrl->tasklet_lock); - INIT_LIST_HEAD(&ctrl->tasklet_q); - - ctrl->syncdata = sdata; - return 0; - -cmd_init_failed3: - disable_irq(ctrl->vfeirq); - free_irq(ctrl->vfeirq, 0); - iounmap(ctrl->vfebase); -cmd_init_failed2: - kfree(ctrl); -cmd_init_failed1: - release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1); - return rc; -} - -void vfe_cmd_release(struct platform_device *dev) -{ - struct resource *mem; - - disable_irq(ctrl->vfeirq); - free_irq(ctrl->vfeirq, 0); - - iounmap(ctrl->vfebase); - mem = platform_get_resource(dev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, (mem->end - mem->start) + 1); - - ctrl->extlen = 0; - - kfree(ctrl->extdata); - kfree(ctrl); -} - -void vfe_stats_af_stop(void) -{ - ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE; - ctrl->vfeImaskLocal.afPingpongIrq = FALSE; -} - -void vfe_stop(void) -{ - boolean vfeAxiBusy; - uint32_t vfeAxiStauts; - - /* for reset hw modules, and send msg when reset_irq comes.*/ - ctrl->vfeStopAckPending = TRUE; - - ctrl->vfeStatsPingPongReloadFlag = FALSE; - vfe_pm_stop(); - - /* disable all interrupts. */ - vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS); - - /* in either continuous or snapshot mode, stop command can be issued - * at any time. - */ - vfe_camif_stop_immediately(); - vfe_program_axi_cmd(AXI_HALT); - vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP); - - vfeAxiBusy = TRUE; - - while (vfeAxiBusy) { - vfeAxiStauts = vfe_read_axi_status(); - if ((vfeAxiStauts & AXI_STATUS_BUSY_MASK) != 0) - vfeAxiBusy = FALSE; - } - - vfe_program_axi_cmd(AXI_HALT_CLEAR); - - /* clear all pending interrupts */ - writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR); - - /* enable reset_ack and async timer interrupt only while stopping - * the pipeline. - */ - vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING); - - vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD); -} - -void vfe_update(void) -{ - ctrl->vfeModuleEnableLocal.statsEnable = - ctrl->vfeStatsCmdLocal.autoFocusEnable | - ctrl->vfeStatsCmdLocal.axwEnable; - - vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal); - - vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal); - - ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); - vfe_program_irq_mask(ctrl->vfeImaskPacked); - - if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) && - (ctrl->vfeStatsPingPongReloadFlag == FALSE)) { - ctrl->vfeStatsPingPongReloadFlag = TRUE; - - ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE; - vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal); - } - - vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER); -} - -int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in) -{ - int rc = 0; - - ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable; - - switch (in->channelSelect) { - case RGB_GAMMA_CH0_SELECTED: - ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; - vfe_write_gamma_table(0, - ctrl->vfeGammaLutSel.ch0BankSelect, in->table); - break; - - case RGB_GAMMA_CH1_SELECTED: - ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; - vfe_write_gamma_table(1, - ctrl->vfeGammaLutSel.ch1BankSelect, in->table); - break; - - case RGB_GAMMA_CH2_SELECTED: - ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; - vfe_write_gamma_table(2, - ctrl->vfeGammaLutSel.ch2BankSelect, in->table); - break; - - case RGB_GAMMA_CH0_CH1_SELECTED: - ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; - ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; - vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, - in->table); - vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, - in->table); - break; - - case RGB_GAMMA_CH0_CH2_SELECTED: - ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; - ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; - vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, - in->table); - vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, - in->table); - break; - - case RGB_GAMMA_CH1_CH2_SELECTED: - ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; - ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; - vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, - in->table); - vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, - in->table); - break; - - case RGB_GAMMA_CH0_CH1_CH2_SELECTED: - ctrl->vfeGammaLutSel.ch0BankSelect ^= 1; - ctrl->vfeGammaLutSel.ch1BankSelect ^= 1; - ctrl->vfeGammaLutSel.ch2BankSelect ^= 1; - vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect, - in->table); - vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect, - in->table); - vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect, - in->table); - break; - - default: - return -EINVAL; - } /* switch */ - - /* update the gammaLutSel register. */ - vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel); - - return rc; -} - -int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in) -{ - int rc = 0; - - ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable; - - switch (in->channelSelect) { - case RGB_GAMMA_CH0_SELECTED: -vfe_write_gamma_table(0, 0, in->table); -break; - - case RGB_GAMMA_CH1_SELECTED: - vfe_write_gamma_table(1, 0, in->table); - break; - - case RGB_GAMMA_CH2_SELECTED: - vfe_write_gamma_table(2, 0, in->table); - break; - - case RGB_GAMMA_CH0_CH1_SELECTED: - vfe_write_gamma_table(0, 0, in->table); - vfe_write_gamma_table(1, 0, in->table); - break; - - case RGB_GAMMA_CH0_CH2_SELECTED: - vfe_write_gamma_table(0, 0, in->table); - vfe_write_gamma_table(2, 0, in->table); - break; - - case RGB_GAMMA_CH1_CH2_SELECTED: - vfe_write_gamma_table(1, 0, in->table); - vfe_write_gamma_table(2, 0, in->table); - break; - - case RGB_GAMMA_CH0_CH1_CH2_SELECTED: - vfe_write_gamma_table(0, 0, in->table); - vfe_write_gamma_table(1, 0, in->table); - vfe_write_gamma_table(2, 0, in->table); - break; - - default: - rc = -EINVAL; - break; - } /* switch */ - - return rc; -} - -void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in) -{ - ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr; - ctrl->afStatsControl.ackPending = FALSE; -} - -void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in) -{ - ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr; - ctrl->awbStatsControl.ackPending = FALSE; -} - -void vfe_output2_ack(struct vfe_cmd_output_ack *in) -{ - const uint32_t *psrc; - uint32_t *pdest; - uint8_t i; - - pdest = ctrl->encPath.nextFrameAddrBuf; - - CDBG("output2_ack: ack addr = 0x%x\n", in->ybufaddr[0]); - - psrc = in->ybufaddr; - for (i = 0; i < ctrl->encPath.fragCount; i++) - *pdest++ = *psrc++; - - psrc = in->chromabufaddr; - for (i = 0; i < ctrl->encPath.fragCount; i++) - *pdest++ = *psrc++; - - ctrl->encPath.ackPending = FALSE; -} - -void vfe_output1_ack(struct vfe_cmd_output_ack *in) -{ - const uint32_t *psrc; - uint32_t *pdest; - uint8_t i; - - pdest = ctrl->viewPath.nextFrameAddrBuf; - - psrc = in->ybufaddr; - for (i = 0; i < ctrl->viewPath.fragCount; i++) - *pdest++ = *psrc++; - - psrc = in->chromabufaddr; - for (i = 0; i < ctrl->viewPath.fragCount; i++) - *pdest++ = *psrc++; - - ctrl->viewPath.ackPending = FALSE; -} - -void vfe_start(struct vfe_cmd_start *in) -{ - unsigned long flags; - uint32_t pmstatus = 0; - boolean rawmode; - uint32_t demperiod = 0; - uint32_t demeven = 0; - uint32_t demodd = 0; - - /* derived from other commands. (camif config, axi output config, - * etc) - */ - struct vfe_cfg hwcfg; - struct vfe_upsample_cfg chromupcfg; - - CDBG("vfe_start operationMode = %d\n", in->operationMode); - - memset(&hwcfg, 0, sizeof(hwcfg)); - memset(&chromupcfg, 0, sizeof(chromupcfg)); - - switch (in->pixel) { - case VFE_BAYER_RGRGRG: - demperiod = 1; - demeven = 0xC9; - demodd = 0xAC; - break; - - case VFE_BAYER_GRGRGR: - demperiod = 1; - demeven = 0x9C; - demodd = 0xCA; - break; - - case VFE_BAYER_BGBGBG: - demperiod = 1; - demeven = 0xCA; - demodd = 0x9C; - break; - - case VFE_BAYER_GBGBGB: - demperiod = 1; - demeven = 0xAC; - demodd = 0xC9; - break; - - case VFE_YUV_YCbYCr: - demperiod = 3; - demeven = 0x9CAC; - demodd = 0x9CAC; - break; - - case VFE_YUV_YCrYCb: - demperiod = 3; - demeven = 0xAC9C; - demodd = 0xAC9C; - break; - - case VFE_YUV_CbYCrY: - demperiod = 3; - demeven = 0xC9CA; - demodd = 0xC9CA; - break; - - case VFE_YUV_CrYCbY: - demperiod = 3; - demeven = 0xCAC9; - demodd = 0xCAC9; - break; - - default: - return; - } - - vfe_config_demux(demperiod, demeven, demodd); - - vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel); - - /* save variables to local. */ - ctrl->vfeOperationMode = in->operationMode; - if (ctrl->vfeOperationMode == - VFE_START_OPERATION_MODE_SNAPSHOT) { - /* in snapshot mode, initialize snapshot count*/ - ctrl->vfeSnapShotCount = in->snapshotCount; - - /* save the requested count, this is temporarily done, to - help with HJR / multishot. */ - ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount; - - CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount); - - /* Assumption is to have the same pattern and period for both - paths, if both paths are used. */ - if (ctrl->viewPath.pathEnabled) { - ctrl->viewPath.snapshotPendingCount = - in->snapshotCount; - - ctrl->vfeFrameSkipPattern = - ctrl->vfeFrameSkip.output1Pattern; - ctrl->vfeFrameSkipPeriod = - ctrl->vfeFrameSkip.output1Period; - } - - if (ctrl->encPath.pathEnabled) { - ctrl->encPath.snapshotPendingCount = - in->snapshotCount; - - ctrl->vfeFrameSkipPattern = - ctrl->vfeFrameSkip.output2Pattern; - ctrl->vfeFrameSkipPeriod = - ctrl->vfeFrameSkip.output2Period; - } - } - - /* enable color conversion for bayer sensor - if stats enabled, need to do color conversion. */ - if (in->pixel <= VFE_BAYER_GBGBGB) - ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE; - - vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal); - - if (in->pixel >= VFE_YUV_YCbYCr) - ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE; - - ctrl->vfeModuleEnableLocal.demuxEnable = TRUE; - - /* if any stats module is enabled, the main bit is enabled. */ - ctrl->vfeModuleEnableLocal.statsEnable = - ctrl->vfeStatsCmdLocal.autoFocusEnable | - ctrl->vfeStatsCmdLocal.axwEnable; - - vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal); - - /* in case of offline processing, do not need to config camif. Having - * bus output enabled in camif_config register might confuse the - * hardware? - */ - if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) { - vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal); - } else { - /* offline processing, enable axi read */ - ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE; - ctrl->vfeBusCmdLocal.stripeReload = TRUE; - ctrl->vfeBusConfigLocal.rawPixelDataSize = - ctrl->axiInputDataSize; - } - - vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal); - - /* directly from start command */ - hwcfg.pixelPattern = in->pixel; - hwcfg.inputSource = in->inputSource; - writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG); - - /* regardless module enabled or not, it does not hurt - * to program the cositing mode. */ - chromupcfg.chromaCositingForYCbCrInputs = - in->yuvInputCositingMode; - - writel(*(uint32_t *)&(chromupcfg), - ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG); - - /* MISR to monitor the axi read. */ - writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0); - - /* clear all pending interrupts. */ - writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR); - - /* define how composite interrupt work. */ - ctrl->vfeImaskCompositePacked = - vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal); - - vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked); - - /* enable all necessary interrupts. */ - ctrl->vfeImaskLocal.camifSofIrq = TRUE; - ctrl->vfeImaskLocal.regUpdateIrq = TRUE; - ctrl->vfeImaskLocal.resetAckIrq = TRUE; - - ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); - vfe_program_irq_mask(ctrl->vfeImaskPacked); - - /* enable bus performance monitor */ - vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal); - - /* trigger vfe reg update */ - ctrl->vfeStartAckPendingFlag = TRUE; - - /* write bus command to trigger reload of ping pong buffer. */ - ctrl->vfeBusCmdLocal.busPingpongReload = TRUE; - - if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) { - ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE; - ctrl->vfeStatsPingPongReloadFlag = TRUE; - } - - writel(VFE_REG_UPDATE_TRIGGER, - ctrl->vfebase + VFE_REG_UPDATE_CMD); - - /* program later than the reg update. */ - vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal); - - if ((in->inputSource == - VFE_START_INPUT_SOURCE_CAMIF) || - (in->inputSource == - VFE_START_INPUT_SOURCE_TESTGEN)) - writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND); - - /* start test gen if it is enabled */ - if (ctrl->vfeTestGenStartFlag == TRUE) { - ctrl->vfeTestGenStartFlag = FALSE; - vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO); - } - - CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode); - if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) { - /* raw dump mode */ - rawmode = TRUE; - - while (rawmode) { - pmstatus = - readl(ctrl->vfebase + - VFE_BUS_ENC_CBCR_WR_PM_STATS_1); - - if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0) - rawmode = FALSE; - } - - vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK); - ctrl->vfeStartAckPendingFlag = FALSE; - } - - spin_lock_irqsave(&ctrl->state_lock, flags); - ctrl->vstate = VFE_STATE_ACTIVE; - spin_unlock_irqrestore(&ctrl->state_lock, flags); -} - -void vfe_la_update(struct vfe_cmd_la_config *in) -{ - int16_t *pTable; - enum VFE_DMI_RAM_SEL dmiRamSel; - int i; - - pTable = in->table; - ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable; - - /* toggle the bank to be used. */ - ctrl->vfeLaBankSel ^= 1; - - if (ctrl->vfeLaBankSel == 0) - dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0; - else - dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1; - - /* configure the DMI_CFG to select right sram */ - vfe_program_dmi_cfg(dmiRamSel); - - for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) { - writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); - pTable++; - } - - /* After DMI transfer, to make it safe, need to set - * the DMI_CFG to unselect any SRAM */ - writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); - writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG); -} - -void vfe_la_config(struct vfe_cmd_la_config *in) -{ - uint16_t i; - int16_t *pTable; - enum VFE_DMI_RAM_SEL dmiRamSel; - - pTable = in->table; - ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable; - - if (ctrl->vfeLaBankSel == 0) - dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0; - else - dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1; - - /* configure the DMI_CFG to select right sram */ - vfe_program_dmi_cfg(dmiRamSel); - - for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) { - writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO); - pTable++; - } - - /* After DMI transfer, to make it safe, need to set the - * DMI_CFG to unselect any SRAM */ - writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG); - - /* can only be bank 0 or bank 1 for now. */ - writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG); - CDBG("VFE Luma adaptation bank selection is 0x%x\n", - *(uint32_t *)&ctrl->vfeLaBankSel); -} - -void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in) -{ - struct VFE_TestGen_ConfigCmdType cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.numFrame = in->numFrame; - cmd.pixelDataSelect = in->pixelDataSelect; - cmd.systematicDataSelect = in->systematicDataSelect; - cmd.pixelDataSize = (uint32_t)in->pixelDataSize; - cmd.hsyncEdge = (uint32_t)in->hsyncEdge; - cmd.vsyncEdge = (uint32_t)in->vsyncEdge; - cmd.imageWidth = in->imageWidth; - cmd.imageHeight = in->imageHeight; - cmd.sofOffset = in->startOfFrameOffset; - cmd.eofNOffset = in->endOfFrameNOffset; - cmd.solOffset = in->startOfLineOffset; - cmd.eolNOffset = in->endOfLineNOffset; - cmd.hBlankInterval = in->hbi; - cmd.vBlankInterval = in->vbl; - cmd.vBlankIntervalEnable = in->vblEnable; - cmd.sofDummy = in->startOfFrameDummyLine; - cmd.eofDummy = in->endOfFrameDummyLine; - cmd.unicolorBarSelect = in->unicolorBarSelect; - cmd.unicolorBarEnable = in->unicolorBarEnable; - cmd.splitEnable = in->colorBarsSplitEnable; - cmd.pixelPattern = (uint32_t)in->colorBarsPixelPattern; - cmd.rotatePeriod = in->colorBarsRotatePeriod; - cmd.randomSeed = in->testGenRandomSeed; - - vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG, - (uint32_t *) &cmd, sizeof(cmd)); -} - -void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in) -{ - struct VFE_FRAME_SKIP_UpdateCmdType cmd; - - cmd.yPattern = in->output1Pattern; - cmd.cbcrPattern = in->output1Pattern; - vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd.yPattern = in->output2Pattern; - cmd.cbcrPattern = in->output2Pattern; - vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in) -{ - struct vfe_frame_skip_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeFrameSkip = *in; - - cmd.output2YPeriod = in->output2Period; - cmd.output2CbCrPeriod = in->output2Period; - cmd.output2YPattern = in->output2Pattern; - cmd.output2CbCrPattern = in->output2Pattern; - cmd.output1YPeriod = in->output1Period; - cmd.output1CbCrPeriod = in->output1Period; - cmd.output1YPattern = in->output1Pattern; - cmd.output1CbCrPattern = in->output1Pattern; - - vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in) -{ - struct vfe_output_clamp_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - cmd.yChanMax = in->maxCh0; - cmd.cbChanMax = in->maxCh1; - cmd.crChanMax = in->maxCh2; - - cmd.yChanMin = in->minCh0; - cmd.cbChanMin = in->minCh1; - cmd.crChanMin = in->minCh2; - - vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd, - sizeof(cmd)); -} - -void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in) -{ - struct vfe_camifframe_update cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.pixelsPerLine = in->pixelsPerLine; - cmd.linesPerFrame = in->linesPerFrame; - - vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd, - sizeof(cmd)); -} - -void vfe_color_correction_config( - struct vfe_cmd_color_correction_config *in) -{ - struct vfe_color_correction_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable; - - cmd.c0 = in->C0; - cmd.c1 = in->C1; - cmd.c2 = in->C2; - cmd.c3 = in->C3; - cmd.c4 = in->C4; - cmd.c5 = in->C5; - cmd.c6 = in->C6; - cmd.c7 = in->C7; - cmd.c8 = in->C8; - - cmd.k0 = in->K0; - cmd.k1 = in->K1; - cmd.k2 = in->K2; - - cmd.coefQFactor = in->coefQFactor; - - vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in) -{ -struct vfe_demosaic_cfg cmd; - struct vfe_demosaic_abf_cfg cmdabf; - uint32_t temp; - - memset(&cmd, 0, sizeof(cmd)); - temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG); - - cmd = *((struct vfe_demosaic_cfg *)(&temp)); - cmd.abfEnable = in->abfUpdate.enable; - cmd.forceAbfOn = in->abfUpdate.forceOn; - cmd.abfShift = in->abfUpdate.shift; - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmdabf.lpThreshold = in->abfUpdate.lpThreshold; - cmdabf.ratio = in->abfUpdate.ratio; - cmdabf.minValue = in->abfUpdate.min; - cmdabf.maxValue = in->abfUpdate.max; - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0, - (uint32_t *)&cmdabf, sizeof(cmdabf)); -} - -void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in) -{ - struct vfe_demosaic_cfg cmd; - struct vfe_demosaic_bpc_cfg cmdbpc; - uint32_t temp; - - memset(&cmd, 0, sizeof(cmd)); - - temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG); - - cmd = *((struct vfe_demosaic_cfg *)(&temp)); - cmd.badPixelCorrEnable = in->bpcUpdate.enable; - cmd.fminThreshold = in->bpcUpdate.fminThreshold; - cmd.fmaxThreshold = in->bpcUpdate.fmaxThreshold; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmdbpc.blueDiffThreshold = in->bpcUpdate.blueDiffThreshold; - cmdbpc.redDiffThreshold = in->bpcUpdate.redDiffThreshold; - cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0, - (uint32_t *)&cmdbpc, sizeof(cmdbpc)); -} - -void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in) -{ - struct vfe_demosaic_cfg cmd; - struct vfe_demosaic_bpc_cfg cmd_bpc; - struct vfe_demosaic_abf_cfg cmd_abf; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd_bpc, 0, sizeof(cmd_bpc)); - memset(&cmd_abf, 0, sizeof(cmd_abf)); - - ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable; - - cmd.abfEnable = in->abfConfig.enable; - cmd.badPixelCorrEnable = in->bpcConfig.enable; - cmd.forceAbfOn = in->abfConfig.forceOn; - cmd.abfShift = in->abfConfig.shift; - cmd.fminThreshold = in->bpcConfig.fminThreshold; - cmd.fmaxThreshold = in->bpcConfig.fmaxThreshold; - cmd.slopeShift = in->slopeShift; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd_abf.lpThreshold = in->abfConfig.lpThreshold; - cmd_abf.ratio = in->abfConfig.ratio; - cmd_abf.minValue = in->abfConfig.min; - cmd_abf.maxValue = in->abfConfig.max; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0, - (uint32_t *)&cmd_abf, sizeof(cmd_abf)); - - cmd_bpc.blueDiffThreshold = in->bpcConfig.blueDiffThreshold; - cmd_bpc.redDiffThreshold = in->bpcConfig.redDiffThreshold; - cmd_bpc.greenDiffThreshold = in->bpcConfig.greenDiffThreshold; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0, - (uint32_t *)&cmd_bpc, sizeof(cmd_bpc)); -} - -void vfe_demux_channel_gain_update( - struct vfe_cmd_demux_channel_gain_config *in) -{ - struct vfe_demux_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.ch0EvenGain = in->ch0EvenGain; - cmd.ch0OddGain = in->ch0OddGain; - cmd.ch1Gain = in->ch1Gain; - cmd.ch2Gain = in->ch2Gain; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_demux_channel_gain_config( - struct vfe_cmd_demux_channel_gain_config *in) -{ - struct vfe_demux_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.ch0EvenGain = in->ch0EvenGain; - cmd.ch0OddGain = in->ch0OddGain; - cmd.ch1Gain = in->ch1Gain; - cmd.ch2Gain = in->ch2Gain; - - vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_black_level_update(struct vfe_cmd_black_level_config *in) -{ - struct vfe_blacklevel_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable; - - cmd.evenEvenAdjustment = in->evenEvenAdjustment; - cmd.evenOddAdjustment = in->evenOddAdjustment; - cmd.oddEvenAdjustment = in->oddEvenAdjustment; - cmd.oddOddAdjustment = in->oddOddAdjustment; - - vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_black_level_config(struct vfe_cmd_black_level_config *in) -{ - struct vfe_blacklevel_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable; - - cmd.evenEvenAdjustment = in->evenEvenAdjustment; - cmd.evenOddAdjustment = in->evenOddAdjustment; - cmd.oddEvenAdjustment = in->oddEvenAdjustment; - cmd.oddOddAdjustment = in->oddOddAdjustment; - - vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_asf_update(struct vfe_cmd_asf_update *in) -{ - struct vfe_asf_update cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.asfEnable = in->enable; - - cmd.smoothEnable = in->smoothFilterEnabled; - cmd.sharpMode = in->sharpMode; - cmd.smoothCoeff1 = in->smoothCoefCenter; - cmd.smoothCoeff0 = in->smoothCoefSurr; - cmd.cropEnable = in->cropEnable; - cmd.sharpThresholdE1 = in->sharpThreshE1; - cmd.sharpDegreeK1 = in->sharpK1; - cmd.sharpDegreeK2 = in->sharpK2; - cmd.normalizeFactor = in->normalizeFactor; - cmd.sharpThresholdE2 = in->sharpThreshE2; - cmd.sharpThresholdE3 = in->sharpThreshE3; - cmd.sharpThresholdE4 = in->sharpThreshE4; - cmd.sharpThresholdE5 = in->sharpThreshE5; - cmd.F1Coeff0 = in->filter1Coefficients[0]; - cmd.F1Coeff1 = in->filter1Coefficients[1]; - cmd.F1Coeff2 = in->filter1Coefficients[2]; - cmd.F1Coeff3 = in->filter1Coefficients[3]; - cmd.F1Coeff4 = in->filter1Coefficients[4]; - cmd.F1Coeff5 = in->filter1Coefficients[5]; - cmd.F1Coeff6 = in->filter1Coefficients[6]; - cmd.F1Coeff7 = in->filter1Coefficients[7]; - cmd.F1Coeff8 = in->filter1Coefficients[8]; - cmd.F2Coeff0 = in->filter2Coefficients[0]; - cmd.F2Coeff1 = in->filter2Coefficients[1]; - cmd.F2Coeff2 = in->filter2Coefficients[2]; - cmd.F2Coeff3 = in->filter2Coefficients[3]; - cmd.F2Coeff4 = in->filter2Coefficients[4]; - cmd.F2Coeff5 = in->filter2Coefficients[5]; - cmd.F2Coeff6 = in->filter2Coefficients[6]; - cmd.F2Coeff7 = in->filter2Coefficients[7]; - cmd.F2Coeff8 = in->filter2Coefficients[8]; - - vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_asf_config(struct vfe_cmd_asf_config *in) -{ - struct vfe_asf_update cmd; - struct vfe_asfcrop_cfg cmd2; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd2, 0, sizeof(cmd2)); - - ctrl->vfeModuleEnableLocal.asfEnable = in->enable; - - cmd.smoothEnable = in->smoothFilterEnabled; - cmd.sharpMode = in->sharpMode; - cmd.smoothCoeff0 = in->smoothCoefCenter; - cmd.smoothCoeff1 = in->smoothCoefSurr; - cmd.cropEnable = in->cropEnable; - cmd.sharpThresholdE1 = in->sharpThreshE1; - cmd.sharpDegreeK1 = in->sharpK1; - cmd.sharpDegreeK2 = in->sharpK2; - cmd.normalizeFactor = in->normalizeFactor; - cmd.sharpThresholdE2 = in->sharpThreshE2; - cmd.sharpThresholdE3 = in->sharpThreshE3; - cmd.sharpThresholdE4 = in->sharpThreshE4; - cmd.sharpThresholdE5 = in->sharpThreshE5; - cmd.F1Coeff0 = in->filter1Coefficients[0]; - cmd.F1Coeff1 = in->filter1Coefficients[1]; - cmd.F1Coeff2 = in->filter1Coefficients[2]; - cmd.F1Coeff3 = in->filter1Coefficients[3]; - cmd.F1Coeff4 = in->filter1Coefficients[4]; - cmd.F1Coeff5 = in->filter1Coefficients[5]; - cmd.F1Coeff6 = in->filter1Coefficients[6]; - cmd.F1Coeff7 = in->filter1Coefficients[7]; - cmd.F1Coeff8 = in->filter1Coefficients[8]; - cmd.F2Coeff0 = in->filter2Coefficients[0]; - cmd.F2Coeff1 = in->filter2Coefficients[1]; - cmd.F2Coeff2 = in->filter2Coefficients[2]; - cmd.F2Coeff3 = in->filter2Coefficients[3]; - cmd.F2Coeff4 = in->filter2Coefficients[4]; - cmd.F2Coeff5 = in->filter2Coefficients[5]; - cmd.F2Coeff6 = in->filter2Coefficients[6]; - cmd.F2Coeff7 = in->filter2Coefficients[7]; - cmd.F2Coeff8 = in->filter2Coefficients[8]; - - vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd2.firstLine = in->cropFirstLine; - cmd2.lastLine = in->cropLastLine; - cmd2.firstPixel = in->cropFirstPixel; - cmd2.lastPixel = in->cropLastPixel; - - vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG, - (uint32_t *)&cmd2, sizeof(cmd2)); -} - -void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in) -{ - struct vfe_wb_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.whiteBalanceEnable = - in->enable; - - cmd.ch0Gain = in->ch0Gain; - cmd.ch1Gain = in->ch1Gain; - cmd.ch2Gain = in->ch2Gain; - - vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in) -{ - struct vfe_chroma_suppress_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable; - - cmd.m1 = in->m1; - cmd.m3 = in->m3; - cmd.n1 = in->n1; - cmd.n3 = in->n3; - cmd.mm1 = in->mm1; - cmd.nn1 = in->nn1; - - vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in) -{ - struct vfe_rolloff_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable; - - cmd.gridWidth = in->gridWidth; - cmd.gridHeight = in->gridHeight; - cmd.yDelta = in->yDelta; - cmd.gridX = in->gridXIndex; - cmd.gridY = in->gridYIndex; - cmd.pixelX = in->gridPixelXIndex; - cmd.pixelY = in->gridPixelYIndex; - cmd.yDeltaAccum = in->yDeltaAccum; - - vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0, - (uint32_t *)&cmd, sizeof(cmd)); - - vfe_write_lens_roll_off_table(in); -} - -void vfe_chroma_subsample_config( - struct vfe_cmd_chroma_subsample_config *in) -{ - struct vfe_chromasubsample_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable; - - cmd.hCositedPhase = in->hCositedPhase; - cmd.vCositedPhase = in->vCositedPhase; - cmd.hCosited = in->hCosited; - cmd.vCosited = in->vCosited; - cmd.hsubSampleEnable = in->hsubSampleEnable; - cmd.vsubSampleEnable = in->vsubSampleEnable; - cmd.cropEnable = in->cropEnable; - cmd.cropWidthLastPixel = in->cropWidthLastPixel; - cmd.cropWidthFirstPixel = in->cropWidthFirstPixel; - cmd.cropHeightLastLine = in->cropHeightLastLine; - cmd.cropHeightFirstLine = in->cropHeightFirstLine; - - vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in) -{ - struct vfe_chroma_enhance_cfg cmd; - struct vfe_color_convert_cfg cmd2; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd2, 0, sizeof(cmd2)); - - ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable; - - cmd.ap = in->ap; - cmd.am = in->am; - cmd.bp = in->bp; - cmd.bm = in->bm; - cmd.cp = in->cp; - cmd.cm = in->cm; - cmd.dp = in->dp; - cmd.dm = in->dm; - cmd.kcb = in->kcb; - cmd.kcr = in->kcr; - - cmd2.v0 = in->RGBtoYConversionV0; - cmd2.v1 = in->RGBtoYConversionV1; - cmd2.v2 = in->RGBtoYConversionV2; - cmd2.ConvertOffset = in->RGBtoYConversionOffset; - - vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A, - (uint32_t *)&cmd, sizeof(cmd)); - - vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0, - (uint32_t *)&cmd2, sizeof(cmd2)); -} - -void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in) -{ - struct vfe_scaler2_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable; - - cmd.hEnable = in->hconfig.enable; - cmd.vEnable = in->vconfig.enable; - cmd.inWidth = in->hconfig.inputSize; - cmd.outWidth = in->hconfig.outputSize; - cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; - cmd.horizInterResolution = in->hconfig.interpolationResolution; - cmd.inHeight = in->vconfig.inputSize; - cmd.outHeight = in->vconfig.outputSize; - cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; - cmd.vertInterResolution = in->vconfig.interpolationResolution; - - vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in) -{ - struct vfe_scaler2_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable; - - cmd.hEnable = in->hconfig.enable; - cmd.vEnable = in->vconfig.enable; - cmd.inWidth = in->hconfig.inputSize; - cmd.outWidth = in->hconfig.outputSize; - cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; - cmd.horizInterResolution = in->hconfig.interpolationResolution; - cmd.inHeight = in->vconfig.inputSize; - cmd.outHeight = in->vconfig.outputSize; - cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; - cmd.vertInterResolution = in->vconfig.interpolationResolution; - - vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in) -{ - struct vfe_main_scaler_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable; - - cmd.hEnable = in->hconfig.enable; - cmd.vEnable = in->vconfig.enable; - cmd.inWidth = in->hconfig.inputSize; - cmd.outWidth = in->hconfig.outputSize; - cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor; - cmd.horizInterResolution = in->hconfig.interpolationResolution; - cmd.horizMNInit = in->MNInitH.MNCounterInit; - cmd.horizPhaseInit = in->MNInitH.phaseInit; - cmd.inHeight = in->vconfig.inputSize; - cmd.outHeight = in->vconfig.outputSize; - cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor; - cmd.vertInterResolution = in->vconfig.interpolationResolution; - cmd.vertMNInit = in->MNInitV.MNCounterInit; - cmd.vertPhaseInit = in->MNInitV.phaseInit; - - vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_stats_wb_exp_stop(void) -{ - ctrl->vfeStatsCmdLocal.axwEnable = FALSE; - ctrl->vfeImaskLocal.awbPingpongIrq = FALSE; -} - -void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in) -{ - struct vfe_statsawb_update cmd; - struct vfe_statsawbae_update cmd2; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd2, 0, sizeof(cmd2)); - - cmd.m1 = in->awbMCFG[0]; - cmd.m2 = in->awbMCFG[1]; - cmd.m3 = in->awbMCFG[2]; - cmd.m4 = in->awbMCFG[3]; - cmd.c1 = in->awbCCFG[0]; - cmd.c2 = in->awbCCFG[1]; - cmd.c3 = in->awbCCFG[2]; - cmd.c4 = in->awbCCFG[3]; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd2.aeRegionCfg = in->wbExpRegions; - cmd2.aeSubregionCfg = in->wbExpSubRegion; - cmd2.awbYMin = in->awbYMin; - cmd2.awbYMax = in->awbYMax; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG, - (uint32_t *)&cmd2, sizeof(cmd2)); -} - -void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in) -{ - struct vfe_statsaf_update cmd; - memset(&cmd, 0, sizeof(cmd)); - - cmd.windowVOffset = in->windowVOffset; - cmd.windowHOffset = in->windowHOffset; - cmd.windowMode = in->windowMode; - cmd.windowHeight = in->windowHeight; - cmd.windowWidth = in->windowWidth; - - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in) -{ - struct vfe_statsawb_update cmd; - struct vfe_statsawbae_update cmd2; - struct vfe_statsaxw_hdr_cfg cmd3; - - ctrl->vfeStatsCmdLocal.axwEnable = in->enable; - ctrl->vfeImaskLocal.awbPingpongIrq = TRUE; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd2, 0, sizeof(cmd2)); - memset(&cmd3, 0, sizeof(cmd3)); - - cmd.m1 = in->awbMCFG[0]; - cmd.m2 = in->awbMCFG[1]; - cmd.m3 = in->awbMCFG[2]; - cmd.m4 = in->awbMCFG[3]; - cmd.c1 = in->awbCCFG[0]; - cmd.c2 = in->awbCCFG[1]; - cmd.c3 = in->awbCCFG[2]; - cmd.c4 = in->awbCCFG[3]; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd2.aeRegionCfg = in->wbExpRegions; - cmd2.aeSubregionCfg = in->wbExpSubRegion; - cmd2.awbYMin = in->awbYMin; - cmd2.awbYMax = in->awbYMax; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG, - (uint32_t *)&cmd2, sizeof(cmd2)); - - cmd3.axwHeader = in->axwHeader; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER, - (uint32_t *)&cmd3, sizeof(cmd3)); -} - -void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in) -{ - struct vfe_statsaf_update cmd; - struct vfe_statsaf_cfg cmd2; - - memset(&cmd, 0, sizeof(cmd)); - memset(&cmd2, 0, sizeof(cmd2)); - -ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable; -ctrl->vfeImaskLocal.afPingpongIrq = TRUE; - - cmd.windowVOffset = in->windowVOffset; - cmd.windowHOffset = in->windowHOffset; - cmd.windowMode = in->windowMode; - cmd.windowHeight = in->windowHeight; - cmd.windowWidth = in->windowWidth; - - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG, - (uint32_t *)&cmd, sizeof(cmd)); - - cmd2.a00 = in->highPassCoef[0]; - cmd2.a04 = in->highPassCoef[1]; - cmd2.a20 = in->highPassCoef[2]; - cmd2.a21 = in->highPassCoef[3]; - cmd2.a22 = in->highPassCoef[4]; - cmd2.a23 = in->highPassCoef[5]; - cmd2.a24 = in->highPassCoef[6]; - cmd2.fvMax = in->metricMax; - cmd2.fvMetric = in->metricSelection; - cmd2.afHeader = in->bufferHeader; - cmd2.entry00 = in->gridForMultiWindows[0]; - cmd2.entry01 = in->gridForMultiWindows[1]; - cmd2.entry02 = in->gridForMultiWindows[2]; - cmd2.entry03 = in->gridForMultiWindows[3]; - cmd2.entry10 = in->gridForMultiWindows[4]; - cmd2.entry11 = in->gridForMultiWindows[5]; - cmd2.entry12 = in->gridForMultiWindows[6]; - cmd2.entry13 = in->gridForMultiWindows[7]; - cmd2.entry20 = in->gridForMultiWindows[8]; - cmd2.entry21 = in->gridForMultiWindows[9]; - cmd2.entry22 = in->gridForMultiWindows[10]; - cmd2.entry23 = in->gridForMultiWindows[11]; - cmd2.entry30 = in->gridForMultiWindows[12]; - cmd2.entry31 = in->gridForMultiWindows[13]; - cmd2.entry32 = in->gridForMultiWindows[14]; - cmd2.entry33 = in->gridForMultiWindows[15]; - - vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0, - (uint32_t *)&cmd2, sizeof(cmd2)); -} - -void vfe_stats_setting(struct vfe_cmd_stats_setting *in) -{ - struct vfe_statsframe cmd1; - struct vfe_busstats_wrprio cmd2; - - memset(&cmd1, 0, sizeof(cmd1)); - memset(&cmd2, 0, sizeof(cmd2)); - - ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0]; - ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1]; - ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2]; - - ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0]; - ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1]; - ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2]; - - cmd1.lastPixel = in->frameHDimension; - cmd1.lastLine = in->frameVDimension; - vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE, - (uint32_t *)&cmd1, sizeof(cmd1)); - - cmd2.afBusPriority = in->afBusPriority; - cmd2.awbBusPriority = in->awbBusPriority; - cmd2.histBusPriority = in->histBusPriority; - cmd2.afBusPriorityEn = in->afBusPrioritySelection; - cmd2.awbBusPriorityEn = in->awbBusPrioritySelection; - cmd2.histBusPriorityEn = in->histBusPrioritySelection; - - vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY, - (uint32_t *)&cmd2, sizeof(cmd2)); - - /* Program the bus ping pong address for statistics modules. */ - writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR); - writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR); - writel(in->awbBuffer[0], - ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR); - writel(in->awbBuffer[1], - ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR); - writel(in->histBuffer[0], - ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR); - writel(in->histBuffer[1], - ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR); -} - -void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in) -{ - struct VFE_AxiInputCmdType cmd; - uint32_t xSizeWord, axiRdUnpackPattern; - uint8_t axiInputPpw; - uint32_t busPingpongRdIrqEnable; - - ctrl->vfeImaskLocal.rdPingpongIrq = TRUE; - - switch (in->pixelSize) { - case VFE_RAW_PIXEL_DATA_SIZE_10BIT: - ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_12BIT: - ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_8BIT: - default: - ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT; - break; - } - - memset(&cmd, 0, sizeof(cmd)); - - switch (in->pixelSize) { - case VFE_RAW_PIXEL_DATA_SIZE_10BIT: - axiInputPpw = 6; - axiRdUnpackPattern = 0xD43210; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_12BIT: - axiInputPpw = 5; - axiRdUnpackPattern = 0xC3210; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_8BIT: - default: - axiInputPpw = 8; - axiRdUnpackPattern = 0xF6543210; - break; - } - - xSizeWord = - ((((in->xOffset % axiInputPpw) + in->xSize) + - (axiInputPpw-1)) / axiInputPpw) - 1; - - cmd.stripeStartAddr0 = in->fragAddr[0]; - cmd.stripeStartAddr1 = in->fragAddr[1]; - cmd.stripeStartAddr2 = in->fragAddr[2]; - cmd.stripeStartAddr3 = in->fragAddr[3]; - cmd.ySize = in->ySize; - cmd.yOffsetDelta = 0; - cmd.xSizeWord = xSizeWord; - cmd.burstLength = 1; - cmd.NumOfRows = in->numOfRows; - cmd.RowIncrement = - (in->rowIncrement + (axiInputPpw-1))/axiInputPpw; - cmd.mainUnpackHeight = in->ySize; - cmd.mainUnpackWidth = in->xSize - 1; - cmd.mainUnpackHbiSel = (uint32_t)in->unpackHbi; - cmd.mainUnpackPhase = in->unpackPhase; - cmd.unpackPattern = axiRdUnpackPattern; - cmd.padLeft = in->padRepeatCountLeft; - cmd.padRight = in->padRepeatCountRight; - cmd.padTop = in->padRepeatCountTop; - cmd.padBottom = in->padRepeatCountBottom; - cmd.leftUnpackPattern0 = in->padLeftComponentSelectCycle0; - cmd.leftUnpackPattern1 = in->padLeftComponentSelectCycle1; - cmd.leftUnpackPattern2 = in->padLeftComponentSelectCycle2; - cmd.leftUnpackPattern3 = in->padLeftComponentSelectCycle3; - cmd.leftUnpackStop0 = in->padLeftStopCycle0; - cmd.leftUnpackStop1 = in->padLeftStopCycle1; - cmd.leftUnpackStop2 = in->padLeftStopCycle2; - cmd.leftUnpackStop3 = in->padLeftStopCycle3; - cmd.rightUnpackPattern0 = in->padRightComponentSelectCycle0; - cmd.rightUnpackPattern1 = in->padRightComponentSelectCycle1; - cmd.rightUnpackPattern2 = in->padRightComponentSelectCycle2; - cmd.rightUnpackPattern3 = in->padRightComponentSelectCycle3; - cmd.rightUnpackStop0 = in->padRightStopCycle0; - cmd.rightUnpackStop1 = in->padRightStopCycle1; - cmd.rightUnpackStop2 = in->padRightStopCycle2; - cmd.rightUnpackStop3 = in->padRightStopCycle3; - cmd.topUnapckPattern = in->padTopLineCount; - cmd.bottomUnapckPattern = in->padBottomLineCount; - - /* program vfe_bus_cfg */ - vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0, - (uint32_t *)&cmd, sizeof(cmd)); - - /* hacking code, put it to default value */ - busPingpongRdIrqEnable = 0xf; - - writel(busPingpongRdIrqEnable, - ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN); -} - -void vfe_stats_config(struct vfe_cmd_stats_setting *in) -{ - ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0]; - ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1]; - ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2]; - - ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0]; - ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1]; - ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2]; - - vfe_stats_setting(in); -} - -void vfe_axi_output_config( - struct vfe_cmd_axi_output_config *in) -{ - /* local variable */ - uint32_t *pcircle; - uint32_t *pdest; - uint32_t *psrc; - uint8_t i; - uint8_t fcnt; - uint16_t axioutpw = 8; - - /* parameters check, condition and usage mode check */ - ctrl->encPath.fragCount = in->output2.fragmentCount; - if (ctrl->encPath.fragCount > 1) - ctrl->encPath.multiFrag = TRUE; - - ctrl->viewPath.fragCount = in->output1.fragmentCount; - if (ctrl->viewPath.fragCount > 1) - ctrl->viewPath.multiFrag = TRUE; - - /* VFE_BUS_CFG. raw data size */ - ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize; - - switch (in->outputDataSize) { - case VFE_RAW_PIXEL_DATA_SIZE_8BIT: - axioutpw = 8; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_10BIT: - axioutpw = 6; - break; - - case VFE_RAW_PIXEL_DATA_SIZE_12BIT: - axioutpw = 5; - break; - } - - ctrl->axiOutputMode = in->outputMode; - - CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode); - - switch (ctrl->axiOutputMode) { - case VFE_AXI_OUTPUT_MODE_Output1: { - ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_DISABLED; - - ctrl->encPath.pathEnabled = FALSE; - ctrl->vfeImaskLocal.encIrq = FALSE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = FALSE; - ctrl->viewPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.viewIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_Output1 */ - break; - - case VFE_AXI_OUTPUT_MODE_Output2: { - ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_DISABLED; - - ctrl->encPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.encIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; - - ctrl->viewPath.pathEnabled = FALSE; - ctrl->vfeImaskLocal.viewIrq = FALSE; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_Output2 */ - break; - - case VFE_AXI_OUTPUT_MODE_Output1AndOutput2: { - ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_DISABLED; - - ctrl->encPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.encIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; - ctrl->viewPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.viewIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */ - break; - - case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2: { - /* For raw snapshot, we need both ping and pong buffer - * initialized to the same address. Otherwise, if we - * leave the pong buffer to NULL, there will be axi_error. - * Note that ideally we should deal with this at upper layer, - * which is in msm_vfe8x.c */ - if (!in->output2.outputCbcr.outFragments[1][0]) { - in->output2.outputCbcr.outFragments[1][0] = - in->output2.outputCbcr.outFragments[0][0]; - } - - ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_ENC_CBCR_PATH; - - ctrl->encPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.encIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_CBCR_ONLY; - - ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; - - ctrl->viewPath.pathEnabled = FALSE; - ctrl->vfeImaskLocal.viewIrq = FALSE; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */ - break; - - case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1: { - ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_VIEW_CBCR_PATH; - - ctrl->encPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.encIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; - - ctrl->viewPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.viewIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_CBCR_ONLY; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */ - break; - - case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2: { - ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE; - ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE; - ctrl->vfeBusConfigLocal.rawWritePathSelect = - VFE_RAW_OUTPUT_ENC_CBCR_PATH; - - ctrl->encPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.encIrq = TRUE; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_CBCR_ONLY; - - ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE; - ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE; - - ctrl->viewPath.pathEnabled = TRUE; - ctrl->vfeImaskLocal.viewIrq = TRUE; - - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE; - ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE; - - if (ctrl->vfeBusConfigLocal.encYWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn && - ctrl->encPath.multiFrag) - ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewYWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE; - - if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn && - ctrl->viewPath.multiFrag) - ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE; - } /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */ - break; - - case VFE_AXI_LAST_OUTPUT_MODE_ENUM: - break; - } /* switch */ - - /* Save the addresses for each path. */ - /* output2 path */ - fcnt = ctrl->encPath.fragCount; - - pcircle = ctrl->encPath.yPath.addressBuffer; - pdest = ctrl->encPath.nextFrameAddrBuf; - - psrc = &(in->output2.outputY.outFragments[0][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output2.outputY.outFragments[1][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output2.outputY.outFragments[2][0]); - for (i = 0; i < fcnt; i++) - *pdest++ = *psrc++; - - pcircle = ctrl->encPath.cbcrPath.addressBuffer; - - psrc = &(in->output2.outputCbcr.outFragments[0][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output2.outputCbcr.outFragments[1][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output2.outputCbcr.outFragments[2][0]); - for (i = 0; i < fcnt; i++) - *pdest++ = *psrc++; - - vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath); - - ctrl->encPath.ackPending = FALSE; - ctrl->encPath.currentFrame = ping; - ctrl->encPath.whichOutputPath = 1; - ctrl->encPath.yPath.fragIndex = 2; - ctrl->encPath.cbcrPath.fragIndex = 2; - ctrl->encPath.yPath.hwCurrentFlag = ping; - ctrl->encPath.cbcrPath.hwCurrentFlag = ping; - - /* output1 path */ - pcircle = ctrl->viewPath.yPath.addressBuffer; - pdest = ctrl->viewPath.nextFrameAddrBuf; - fcnt = ctrl->viewPath.fragCount; - - psrc = &(in->output1.outputY.outFragments[0][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output1.outputY.outFragments[1][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output1.outputY.outFragments[2][0]); - for (i = 0; i < fcnt; i++) - *pdest++ = *psrc++; - - pcircle = ctrl->viewPath.cbcrPath.addressBuffer; - - psrc = &(in->output1.outputCbcr.outFragments[0][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output1.outputCbcr.outFragments[1][0]); - for (i = 0; i < fcnt; i++) - *pcircle++ = *psrc++; - - psrc = &(in->output1.outputCbcr.outFragments[2][0]); - for (i = 0; i < fcnt; i++) - *pdest++ = *psrc++; - - ctrl->viewPath.ackPending = FALSE; - ctrl->viewPath.currentFrame = ping; - ctrl->viewPath.whichOutputPath = 0; - ctrl->viewPath.yPath.fragIndex = 2; - ctrl->viewPath.cbcrPath.fragIndex = 2; - ctrl->viewPath.yPath.hwCurrentFlag = ping; - ctrl->viewPath.cbcrPath.hwCurrentFlag = ping; - - /* call to program the registers. */ - vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw); -} - -void vfe_camif_config(struct vfe_cmd_camif_config *in) -{ - struct vfe_camifcfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine); - CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame); - CDBG("camif.window firstpixel = %d\n", in->window.firstpixel); - CDBG("camif.window lastpixel = %d\n", in->window.lastpixel); - CDBG("camif.window firstline = %d\n", in->window.firstline); - CDBG("camif.window lastline = %d\n", in->window.lastline); - - /* determine if epoch interrupt needs to be enabled. */ - if ((in->epoch1.enable == TRUE) && - (in->epoch1.lineindex <= - in->frame.linesPerFrame)) - ctrl->vfeImaskLocal.camifEpoch1Irq = 1; - - if ((in->epoch2.enable == TRUE) && - (in->epoch2.lineindex <= - in->frame.linesPerFrame)) { - ctrl->vfeImaskLocal.camifEpoch2Irq = 1; - } - - /* save the content to program CAMIF_CONFIG separately. */ - ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig; - - /* EFS_Config */ - cmd.efsEndOfLine = in->EFS.efsendofline; - cmd.efsStartOfLine = in->EFS.efsstartofline; - cmd.efsEndOfFrame = in->EFS.efsendofframe; - cmd.efsStartOfFrame = in->EFS.efsstartofframe; - - /* Frame Config */ - cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine; - cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame; - - /* Window Width Config */ - cmd.windowWidthCfgLastPixel = in->window.lastpixel; - cmd.windowWidthCfgFirstPixel = in->window.firstpixel; - - /* Window Height Config */ - cmd.windowHeightCfglastLine = in->window.lastline; - cmd.windowHeightCfgfirstLine = in->window.firstline; - - /* Subsample 1 Config */ - cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask; - cmd.subsample1CfgLineSkip = in->subsample.lineskipmask; - - /* Subsample 2 Config */ - cmd.subsample2CfgFrameSkip = in->subsample.frameskip; - cmd.subsample2CfgFrameSkipMode = in->subsample.frameskipmode; - cmd.subsample2CfgPixelSkipWrap = in->subsample.pixelskipwrap; - - /* Epoch Interrupt */ - cmd.epoch1Line = in->epoch1.lineindex; - cmd.epoch2Line = in->epoch2.lineindex; - - vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in) -{ - struct vfe_fov_crop_cfg cmd; - memset(&cmd, 0, sizeof(cmd)); - - ctrl->vfeModuleEnableLocal.cropEnable = in->enable; - - /* FOV Corp, Part 1 */ - cmd.lastPixel = in->lastPixel; - cmd.firstPixel = in->firstPixel; - - /* FOV Corp, Part 2 */ - cmd.lastLine = in->lastLine; - cmd.firstLine = in->firstLine; - - vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG, - (uint32_t *)&cmd, sizeof(cmd)); -} - -void vfe_get_hw_version(struct vfe_cmd_hw_version *out) -{ - uint32_t vfeHwVersionPacked; - struct vfe_hw_ver ver; - - vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION); - - ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked); - - out->coreVersion = ver.coreVersion; - out->minorVersion = ver.minorVersion; - out->majorVersion = ver.majorVersion; -} - -static void vfe_reset_internal_variables(void) -{ - unsigned long flags; - - /* local variables to program the hardware. */ - ctrl->vfeImaskPacked = 0; - ctrl->vfeImaskCompositePacked = 0; - - /* FALSE = disable, 1 = enable. */ - memset(&ctrl->vfeModuleEnableLocal, 0, - sizeof(ctrl->vfeModuleEnableLocal)); - - /* 0 = disable, 1 = enable */ - memset(&ctrl->vfeCamifConfigLocal, 0, - sizeof(ctrl->vfeCamifConfigLocal)); - /* 0 = disable, 1 = enable */ - memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal)); - memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal)); - memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal)); - memset(&ctrl->vfeBusPmConfigLocal, 0, - sizeof(ctrl->vfeBusPmConfigLocal)); - memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal)); - memset(&ctrl->vfeInterruptNameLocal, 0, - sizeof(ctrl->vfeInterruptNameLocal)); - memset(&ctrl->vfeDroppedFrameCounts, 0, - sizeof(ctrl->vfeDroppedFrameCounts)); - memset(&ctrl->vfeIrqThreadMsgLocal, 0, - sizeof(ctrl->vfeIrqThreadMsgLocal)); - - /* state control variables */ - ctrl->vfeStartAckPendingFlag = FALSE; - ctrl->vfeStopAckPending = FALSE; - ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0; - ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask = - VFE_COMP_IRQ_BOTH_Y_CBCR; - - spin_lock_irqsave(&ctrl->state_lock, flags); - ctrl->vstate = VFE_STATE_IDLE; - spin_unlock_irqrestore(&ctrl->state_lock, flags); - - ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM; - /* 0 for continuous mode, 1 for snapshot mode */ - ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS; - ctrl->vfeSnapShotCount = 0; - ctrl->vfeStatsPingPongReloadFlag = FALSE; - /* this is unsigned 32 bit integer. */ - ctrl->vfeFrameId = 0; - ctrl->vfeFrameSkip.output1Pattern = 0xffffffff; - ctrl->vfeFrameSkip.output1Period = 31; - ctrl->vfeFrameSkip.output2Pattern = 0xffffffff; - ctrl->vfeFrameSkip.output2Period = 31; - ctrl->vfeFrameSkipPattern = 0xffffffff; - ctrl->vfeFrameSkipCount = 0; - ctrl->vfeFrameSkipPeriod = 31; - - memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath)); - memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath)); - - ctrl->encPath.whichOutputPath = 1; - ctrl->encPath.cbcrStatusBit = 5; - ctrl->viewPath.whichOutputPath = 0; - ctrl->viewPath.cbcrStatusBit = 7; - - ctrl->vfeTestGenStartFlag = FALSE; - - /* default to bank 0. */ - ctrl->vfeLaBankSel = 0; - - /* default to bank 0 for all channels. */ - memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel)); - - /* Stats control variables. */ - memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl)); - memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl)); - vfe_set_stats_pingpong_address(&ctrl->afStatsControl, - &ctrl->awbStatsControl); -} - -void vfe_reset(void) -{ - vfe_reset_internal_variables(); - - ctrl->vfeImaskLocal.resetAckIrq = TRUE; - ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); - - /* disable all interrupts. */ - writel(VFE_DISABLE_ALL_IRQS, - ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK); - - /* clear all pending interrupts*/ - writel(VFE_CLEAR_ALL_IRQS, - ctrl->vfebase + VFE_IRQ_CLEAR); - - /* enable reset_ack interrupt. */ - writel(ctrl->vfeImaskPacked, - ctrl->vfebase + VFE_IRQ_MASK); - - writel(VFE_RESET_UPON_RESET_CMD, - ctrl->vfebase + VFE_GLOBAL_RESET_CMD); -} diff --git a/drivers/staging/dream/camera/msm_vfe8x_proc.h b/drivers/staging/dream/camera/msm_vfe8x_proc.h deleted file mode 100644 index 91828569a4d7..000000000000 --- a/drivers/staging/dream/camera/msm_vfe8x_proc.h +++ /dev/null @@ -1,1549 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#ifndef __MSM_VFE8X_REG_H__ -#define __MSM_VFE8X_REG_H__ - -#include <mach/msm_iomap.h> -#include <mach/camera.h> -#include "msm_vfe8x.h" - -/* at start of camif, bit 1:0 = 0x01:enable - * image data capture at frame boundary. */ -#define CAMIF_COMMAND_START 0x00000005 - -/* bit 2= 0x1:clear the CAMIF_STATUS register - * value. */ -#define CAMIF_COMMAND_CLEAR 0x00000004 - -/* at stop of vfe pipeline, for now it is assumed - * that camif will stop at any time. Bit 1:0 = 0x10: - * disable image data capture immediately. */ -#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002 - -/* at stop of vfe pipeline, for now it is assumed - * that camif will stop at any time. Bit 1:0 = 0x00: - * disable image data capture at frame boundary */ -#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000 - -/* to halt axi bridge */ -#define AXI_HALT 0x00000001 - -/* clear the halt bit. */ -#define AXI_HALT_CLEAR 0x00000000 - -/* reset the pipeline when stop command is issued. - * (without reset the register.) bit 26-31 = 0, - * domain reset, bit 0-9 = 1 for module reset, except - * register module. */ -#define VFE_RESET_UPON_STOP_CMD 0x000003ef - -/* reset the pipeline when reset command. - * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */ -#define VFE_RESET_UPON_RESET_CMD 0x000003ff - -/* bit 5 is for axi status idle or busy. - * 1 = halted, 0 = busy */ -#define AXI_STATUS_BUSY_MASK 0x00000020 - -/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present - * for frame done interrupt */ -#define VFE_COMP_IRQ_BOTH_Y_CBCR 3 - -/* bit 1 = 1, only cbcr irq triggers frame done interrupt */ -#define VFE_COMP_IRQ_CBCR_ONLY 2 - -/* bit 0 = 1, only y irq triggers frame done interrupt */ -#define VFE_COMP_IRQ_Y_ONLY 1 - -/* bit 0 = 1, PM go; bit1 = 1, PM stop */ -#define VFE_PERFORMANCE_MONITOR_GO 0x00000001 -#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002 - -/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */ -#define VFE_TEST_GEN_GO 0x00000001 -#define VFE_TEST_GEN_STOP 0x00000002 - -/* the chroma is assumed to be interpolated between - * the luma samples. JPEG 4:2:2 */ -#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0 - -/* constants for irq registers */ -#define VFE_DISABLE_ALL_IRQS 0 -/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */ -#define VFE_CLEAR_ALL_IRQS 0xffffffff -/* imask for while waiting for stop ack, driver has already - * requested stop, waiting for reset irq, - * bit 29,28,27,26 for async timer, bit 9 for reset */ -#define VFE_IMASK_WHILE_STOPPING 0x3c000200 - -/* when normal case, don't want to block error status. - * bit 0,6,20,21,22,30,31 */ -#define VFE_IMASK_ERROR_ONLY 0xC0700041 -#define VFE_REG_UPDATE_TRIGGER 1 -#define VFE_PM_BUF_MAX_CNT_MASK 0xFF -#define VFE_DMI_CFG_DEFAULT 0x00000100 -#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32 -#define VFE_AF_PINGPONG_STATUS_BIT 0x100 -#define VFE_AWB_PINGPONG_STATUS_BIT 0x200 - -/* VFE I/O registers */ -enum { - VFE_HW_VERSION = 0x00000000, - VFE_GLOBAL_RESET_CMD = 0x00000004, - VFE_MODULE_RESET = 0x00000008, - VFE_CGC_OVERRIDE = 0x0000000C, - VFE_MODULE_CFG = 0x00000010, - VFE_CFG = 0x00000014, - VFE_IRQ_MASK = 0x00000018, - VFE_IRQ_CLEAR = 0x0000001C, -VFE_IRQ_STATUS = 0x00000020, -VFE_IRQ_COMPOSITE_MASK = 0x00000024, -VFE_BUS_CMD = 0x00000028, -VFE_BUS_CFG = 0x0000002C, -VFE_BUS_ENC_Y_WR_PING_ADDR = 0x00000030, -VFE_BUS_ENC_Y_WR_PONG_ADDR = 0x00000034, -VFE_BUS_ENC_Y_WR_IMAGE_SIZE = 0x00000038, -VFE_BUS_ENC_Y_WR_BUFFER_CFG = 0x0000003C, -VFE_BUS_ENC_CBCR_WR_PING_ADDR = 0x00000040, -VFE_BUS_ENC_CBCR_WR_PONG_ADDR = 0x00000044, -VFE_BUS_ENC_CBCR_WR_IMAGE_SIZE = 0x00000048, -VFE_BUS_ENC_CBCR_WR_BUFFER_CFG = 0x0000004C, -VFE_BUS_VIEW_Y_WR_PING_ADDR = 0x00000050, -VFE_BUS_VIEW_Y_WR_PONG_ADDR = 0x00000054, -VFE_BUS_VIEW_Y_WR_IMAGE_SIZE = 0x00000058, -VFE_BUS_VIEW_Y_WR_BUFFER_CFG = 0x0000005C, -VFE_BUS_VIEW_CBCR_WR_PING_ADDR = 0x00000060, -VFE_BUS_VIEW_CBCR_WR_PONG_ADDR = 0x00000064, -VFE_BUS_VIEW_CBCR_WR_IMAGE_SIZE = 0x00000068, -VFE_BUS_VIEW_CBCR_WR_BUFFER_CFG = 0x0000006C, -VFE_BUS_STATS_AF_WR_PING_ADDR = 0x00000070, -VFE_BUS_STATS_AF_WR_PONG_ADDR = 0x00000074, -VFE_BUS_STATS_AWB_WR_PING_ADDR = 0x00000078, -VFE_BUS_STATS_AWB_WR_PONG_ADDR = 0x0000007C, -VFE_BUS_STATS_HIST_WR_PING_ADDR = 0x00000080, -VFE_BUS_STATS_HIST_WR_PONG_ADDR = 0x00000084, -VFE_BUS_STATS_WR_PRIORITY = 0x00000088, -VFE_BUS_STRIPE_RD_ADDR_0 = 0x0000008C, -VFE_BUS_STRIPE_RD_ADDR_1 = 0x00000090, -VFE_BUS_STRIPE_RD_ADDR_2 = 0x00000094, -VFE_BUS_STRIPE_RD_ADDR_3 = 0x00000098, -VFE_BUS_STRIPE_RD_VSIZE = 0x0000009C, -VFE_BUS_STRIPE_RD_HSIZE = 0x000000A0, -VFE_BUS_STRIPE_RD_BUFFER_CFG = 0x000000A4, -VFE_BUS_STRIPE_RD_UNPACK_CFG = 0x000000A8, -VFE_BUS_STRIPE_RD_UNPACK = 0x000000AC, -VFE_BUS_STRIPE_RD_PAD_SIZE = 0x000000B0, -VFE_BUS_STRIPE_RD_PAD_L_UNPACK = 0x000000B4, -VFE_BUS_STRIPE_RD_PAD_R_UNPACK = 0x000000B8, -VFE_BUS_STRIPE_RD_PAD_TB_UNPACK = 0x000000BC, -VFE_BUS_PINGPONG_IRQ_EN = 0x000000C0, -VFE_BUS_PINGPONG_STATUS = 0x000000C4, -VFE_BUS_PM_CMD = 0x000000C8, -VFE_BUS_PM_CFG = 0x000000CC, -VFE_BUS_ENC_Y_WR_PM_STATS_0 = 0x000000D0, -VFE_BUS_ENC_Y_WR_PM_STATS_1 = 0x000000D4, -VFE_BUS_ENC_CBCR_WR_PM_STATS_0 = 0x000000D8, -VFE_BUS_ENC_CBCR_WR_PM_STATS_1 = 0x000000DC, -VFE_BUS_VIEW_Y_WR_PM_STATS_0 = 0x000000E0, -VFE_BUS_VIEW_Y_WR_PM_STATS_1 = 0x000000E4, -VFE_BUS_VIEW_CBCR_WR_PM_STATS_0 = 0x000000E8, -VFE_BUS_VIEW_CBCR_WR_PM_STATS_1 = 0x000000EC, -VFE_BUS_MISR_CFG = 0x000000F4, -VFE_BUS_MISR_MAST_CFG_0 = 0x000000F8, -VFE_BUS_MISR_MAST_CFG_1 = 0x000000FC, -VFE_BUS_MISR_RD_VAL = 0x00000100, -VFE_AXI_CMD = 0x00000104, -VFE_AXI_CFG = 0x00000108, -VFE_AXI_STATUS = 0x0000010C, -CAMIF_COMMAND = 0x00000110, -CAMIF_CONFIG = 0x00000114, -CAMIF_EFS_CONFIG = 0x00000118, -CAMIF_FRAME_CONFIG = 0x0000011C, -CAMIF_WINDOW_WIDTH_CONFIG = 0x00000120, -CAMIF_WINDOW_HEIGHT_CONFIG = 0x00000124, -CAMIF_SUBSAMPLE1_CONFIG = 0x00000128, -CAMIF_SUBSAMPLE2_CONFIG = 0x0000012C, -CAMIF_EPOCH_IRQ = 0x00000130, -CAMIF_STATUS = 0x00000134, -CAMIF_MISR = 0x00000138, -VFE_SYNC_TIMER_CMD = 0x0000013C, -VFE_SYNC_TIMER0_LINE_START = 0x00000140, -VFE_SYNC_TIMER0_PIXEL_START = 0x00000144, -VFE_SYNC_TIMER0_PIXEL_DURATION = 0x00000148, -VFE_SYNC_TIMER1_LINE_START = 0x0000014C, -VFE_SYNC_TIMER1_PIXEL_START = 0x00000150, -VFE_SYNC_TIMER1_PIXEL_DURATION = 0x00000154, -VFE_SYNC_TIMER2_LINE_START = 0x00000158, -VFE_SYNC_TIMER2_PIXEL_START = 0x0000015C, -VFE_SYNC_TIMER2_PIXEL_DURATION = 0x00000160, -VFE_SYNC_TIMER_POLARITY = 0x00000164, -VFE_ASYNC_TIMER_CMD = 0x00000168, -VFE_ASYNC_TIMER0_CFG_0 = 0x0000016C, -VFE_ASYNC_TIMER0_CFG_1 = 0x00000170, -VFE_ASYNC_TIMER1_CFG_0 = 0x00000174, -VFE_ASYNC_TIMER1_CFG_1 = 0x00000178, -VFE_ASYNC_TIMER2_CFG_0 = 0x0000017C, -VFE_ASYNC_TIMER2_CFG_1 = 0x00000180, -VFE_ASYNC_TIMER3_CFG_0 = 0x00000184, -VFE_ASYNC_TIMER3_CFG_1 = 0x00000188, -VFE_TIMER_SEL = 0x0000018C, -VFE_REG_UPDATE_CMD = 0x00000190, -VFE_BLACK_EVEN_EVEN_VALUE = 0x00000194, -VFE_BLACK_EVEN_ODD_VALUE = 0x00000198, -VFE_BLACK_ODD_EVEN_VALUE = 0x0000019C, -VFE_BLACK_ODD_ODD_VALUE = 0x000001A0, -VFE_ROLLOFF_CFG_0 = 0x000001A4, -VFE_ROLLOFF_CFG_1 = 0x000001A8, -VFE_ROLLOFF_CFG_2 = 0x000001AC, -VFE_DEMUX_CFG = 0x000001B0, -VFE_DEMUX_GAIN_0 = 0x000001B4, -VFE_DEMUX_GAIN_1 = 0x000001B8, -VFE_DEMUX_EVEN_CFG = 0x000001BC, -VFE_DEMUX_ODD_CFG = 0x000001C0, -VFE_DEMOSAIC_CFG = 0x000001C4, -VFE_DEMOSAIC_ABF_CFG_0 = 0x000001C8, -VFE_DEMOSAIC_ABF_CFG_1 = 0x000001CC, -VFE_DEMOSAIC_BPC_CFG_0 = 0x000001D0, -VFE_DEMOSAIC_BPC_CFG_1 = 0x000001D4, -VFE_DEMOSAIC_STATUS = 0x000001D8, -VFE_CHROMA_UPSAMPLE_CFG = 0x000001DC, -VFE_CROP_WIDTH_CFG = 0x000001E0, -VFE_CROP_HEIGHT_CFG = 0x000001E4, -VFE_COLOR_CORRECT_COEFF_0 = 0x000001E8, -VFE_COLOR_CORRECT_COEFF_1 = 0x000001EC, -VFE_COLOR_CORRECT_COEFF_2 = 0x000001F0, -VFE_COLOR_CORRECT_COEFF_3 = 0x000001F4, -VFE_COLOR_CORRECT_COEFF_4 = 0x000001F8, -VFE_COLOR_CORRECT_COEFF_5 = 0x000001FC, -VFE_COLOR_CORRECT_COEFF_6 = 0x00000200, -VFE_COLOR_CORRECT_COEFF_7 = 0x00000204, -VFE_COLOR_CORRECT_COEFF_8 = 0x00000208, -VFE_COLOR_CORRECT_OFFSET_0 = 0x0000020C, -VFE_COLOR_CORRECT_OFFSET_1 = 0x00000210, -VFE_COLOR_CORRECT_OFFSET_2 = 0x00000214, -VFE_COLOR_CORRECT_COEFF_Q = 0x00000218, -VFE_LA_CFG = 0x0000021C, -VFE_LUT_BANK_SEL = 0x00000220, -VFE_CHROMA_ENHAN_A = 0x00000224, -VFE_CHROMA_ENHAN_B = 0x00000228, -VFE_CHROMA_ENHAN_C = 0x0000022C, -VFE_CHROMA_ENHAN_D = 0x00000230, -VFE_CHROMA_ENHAN_K = 0x00000234, -VFE_COLOR_CONVERT_COEFF_0 = 0x00000238, -VFE_COLOR_CONVERT_COEFF_1 = 0x0000023C, -VFE_COLOR_CONVERT_COEFF_2 = 0x00000240, -VFE_COLOR_CONVERT_OFFSET = 0x00000244, -VFE_ASF_CFG = 0x00000248, -VFE_ASF_SHARP_CFG_0 = 0x0000024C, -VFE_ASF_SHARP_CFG_1 = 0x00000250, -VFE_ASF_SHARP_COEFF_0 = 0x00000254, -VFE_ASF_SHARP_COEFF_1 = 0x00000258, -VFE_ASF_SHARP_COEFF_2 = 0x0000025C, -VFE_ASF_SHARP_COEFF_3 = 0x00000260, -VFE_ASF_MAX_EDGE = 0x00000264, -VFE_ASF_CROP_WIDTH_CFG = 0x00000268, -VFE_ASF_CROP_HEIGHT_CFG = 0x0000026C, -VFE_SCALE_CFG = 0x00000270, -VFE_SCALE_H_IMAGE_SIZE_CFG = 0x00000274, -VFE_SCALE_H_PHASE_CFG = 0x00000278, -VFE_SCALE_H_STRIPE_CFG = 0x0000027C, -VFE_SCALE_V_IMAGE_SIZE_CFG = 0x00000280, -VFE_SCALE_V_PHASE_CFG = 0x00000284, -VFE_SCALE_V_STRIPE_CFG = 0x00000288, -VFE_SCALE_Y_CFG = 0x0000028C, -VFE_SCALE_Y_H_IMAGE_SIZE_CFG = 0x00000290, -VFE_SCALE_Y_H_PHASE_CFG = 0x00000294, -VFE_SCALE_Y_V_IMAGE_SIZE_CFG = 0x00000298, -VFE_SCALE_Y_V_PHASE_CFG = 0x0000029C, -VFE_SCALE_CBCR_CFG = 0x000002A0, -VFE_SCALE_CBCR_H_IMAGE_SIZE_CFG = 0x000002A4, -VFE_SCALE_CBCR_H_PHASE_CFG = 0x000002A8, -VFE_SCALE_CBCR_V_IMAGE_SIZE_CFG = 0x000002AC, -VFE_SCALE_CBCR_V_PHASE_CFG = 0x000002B0, -VFE_WB_CFG = 0x000002B4, -VFE_CHROMA_SUPPRESS_CFG_0 = 0x000002B8, -VFE_CHROMA_SUPPRESS_CFG_1 = 0x000002BC, -VFE_CHROMA_SUBSAMPLE_CFG = 0x000002C0, -VFE_CHROMA_SUB_CROP_WIDTH_CFG = 0x000002C4, -VFE_CHROMA_SUB_CROP_HEIGHT_CFG = 0x000002C8, -VFE_FRAMEDROP_ENC_Y_CFG = 0x000002CC, -VFE_FRAMEDROP_ENC_CBCR_CFG = 0x000002D0, -VFE_FRAMEDROP_ENC_Y_PATTERN = 0x000002D4, -VFE_FRAMEDROP_ENC_CBCR_PATTERN = 0x000002D8, -VFE_FRAMEDROP_VIEW_Y_CFG = 0x000002DC, -VFE_FRAMEDROP_VIEW_CBCR_CFG = 0x000002E0, -VFE_FRAMEDROP_VIEW_Y_PATTERN = 0x000002E4, -VFE_FRAMEDROP_VIEW_CBCR_PATTERN = 0x000002E8, -VFE_CLAMP_MAX_CFG = 0x000002EC, -VFE_CLAMP_MIN_CFG = 0x000002F0, -VFE_STATS_CMD = 0x000002F4, -VFE_STATS_AF_CFG = 0x000002F8, -VFE_STATS_AF_DIM = 0x000002FC, -VFE_STATS_AF_GRID_0 = 0x00000300, -VFE_STATS_AF_GRID_1 = 0x00000304, -VFE_STATS_AF_GRID_2 = 0x00000308, -VFE_STATS_AF_GRID_3 = 0x0000030C, -VFE_STATS_AF_HEADER = 0x00000310, -VFE_STATS_AF_COEF0 = 0x00000314, -VFE_STATS_AF_COEF1 = 0x00000318, -VFE_STATS_AWBAE_CFG = 0x0000031C, -VFE_STATS_AXW_HEADER = 0x00000320, -VFE_STATS_AWB_MCFG = 0x00000324, -VFE_STATS_AWB_CCFG1 = 0x00000328, -VFE_STATS_AWB_CCFG2 = 0x0000032C, -VFE_STATS_HIST_HEADER = 0x00000330, -VFE_STATS_HIST_INNER_OFFSET = 0x00000334, -VFE_STATS_HIST_INNER_DIM = 0x00000338, -VFE_STATS_FRAME_SIZE = 0x0000033C, -VFE_DMI_CFG = 0x00000340, -VFE_DMI_ADDR = 0x00000344, -VFE_DMI_DATA_HI = 0x00000348, -VFE_DMI_DATA_LO = 0x0000034C, -VFE_DMI_RAM_AUTO_LOAD_CMD = 0x00000350, -VFE_DMI_RAM_AUTO_LOAD_STATUS = 0x00000354, -VFE_DMI_RAM_AUTO_LOAD_CFG = 0x00000358, -VFE_DMI_RAM_AUTO_LOAD_SEED = 0x0000035C, -VFE_TESTBUS_SEL = 0x00000360, -VFE_TESTGEN_CFG = 0x00000364, -VFE_SW_TESTGEN_CMD = 0x00000368, -VFE_HW_TESTGEN_CMD = 0x0000036C, -VFE_HW_TESTGEN_CFG = 0x00000370, -VFE_HW_TESTGEN_IMAGE_CFG = 0x00000374, -VFE_HW_TESTGEN_SOF_OFFSET_CFG = 0x00000378, -VFE_HW_TESTGEN_EOF_NOFFSET_CFG = 0x0000037C, -VFE_HW_TESTGEN_SOL_OFFSET_CFG = 0x00000380, -VFE_HW_TESTGEN_EOL_NOFFSET_CFG = 0x00000384, -VFE_HW_TESTGEN_HBI_CFG = 0x00000388, -VFE_HW_TESTGEN_VBL_CFG = 0x0000038C, -VFE_HW_TESTGEN_SOF_DUMMY_LINE_CFG2 = 0x00000390, -VFE_HW_TESTGEN_EOF_DUMMY_LINE_CFG2 = 0x00000394, -VFE_HW_TESTGEN_COLOR_BARS_CFG = 0x00000398, -VFE_HW_TESTGEN_RANDOM_CFG = 0x0000039C, -VFE_SPARE = 0x000003A0, -}; - -#define ping 0x0 -#define pong 0x1 - -struct vfe_bus_cfg_data { - boolean stripeRdPathEn; - boolean encYWrPathEn; - boolean encCbcrWrPathEn; - boolean viewYWrPathEn; - boolean viewCbcrWrPathEn; - enum VFE_RAW_PIXEL_DATA_SIZE rawPixelDataSize; - enum VFE_RAW_WR_PATH_SEL rawWritePathSelect; -}; - -struct vfe_camif_cfg_data { - boolean camif2OutputEnable; - boolean camif2BusEnable; - struct vfe_cmds_camif_cfg camifCfgFromCmd; -}; - -struct vfe_irq_composite_mask_config { - uint8_t encIrqComMask; - uint8_t viewIrqComMask; - uint8_t ceDoneSel; -}; - -/* define a structure for each output path.*/ -struct vfe_output_path { - uint32_t addressBuffer[8]; - uint16_t fragIndex; - boolean hwCurrentFlag; - uint8_t *hwRegPingAddress; - uint8_t *hwRegPongAddress; -}; - -struct vfe_output_path_combo { - boolean whichOutputPath; - boolean pathEnabled; - boolean multiFrag; - uint8_t fragCount; - boolean ackPending; - uint8_t currentFrame; - uint32_t nextFrameAddrBuf[8]; - struct vfe_output_path yPath; - struct vfe_output_path cbcrPath; - uint8_t snapshotPendingCount; - boolean pmEnabled; - uint8_t cbcrStatusBit; -}; - -struct vfe_stats_control { - boolean ackPending; - uint32_t addressBuffer[2]; - uint32_t nextFrameAddrBuf; - boolean pingPongStatus; - uint8_t *hwRegPingAddress; - uint8_t *hwRegPongAddress; - uint32_t droppedStatsFrameCount; - uint32_t bufToRender; -}; - -struct vfe_gamma_lut_sel { - boolean ch0BankSelect; - boolean ch1BankSelect; - boolean ch2BankSelect; -}; - -struct vfe_interrupt_mask { - boolean camifErrorIrq; - boolean camifSofIrq; - boolean camifEolIrq; - boolean camifEofIrq; - boolean camifEpoch1Irq; - boolean camifEpoch2Irq; - boolean camifOverflowIrq; - boolean ceIrq; - boolean regUpdateIrq; - boolean resetAckIrq; - boolean encYPingpongIrq; - boolean encCbcrPingpongIrq; - boolean viewYPingpongIrq; - boolean viewCbcrPingpongIrq; - boolean rdPingpongIrq; - boolean afPingpongIrq; - boolean awbPingpongIrq; - boolean histPingpongIrq; - boolean encIrq; - boolean viewIrq; - boolean busOverflowIrq; - boolean afOverflowIrq; - boolean awbOverflowIrq; - boolean syncTimer0Irq; - boolean syncTimer1Irq; - boolean syncTimer2Irq; - boolean asyncTimer0Irq; - boolean asyncTimer1Irq; - boolean asyncTimer2Irq; - boolean asyncTimer3Irq; - boolean axiErrorIrq; - boolean violationIrq; -}; - -enum vfe_interrupt_name { - CAMIF_ERROR_IRQ, - CAMIF_SOF_IRQ, - CAMIF_EOL_IRQ, - CAMIF_EOF_IRQ, - CAMIF_EPOCH1_IRQ, - CAMIF_EPOCH2_IRQ, - CAMIF_OVERFLOW_IRQ, - CE_IRQ, - REG_UPDATE_IRQ, - RESET_ACK_IRQ, - ENC_Y_PINGPONG_IRQ, - ENC_CBCR_PINGPONG_IRQ, - VIEW_Y_PINGPONG_IRQ, - VIEW_CBCR_PINGPONG_IRQ, - RD_PINGPONG_IRQ, - AF_PINGPONG_IRQ, - AWB_PINGPONG_IRQ, - HIST_PINGPONG_IRQ, - ENC_IRQ, - VIEW_IRQ, - BUS_OVERFLOW_IRQ, - AF_OVERFLOW_IRQ, - AWB_OVERFLOW_IRQ, - SYNC_TIMER0_IRQ, - SYNC_TIMER1_IRQ, - SYNC_TIMER2_IRQ, - ASYNC_TIMER0_IRQ, - ASYNC_TIMER1_IRQ, - ASYNC_TIMER2_IRQ, - ASYNC_TIMER3_IRQ, - AXI_ERROR_IRQ, - VIOLATION_IRQ -}; - -enum VFE_DMI_RAM_SEL { - NO_MEM_SELECTED = 0, - ROLLOFF_RAM = 0x1, - RGBLUT_RAM_CH0_BANK0 = 0x2, - RGBLUT_RAM_CH0_BANK1 = 0x3, - RGBLUT_RAM_CH1_BANK0 = 0x4, - RGBLUT_RAM_CH1_BANK1 = 0x5, - RGBLUT_RAM_CH2_BANK0 = 0x6, - RGBLUT_RAM_CH2_BANK1 = 0x7, - STATS_HIST_CB_EVEN_RAM = 0x8, - STATS_HIST_CB_ODD_RAM = 0x9, - STATS_HIST_CR_EVEN_RAM = 0xa, - STATS_HIST_CR_ODD_RAM = 0xb, - RGBLUT_CHX_BANK0 = 0xc, - RGBLUT_CHX_BANK1 = 0xd, - LUMA_ADAPT_LUT_RAM_BANK0 = 0xe, - LUMA_ADAPT_LUT_RAM_BANK1 = 0xf -}; - -struct vfe_module_enable { - boolean blackLevelCorrectionEnable; - boolean lensRollOffEnable; - boolean demuxEnable; - boolean chromaUpsampleEnable; - boolean demosaicEnable; - boolean statsEnable; - boolean cropEnable; - boolean mainScalerEnable; - boolean whiteBalanceEnable; - boolean colorCorrectionEnable; - boolean yHistEnable; - boolean skinToneEnable; - boolean lumaAdaptationEnable; - boolean rgbLUTEnable; - boolean chromaEnhanEnable; - boolean asfEnable; - boolean chromaSuppressionEnable; - boolean chromaSubsampleEnable; - boolean scaler2YEnable; - boolean scaler2CbcrEnable; -}; - -struct vfe_bus_cmd_data { - boolean stripeReload; - boolean busPingpongReload; - boolean statsPingpongReload; -}; - -struct vfe_stats_cmd_data { - boolean autoFocusEnable; - boolean axwEnable; - boolean histEnable; - boolean clearHistEnable; - boolean histAutoClearEnable; - boolean colorConversionEnable; -}; - -struct vfe_hw_ver { - uint32_t minorVersion:8; - uint32_t majorVersion:8; - uint32_t coreVersion:4; - uint32_t /* reserved */ : 12; -} __attribute__((packed, aligned(4))); - -struct vfe_cfg { - uint32_t pixelPattern:3; - uint32_t /* reserved */ : 13; - uint32_t inputSource:2; - uint32_t /* reserved */ : 14; -} __attribute__((packed, aligned(4))); - -struct vfe_buscmd { - uint32_t stripeReload:1; - uint32_t /* reserved */ : 3; - uint32_t busPingpongReload:1; - uint32_t statsPingpongReload:1; - uint32_t /* reserved */ : 26; -} __attribute__((packed, aligned(4))); - -struct VFE_Irq_Composite_MaskType { - uint32_t encIrqComMaskBits:2; - uint32_t viewIrqComMaskBits:2; - uint32_t ceDoneSelBits:5; - uint32_t /* reserved */ : 23; -} __attribute__((packed, aligned(4))); - -struct vfe_mod_enable { - uint32_t blackLevelCorrectionEnable:1; - uint32_t lensRollOffEnable:1; - uint32_t demuxEnable:1; - uint32_t chromaUpsampleEnable:1; - uint32_t demosaicEnable:1; - uint32_t statsEnable:1; - uint32_t cropEnable:1; - uint32_t mainScalerEnable:1; - uint32_t whiteBalanceEnable:1; - uint32_t colorCorrectionEnable:1; - uint32_t yHistEnable:1; - uint32_t skinToneEnable:1; - uint32_t lumaAdaptationEnable:1; - uint32_t rgbLUTEnable:1; - uint32_t chromaEnhanEnable:1; - uint32_t asfEnable:1; - uint32_t chromaSuppressionEnable:1; - uint32_t chromaSubsampleEnable:1; - uint32_t scaler2YEnable:1; - uint32_t scaler2CbcrEnable:1; - uint32_t /* reserved */ : 14; -} __attribute__((packed, aligned(4))); - -struct vfe_irqenable { - uint32_t camifErrorIrq:1; - uint32_t camifSofIrq:1; - uint32_t camifEolIrq:1; - uint32_t camifEofIrq:1; - uint32_t camifEpoch1Irq:1; - uint32_t camifEpoch2Irq:1; - uint32_t camifOverflowIrq:1; - uint32_t ceIrq:1; - uint32_t regUpdateIrq:1; - uint32_t resetAckIrq:1; - uint32_t encYPingpongIrq:1; - uint32_t encCbcrPingpongIrq:1; - uint32_t viewYPingpongIrq:1; - uint32_t viewCbcrPingpongIrq:1; - uint32_t rdPingpongIrq:1; - uint32_t afPingpongIrq:1; - uint32_t awbPingpongIrq:1; - uint32_t histPingpongIrq:1; - uint32_t encIrq:1; - uint32_t viewIrq:1; - uint32_t busOverflowIrq:1; - uint32_t afOverflowIrq:1; - uint32_t awbOverflowIrq:1; - uint32_t syncTimer0Irq:1; - uint32_t syncTimer1Irq:1; - uint32_t syncTimer2Irq:1; - uint32_t asyncTimer0Irq:1; - uint32_t asyncTimer1Irq:1; - uint32_t asyncTimer2Irq:1; - uint32_t asyncTimer3Irq:1; - uint32_t axiErrorIrq:1; - uint32_t violationIrq:1; -} __attribute__((packed, aligned(4))); - -struct vfe_upsample_cfg { - uint32_t chromaCositingForYCbCrInputs:1; - uint32_t /* reserved */ : 31; -} __attribute__((packed, aligned(4))); - -struct VFE_CAMIFConfigType { - /* CAMIF Config */ - uint32_t /* reserved */ : 1; - uint32_t VSyncEdge:1; - uint32_t HSyncEdge:1; - uint32_t syncMode:2; - uint32_t vfeSubsampleEnable:1; - uint32_t /* reserved */ : 1; - uint32_t busSubsampleEnable:1; - uint32_t camif2vfeEnable:1; - uint32_t /* reserved */ : 1; - uint32_t camif2busEnable:1; - uint32_t irqSubsampleEnable:1; - uint32_t binningEnable:1; - uint32_t /* reserved */ : 18; - uint32_t misrEnable:1; -} __attribute__((packed, aligned(4))); - -struct vfe_camifcfg { - /* EFS_Config */ - uint32_t efsEndOfLine:8; - uint32_t efsStartOfLine:8; - uint32_t efsEndOfFrame:8; - uint32_t efsStartOfFrame:8; - /* Frame Config */ - uint32_t frameConfigPixelsPerLine:14; - uint32_t /* reserved */ : 2; - uint32_t frameConfigLinesPerFrame:14; - uint32_t /* reserved */ : 2; - /* Window Width Config */ - uint32_t windowWidthCfgLastPixel:14; - uint32_t /* reserved */ : 2; - uint32_t windowWidthCfgFirstPixel:14; - uint32_t /* reserved */ : 2; - /* Window Height Config */ - uint32_t windowHeightCfglastLine:14; - uint32_t /* reserved */ : 2; - uint32_t windowHeightCfgfirstLine:14; - uint32_t /* reserved */ : 2; - /* Subsample 1 Config */ - uint32_t subsample1CfgPixelSkip:16; - uint32_t subsample1CfgLineSkip:16; - /* Subsample 2 Config */ - uint32_t subsample2CfgFrameSkip:4; - uint32_t subsample2CfgFrameSkipMode:1; - uint32_t subsample2CfgPixelSkipWrap:1; - uint32_t /* reserved */ : 26; - /* Epoch Interrupt */ - uint32_t epoch1Line:14; - uint32_t /* reserved */ : 2; - uint32_t epoch2Line:14; - uint32_t /* reserved */ : 2; -} __attribute__((packed, aligned(4))); - -struct vfe_camifframe_update { - uint32_t pixelsPerLine:14; - uint32_t /* reserved */ : 2; - uint32_t linesPerFrame:14; - uint32_t /* reserved */ : 2; -} __attribute__((packed, aligned(4))); - -struct vfe_axi_bus_cfg { - uint32_t stripeRdPathEn:1; - uint32_t /* reserved */ : 3; - uint32_t encYWrPathEn:1; - uint32_t encCbcrWrPathEn:1; - uint32_t viewYWrPathEn:1; - uint32_t viewCbcrWrPathEn:1; - uint32_t rawPixelDataSize:2; - uint32_t rawWritePathSelect:2; - uint32_t /* reserved */ : 20; -} __attribute__((packed, aligned(4))); - -struct vfe_axi_out_cfg { - uint32_t out2YPingAddr:32; - uint32_t out2YPongAddr:32; - uint32_t out2YImageHeight:12; - uint32_t /* reserved */ : 4; - uint32_t out2YImageWidthin64bit:10; - uint32_t /* reserved */ : 6; - uint32_t out2YBurstLength:2; - uint32_t /* reserved */ : 2; - uint32_t out2YNumRows:12; - uint32_t out2YRowIncrementIn64bit:12; - uint32_t /* reserved */ : 4; - uint32_t out2CbcrPingAddr:32; - uint32_t out2CbcrPongAddr:32; - uint32_t out2CbcrImageHeight:12; - uint32_t /* reserved */ : 4; - uint32_t out2CbcrImageWidthIn64bit:10; - uint32_t /* reserved */ : 6; - uint32_t out2CbcrBurstLength:2; - uint32_t /* reserved */ : 2; - uint32_t out2CbcrNumRows:12; - uint32_t out2CbcrRowIncrementIn64bit:12; - uint32_t /* reserved */ : 4; - uint32_t out1YPingAddr:32; - uint32_t out1YPongAddr:32; - uint32_t out1YImageHeight:12; - uint32_t /* reserved */ : 4; - uint32_t out1YImageWidthin64bit:10; - uint32_t /* reserved */ : 6; - uint32_t out1YBurstLength:2; - uint32_t /* reserved */ : 2; - uint32_t out1YNumRows:12; - uint32_t out1YRowIncrementIn64bit:12; - uint32_t /* reserved */ : 4; - uint32_t out1CbcrPingAddr:32; - uint32_t out1CbcrPongAddr:32; - uint32_t out1CbcrImageHeight:12; - uint32_t /* reserved */ : 4; - uint32_t out1CbcrImageWidthIn64bit:10; - uint32_t /* reserved */ : 6; - uint32_t out1CbcrBurstLength:2; - uint32_t /* reserved */ : 2; - uint32_t out1CbcrNumRows:12; - uint32_t out1CbcrRowIncrementIn64bit:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_output_clamp_cfg { - /* Output Clamp Maximums */ - uint32_t yChanMax:8; - uint32_t cbChanMax:8; - uint32_t crChanMax:8; - uint32_t /* reserved */ : 8; - /* Output Clamp Minimums */ - uint32_t yChanMin:8; - uint32_t cbChanMin:8; - uint32_t crChanMin:8; - uint32_t /* reserved */ : 8; -} __attribute__((packed, aligned(4))); - -struct vfe_fov_crop_cfg { - uint32_t lastPixel:12; - uint32_t /* reserved */ : 4; - uint32_t firstPixel:12; - uint32_t /* reserved */ : 4; - - /* FOV Corp, Part 2 */ - uint32_t lastLine:12; - uint32_t /* reserved */ : 4; - uint32_t firstLine:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct VFE_FRAME_SKIP_UpdateCmdType { - uint32_t yPattern:32; - uint32_t cbcrPattern:32; -} __attribute__((packed, aligned(4))); - -struct vfe_frame_skip_cfg { - /* Frame Drop Enc (output2) */ - uint32_t output2YPeriod:5; - uint32_t /* reserved */ : 27; - uint32_t output2CbCrPeriod:5; - uint32_t /* reserved */ : 27; - uint32_t output2YPattern:32; - uint32_t output2CbCrPattern:32; - /* Frame Drop View (output1) */ - uint32_t output1YPeriod:5; - uint32_t /* reserved */ : 27; - uint32_t output1CbCrPeriod:5; - uint32_t /* reserved */ : 27; - uint32_t output1YPattern:32; - uint32_t output1CbCrPattern:32; -} __attribute__((packed, aligned(4))); - -struct vfe_main_scaler_cfg { - /* Scaler Enable Config */ - uint32_t hEnable:1; - uint32_t vEnable:1; - uint32_t /* reserved */ : 30; - /* Scale H Image Size Config */ - uint32_t inWidth:12; - uint32_t /* reserved */ : 4; - uint32_t outWidth:12; - uint32_t /* reserved */ : 4; - /* Scale H Phase Config */ - uint32_t horizPhaseMult:18; - uint32_t /* reserved */ : 2; - uint32_t horizInterResolution:2; - uint32_t /* reserved */ : 10; - /* Scale H Stripe Config */ - uint32_t horizMNInit:12; - uint32_t /* reserved */ : 4; - uint32_t horizPhaseInit:15; - uint32_t /* reserved */ : 1; - /* Scale V Image Size Config */ - uint32_t inHeight:12; - uint32_t /* reserved */ : 4; - uint32_t outHeight:12; - uint32_t /* reserved */ : 4; - /* Scale V Phase Config */ - uint32_t vertPhaseMult:18; - uint32_t /* reserved */ : 2; - uint32_t vertInterResolution:2; - uint32_t /* reserved */ : 10; - /* Scale V Stripe Config */ - uint32_t vertMNInit:12; - uint32_t /* reserved */ : 4; - uint32_t vertPhaseInit:15; - uint32_t /* reserved */ : 1; -} __attribute__((packed, aligned(4))); - -struct vfe_scaler2_cfg { - /* Scaler Enable Config */ - uint32_t hEnable:1; - uint32_t vEnable:1; - uint32_t /* reserved */ : 30; - /* Scaler H Image Size Config */ - uint32_t inWidth:12; - uint32_t /* reserved */ : 4; - uint32_t outWidth:12; - uint32_t /* reserved */ : 4; - /* Scaler H Phase Config */ - uint32_t horizPhaseMult:18; - uint32_t /* reserved */ : 2; - uint32_t horizInterResolution:2; - uint32_t /* reserved */ : 10; - /* Scaler V Image Size Config */ - uint32_t inHeight:12; - uint32_t /* reserved */ : 4; - uint32_t outHeight:12; - uint32_t /* reserved */ : 4; - /* Scaler V Phase Config */ - uint32_t vertPhaseMult:18; - uint32_t /* reserved */ : 2; - uint32_t vertInterResolution:2; - uint32_t /* reserved */ : 10; -} __attribute__((packed, aligned(4))); - -struct vfe_rolloff_cfg { - /* Rolloff 0 Config */ - uint32_t gridWidth:9; - uint32_t gridHeight:9; - uint32_t yDelta:9; - uint32_t /* reserved */ : 5; - /* Rolloff 1 Config*/ - uint32_t gridX:4; - uint32_t gridY:4; - uint32_t pixelX:9; - uint32_t /* reserved */ : 3; - uint32_t pixelY:9; - uint32_t /* reserved */ : 3; - /* Rolloff 2 Config */ - uint32_t yDeltaAccum:12; - uint32_t /* reserved */ : 20; -} __attribute__((packed, aligned(4))); - -struct vfe_asf_update { - /* ASF Config Command */ - uint32_t smoothEnable:1; - uint32_t sharpMode:2; - uint32_t /* reserved */ : 1; - uint32_t smoothCoeff1:4; - uint32_t smoothCoeff0:8; - uint32_t pipeFlushCount:12; - uint32_t pipeFlushOvd:1; - uint32_t flushHaltOvd:1; - uint32_t cropEnable:1; - uint32_t /* reserved */ : 1; - /* Sharpening Config 0 */ - uint32_t sharpThresholdE1:7; - uint32_t /* reserved */ : 1; - uint32_t sharpDegreeK1:5; - uint32_t /* reserved */ : 3; - uint32_t sharpDegreeK2:5; - uint32_t /* reserved */ : 3; - uint32_t normalizeFactor:7; - uint32_t /* reserved */ : 1; - /* Sharpening Config 1 */ - uint32_t sharpThresholdE2:8; - uint32_t sharpThresholdE3:8; - uint32_t sharpThresholdE4:8; - uint32_t sharpThresholdE5:8; - /* Sharpening Coefficients 0 */ - uint32_t F1Coeff0:6; - uint32_t F1Coeff1:6; - uint32_t F1Coeff2:6; - uint32_t F1Coeff3:6; - uint32_t F1Coeff4:6; - uint32_t /* reserved */ : 2; - /* Sharpening Coefficients 1 */ - uint32_t F1Coeff5:6; - uint32_t F1Coeff6:6; - uint32_t F1Coeff7:6; - uint32_t F1Coeff8:7; - uint32_t /* reserved */ : 7; - /* Sharpening Coefficients 2 */ - uint32_t F2Coeff0:6; - uint32_t F2Coeff1:6; - uint32_t F2Coeff2:6; - uint32_t F2Coeff3:6; - uint32_t F2Coeff4:6; - uint32_t /* reserved */ : 2; - /* Sharpening Coefficients 3 */ - uint32_t F2Coeff5:6; - uint32_t F2Coeff6:6; - uint32_t F2Coeff7:6; - uint32_t F2Coeff8:7; - uint32_t /* reserved */ : 7; -} __attribute__((packed, aligned(4))); - -struct vfe_asfcrop_cfg { - /* ASF Crop Width Config */ - uint32_t lastPixel:12; - uint32_t /* reserved */ : 4; - uint32_t firstPixel:12; - uint32_t /* reserved */ : 4; - /* ASP Crop Height Config */ - uint32_t lastLine:12; - uint32_t /* reserved */ : 4; - uint32_t firstLine:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_chroma_suppress_cfg { - /* Chroma Suppress 0 Config */ - uint32_t m1:8; - uint32_t m3:8; - uint32_t n1:3; - uint32_t /* reserved */ : 1; - uint32_t n3:3; - uint32_t /* reserved */ : 9; - /* Chroma Suppress 1 Config */ - uint32_t mm1:8; - uint32_t nn1:3; - uint32_t /* reserved */ : 21; -} __attribute__((packed, aligned(4))); - -struct vfe_chromasubsample_cfg { - /* Chroma Subsample Selection */ - uint32_t hCositedPhase:1; - uint32_t vCositedPhase:1; - uint32_t hCosited:1; - uint32_t vCosited:1; - uint32_t hsubSampleEnable:1; - uint32_t vsubSampleEnable:1; - uint32_t cropEnable:1; - uint32_t /* reserved */ : 25; - uint32_t cropWidthLastPixel:12; - uint32_t /* reserved */ : 4; - uint32_t cropWidthFirstPixel:12; - uint32_t /* reserved */ : 4; - uint32_t cropHeightLastLine:12; - uint32_t /* reserved */ : 4; - uint32_t cropHeightFirstLine:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_blacklevel_cfg { - /* Black Even-Even Value Config */ - uint32_t evenEvenAdjustment:9; - uint32_t /* reserved */ : 23; - /* Black Even-Odd Value Config */ - uint32_t evenOddAdjustment:9; - uint32_t /* reserved */ : 23; - /* Black Odd-Even Value Config */ - uint32_t oddEvenAdjustment:9; - uint32_t /* reserved */ : 23; - /* Black Odd-Odd Value Config */ - uint32_t oddOddAdjustment:9; - uint32_t /* reserved */ : 23; -} __attribute__((packed, aligned(4))); - -struct vfe_demux_cfg { - /* Demux Gain 0 Config */ - uint32_t ch0EvenGain:10; - uint32_t /* reserved */ : 6; - uint32_t ch0OddGain:10; - uint32_t /* reserved */ : 6; - /* Demux Gain 1 Config */ - uint32_t ch1Gain:10; - uint32_t /* reserved */ : 6; - uint32_t ch2Gain:10; - uint32_t /* reserved */ : 6; -} __attribute__((packed, aligned(4))); - -struct vfe_bps_info { - uint32_t greenBadPixelCount:8; - uint32_t /* reserved */ : 8; - uint32_t RedBlueBadPixelCount:8; - uint32_t /* reserved */ : 8; -} __attribute__((packed, aligned(4))); - -struct vfe_demosaic_cfg { - /* Demosaic Config */ - uint32_t abfEnable:1; - uint32_t badPixelCorrEnable:1; - uint32_t forceAbfOn:1; - uint32_t /* reserved */ : 1; - uint32_t abfShift:4; - uint32_t fminThreshold:7; - uint32_t /* reserved */ : 1; - uint32_t fmaxThreshold:7; - uint32_t /* reserved */ : 5; - uint32_t slopeShift:3; - uint32_t /* reserved */ : 1; -} __attribute__((packed, aligned(4))); - -struct vfe_demosaic_bpc_cfg { - /* Demosaic BPC Config 0 */ - uint32_t blueDiffThreshold:12; - uint32_t redDiffThreshold:12; - uint32_t /* reserved */ : 8; - /* Demosaic BPC Config 1 */ - uint32_t greenDiffThreshold:12; - uint32_t /* reserved */ : 20; -} __attribute__((packed, aligned(4))); - -struct vfe_demosaic_abf_cfg { - /* Demosaic ABF Config 0 */ - uint32_t lpThreshold:10; - uint32_t /* reserved */ : 22; - /* Demosaic ABF Config 1 */ - uint32_t ratio:4; - uint32_t minValue:10; - uint32_t /* reserved */ : 2; - uint32_t maxValue:10; - uint32_t /* reserved */ : 6; -} __attribute__((packed, aligned(4))); - -struct vfe_color_correction_cfg { - /* Color Corr. Coefficient 0 Config */ - uint32_t c0:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 1 Config */ - uint32_t c1:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 2 Config */ - uint32_t c2:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 3 Config */ - uint32_t c3:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 4 Config */ - uint32_t c4:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 5 Config */ - uint32_t c5:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 6 Config */ - uint32_t c6:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 7 Config */ - uint32_t c7:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Coefficient 8 Config */ - uint32_t c8:12; - uint32_t /* reserved */ : 20; - /* Color Corr. Offset 0 Config */ - uint32_t k0:11; - uint32_t /* reserved */ : 21; - /* Color Corr. Offset 1 Config */ - uint32_t k1:11; - uint32_t /* reserved */ : 21; - /* Color Corr. Offset 2 Config */ - uint32_t k2:11; - uint32_t /* reserved */ : 21; - /* Color Corr. Coefficient Q Config */ - uint32_t coefQFactor:2; - uint32_t /* reserved */ : 30; -} __attribute__((packed, aligned(4))); - -struct VFE_LumaAdaptation_ConfigCmdType { - /* LA Config */ - uint32_t lutBankSelect:1; - uint32_t /* reserved */ : 31; -} __attribute__((packed, aligned(4))); - -struct vfe_wb_cfg { - /* WB Config */ - uint32_t ch0Gain:9; - uint32_t ch1Gain:9; - uint32_t ch2Gain:9; - uint32_t /* reserved */ : 5; -} __attribute__((packed, aligned(4))); - -struct VFE_GammaLutSelect_ConfigCmdType { - /* LUT Bank Select Config */ - uint32_t ch0BankSelect:1; - uint32_t ch1BankSelect:1; - uint32_t ch2BankSelect:1; - uint32_t /* reserved */ : 29; -} __attribute__((packed, aligned(4))); - -struct vfe_chroma_enhance_cfg { - /* Chroma Enhance A Config */ - uint32_t ap:11; - uint32_t /* reserved */ : 5; - uint32_t am:11; - uint32_t /* reserved */ : 5; - /* Chroma Enhance B Config */ - uint32_t bp:11; - uint32_t /* reserved */ : 5; - uint32_t bm:11; - uint32_t /* reserved */ : 5; - /* Chroma Enhance C Config */ - uint32_t cp:11; - uint32_t /* reserved */ : 5; - uint32_t cm:11; - uint32_t /* reserved */ : 5; - /* Chroma Enhance D Config */ - uint32_t dp:11; - uint32_t /* reserved */ : 5; - uint32_t dm:11; - uint32_t /* reserved */ : 5; - /* Chroma Enhance K Config */ - uint32_t kcb:11; - uint32_t /* reserved */ : 5; - uint32_t kcr:11; - uint32_t /* reserved */ : 5; -} __attribute__((packed, aligned(4))); - -struct vfe_color_convert_cfg { - /* Conversion Coefficient 0 */ - uint32_t v0:12; - uint32_t /* reserved */ : 20; - /* Conversion Coefficient 1 */ - uint32_t v1:12; - uint32_t /* reserved */ : 20; - /* Conversion Coefficient 2 */ - uint32_t v2:12; - uint32_t /* reserved */ : 20; - /* Conversion Offset */ - uint32_t ConvertOffset:8; - uint32_t /* reserved */ : 24; -} __attribute__((packed, aligned(4))); - -struct VFE_SyncTimer_ConfigCmdType { - /* Timer Line Start Config */ - uint32_t timerLineStart:12; - uint32_t /* reserved */ : 20; - /* Timer Pixel Start Config */ - uint32_t timerPixelStart:18; - uint32_t /* reserved */ : 14; - /* Timer Pixel Duration Config */ - uint32_t timerPixelDuration:28; - uint32_t /* reserved */ : 4; - /* Sync Timer Polarity Config */ - uint32_t timer0Polarity:1; - uint32_t timer1Polarity:1; - uint32_t timer2Polarity:1; - uint32_t /* reserved */ : 29; -} __attribute__((packed, aligned(4))); - -struct VFE_AsyncTimer_ConfigCmdType { - /* Async Timer Config 0 */ - uint32_t inactiveLength:20; - uint32_t numRepetition:10; - uint32_t /* reserved */ : 1; - uint32_t polarity:1; - /* Async Timer Config 1 */ - uint32_t activeLength:20; - uint32_t /* reserved */ : 12; -} __attribute__((packed, aligned(4))); - -struct VFE_AWBAEStatistics_ConfigCmdType { - /* AWB autoexposure Config */ - uint32_t aeRegionConfig:1; - uint32_t aeSubregionConfig:1; - uint32_t /* reserved */ : 14; - uint32_t awbYMin:8; - uint32_t awbYMax:8; - /* AXW Header */ - uint32_t axwHeader:8; - uint32_t /* reserved */ : 24; - /* AWB Mconfig */ - uint32_t m4:8; - uint32_t m3:8; - uint32_t m2:8; - uint32_t m1:8; - /* AWB Cconfig */ - uint32_t c2:12; - uint32_t /* reserved */ : 4; - uint32_t c1:12; - uint32_t /* reserved */ : 4; - /* AWB Cconfig 2 */ - uint32_t c4:12; - uint32_t /* reserved */ : 4; - uint32_t c3:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct VFE_TestGen_ConfigCmdType { - /* HW Test Gen Config */ - uint32_t numFrame:10; - uint32_t /* reserved */ : 2; - uint32_t pixelDataSelect:1; - uint32_t systematicDataSelect:1; - uint32_t /* reserved */ : 2; - uint32_t pixelDataSize:2; - uint32_t hsyncEdge:1; - uint32_t vsyncEdge:1; - uint32_t /* reserved */ : 12; - /* HW Test Gen Image Config */ - uint32_t imageWidth:14; - uint32_t /* reserved */ : 2; - uint32_t imageHeight:14; - uint32_t /* reserved */ : 2; - /* SOF Offset Config */ - uint32_t sofOffset:24; - uint32_t /* reserved */ : 8; - /* EOF NOffset Config */ - uint32_t eofNOffset:24; - uint32_t /* reserved */ : 8; - /* SOL Offset Config */ - uint32_t solOffset:9; - uint32_t /* reserved */ : 23; - /* EOL NOffset Config */ - uint32_t eolNOffset:9; - uint32_t /* reserved */ : 23; - /* HBI Config */ - uint32_t hBlankInterval:14; - uint32_t /* reserved */ : 18; - /* VBL Config */ - uint32_t vBlankInterval:14; - uint32_t /* reserved */ : 2; - uint32_t vBlankIntervalEnable:1; - uint32_t /* reserved */ : 15; - /* SOF Dummy Line Config */ - uint32_t sofDummy:8; - uint32_t /* reserved */ : 24; - /* EOF Dummy Line Config */ - uint32_t eofDummy:8; - uint32_t /* reserved */ : 24; - /* Color Bars Config */ - uint32_t unicolorBarSelect:3; - uint32_t /* reserved */ : 1; - uint32_t unicolorBarEnable:1; - uint32_t splitEnable:1; - uint32_t pixelPattern:2; - uint32_t rotatePeriod:6; - uint32_t /* reserved */ : 18; - /* Random Config */ - uint32_t randomSeed:16; - uint32_t /* reserved */ : 16; -} __attribute__((packed, aligned(4))); - -struct VFE_Bus_Pm_ConfigCmdType { - /* VFE Bus Performance Monitor Config */ - uint32_t output2YWrPmEnable:1; - uint32_t output2CbcrWrPmEnable:1; - uint32_t output1YWrPmEnable:1; - uint32_t output1CbcrWrPmEnable:1; - uint32_t /* reserved */ : 28; -} __attribute__((packed, aligned(4))); - -struct vfe_asf_info { - /* asf max edge */ - uint32_t maxEdge:13; - uint32_t /* reserved */ : 3; - /* HBi count */ - uint32_t HBICount:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_camif_stats { - uint32_t pixelCount:14; - uint32_t /* reserved */ : 2; - uint32_t lineCount:14; - uint32_t /* reserved */ : 1; - uint32_t camifHalt:1; -} __attribute__((packed, aligned(4))); - -struct VFE_StatsCmdType { - uint32_t autoFocusEnable:1; - uint32_t axwEnable:1; - uint32_t histEnable:1; - uint32_t clearHistEnable:1; - uint32_t histAutoClearEnable:1; - uint32_t colorConversionEnable:1; - uint32_t /* reserved */ : 26; -} __attribute__((packed, aligned(4))); - - -struct vfe_statsframe { - uint32_t lastPixel:12; - uint32_t /* reserved */ : 4; - uint32_t lastLine:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_busstats_wrprio { - uint32_t afBusPriority:4; - uint32_t awbBusPriority:4; - uint32_t histBusPriority:4; - uint32_t afBusPriorityEn:1; - uint32_t awbBusPriorityEn:1; - uint32_t histBusPriorityEn:1; - uint32_t /* reserved */ : 17; -} __attribute__((packed, aligned(4))); - -struct vfe_statsaf_update { - /* VFE_STATS_AF_CFG */ - uint32_t windowVOffset:12; - uint32_t /* reserved */ : 4; - uint32_t windowHOffset:12; - uint32_t /* reserved */ : 3; - uint32_t windowMode:1; - - /* VFE_STATS_AF_DIM */ - uint32_t windowHeight:12; - uint32_t /* reserved */ : 4; - uint32_t windowWidth:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct vfe_statsaf_cfg { - /* VFE_STATS_AF_GRID_0 */ - uint32_t entry00:8; - uint32_t entry01:8; - uint32_t entry02:8; - uint32_t entry03:8; - - /* VFE_STATS_AF_GRID_1 */ - uint32_t entry10:8; - uint32_t entry11:8; - uint32_t entry12:8; - uint32_t entry13:8; - - /* VFE_STATS_AF_GRID_2 */ - uint32_t entry20:8; - uint32_t entry21:8; - uint32_t entry22:8; - uint32_t entry23:8; - - /* VFE_STATS_AF_GRID_3 */ - uint32_t entry30:8; - uint32_t entry31:8; - uint32_t entry32:8; - uint32_t entry33:8; - - /* VFE_STATS_AF_HEADER */ - uint32_t afHeader:8; - uint32_t /* reserved */ : 24; - /* VFE_STATS_AF_COEF0 */ - uint32_t a00:5; - uint32_t a04:5; - uint32_t fvMax:11; - uint32_t fvMetric:1; - uint32_t /* reserved */ : 10; - - /* VFE_STATS_AF_COEF1 */ - uint32_t a20:5; - uint32_t a21:5; - uint32_t a22:5; - uint32_t a23:5; - uint32_t a24:5; - uint32_t /* reserved */ : 7; -} __attribute__((packed, aligned(4))); - -struct vfe_statsawbae_update { - uint32_t aeRegionCfg:1; - uint32_t aeSubregionCfg:1; - uint32_t /* reserved */ : 14; - uint32_t awbYMin:8; - uint32_t awbYMax:8; -} __attribute__((packed, aligned(4))); - -struct vfe_statsaxw_hdr_cfg { - /* Stats AXW Header Config */ - uint32_t axwHeader:8; - uint32_t /* reserved */ : 24; -} __attribute__((packed, aligned(4))); - -struct vfe_statsawb_update { - /* AWB MConfig */ - uint32_t m4:8; - uint32_t m3:8; - uint32_t m2:8; - uint32_t m1:8; - - /* AWB CConfig1 */ - uint32_t c2:12; - uint32_t /* reserved */ : 4; - uint32_t c1:12; - uint32_t /* reserved */ : 4; - - /* AWB CConfig2 */ - uint32_t c4:12; - uint32_t /* reserved */ : 4; - uint32_t c3:12; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct VFE_SyncTimerCmdType { - uint32_t hsyncCount:12; - uint32_t /* reserved */ : 20; - uint32_t pclkCount:18; - uint32_t /* reserved */ : 14; - uint32_t outputDuration:28; - uint32_t /* reserved */ : 4; -} __attribute__((packed, aligned(4))); - -struct VFE_AsyncTimerCmdType { - /* config 0 */ - uint32_t inactiveCount:20; - uint32_t repeatCount:10; - uint32_t /* reserved */ : 1; - uint32_t polarity:1; - /* config 1 */ - uint32_t activeCount:20; - uint32_t /* reserved */ : 12; -} __attribute__((packed, aligned(4))); - -struct VFE_AxiInputCmdType { - uint32_t stripeStartAddr0:32; - uint32_t stripeStartAddr1:32; - uint32_t stripeStartAddr2:32; - uint32_t stripeStartAddr3:32; - - uint32_t ySize:12; - uint32_t yOffsetDelta:12; - uint32_t /* reserved */ : 8; - - /* bus_stripe_rd_hSize */ - uint32_t /* reserved */ : 16; - uint32_t xSizeWord:10; - uint32_t /* reserved */ : 6; - - /* bus_stripe_rd_buffer_cfg */ - uint32_t burstLength:2; - uint32_t /* reserved */ : 2; - uint32_t NumOfRows:12; - uint32_t RowIncrement:12; - uint32_t /* reserved */ : 4; - - /* bus_stripe_rd_unpack_cfg */ - uint32_t mainUnpackHeight:12; - uint32_t mainUnpackWidth:13; - uint32_t mainUnpackHbiSel:3; - uint32_t mainUnpackPhase:3; - uint32_t /* reserved */ : 1; - - /* bus_stripe_rd_unpack */ - uint32_t unpackPattern:32; - - /* bus_stripe_rd_pad_size */ - uint32_t padLeft:7; - uint32_t /* reserved */ : 1; - uint32_t padRight:7; - uint32_t /* reserved */ : 1; - uint32_t padTop:7; - uint32_t /* reserved */ : 1; - uint32_t padBottom:7; - uint32_t /* reserved */ : 1; - - /* bus_stripe_rd_pad_L_unpack */ - uint32_t leftUnpackPattern0:4; - uint32_t leftUnpackPattern1:4; - uint32_t leftUnpackPattern2:4; - uint32_t leftUnpackPattern3:4; - uint32_t leftUnpackStop0:1; - uint32_t leftUnpackStop1:1; - uint32_t leftUnpackStop2:1; - uint32_t leftUnpackStop3:1; - uint32_t /* reserved */ : 12; - - /* bus_stripe_rd_pad_R_unpack */ - uint32_t rightUnpackPattern0:4; - uint32_t rightUnpackPattern1:4; - uint32_t rightUnpackPattern2:4; - uint32_t rightUnpackPattern3:4; - uint32_t rightUnpackStop0:1; - uint32_t rightUnpackStop1:1; - uint32_t rightUnpackStop2:1; - uint32_t rightUnpackStop3:1; - uint32_t /* reserved */ : 12; - - /* bus_stripe_rd_pad_tb_unpack */ - uint32_t topUnapckPattern:4; - uint32_t /* reserved */ : 12; - uint32_t bottomUnapckPattern:4; - uint32_t /* reserved */ : 12; -} __attribute__((packed, aligned(4))); - -struct VFE_AxiRdFragIrqEnable { - uint32_t stripeRdFragirq0Enable:1; - uint32_t stripeRdFragirq1Enable:1; - uint32_t stripeRdFragirq2Enable:1; - uint32_t stripeRdFragirq3Enable:1; - uint32_t /* reserved */ : 28; -} __attribute__((packed, aligned(4))); - -int vfe_cmd_init(struct msm_vfe_callback *, struct platform_device *, void *); -void vfe_stats_af_stop(void); -void vfe_stop(void); -void vfe_update(void); -int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *); -int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *); -void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *); -void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *); -void vfe_start(struct vfe_cmd_start *); -void vfe_la_update(struct vfe_cmd_la_config *); -void vfe_la_config(struct vfe_cmd_la_config *); -void vfe_test_gen_start(struct vfe_cmd_test_gen_start *); -void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *); -void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *); -void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *); -void vfe_camif_frame_update(struct vfe_cmds_camif_frame *); -void vfe_color_correction_config(struct vfe_cmd_color_correction_config *); -void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *); -void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *); -void vfe_demosaic_config(struct vfe_cmd_demosaic_config *); -void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *); -void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *); -void vfe_black_level_update(struct vfe_cmd_black_level_config *); -void vfe_black_level_config(struct vfe_cmd_black_level_config *); -void vfe_asf_update(struct vfe_cmd_asf_update *); -void vfe_asf_config(struct vfe_cmd_asf_config *); -void vfe_white_balance_config(struct vfe_cmd_white_balance_config *); -void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *); -void vfe_roll_off_config(struct vfe_cmd_roll_off_config *); -void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *); -void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *); -void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *); -void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *); -void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *); -void vfe_stats_wb_exp_stop(void); -void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *); -void vfe_stats_update_af(struct vfe_cmd_stats_af_update *); -void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *); -void vfe_stats_start_af(struct vfe_cmd_stats_af_start *); -void vfe_stats_setting(struct vfe_cmd_stats_setting *); -void vfe_axi_input_config(struct vfe_cmd_axi_input_config *); -void vfe_stats_config(struct vfe_cmd_stats_setting *); -void vfe_axi_output_config(struct vfe_cmd_axi_output_config *); -void vfe_camif_config(struct vfe_cmd_camif_config *); -void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *); -void vfe_get_hw_version(struct vfe_cmd_hw_version *); -void vfe_reset(void); -void vfe_cmd_release(struct platform_device *); -void vfe_output1_ack(struct vfe_cmd_output_ack *); -void vfe_output2_ack(struct vfe_cmd_output_ack *); -#endif /* __MSM_VFE8X_REG_H__ */ diff --git a/drivers/staging/dream/camera/mt9d112.c b/drivers/staging/dream/camera/mt9d112.c deleted file mode 100644 index e6f2d5124611..000000000000 --- a/drivers/staging/dream/camera/mt9d112.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/uaccess.h> -#include <linux/miscdevice.h> -#include <media/msm_camera.h> -#include <mach/gpio.h> -#include "mt9d112.h" - -/* Micron MT9D112 Registers and their values */ -/* Sensor Core Registers */ -#define REG_MT9D112_MODEL_ID 0x3000 -#define MT9D112_MODEL_ID 0x1580 - -/* SOC Registers Page 1 */ -#define REG_MT9D112_SENSOR_RESET 0x301A -#define REG_MT9D112_STANDBY_CONTROL 0x3202 -#define REG_MT9D112_MCU_BOOT 0x3386 - -struct mt9d112_work { - struct work_struct work; -}; - -static struct mt9d112_work *mt9d112_sensorw; -static struct i2c_client *mt9d112_client; - -struct mt9d112_ctrl { - const struct msm_camera_sensor_info *sensordata; -}; - - -static struct mt9d112_ctrl *mt9d112_ctrl; - -static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue); -DECLARE_MUTEX(mt9d112_sem); - - -/*============================================================= - EXTERNAL DECLARATIONS -==============================================================*/ -extern struct mt9d112_reg mt9d112_regs; - - -/*=============================================================*/ - -static int mt9d112_reset(const struct msm_camera_sensor_info *dev) -{ - int rc = 0; - - rc = gpio_request(dev->sensor_reset, "mt9d112"); - - if (!rc) { - rc = gpio_direction_output(dev->sensor_reset, 0); - mdelay(20); - rc = gpio_direction_output(dev->sensor_reset, 1); - } - - gpio_free(dev->sensor_reset); - return rc; -} - -static int32_t mt9d112_i2c_txdata(unsigned short saddr, - unsigned char *txdata, int length) -{ - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - - if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) { - CDBG("mt9d112_i2c_txdata failed\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9d112_i2c_write(unsigned short saddr, - unsigned short waddr, unsigned short wdata, enum mt9d112_width width) -{ - int32_t rc = -EIO; - unsigned char buf[4]; - - memset(buf, 0, sizeof(buf)); - switch (width) { - case WORD_LEN: { - buf[0] = (waddr & 0xFF00)>>8; - buf[1] = (waddr & 0x00FF); - buf[2] = (wdata & 0xFF00)>>8; - buf[3] = (wdata & 0x00FF); - - rc = mt9d112_i2c_txdata(saddr, buf, 4); - } - break; - - case BYTE_LEN: { - buf[0] = waddr; - buf[1] = wdata; - rc = mt9d112_i2c_txdata(saddr, buf, 2); - } - break; - - default: - break; - } - - if (rc < 0) - CDBG( - "i2c_write failed, addr = 0x%x, val = 0x%x!\n", - waddr, wdata); - - return rc; -} - -static int32_t mt9d112_i2c_write_table( - struct mt9d112_i2c_reg_conf const *reg_conf_tbl, - int num_of_items_in_table) -{ - int i; - int32_t rc = -EIO; - - for (i = 0; i < num_of_items_in_table; i++) { - rc = mt9d112_i2c_write(mt9d112_client->addr, - reg_conf_tbl->waddr, reg_conf_tbl->wdata, - reg_conf_tbl->width); - if (rc < 0) - break; - if (reg_conf_tbl->mdelay_time != 0) - mdelay(reg_conf_tbl->mdelay_time); - reg_conf_tbl++; - } - - return rc; -} - -static int mt9d112_i2c_rxdata(unsigned short saddr, - unsigned char *rxdata, int length) -{ - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = 2, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = length, - .buf = rxdata, - }, - }; - - if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) { - CDBG("mt9d112_i2c_rxdata failed!\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9d112_i2c_read(unsigned short saddr, - unsigned short raddr, unsigned short *rdata, enum mt9d112_width width) -{ - int32_t rc = 0; - unsigned char buf[4]; - - if (!rdata) - return -EIO; - - memset(buf, 0, sizeof(buf)); - - switch (width) { - case WORD_LEN: { - buf[0] = (raddr & 0xFF00)>>8; - buf[1] = (raddr & 0x00FF); - - rc = mt9d112_i2c_rxdata(saddr, buf, 2); - if (rc < 0) - return rc; - - *rdata = buf[0] << 8 | buf[1]; - } - break; - - default: - break; - } - - if (rc < 0) - CDBG("mt9d112_i2c_read failed!\n"); - - return rc; -} - -static int32_t mt9d112_set_lens_roll_off(void) -{ - int32_t rc = 0; - rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0], - mt9d112_regs.rftbl_size); - return rc; -} - -static long mt9d112_reg_init(void) -{ - int32_t array_length; - int32_t i; - long rc; - - /* PLL Setup Start */ - rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0], - mt9d112_regs.plltbl_size); - - if (rc < 0) - return rc; - /* PLL Setup End */ - - array_length = mt9d112_regs.prev_snap_reg_settings_size; - - /* Configure sensor for Preview mode and Snapshot mode */ - for (i = 0; i < array_length; i++) { - rc = mt9d112_i2c_write(mt9d112_client->addr, - mt9d112_regs.prev_snap_reg_settings[i].register_address, - mt9d112_regs.prev_snap_reg_settings[i].register_value, - WORD_LEN); - - if (rc < 0) - return rc; - } - - /* Configure for Noise Reduction, Saturation and Aperture Correction */ - array_length = mt9d112_regs.noise_reduction_reg_settings_size; - - for (i = 0; i < array_length; i++) { - rc = mt9d112_i2c_write(mt9d112_client->addr, - mt9d112_regs.noise_reduction_reg_settings[i].register_address, - mt9d112_regs.noise_reduction_reg_settings[i].register_value, - WORD_LEN); - - if (rc < 0) - return rc; - } - - /* Set Color Kill Saturation point to optimum value */ - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x35A4, - 0x0593, - WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0], - mt9d112_regs.stbl_size); - if (rc < 0) - return rc; - - rc = mt9d112_set_lens_roll_off(); - if (rc < 0) - return rc; - - return 0; -} - -static long mt9d112_set_sensor_mode(int mode) -{ - uint16_t clock; - long rc = 0; - - switch (mode) { - case SENSOR_PREVIEW_MODE: - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA20C, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0004, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA215, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0004, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA20B, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0000, WORD_LEN); - if (rc < 0) - return rc; - - clock = 0x0250; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x341C, clock, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA103, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0001, WORD_LEN); - if (rc < 0) - return rc; - - mdelay(5); - break; - - case SENSOR_SNAPSHOT_MODE: - /* Switch to lower fps for Snapshot */ - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x341C, 0x0120, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA120, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0002, WORD_LEN); - if (rc < 0) - return rc; - - mdelay(5); - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA103, WORD_LEN); - if (rc < 0) - return rc; - - rc = - mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0002, WORD_LEN); - if (rc < 0) - return rc; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static long mt9d112_set_effect(int mode, int effect) -{ - uint16_t reg_addr; - uint16_t reg_val; - long rc = 0; - - switch (mode) { - case SENSOR_PREVIEW_MODE: - /* Context A Special Effects */ - reg_addr = 0x2799; - break; - - case SENSOR_SNAPSHOT_MODE: - /* Context B Special Effects */ - reg_addr = 0x279B; - break; - - default: - reg_addr = 0x2799; - break; - } - - switch (effect) { - case CAMERA_EFFECT_OFF: { - reg_val = 0x6440; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - } - break; - - case CAMERA_EFFECT_MONO: { - reg_val = 0x6441; - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - } - break; - - case CAMERA_EFFECT_NEGATIVE: { - reg_val = 0x6443; - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - } - break; - - case CAMERA_EFFECT_SOLARIZE: { - reg_val = 0x6445; - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - } - break; - - case CAMERA_EFFECT_SEPIA: { - reg_val = 0x6442; - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - } - break; - - case CAMERA_EFFECT_PASTEL: - case CAMERA_EFFECT_MOSAIC: - case CAMERA_EFFECT_RESIZE: - return -EINVAL; - - default: { - reg_val = 0x6440; - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, reg_addr, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, reg_val, WORD_LEN); - if (rc < 0) - return rc; - - return -EINVAL; - } - } - - /* Refresh Sequencer */ - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x338C, 0xA103, WORD_LEN); - if (rc < 0) - return rc; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x3390, 0x0005, WORD_LEN); - - return rc; -} - -static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data) -{ - uint16_t model_id = 0; - int rc = 0; - - CDBG("init entry \n"); - rc = mt9d112_reset(data); - if (rc < 0) { - CDBG("reset failed!\n"); - goto init_probe_fail; - } - - mdelay(5); - - /* Micron suggested Power up block Start: - * Put MCU into Reset - Stop MCU */ - rc = mt9d112_i2c_write(mt9d112_client->addr, - REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - /* Pull MCU from Reset - Start MCU */ - rc = mt9d112_i2c_write(mt9d112_client->addr, - REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - mdelay(5); - - /* Micron Suggested - Power up block */ - rc = mt9d112_i2c_write(mt9d112_client->addr, - REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - rc = mt9d112_i2c_write(mt9d112_client->addr, - REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - /* FUSED_DEFECT_CORRECTION */ - rc = mt9d112_i2c_write(mt9d112_client->addr, - 0x33F4, 0x031D, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - mdelay(5); - - /* Micron suggested Power up block End */ - /* Read the Model ID of the sensor */ - rc = mt9d112_i2c_read(mt9d112_client->addr, - REG_MT9D112_MODEL_ID, &model_id, WORD_LEN); - if (rc < 0) - goto init_probe_fail; - - CDBG("mt9d112 model_id = 0x%x\n", model_id); - - /* Check if it matches it with the value in Datasheet */ - if (model_id != MT9D112_MODEL_ID) { - rc = -EINVAL; - goto init_probe_fail; - } - - rc = mt9d112_reg_init(); - if (rc < 0) - goto init_probe_fail; - - return rc; - -init_probe_fail: - return rc; -} - -int mt9d112_sensor_init(const struct msm_camera_sensor_info *data) -{ - int rc = 0; - - mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL); - if (!mt9d112_ctrl) { - CDBG("mt9d112_init failed!\n"); - rc = -ENOMEM; - goto init_done; - } - - if (data) - mt9d112_ctrl->sensordata = data; - - /* Input MCLK = 24MHz */ - msm_camio_clk_rate_set(24000000); - mdelay(5); - - msm_camio_camif_pad_reg_reset(); - - rc = mt9d112_sensor_init_probe(data); - if (rc < 0) { - CDBG("mt9d112_sensor_init failed!\n"); - goto init_fail; - } - -init_done: - return rc; - -init_fail: - kfree(mt9d112_ctrl); - return rc; -} - -static int mt9d112_init_client(struct i2c_client *client) -{ - /* Initialize the MSM_CAMI2C Chip */ - init_waitqueue_head(&mt9d112_wait_queue); - return 0; -} - -int mt9d112_sensor_config(void __user *argp) -{ - struct sensor_cfg_data cfg_data; - long rc = 0; - - if (copy_from_user(&cfg_data, - (void *)argp, - sizeof(struct sensor_cfg_data))) - return -EFAULT; - - /* down(&mt9d112_sem); */ - - CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n", - cfg_data.cfgtype, cfg_data.mode); - - switch (cfg_data.cfgtype) { - case CFG_SET_MODE: - rc = mt9d112_set_sensor_mode( - cfg_data.mode); - break; - - case CFG_SET_EFFECT: - rc = mt9d112_set_effect(cfg_data.mode, - cfg_data.cfg.effect); - break; - - case CFG_GET_AF_MAX_STEPS: - default: - rc = -EINVAL; - break; - } - - /* up(&mt9d112_sem); */ - - return rc; -} - -int mt9d112_sensor_release(void) -{ - int rc = 0; - - /* down(&mt9d112_sem); */ - - kfree(mt9d112_ctrl); - /* up(&mt9d112_sem); */ - - return rc; -} - -static int mt9d112_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - rc = -ENOTSUPP; - goto probe_failure; - } - - mt9d112_sensorw = - kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL); - - if (!mt9d112_sensorw) { - rc = -ENOMEM; - goto probe_failure; - } - - i2c_set_clientdata(client, mt9d112_sensorw); - mt9d112_init_client(client); - mt9d112_client = client; - - CDBG("mt9d112_probe succeeded!\n"); - - return 0; - -probe_failure: - kfree(mt9d112_sensorw); - mt9d112_sensorw = NULL; - CDBG("mt9d112_probe failed!\n"); - return rc; -} - -static const struct i2c_device_id mt9d112_i2c_id[] = { - { "mt9d112", 0}, - { }, -}; - -static struct i2c_driver mt9d112_i2c_driver = { - .id_table = mt9d112_i2c_id, - .probe = mt9d112_i2c_probe, - .remove = __exit_p(mt9d112_i2c_remove), - .driver = { - .name = "mt9d112", - }, -}; - -static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info, - struct msm_sensor_ctrl *s) -{ - int rc = i2c_add_driver(&mt9d112_i2c_driver); - if (rc < 0 || mt9d112_client == NULL) { - rc = -ENOTSUPP; - goto probe_done; - } - - /* Input MCLK = 24MHz */ - msm_camio_clk_rate_set(24000000); - mdelay(5); - - rc = mt9d112_sensor_init_probe(info); - if (rc < 0) - goto probe_done; - - s->s_init = mt9d112_sensor_init; - s->s_release = mt9d112_sensor_release; - s->s_config = mt9d112_sensor_config; - -probe_done: - CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); - return rc; -} - -static int __mt9d112_probe(struct platform_device *pdev) -{ - return msm_camera_drv_start(pdev, mt9d112_sensor_probe); -} - -static struct platform_driver msm_camera_driver = { - .probe = __mt9d112_probe, - .driver = { - .name = "msm_camera_mt9d112", - .owner = THIS_MODULE, - }, -}; - -static int __init mt9d112_init(void) -{ - return platform_driver_register(&msm_camera_driver); -} - -module_init(mt9d112_init); diff --git a/drivers/staging/dream/camera/mt9d112.h b/drivers/staging/dream/camera/mt9d112.h deleted file mode 100644 index c678996f9e2b..000000000000 --- a/drivers/staging/dream/camera/mt9d112.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#ifndef MT9D112_H -#define MT9D112_H - -#include <linux/types.h> -#include <mach/camera.h> - -enum mt9d112_width { - WORD_LEN, - BYTE_LEN -}; - -struct mt9d112_i2c_reg_conf { - unsigned short waddr; - unsigned short wdata; - enum mt9d112_width width; - unsigned short mdelay_time; -}; - -struct mt9d112_reg { - const struct register_address_value_pair *prev_snap_reg_settings; - uint16_t prev_snap_reg_settings_size; - const struct register_address_value_pair *noise_reduction_reg_settings; - uint16_t noise_reduction_reg_settings_size; - const struct mt9d112_i2c_reg_conf *plltbl; - uint16_t plltbl_size; - const struct mt9d112_i2c_reg_conf *stbl; - uint16_t stbl_size; - const struct mt9d112_i2c_reg_conf *rftbl; - uint16_t rftbl_size; -}; - -#endif /* MT9D112_H */ diff --git a/drivers/staging/dream/camera/mt9d112_reg.c b/drivers/staging/dream/camera/mt9d112_reg.c deleted file mode 100644 index c52e96f47141..000000000000 --- a/drivers/staging/dream/camera/mt9d112_reg.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include "mt9d112.h" - -struct register_address_value_pair -preview_snapshot_mode_reg_settings_array[] = { - {0x338C, 0x2703}, - {0x3390, 800}, /* Output Width (P) = 640 */ - {0x338C, 0x2705}, - {0x3390, 600}, /* Output Height (P) = 480 */ - {0x338C, 0x2707}, - {0x3390, 0x0640}, /* Output Width (S) = 1600 */ - {0x338C, 0x2709}, - {0x3390, 0x04B0}, /* Output Height (S) = 1200 */ - {0x338C, 0x270D}, - {0x3390, 0x0000}, /* Row Start (P) = 0 */ - {0x338C, 0x270F}, - {0x3390, 0x0000}, /* Column Start (P) = 0 */ - {0x338C, 0x2711}, - {0x3390, 0x04BD}, /* Row End (P) = 1213 */ - {0x338C, 0x2713}, - {0x3390, 0x064D}, /* Column End (P) = 1613 */ - {0x338C, 0x2715}, - {0x3390, 0x0000}, /* Extra Delay (P) = 0 */ - {0x338C, 0x2717}, - {0x3390, 0x2111}, /* Row Speed (P) = 8465 */ - {0x338C, 0x2719}, - {0x3390, 0x046C}, /* Read Mode (P) = 1132 */ - {0x338C, 0x271B}, - {0x3390, 0x024F}, /* Sensor_Sample_Time_pck(P) = 591 */ - {0x338C, 0x271D}, - {0x3390, 0x0102}, /* Sensor_Fine_Correction(P) = 258 */ - {0x338C, 0x271F}, - {0x3390, 0x0279}, /* Sensor_Fine_IT_min(P) = 633 */ - {0x338C, 0x2721}, - {0x3390, 0x0155}, /* Sensor_Fine_IT_max_margin(P) = 341 */ - {0x338C, 0x2723}, - {0x3390, 659}, /* Frame Lines (P) = 679 */ - {0x338C, 0x2725}, - {0x3390, 0x0824}, /* Line Length (P) = 2084 */ - {0x338C, 0x2727}, - {0x3390, 0x2020}, - {0x338C, 0x2729}, - {0x3390, 0x2020}, - {0x338C, 0x272B}, - {0x3390, 0x1020}, - {0x338C, 0x272D}, - {0x3390, 0x2007}, - {0x338C, 0x272F}, - {0x3390, 0x0004}, /* Row Start(S) = 4 */ - {0x338C, 0x2731}, - {0x3390, 0x0004}, /* Column Start(S) = 4 */ - {0x338C, 0x2733}, - {0x3390, 0x04BB}, /* Row End(S) = 1211 */ - {0x338C, 0x2735}, - {0x3390, 0x064B}, /* Column End(S) = 1611 */ - {0x338C, 0x2737}, - {0x3390, 0x04CE}, /* Extra Delay(S) = 1230 */ - {0x338C, 0x2739}, - {0x3390, 0x2111}, /* Row Speed(S) = 8465 */ - {0x338C, 0x273B}, - {0x3390, 0x0024}, /* Read Mode(S) = 36 */ - {0x338C, 0x273D}, - {0x3390, 0x0120}, /* Sensor sample time pck(S) = 288 */ - {0x338C, 0x2741}, - {0x3390, 0x0169}, /* Sensor_Fine_IT_min(P) = 361 */ - {0x338C, 0x2745}, - {0x3390, 0x04FF}, /* Frame Lines(S) = 1279 */ - {0x338C, 0x2747}, - {0x3390, 0x0824}, /* Line Length(S) = 2084 */ - {0x338C, 0x2751}, - {0x3390, 0x0000}, /* Crop_X0(P) = 0 */ - {0x338C, 0x2753}, - {0x3390, 0x0320}, /* Crop_X1(P) = 800 */ - {0x338C, 0x2755}, - {0x3390, 0x0000}, /* Crop_Y0(P) = 0 */ - {0x338C, 0x2757}, - {0x3390, 0x0258}, /* Crop_Y1(P) = 600 */ - {0x338C, 0x275F}, - {0x3390, 0x0000}, /* Crop_X0(S) = 0 */ - {0x338C, 0x2761}, - {0x3390, 0x0640}, /* Crop_X1(S) = 1600 */ - {0x338C, 0x2763}, - {0x3390, 0x0000}, /* Crop_Y0(S) = 0 */ - {0x338C, 0x2765}, - {0x3390, 0x04B0}, /* Crop_Y1(S) = 1200 */ - {0x338C, 0x222E}, - {0x3390, 0x00A0}, /* R9 Step = 160 */ - {0x338C, 0xA408}, - {0x3390, 0x001F}, - {0x338C, 0xA409}, - {0x3390, 0x0021}, - {0x338C, 0xA40A}, - {0x3390, 0x0025}, - {0x338C, 0xA40B}, - {0x3390, 0x0027}, - {0x338C, 0x2411}, - {0x3390, 0x00A0}, - {0x338C, 0x2413}, - {0x3390, 0x00C0}, - {0x338C, 0x2415}, - {0x3390, 0x00A0}, - {0x338C, 0x2417}, - {0x3390, 0x00C0}, - {0x338C, 0x2799}, - {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(P) */ - {0x338C, 0x279B}, - {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(S) */ -}; - -static struct register_address_value_pair -noise_reduction_reg_settings_array[] = { - {0x338C, 0xA76D}, - {0x3390, 0x0003}, - {0x338C, 0xA76E}, - {0x3390, 0x0003}, - {0x338C, 0xA76F}, - {0x3390, 0}, - {0x338C, 0xA770}, - {0x3390, 21}, - {0x338C, 0xA771}, - {0x3390, 37}, - {0x338C, 0xA772}, - {0x3390, 63}, - {0x338C, 0xA773}, - {0x3390, 100}, - {0x338C, 0xA774}, - {0x3390, 128}, - {0x338C, 0xA775}, - {0x3390, 151}, - {0x338C, 0xA776}, - {0x3390, 169}, - {0x338C, 0xA777}, - {0x3390, 186}, - {0x338C, 0xA778}, - {0x3390, 199}, - {0x338C, 0xA779}, - {0x3390, 210}, - {0x338C, 0xA77A}, - {0x3390, 220}, - {0x338C, 0xA77B}, - {0x3390, 228}, - {0x338C, 0xA77C}, - {0x3390, 234}, - {0x338C, 0xA77D}, - {0x3390, 240}, - {0x338C, 0xA77E}, - {0x3390, 244}, - {0x338C, 0xA77F}, - {0x3390, 248}, - {0x338C, 0xA780}, - {0x3390, 252}, - {0x338C, 0xA781}, - {0x3390, 255}, - {0x338C, 0xA782}, - {0x3390, 0}, - {0x338C, 0xA783}, - {0x3390, 21}, - {0x338C, 0xA784}, - {0x3390, 37}, - {0x338C, 0xA785}, - {0x3390, 63}, - {0x338C, 0xA786}, - {0x3390, 100}, - {0x338C, 0xA787}, - {0x3390, 128}, - {0x338C, 0xA788}, - {0x3390, 151}, - {0x338C, 0xA789}, - {0x3390, 169}, - {0x338C, 0xA78A}, - {0x3390, 186}, - {0x338C, 0xA78B}, - {0x3390, 199}, - {0x338C, 0xA78C}, - {0x3390, 210}, - {0x338C, 0xA78D}, - {0x3390, 220}, - {0x338C, 0xA78E}, - {0x3390, 228}, - {0x338C, 0xA78F}, - {0x3390, 234}, - {0x338C, 0xA790}, - {0x3390, 240}, - {0x338C, 0xA791}, - {0x3390, 244}, - {0x338C, 0xA793}, - {0x3390, 252}, - {0x338C, 0xA794}, - {0x3390, 255}, - {0x338C, 0xA103}, - {0x3390, 6}, -}; - -static const struct mt9d112_i2c_reg_conf const lens_roll_off_tbl[] = { - { 0x34CE, 0x81A0, WORD_LEN, 0 }, - { 0x34D0, 0x6331, WORD_LEN, 0 }, - { 0x34D2, 0x3394, WORD_LEN, 0 }, - { 0x34D4, 0x9966, WORD_LEN, 0 }, - { 0x34D6, 0x4B25, WORD_LEN, 0 }, - { 0x34D8, 0x2670, WORD_LEN, 0 }, - { 0x34DA, 0x724C, WORD_LEN, 0 }, - { 0x34DC, 0xFFFD, WORD_LEN, 0 }, - { 0x34DE, 0x00CA, WORD_LEN, 0 }, - { 0x34E6, 0x00AC, WORD_LEN, 0 }, - { 0x34EE, 0x0EE1, WORD_LEN, 0 }, - { 0x34F6, 0x0D87, WORD_LEN, 0 }, - { 0x3500, 0xE1F7, WORD_LEN, 0 }, - { 0x3508, 0x1CF4, WORD_LEN, 0 }, - { 0x3510, 0x1D28, WORD_LEN, 0 }, - { 0x3518, 0x1F26, WORD_LEN, 0 }, - { 0x3520, 0x2220, WORD_LEN, 0 }, - { 0x3528, 0x333D, WORD_LEN, 0 }, - { 0x3530, 0x15D9, WORD_LEN, 0 }, - { 0x3538, 0xCFB8, WORD_LEN, 0 }, - { 0x354C, 0x05FE, WORD_LEN, 0 }, - { 0x3544, 0x05F8, WORD_LEN, 0 }, - { 0x355C, 0x0596, WORD_LEN, 0 }, - { 0x3554, 0x0611, WORD_LEN, 0 }, - { 0x34E0, 0x00F2, WORD_LEN, 0 }, - { 0x34E8, 0x00A8, WORD_LEN, 0 }, - { 0x34F0, 0x0F7B, WORD_LEN, 0 }, - { 0x34F8, 0x0CD7, WORD_LEN, 0 }, - { 0x3502, 0xFEDB, WORD_LEN, 0 }, - { 0x350A, 0x13E4, WORD_LEN, 0 }, - { 0x3512, 0x1F2C, WORD_LEN, 0 }, - { 0x351A, 0x1D20, WORD_LEN, 0 }, - { 0x3522, 0x2422, WORD_LEN, 0 }, - { 0x352A, 0x2925, WORD_LEN, 0 }, - { 0x3532, 0x1D04, WORD_LEN, 0 }, - { 0x353A, 0xFBF2, WORD_LEN, 0 }, - { 0x354E, 0x0616, WORD_LEN, 0 }, - { 0x3546, 0x0597, WORD_LEN, 0 }, - { 0x355E, 0x05CD, WORD_LEN, 0 }, - { 0x3556, 0x0529, WORD_LEN, 0 }, - { 0x34E4, 0x00B2, WORD_LEN, 0 }, - { 0x34EC, 0x005E, WORD_LEN, 0 }, - { 0x34F4, 0x0F43, WORD_LEN, 0 }, - { 0x34FC, 0x0E2F, WORD_LEN, 0 }, - { 0x3506, 0xF9FC, WORD_LEN, 0 }, - { 0x350E, 0x0CE4, WORD_LEN, 0 }, - { 0x3516, 0x1E1E, WORD_LEN, 0 }, - { 0x351E, 0x1B19, WORD_LEN, 0 }, - { 0x3526, 0x151B, WORD_LEN, 0 }, - { 0x352E, 0x1416, WORD_LEN, 0 }, - { 0x3536, 0x10FC, WORD_LEN, 0 }, - { 0x353E, 0xC018, WORD_LEN, 0 }, - { 0x3552, 0x06B4, WORD_LEN, 0 }, - { 0x354A, 0x0506, WORD_LEN, 0 }, - { 0x3562, 0x06AB, WORD_LEN, 0 }, - { 0x355A, 0x063A, WORD_LEN, 0 }, - { 0x34E2, 0x00E5, WORD_LEN, 0 }, - { 0x34EA, 0x008B, WORD_LEN, 0 }, - { 0x34F2, 0x0E4C, WORD_LEN, 0 }, - { 0x34FA, 0x0CA3, WORD_LEN, 0 }, - { 0x3504, 0x0907, WORD_LEN, 0 }, - { 0x350C, 0x1DFD, WORD_LEN, 0 }, - { 0x3514, 0x1E24, WORD_LEN, 0 }, - { 0x351C, 0x2529, WORD_LEN, 0 }, - { 0x3524, 0x1D20, WORD_LEN, 0 }, - { 0x352C, 0x2332, WORD_LEN, 0 }, - { 0x3534, 0x10E9, WORD_LEN, 0 }, - { 0x353C, 0x0BCB, WORD_LEN, 0 }, - { 0x3550, 0x04EF, WORD_LEN, 0 }, - { 0x3548, 0x0609, WORD_LEN, 0 }, - { 0x3560, 0x0580, WORD_LEN, 0 }, - { 0x3558, 0x05DD, WORD_LEN, 0 }, - { 0x3540, 0x0000, WORD_LEN, 0 }, - { 0x3542, 0x0000, WORD_LEN, 0 } -}; - -static const struct mt9d112_i2c_reg_conf const pll_setup_tbl[] = { - { 0x341E, 0x8F09, WORD_LEN, 0 }, - { 0x341C, 0x0250, WORD_LEN, 0 }, - { 0x341E, 0x8F09, WORD_LEN, 5 }, - { 0x341E, 0x8F08, WORD_LEN, 0 } -}; - -/* Refresh Sequencer */ -static const struct mt9d112_i2c_reg_conf const sequencer_tbl[] = { - { 0x338C, 0x2799, WORD_LEN, 0}, - { 0x3390, 0x6440, WORD_LEN, 5}, - { 0x338C, 0x279B, WORD_LEN, 0}, - { 0x3390, 0x6440, WORD_LEN, 5}, - { 0x338C, 0xA103, WORD_LEN, 0}, - { 0x3390, 0x0005, WORD_LEN, 5}, - { 0x338C, 0xA103, WORD_LEN, 0}, - { 0x3390, 0x0006, WORD_LEN, 5} -}; - -struct mt9d112_reg mt9d112_regs = { - .prev_snap_reg_settings = &preview_snapshot_mode_reg_settings_array[0], - .prev_snap_reg_settings_size = ARRAY_SIZE(preview_snapshot_mode_reg_settings_array), - .noise_reduction_reg_settings = &noise_reduction_reg_settings_array[0], - .noise_reduction_reg_settings_size = ARRAY_SIZE(noise_reduction_reg_settings_array), - .plltbl = pll_setup_tbl, - .plltbl_size = ARRAY_SIZE(pll_setup_tbl), - .stbl = sequencer_tbl, - .stbl_size = ARRAY_SIZE(sequencer_tbl), - .rftbl = lens_roll_off_tbl, - .rftbl_size = ARRAY_SIZE(lens_roll_off_tbl) -}; - - - diff --git a/drivers/staging/dream/camera/mt9p012.h b/drivers/staging/dream/camera/mt9p012.h deleted file mode 100644 index 678a0027d42e..000000000000 --- a/drivers/staging/dream/camera/mt9p012.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - - -#ifndef MT9T012_H -#define MT9T012_H - -#include <linux/types.h> - -struct reg_struct { - uint16_t vt_pix_clk_div; /* 0x0300 */ - uint16_t vt_sys_clk_div; /* 0x0302 */ - uint16_t pre_pll_clk_div; /* 0x0304 */ - uint16_t pll_multiplier; /* 0x0306 */ - uint16_t op_pix_clk_div; /* 0x0308 */ - uint16_t op_sys_clk_div; /* 0x030A */ - uint16_t scale_m; /* 0x0404 */ - uint16_t row_speed; /* 0x3016 */ - uint16_t x_addr_start; /* 0x3004 */ - uint16_t x_addr_end; /* 0x3008 */ - uint16_t y_addr_start; /* 0x3002 */ - uint16_t y_addr_end; /* 0x3006 */ - uint16_t read_mode; /* 0x3040 */ - uint16_t x_output_size ; /* 0x034C */ - uint16_t y_output_size; /* 0x034E */ - uint16_t line_length_pck; /* 0x300C */ - uint16_t frame_length_lines; /* 0x300A */ - uint16_t coarse_int_time; /* 0x3012 */ - uint16_t fine_int_time; /* 0x3014 */ -}; - - -struct mt9p012_i2c_reg_conf { - unsigned short waddr; - unsigned short wdata; -}; - - -struct mt9p012_reg { - struct reg_struct *reg_pat; - uint16_t reg_pat_size; - struct mt9p012_i2c_reg_conf *ttbl; - uint16_t ttbl_size; - struct mt9p012_i2c_reg_conf *lctbl; - uint16_t lctbl_size; - struct mt9p012_i2c_reg_conf *rftbl; - uint16_t rftbl_size; -}; - -#endif /* MT9T012_H */ diff --git a/drivers/staging/dream/camera/mt9p012_fox.c b/drivers/staging/dream/camera/mt9p012_fox.c deleted file mode 100644 index 791bd6c40615..000000000000 --- a/drivers/staging/dream/camera/mt9p012_fox.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/uaccess.h> -#include <linux/miscdevice.h> -#include <linux/kernel.h> -#include <media/msm_camera.h> -#include <mach/gpio.h> -#include <mach/camera.h> -#include "mt9p012.h" - -/*============================================================= - SENSOR REGISTER DEFINES -==============================================================*/ -#define MT9P012_REG_MODEL_ID 0x0000 -#define MT9P012_MODEL_ID 0x2801 -#define REG_GROUPED_PARAMETER_HOLD 0x0104 -#define GROUPED_PARAMETER_HOLD 0x0100 -#define GROUPED_PARAMETER_UPDATE 0x0000 -#define REG_COARSE_INT_TIME 0x3012 -#define REG_VT_PIX_CLK_DIV 0x0300 -#define REG_VT_SYS_CLK_DIV 0x0302 -#define REG_PRE_PLL_CLK_DIV 0x0304 -#define REG_PLL_MULTIPLIER 0x0306 -#define REG_OP_PIX_CLK_DIV 0x0308 -#define REG_OP_SYS_CLK_DIV 0x030A -#define REG_SCALE_M 0x0404 -#define REG_FRAME_LENGTH_LINES 0x300A -#define REG_LINE_LENGTH_PCK 0x300C -#define REG_X_ADDR_START 0x3004 -#define REG_Y_ADDR_START 0x3002 -#define REG_X_ADDR_END 0x3008 -#define REG_Y_ADDR_END 0x3006 -#define REG_X_OUTPUT_SIZE 0x034C -#define REG_Y_OUTPUT_SIZE 0x034E -#define REG_FINE_INTEGRATION_TIME 0x3014 -#define REG_ROW_SPEED 0x3016 -#define MT9P012_REG_RESET_REGISTER 0x301A -#define MT9P012_RESET_REGISTER_PWON 0x10CC -#define MT9P012_RESET_REGISTER_PWOFF 0x10C8 -#define REG_READ_MODE 0x3040 -#define REG_GLOBAL_GAIN 0x305E -#define REG_TEST_PATTERN_MODE 0x3070 - -#define MT9P012_REV_7 - - -enum mt9p012_test_mode { - TEST_OFF, - TEST_1, - TEST_2, - TEST_3 -}; - -enum mt9p012_resolution { - QTR_SIZE, - FULL_SIZE, - INVALID_SIZE -}; - -enum mt9p012_reg_update { - /* Sensor egisters that need to be updated during initialization */ - REG_INIT, - /* Sensor egisters that needs periodic I2C writes */ - UPDATE_PERIODIC, - /* All the sensor Registers will be updated */ - UPDATE_ALL, - /* Not valid update */ - UPDATE_INVALID -}; - -enum mt9p012_setting { - RES_PREVIEW, - RES_CAPTURE -}; - -/* actuator's Slave Address */ -#define MT9P012_AF_I2C_ADDR 0x18 - -/* AF Total steps parameters */ -#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF 32 -#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR 32 - -#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0 -#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES 0 - -/* Time in milisecs for waiting for the sensor to reset.*/ -#define MT9P012_RESET_DELAY_MSECS 66 - -/* for 20 fps preview */ -#define MT9P012_DEFAULT_CLOCK_RATE 24000000 -#define MT9P012_DEFAULT_MAX_FPS 26 /* ???? */ - -struct mt9p012_work { - struct work_struct work; -}; -static struct mt9p012_work *mt9p012_sensorw; -static struct i2c_client *mt9p012_client; - -struct mt9p012_ctrl { - const struct msm_camera_sensor_info *sensordata; - - int sensormode; - uint32_t fps_divider; /* init to 1 * 0x00000400 */ - uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ - - uint16_t curr_lens_pos; - uint16_t init_curr_lens_pos; - uint16_t my_reg_gain; - uint32_t my_reg_line_count; - - enum mt9p012_resolution prev_res; - enum mt9p012_resolution pict_res; - enum mt9p012_resolution curr_res; - enum mt9p012_test_mode set_test; -}; - - -static struct mt9p012_ctrl *mt9p012_ctrl; -static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue); -DECLARE_MUTEX(mt9p012_sem); - -/*============================================================= - EXTERNAL DECLARATIONS -==============================================================*/ -extern struct mt9p012_reg mt9p012_regs; /* from mt9p012_reg.c */ - - - -/*=============================================================*/ - -static int mt9p012_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, - int length) -{ - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = 2, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = length, - .buf = rxdata, - }, - }; - - if (i2c_transfer(mt9p012_client->adapter, msgs, 2) < 0) { - CDBG("mt9p012_i2c_rxdata failed!\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr, - unsigned short *rdata) -{ - int32_t rc = 0; - unsigned char buf[4]; - - if (!rdata) - return -EIO; - - memset(buf, 0, sizeof(buf)); - - buf[0] = (raddr & 0xFF00)>>8; - buf[1] = (raddr & 0x00FF); - - rc = mt9p012_i2c_rxdata(saddr, buf, 2); - if (rc < 0) - return rc; - - *rdata = buf[0] << 8 | buf[1]; - - if (rc < 0) - CDBG("mt9p012_i2c_read failed!\n"); - - return rc; -} - -static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata, - int length) -{ - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - - if (i2c_transfer(mt9p012_client->adapter, msg, 1) < 0) { - CDBG("mt9p012_i2c_txdata failed\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr, - unsigned short bdata) -{ - int32_t rc = -EIO; - unsigned char buf[2]; - - memset(buf, 0, sizeof(buf)); - buf[0] = baddr; - buf[1] = bdata; - rc = mt9p012_i2c_txdata(saddr, buf, 2); - - if (rc < 0) - CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n", - saddr, baddr, bdata); - - return rc; -} - -static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr, - unsigned short wdata) -{ - int32_t rc = -EIO; - unsigned char buf[4]; - - memset(buf, 0, sizeof(buf)); - buf[0] = (waddr & 0xFF00)>>8; - buf[1] = (waddr & 0x00FF); - buf[2] = (wdata & 0xFF00)>>8; - buf[3] = (wdata & 0x00FF); - - rc = mt9p012_i2c_txdata(saddr, buf, 4); - - if (rc < 0) - CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", - waddr, wdata); - - return rc; -} - -static int32_t mt9p012_i2c_write_w_table( - struct mt9p012_i2c_reg_conf *reg_conf_tbl, int num) -{ - int i; - int32_t rc = -EIO; - - for (i = 0; i < num; i++) { - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - reg_conf_tbl->waddr, reg_conf_tbl->wdata); - if (rc < 0) - break; - reg_conf_tbl++; - } - - return rc; -} - -static int32_t mt9p012_test(enum mt9p012_test_mode mo) -{ - int32_t rc = 0; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - if (mo == TEST_OFF) - return 0; - else { - rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl, mt9p012_regs.ttbl_size); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_TEST_PATTERN_MODE, (uint16_t)mo); - if (rc < 0) - return rc; - } - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - return rc; -} - -static int32_t mt9p012_lens_shading_enable(uint8_t is_enable) -{ - int32_t rc = 0; - - CDBG("%s: entered. enable = %d\n", __func__, is_enable); - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780, - ((uint16_t) is_enable) << 15); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE); - - CDBG("%s: exiting. rc = %d\n", __func__, rc); - return rc; -} - -static int32_t mt9p012_set_lc(void) -{ - int32_t rc; - - rc = mt9p012_i2c_write_w_table(mt9p012_regs.lctbl, mt9p012_regs.lctbl_size); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl, mt9p012_regs.rftbl_size); - - return rc; -} - -static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps) -{ - /* input fps is preview fps in Q8 format */ - uint32_t divider; /*Q10 */ - uint32_t pclk_mult; /*Q10 */ - - if (mt9p012_ctrl->prev_res == QTR_SIZE) { - divider = (uint32_t) - (((mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines * - mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck) * 0x00000400) / - (mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines * - mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck)); - - pclk_mult = - (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].pll_multiplier * - 0x00000400) / (mt9p012_regs.reg_pat[RES_PREVIEW].pll_multiplier)); - } else { - /* full size resolution used for preview. */ - divider = 0x00000400; /*1.0 */ - pclk_mult = 0x00000400; /*1.0 */ - } - - /* Verify PCLK settings and frame sizes. */ - *pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 / - 0x00000400); -} - -static uint16_t mt9p012_get_prev_lines_pf(void) -{ - if (mt9p012_ctrl->prev_res == QTR_SIZE) - return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines; - else - return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; -} - -static uint16_t mt9p012_get_prev_pixels_pl(void) -{ - if (mt9p012_ctrl->prev_res == QTR_SIZE) - return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck; - else - return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; -} - -static uint16_t mt9p012_get_pict_lines_pf(void) -{ - return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines; -} - -static uint16_t mt9p012_get_pict_pixels_pl(void) -{ - return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck; -} - -static uint32_t mt9p012_get_pict_max_exp_lc(void) -{ - uint16_t snapshot_lines_per_frame; - - if (mt9p012_ctrl->pict_res == QTR_SIZE) - snapshot_lines_per_frame = - mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; - else - snapshot_lines_per_frame = - mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; - - return snapshot_lines_per_frame * 24; -} - -static int32_t mt9p012_set_fps(struct fps_cfg *fps) -{ - /* input is new fps in Q10 format */ - int32_t rc = 0; - - mt9p012_ctrl->fps_divider = fps->fps_div; - mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div; - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return -EBUSY; - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_LINE_LENGTH_PCK, - (mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck * - fps->f_mult / 0x00000400)); - if (rc < 0) - return rc; - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - - return rc; -} - -static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line) -{ - uint16_t max_legal_gain = 0x01FF; - uint32_t line_length_ratio = 0x00000400; - enum mt9p012_setting setting; - int32_t rc = 0; - - CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__); - - if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) { - mt9p012_ctrl->my_reg_gain = gain; - mt9p012_ctrl->my_reg_line_count = (uint16_t)line; - } - - if (gain > max_legal_gain) { - CDBG("Max legal gain Line:%d \n", __LINE__); - gain = max_legal_gain; - } - - /* Verify no overflow */ - if (mt9p012_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { - line = (uint32_t)(line * mt9p012_ctrl->fps_divider / - 0x00000400); - setting = RES_PREVIEW; - } else { - line = (uint32_t)(line * mt9p012_ctrl->pict_fps_divider / - 0x00000400); - setting = RES_CAPTURE; - } - - /* Set digital gain to 1 */ -#ifdef MT9P012_REV_7 - gain |= 0x1000; -#else - gain |= 0x0200; -#endif - - if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) { - line_length_ratio = (uint32_t) (line * 0x00000400) / - (mt9p012_regs.reg_pat[setting].frame_length_lines - 1); - } else - line_length_ratio = 0x00000400; - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) { - CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); - return rc; - } - - rc = - mt9p012_i2c_write_w( - mt9p012_client->addr, - REG_GLOBAL_GAIN, gain); - if (rc < 0) { - CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); - return rc; - } - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_COARSE_INT_TIME, - line); - if (rc < 0) { - CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); - return rc; - } - - CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line); - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); - - return rc; -} - -static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line) -{ - int32_t rc = 0; - - CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__); - - rc = - mt9p012_write_exp_gain(gain, line); - if (rc < 0) { - CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n", - __LINE__); - return rc; - } - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, - 0x10CC | 0x0002); - if (rc < 0) { - CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__); - return rc; - } - - mdelay(5); - - /* camera_timed_wait(snapshot_wait*exposure_ratio); */ - return rc; -} - -static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate, - enum mt9p012_setting rt) -{ - int32_t rc = 0; - - switch (rupdate) { - case UPDATE_PERIODIC: - if (rt == RES_PREVIEW || rt == RES_CAPTURE) { - - struct mt9p012_i2c_reg_conf ppc_tbl[] = { - {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD}, - {REG_ROW_SPEED, mt9p012_regs.reg_pat[rt].row_speed}, - {REG_X_ADDR_START, mt9p012_regs.reg_pat[rt].x_addr_start}, - {REG_X_ADDR_END, mt9p012_regs.reg_pat[rt].x_addr_end}, - {REG_Y_ADDR_START, mt9p012_regs.reg_pat[rt].y_addr_start}, - {REG_Y_ADDR_END, mt9p012_regs.reg_pat[rt].y_addr_end}, - {REG_READ_MODE, mt9p012_regs.reg_pat[rt].read_mode}, - {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, - {REG_X_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].x_output_size}, - {REG_Y_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].y_output_size}, - - {REG_LINE_LENGTH_PCK, mt9p012_regs.reg_pat[rt].line_length_pck}, - {REG_FRAME_LENGTH_LINES, - (mt9p012_regs.reg_pat[rt].frame_length_lines * - mt9p012_ctrl->fps_divider / 0x00000400)}, - {REG_COARSE_INT_TIME, mt9p012_regs.reg_pat[rt].coarse_int_time}, - {REG_FINE_INTEGRATION_TIME, mt9p012_regs.reg_pat[rt].fine_int_time}, - {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE}, - }; - - rc = mt9p012_i2c_write_w_table(&ppc_tbl[0], - ARRAY_SIZE(ppc_tbl)); - if (rc < 0) - return rc; - - rc = mt9p012_test(mt9p012_ctrl->set_test); - if (rc < 0) - return rc; - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, - MT9P012_RESET_REGISTER_PWON | 0x0002); - if (rc < 0) - return rc; - - mdelay(5); /* 15? wait for sensor to transition*/ - - return rc; - } - break; /* UPDATE_PERIODIC */ - - case REG_INIT: - if (rt == RES_PREVIEW || rt == RES_CAPTURE) { - struct mt9p012_i2c_reg_conf ipc_tbl1[] = { - {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWOFF}, - {REG_VT_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, - {REG_VT_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, - {REG_PRE_PLL_CLK_DIV, mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, - {REG_PLL_MULTIPLIER, mt9p012_regs.reg_pat[rt].pll_multiplier}, - {REG_OP_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].op_pix_clk_div}, - {REG_OP_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].op_sys_clk_div}, -#ifdef MT9P012_REV_7 - {0x30B0, 0x0001}, - {0x308E, 0xE060}, - {0x3092, 0x0A52}, - {0x3094, 0x4656}, - {0x3096, 0x5652}, - {0x30CA, 0x8006}, - {0x312A, 0xDD02}, - {0x312C, 0x00E4}, - {0x3170, 0x299A}, -#endif - /* optimized settings for noise */ - {0x3088, 0x6FF6}, - {0x3154, 0x0282}, - {0x3156, 0x0381}, - {0x3162, 0x04CE}, - {0x0204, 0x0010}, - {0x0206, 0x0010}, - {0x0208, 0x0010}, - {0x020A, 0x0010}, - {0x020C, 0x0010}, - {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON}, - }; - - struct mt9p012_i2c_reg_conf ipc_tbl2[] = { - {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWOFF}, - {REG_VT_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_pix_clk_div}, - {REG_VT_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_sys_clk_div}, - {REG_PRE_PLL_CLK_DIV, mt9p012_regs.reg_pat[rt].pre_pll_clk_div}, - {REG_PLL_MULTIPLIER, mt9p012_regs.reg_pat[rt].pll_multiplier}, - {REG_OP_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].op_pix_clk_div}, - {REG_OP_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].op_sys_clk_div}, -#ifdef MT9P012_REV_7 - {0x30B0, 0x0001}, - {0x308E, 0xE060}, - {0x3092, 0x0A52}, - {0x3094, 0x4656}, - {0x3096, 0x5652}, - {0x30CA, 0x8006}, - {0x312A, 0xDD02}, - {0x312C, 0x00E4}, - {0x3170, 0x299A}, -#endif - /* optimized settings for noise */ - {0x3088, 0x6FF6}, - {0x3154, 0x0282}, - {0x3156, 0x0381}, - {0x3162, 0x04CE}, - {0x0204, 0x0010}, - {0x0206, 0x0010}, - {0x0208, 0x0010}, - {0x020A, 0x0010}, - {0x020C, 0x0010}, - {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON}, - }; - - struct mt9p012_i2c_reg_conf ipc_tbl3[] = { - {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD}, - /* Set preview or snapshot mode */ - {REG_ROW_SPEED, mt9p012_regs.reg_pat[rt].row_speed}, - {REG_X_ADDR_START, mt9p012_regs.reg_pat[rt].x_addr_start}, - {REG_X_ADDR_END, mt9p012_regs.reg_pat[rt].x_addr_end}, - {REG_Y_ADDR_START, mt9p012_regs.reg_pat[rt].y_addr_start}, - {REG_Y_ADDR_END, mt9p012_regs.reg_pat[rt].y_addr_end}, - {REG_READ_MODE, mt9p012_regs.reg_pat[rt].read_mode}, - {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m}, - {REG_X_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].x_output_size}, - {REG_Y_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].y_output_size}, - {REG_LINE_LENGTH_PCK, mt9p012_regs.reg_pat[rt].line_length_pck}, - {REG_FRAME_LENGTH_LINES, - mt9p012_regs.reg_pat[rt].frame_length_lines}, - {REG_COARSE_INT_TIME, mt9p012_regs.reg_pat[rt].coarse_int_time}, - {REG_FINE_INTEGRATION_TIME, mt9p012_regs.reg_pat[rt].fine_int_time}, - {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE}, - }; - - /* reset fps_divider */ - mt9p012_ctrl->fps_divider = 1 * 0x0400; - - rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0], - ARRAY_SIZE(ipc_tbl1)); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0], - ARRAY_SIZE(ipc_tbl2)); - if (rc < 0) - return rc; - - mdelay(5); - - rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0], - ARRAY_SIZE(ipc_tbl3)); - if (rc < 0) - return rc; - - /* load lens shading */ - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - rc = mt9p012_set_lc(); - if (rc < 0) - return rc; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE); - - if (rc < 0) - return rc; - } - break; /* case REG_INIT: */ - - default: - rc = -EINVAL; - break; - } /* switch (rupdate) */ - - return rc; -} - -static int32_t mt9p012_video_config(int mode, int res) -{ - int32_t rc; - - switch (res) { - case QTR_SIZE: - rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW); - if (rc < 0) - return rc; - - CDBG("mt9p012 sensor configuration done!\n"); - break; - - case FULL_SIZE: - rc = - mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - - break; - - default: - return 0; - } /* switch */ - - mt9p012_ctrl->prev_res = res; - mt9p012_ctrl->curr_res = res; - mt9p012_ctrl->sensormode = mode; - - rc = - mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain, - mt9p012_ctrl->my_reg_line_count); - - rc = - mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, - 0x10cc|0x0002); - - return rc; -} - -static int32_t mt9p012_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - - mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; - - mt9p012_ctrl->sensormode = mode; - - return rc; -} - -static int32_t mt9p012_raw_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - - mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res; - - mt9p012_ctrl->sensormode = mode; - - return rc; -} - -static int32_t mt9p012_power_down(void) -{ - int32_t rc = 0; - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, - MT9P012_RESET_REGISTER_PWOFF); - - mdelay(5); - return rc; -} - -static int32_t mt9p012_move_focus(int direction, int32_t num_steps) -{ - int16_t step_direction; - int16_t actual_step; - int16_t next_position; - uint8_t code_val_msb, code_val_lsb; - - if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR) - num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR; - else if (num_steps == 0) { - CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); - return -EINVAL; - } - - if (direction == MOVE_NEAR) - step_direction = 16; /* 10bit */ - else if (direction == MOVE_FAR) - step_direction = -16; /* 10 bit */ - else { - CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); - return -EINVAL; - } - - if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos) - mt9p012_ctrl->curr_lens_pos = - mt9p012_ctrl->init_curr_lens_pos; - - actual_step = (int16_t)(step_direction * (int16_t)num_steps); - next_position = (int16_t)(mt9p012_ctrl->curr_lens_pos + actual_step); - - if (next_position > 1023) - next_position = 1023; - else if (next_position < 0) - next_position = 0; - - code_val_msb = next_position >> 4; - code_val_lsb = (next_position & 0x000F) << 4; - /* code_val_lsb |= mode_mask; */ - - /* Writing the digital code for current to the actuator */ - if (mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, - code_val_msb, code_val_lsb) < 0) { - CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__); - return -EBUSY; - } - - /* Storing the current lens Position */ - mt9p012_ctrl->curr_lens_pos = next_position; - - return 0; -} - -static int32_t mt9p012_set_default_focus(void) -{ - int32_t rc = 0; - uint8_t code_val_msb, code_val_lsb; - - code_val_msb = 0x00; - code_val_lsb = 0x00; - - /* Write the digital code for current to the actuator */ - rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, - code_val_msb, code_val_lsb); - - mt9p012_ctrl->curr_lens_pos = 0; - mt9p012_ctrl->init_curr_lens_pos = 0; - - return rc; -} - -static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data) -{ - gpio_direction_output(data->sensor_reset, 0); - gpio_free(data->sensor_reset); - return 0; -} - -static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data) -{ - int32_t rc; - uint16_t chipid; - - rc = gpio_request(data->sensor_reset, "mt9p012"); - if (!rc) - gpio_direction_output(data->sensor_reset, 1); - else - goto init_probe_done; - - mdelay(20); - - /* RESET the sensor image part via I2C command */ - CDBG("mt9p012_sensor_init(): reseting sensor.\n"); - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, 0x10CC|0x0001); - if (rc < 0) { - CDBG("sensor reset failed. rc = %d\n", rc); - goto init_probe_fail; - } - - mdelay(MT9P012_RESET_DELAY_MSECS); - - /* 3. Read sensor Model ID: */ - rc = mt9p012_i2c_read_w(mt9p012_client->addr, - MT9P012_REG_MODEL_ID, &chipid); - if (rc < 0) - goto init_probe_fail; - - /* 4. Compare sensor ID to MT9T012VC ID: */ - if (chipid != MT9P012_MODEL_ID) { - CDBG("mt9p012 wrong model_id = 0x%x\n", chipid); - rc = -ENODEV; - goto init_probe_fail; - } - - rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000); - if (rc < 0) { - CDBG("REV_7 write failed. rc = %d\n", rc); - goto init_probe_fail; - } - - /* RESET_REGISTER, enable parallel interface and disable serialiser */ - CDBG("mt9p012_sensor_init(): enabling parallel interface.\n"); - rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC); - if (rc < 0) { - CDBG("enable parallel interface failed. rc = %d\n", rc); - goto init_probe_fail; - } - - /* To disable the 2 extra lines */ - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - 0x3064, 0x0805); - - if (rc < 0) { - CDBG("disable the 2 extra lines failed. rc = %d\n", rc); - goto init_probe_fail; - } - - mdelay(MT9P012_RESET_DELAY_MSECS); - goto init_probe_done; - -init_probe_fail: - mt9p012_probe_init_done(data); -init_probe_done: - return rc; -} - -static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data) -{ - int32_t rc; - - mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL); - if (!mt9p012_ctrl) { - CDBG("mt9p012_init failed!\n"); - rc = -ENOMEM; - goto init_done; - } - - mt9p012_ctrl->fps_divider = 1 * 0x00000400; - mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400; - mt9p012_ctrl->set_test = TEST_OFF; - mt9p012_ctrl->prev_res = QTR_SIZE; - mt9p012_ctrl->pict_res = FULL_SIZE; - - if (data) - mt9p012_ctrl->sensordata = data; - - /* enable mclk first */ - msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE); - mdelay(20); - - msm_camio_camif_pad_reg_reset(); - mdelay(20); - - rc = mt9p012_probe_init_sensor(data); - if (rc < 0) - goto init_fail1; - - if (mt9p012_ctrl->prev_res == QTR_SIZE) - rc = mt9p012_setting(REG_INIT, RES_PREVIEW); - else - rc = mt9p012_setting(REG_INIT, RES_CAPTURE); - - if (rc < 0) { - CDBG("mt9p012_setting failed. rc = %d\n", rc); - goto init_fail1; - } - - /* sensor : output enable */ - CDBG("mt9p012_sensor_open_init(): enabling output.\n"); - rc = mt9p012_i2c_write_w(mt9p012_client->addr, - MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON); - if (rc < 0) { - CDBG("sensor output enable failed. rc = %d\n", rc); - goto init_fail1; - } - - /* TODO: enable AF actuator */ -#if 0 - CDBG("enable AF actuator, gpio = %d\n", - mt9p012_ctrl->sensordata->vcm_pwd); - rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, "mt9p012"); - if (!rc) - gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 1); - else { - CDBG("mt9p012_ctrl gpio request failed!\n"); - goto init_fail1; - } - mdelay(20); - - rc = mt9p012_set_default_focus(); -#endif - if (rc >= 0) - goto init_done; - - /* TODO: - * gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0); - * gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); */ -init_fail1: - mt9p012_probe_init_done(data); - kfree(mt9p012_ctrl); -init_done: - return rc; -} - -static int mt9p012_init_client(struct i2c_client *client) -{ - /* Initialize the MSM_CAMI2C Chip */ - init_waitqueue_head(&mt9p012_wait_queue); - return 0; -} - -static int32_t mt9p012_set_sensor_mode(int mode, int res) -{ - int32_t rc = 0; - - switch (mode) { - case SENSOR_PREVIEW_MODE: - rc = mt9p012_video_config(mode, res); - break; - - case SENSOR_SNAPSHOT_MODE: - rc = mt9p012_snapshot_config(mode); - break; - - case SENSOR_RAW_SNAPSHOT_MODE: - rc = mt9p012_raw_snapshot_config(mode); - break; - - default: - rc = -EINVAL; - break; - } - - return rc; -} - -int mt9p012_sensor_config(void __user *argp) -{ - struct sensor_cfg_data cdata; - int rc = 0; - - if (copy_from_user(&cdata, - (void *)argp, - sizeof(struct sensor_cfg_data))) - return -EFAULT; - - down(&mt9p012_sem); - - CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); - switch (cdata.cfgtype) { - case CFG_GET_PICT_FPS: - mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps, - &(cdata.cfg.gfps.pictfps)); - - if (copy_to_user((void *)argp, &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_L_PF: - cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_P_PL: - cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_L_PF: - cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_P_PL: - cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_MAX_EXP_LC: - cdata.cfg.pict_max_exp_lc = - mt9p012_get_pict_max_exp_lc(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_SET_FPS: - case CFG_SET_PICT_FPS: - rc = mt9p012_set_fps(&(cdata.cfg.fps)); - break; - - case CFG_SET_EXP_GAIN: - rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_PICT_EXP_GAIN: - CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); - rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_MODE: - rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs); - break; - - case CFG_PWR_DOWN: - rc = mt9p012_power_down(); - break; - - case CFG_MOVE_FOCUS: - CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d cdata.cfg.focus.steps=%d\n", - cdata.cfg.focus.dir, cdata.cfg.focus.steps); - rc = mt9p012_move_focus(cdata.cfg.focus.dir, - cdata.cfg.focus.steps); - break; - - case CFG_SET_DEFAULT_FOCUS: - rc = mt9p012_set_default_focus(); - break; - - case CFG_SET_LENS_SHADING: - CDBG("%s: CFG_SET_LENS_SHADING\n", __func__); - rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading); - break; - - case CFG_GET_AF_MAX_STEPS: - cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF; - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_SET_EFFECT: - default: - rc = -EINVAL; - break; - } - - up(&mt9p012_sem); - return rc; -} - -int mt9p012_sensor_release(void) -{ - int rc = -EBADF; - - down(&mt9p012_sem); - - mt9p012_power_down(); - - gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, - 0); - gpio_free(mt9p012_ctrl->sensordata->sensor_reset); - - gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0); - gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); - - kfree(mt9p012_ctrl); - mt9p012_ctrl = NULL; - - CDBG("mt9p012_release completed\n"); - - up(&mt9p012_sem); - return rc; -} - -static int mt9p012_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - CDBG("mt9p012_probe called!\n"); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - CDBG("i2c_check_functionality failed\n"); - goto probe_failure; - } - - mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL); - if (!mt9p012_sensorw) { - CDBG("kzalloc failed.\n"); - rc = -ENOMEM; - goto probe_failure; - } - - i2c_set_clientdata(client, mt9p012_sensorw); - mt9p012_init_client(client); - mt9p012_client = client; - - mdelay(50); - - CDBG("mt9p012_probe successed! rc = %d\n", rc); - return 0; - -probe_failure: - CDBG("mt9p012_probe failed! rc = %d\n", rc); - return rc; -} - -static const struct i2c_device_id mt9p012_i2c_id[] = { - { "mt9p012", 0}, - { } -}; - -static struct i2c_driver mt9p012_i2c_driver = { - .id_table = mt9p012_i2c_id, - .probe = mt9p012_i2c_probe, - .remove = __exit_p(mt9p012_i2c_remove), - .driver = { - .name = "mt9p012", - }, -}; - -static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info, - struct msm_sensor_ctrl *s) -{ - int rc = i2c_add_driver(&mt9p012_i2c_driver); - if (rc < 0 || mt9p012_client == NULL) { - rc = -ENOTSUPP; - goto probe_done; - } - - msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE); - mdelay(20); - - rc = mt9p012_probe_init_sensor(info); - if (rc < 0) - goto probe_done; - - s->s_init = mt9p012_sensor_open_init; - s->s_release = mt9p012_sensor_release; - s->s_config = mt9p012_sensor_config; - mt9p012_probe_init_done(info); - -probe_done: - CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__); - return rc; -} - -static int __mt9p012_probe(struct platform_device *pdev) -{ - return msm_camera_drv_start(pdev, mt9p012_sensor_probe); -} - -static struct platform_driver msm_camera_driver = { - .probe = __mt9p012_probe, - .driver = { - .name = "msm_camera_mt9p012", - .owner = THIS_MODULE, - }, -}; - -static int __init mt9p012_init(void) -{ - return platform_driver_register(&msm_camera_driver); -} - -module_init(mt9p012_init); diff --git a/drivers/staging/dream/camera/mt9p012_reg.c b/drivers/staging/dream/camera/mt9p012_reg.c deleted file mode 100644 index e5223d693b2c..000000000000 --- a/drivers/staging/dream/camera/mt9p012_reg.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2009 QUALCOMM Incorporated. - */ - -#include "mt9p012.h" -#include <linux/kernel.h> - -/*Micron settings from Applications for lower power consumption.*/ -struct reg_struct mt9p012_reg_pat[2] = { - { /* Preview */ - /* vt_pix_clk_div REG=0x0300 */ - 6, /* 5 */ - - /* vt_sys_clk_div REG=0x0302 */ - 1, - - /* pre_pll_clk_div REG=0x0304 */ - 2, - - /* pll_multiplier REG=0x0306 */ - 60, - - /* op_pix_clk_div REG=0x0308 */ - 8, /* 10 */ - - /* op_sys_clk_div REG=0x030A */ - 1, - - /* scale_m REG=0x0404 */ - 16, - - /* row_speed REG=0x3016 */ - 0x0111, - - /* x_addr_start REG=0x3004 */ - 8, - - /* x_addr_end REG=0x3008 */ - 2597, - - /* y_addr_start REG=0x3002 */ - 8, - - /* y_addr_end REG=0x3006 */ - 1949, - - /* read_mode REG=0x3040 - * Preview 2x2 skipping */ - 0x00C3, - - /* x_output_size REG=0x034C */ - 1296, - - /* y_output_size REG=0x034E */ - 972, - - /* line_length_pck REG=0x300C */ - 3784, - - /* frame_length_lines REG=0x300A */ - 1057, - - /* coarse_integration_time REG=0x3012 */ - 16, - - /* fine_integration_time REG=0x3014 */ - 1764 - }, - { /*Snapshot*/ - /* vt_pix_clk_div REG=0x0300 */ - 6, - - /* vt_sys_clk_div REG=0x0302 */ - 1, - - /* pre_pll_clk_div REG=0x0304 */ - 2, - - /* pll_multiplier REG=0x0306 - * 60 for 10fps snapshot */ - 60, - - /* op_pix_clk_div REG=0x0308 */ - 8, - - /* op_sys_clk_div REG=0x030A */ - 1, - - /* scale_m REG=0x0404 */ - 16, - - /* row_speed REG=0x3016 */ - 0x0111, - - /* x_addr_start REG=0x3004 */ - 8, - - /* x_addr_end REG=0x3008 */ - 2615, - - /* y_addr_start REG=0x3002 */ - 8, - - /* y_addr_end REG=0x3006 */ - 1967, - - /* read_mode REG=0x3040 */ - 0x0041, - - /* x_output_size REG=0x034C */ - 2608, - - /* y_output_size REG=0x034E */ - 1960, - - /* line_length_pck REG=0x300C */ - 3911, - - /* frame_length_lines REG=0x300A //10 fps snapshot */ - 2045, - - /* coarse_integration_time REG=0x3012 */ - 16, - - /* fine_integration_time REG=0x3014 */ - 882 - } -}; - - -struct mt9p012_i2c_reg_conf mt9p012_test_tbl[] = { - {0x3044, 0x0544 & 0xFBFF}, - {0x30CA, 0x0004 | 0x0001}, - {0x30D4, 0x9020 & 0x7FFF}, - {0x31E0, 0x0003 & 0xFFFE}, - {0x3180, 0x91FF & 0x7FFF}, - {0x301A, (0x10CC | 0x8000) & 0xFFF7}, - {0x301E, 0x0000}, - {0x3780, 0x0000}, -}; - - -struct mt9p012_i2c_reg_conf mt9p012_lc_tbl[] = { - /* [Lens shading 85 Percent TL84] */ - /* P_RD_P0Q0 */ - {0x360A, 0x7FEF}, - /* P_RD_P0Q1 */ - {0x360C, 0x232C}, - /* P_RD_P0Q2 */ - {0x360E, 0x7050}, - /* P_RD_P0Q3 */ - {0x3610, 0xF3CC}, - /* P_RD_P0Q4 */ - {0x3612, 0x89D1}, - /* P_RD_P1Q0 */ - {0x364A, 0xBE0D}, - /* P_RD_P1Q1 */ - {0x364C, 0x9ACB}, - /* P_RD_P1Q2 */ - {0x364E, 0x2150}, - /* P_RD_P1Q3 */ - {0x3650, 0xB26B}, - /* P_RD_P1Q4 */ - {0x3652, 0x9511}, - /* P_RD_P2Q0 */ - {0x368A, 0x2151}, - /* P_RD_P2Q1 */ - {0x368C, 0x00AD}, - /* P_RD_P2Q2 */ - {0x368E, 0x8334}, - /* P_RD_P2Q3 */ - {0x3690, 0x478E}, - /* P_RD_P2Q4 */ - {0x3692, 0x0515}, - /* P_RD_P3Q0 */ - {0x36CA, 0x0710}, - /* P_RD_P3Q1 */ - {0x36CC, 0x452D}, - /* P_RD_P3Q2 */ - {0x36CE, 0xF352}, - /* P_RD_P3Q3 */ - {0x36D0, 0x190F}, - /* P_RD_P3Q4 */ - {0x36D2, 0x4413}, - /* P_RD_P4Q0 */ - {0x370A, 0xD112}, - /* P_RD_P4Q1 */ - {0x370C, 0xF50F}, - /* P_RD_P4Q2 */ - {0x370C, 0xF50F}, - /* P_RD_P4Q3 */ - {0x3710, 0xDC11}, - /* P_RD_P4Q4 */ - {0x3712, 0xD776}, - /* P_GR_P0Q0 */ - {0x3600, 0x1750}, - /* P_GR_P0Q1 */ - {0x3602, 0xF0AC}, - /* P_GR_P0Q2 */ - {0x3604, 0x4711}, - /* P_GR_P0Q3 */ - {0x3606, 0x07CE}, - /* P_GR_P0Q4 */ - {0x3608, 0x96B2}, - /* P_GR_P1Q0 */ - {0x3640, 0xA9AE}, - /* P_GR_P1Q1 */ - {0x3642, 0xF9AC}, - /* P_GR_P1Q2 */ - {0x3644, 0x39F1}, - /* P_GR_P1Q3 */ - {0x3646, 0x016F}, - /* P_GR_P1Q4 */ - {0x3648, 0x8AB2}, - /* P_GR_P2Q0 */ - {0x3680, 0x1752}, - /* P_GR_P2Q1 */ - {0x3682, 0x70F0}, - /* P_GR_P2Q2 */ - {0x3684, 0x83F5}, - /* P_GR_P2Q3 */ - {0x3686, 0x8392}, - /* P_GR_P2Q4 */ - {0x3688, 0x1FD6}, - /* P_GR_P3Q0 */ - {0x36C0, 0x1131}, - /* P_GR_P3Q1 */ - {0x36C2, 0x3DAF}, - /* P_GR_P3Q2 */ - {0x36C4, 0x89B4}, - /* P_GR_P3Q3 */ - {0x36C6, 0xA391}, - /* P_GR_P3Q4 */ - {0x36C8, 0x1334}, - /* P_GR_P4Q0 */ - {0x3700, 0xDC13}, - /* P_GR_P4Q1 */ - {0x3702, 0xD052}, - /* P_GR_P4Q2 */ - {0x3704, 0x5156}, - /* P_GR_P4Q3 */ - {0x3706, 0x1F13}, - /* P_GR_P4Q4 */ - {0x3708, 0x8C38}, - /* P_BL_P0Q0 */ - {0x3614, 0x0050}, - /* P_BL_P0Q1 */ - {0x3616, 0xBD4C}, - /* P_BL_P0Q2 */ - {0x3618, 0x41B0}, - /* P_BL_P0Q3 */ - {0x361A, 0x660D}, - /* P_BL_P0Q4 */ - {0x361C, 0xC590}, - /* P_BL_P1Q0 */ - {0x3654, 0x87EC}, - /* P_BL_P1Q1 */ - {0x3656, 0xE44C}, - /* P_BL_P1Q2 */ - {0x3658, 0x302E}, - /* P_BL_P1Q3 */ - {0x365A, 0x106E}, - /* P_BL_P1Q4 */ - {0x365C, 0xB58E}, - /* P_BL_P2Q0 */ - {0x3694, 0x0DD1}, - /* P_BL_P2Q1 */ - {0x3696, 0x2A50}, - /* P_BL_P2Q2 */ - {0x3698, 0xC793}, - /* P_BL_P2Q3 */ - {0x369A, 0xE8F1}, - /* P_BL_P2Q4 */ - {0x369C, 0x4174}, - /* P_BL_P3Q0 */ - {0x36D4, 0x01EF}, - /* P_BL_P3Q1 */ - {0x36D6, 0x06CF}, - /* P_BL_P3Q2 */ - {0x36D8, 0x8D91}, - /* P_BL_P3Q3 */ - {0x36DA, 0x91F0}, - /* P_BL_P3Q4 */ - {0x36DC, 0x52EF}, - /* P_BL_P4Q0 */ - {0x3714, 0xA6D2}, - /* P_BL_P4Q1 */ - {0x3716, 0xA312}, - /* P_BL_P4Q2 */ - {0x3718, 0x2695}, - /* P_BL_P4Q3 */ - {0x371A, 0x3953}, - /* P_BL_P4Q4 */ - {0x371C, 0x9356}, - /* P_GB_P0Q0 */ - {0x361E, 0x7EAF}, - /* P_GB_P0Q1 */ - {0x3620, 0x2A4C}, - /* P_GB_P0Q2 */ - {0x3622, 0x49F0}, - {0x3624, 0xF1EC}, - /* P_GB_P0Q4 */ - {0x3626, 0xC670}, - /* P_GB_P1Q0 */ - {0x365E, 0x8E0C}, - /* P_GB_P1Q1 */ - {0x3660, 0xC2A9}, - /* P_GB_P1Q2 */ - {0x3662, 0x274F}, - /* P_GB_P1Q3 */ - {0x3664, 0xADAB}, - /* P_GB_P1Q4 */ - {0x3666, 0x8EF0}, - /* P_GB_P2Q0 */ - {0x369E, 0x09B1}, - /* P_GB_P2Q1 */ - {0x36A0, 0xAA2E}, - /* P_GB_P2Q2 */ - {0x36A2, 0xC3D3}, - /* P_GB_P2Q3 */ - {0x36A4, 0x7FAF}, - /* P_GB_P2Q4 */ - {0x36A6, 0x3F34}, - /* P_GB_P3Q0 */ - {0x36DE, 0x4C8F}, - /* P_GB_P3Q1 */ - {0x36E0, 0x886E}, - /* P_GB_P3Q2 */ - {0x36E2, 0xE831}, - /* P_GB_P3Q3 */ - {0x36E4, 0x1FD0}, - /* P_GB_P3Q4 */ - {0x36E6, 0x1192}, - /* P_GB_P4Q0 */ - {0x371E, 0xB952}, - /* P_GB_P4Q1 */ - {0x3720, 0x6DCF}, - /* P_GB_P4Q2 */ - {0x3722, 0x1B55}, - /* P_GB_P4Q3 */ - {0x3724, 0xA112}, - /* P_GB_P4Q4 */ - {0x3726, 0x82F6}, - /* POLY_ORIGIN_C */ - {0x3782, 0x0510}, - /* POLY_ORIGIN_R */ - {0x3784, 0x0390}, - /* POLY_SC_ENABLE */ - {0x3780, 0x8000}, -}; - -/* rolloff table for illuminant A */ -struct mt9p012_i2c_reg_conf mt9p012_rolloff_tbl[] = { - /* P_RD_P0Q0 */ - {0x360A, 0x7FEF}, - /* P_RD_P0Q1 */ - {0x360C, 0x232C}, - /* P_RD_P0Q2 */ - {0x360E, 0x7050}, - /* P_RD_P0Q3 */ - {0x3610, 0xF3CC}, - /* P_RD_P0Q4 */ - {0x3612, 0x89D1}, - /* P_RD_P1Q0 */ - {0x364A, 0xBE0D}, - /* P_RD_P1Q1 */ - {0x364C, 0x9ACB}, - /* P_RD_P1Q2 */ - {0x364E, 0x2150}, - /* P_RD_P1Q3 */ - {0x3650, 0xB26B}, - /* P_RD_P1Q4 */ - {0x3652, 0x9511}, - /* P_RD_P2Q0 */ - {0x368A, 0x2151}, - /* P_RD_P2Q1 */ - {0x368C, 0x00AD}, - /* P_RD_P2Q2 */ - {0x368E, 0x8334}, - /* P_RD_P2Q3 */ - {0x3690, 0x478E}, - /* P_RD_P2Q4 */ - {0x3692, 0x0515}, - /* P_RD_P3Q0 */ - {0x36CA, 0x0710}, - /* P_RD_P3Q1 */ - {0x36CC, 0x452D}, - /* P_RD_P3Q2 */ - {0x36CE, 0xF352}, - /* P_RD_P3Q3 */ - {0x36D0, 0x190F}, - /* P_RD_P3Q4 */ - {0x36D2, 0x4413}, - /* P_RD_P4Q0 */ - {0x370A, 0xD112}, - /* P_RD_P4Q1 */ - {0x370C, 0xF50F}, - /* P_RD_P4Q2 */ - {0x370E, 0x6375}, - /* P_RD_P4Q3 */ - {0x3710, 0xDC11}, - /* P_RD_P4Q4 */ - {0x3712, 0xD776}, - /* P_GR_P0Q0 */ - {0x3600, 0x1750}, - /* P_GR_P0Q1 */ - {0x3602, 0xF0AC}, - /* P_GR_P0Q2 */ - {0x3604, 0x4711}, - /* P_GR_P0Q3 */ - {0x3606, 0x07CE}, - /* P_GR_P0Q4 */ - {0x3608, 0x96B2}, - /* P_GR_P1Q0 */ - {0x3640, 0xA9AE}, - /* P_GR_P1Q1 */ - {0x3642, 0xF9AC}, - /* P_GR_P1Q2 */ - {0x3644, 0x39F1}, - /* P_GR_P1Q3 */ - {0x3646, 0x016F}, - /* P_GR_P1Q4 */ - {0x3648, 0x8AB2}, - /* P_GR_P2Q0 */ - {0x3680, 0x1752}, - /* P_GR_P2Q1 */ - {0x3682, 0x70F0}, - /* P_GR_P2Q2 */ - {0x3684, 0x83F5}, - /* P_GR_P2Q3 */ - {0x3686, 0x8392}, - /* P_GR_P2Q4 */ - {0x3688, 0x1FD6}, - /* P_GR_P3Q0 */ - {0x36C0, 0x1131}, - /* P_GR_P3Q1 */ - {0x36C2, 0x3DAF}, - /* P_GR_P3Q2 */ - {0x36C4, 0x89B4}, - /* P_GR_P3Q3 */ - {0x36C6, 0xA391}, - /* P_GR_P3Q4 */ - {0x36C8, 0x1334}, - /* P_GR_P4Q0 */ - {0x3700, 0xDC13}, - /* P_GR_P4Q1 */ - {0x3702, 0xD052}, - /* P_GR_P4Q2 */ - {0x3704, 0x5156}, - /* P_GR_P4Q3 */ - {0x3706, 0x1F13}, - /* P_GR_P4Q4 */ - {0x3708, 0x8C38}, - /* P_BL_P0Q0 */ - {0x3614, 0x0050}, - /* P_BL_P0Q1 */ - {0x3616, 0xBD4C}, - /* P_BL_P0Q2 */ - {0x3618, 0x41B0}, - /* P_BL_P0Q3 */ - {0x361A, 0x660D}, - /* P_BL_P0Q4 */ - {0x361C, 0xC590}, - /* P_BL_P1Q0 */ - {0x3654, 0x87EC}, - /* P_BL_P1Q1 */ - {0x3656, 0xE44C}, - /* P_BL_P1Q2 */ - {0x3658, 0x302E}, - /* P_BL_P1Q3 */ - {0x365A, 0x106E}, - /* P_BL_P1Q4 */ - {0x365C, 0xB58E}, - /* P_BL_P2Q0 */ - {0x3694, 0x0DD1}, - /* P_BL_P2Q1 */ - {0x3696, 0x2A50}, - /* P_BL_P2Q2 */ - {0x3698, 0xC793}, - /* P_BL_P2Q3 */ - {0x369A, 0xE8F1}, - /* P_BL_P2Q4 */ - {0x369C, 0x4174}, - /* P_BL_P3Q0 */ - {0x36D4, 0x01EF}, - /* P_BL_P3Q1 */ - {0x36D6, 0x06CF}, - /* P_BL_P3Q2 */ - {0x36D8, 0x8D91}, - /* P_BL_P3Q3 */ - {0x36DA, 0x91F0}, - /* P_BL_P3Q4 */ - {0x36DC, 0x52EF}, - /* P_BL_P4Q0 */ - {0x3714, 0xA6D2}, - /* P_BL_P4Q1 */ - {0x3716, 0xA312}, - /* P_BL_P4Q2 */ - {0x3718, 0x2695}, - /* P_BL_P4Q3 */ - {0x371A, 0x3953}, - /* P_BL_P4Q4 */ - {0x371C, 0x9356}, - /* P_GB_P0Q0 */ - {0x361E, 0x7EAF}, - /* P_GB_P0Q1 */ - {0x3620, 0x2A4C}, - /* P_GB_P0Q2 */ - {0x3622, 0x49F0}, - {0x3624, 0xF1EC}, - /* P_GB_P0Q4 */ - {0x3626, 0xC670}, - /* P_GB_P1Q0 */ - {0x365E, 0x8E0C}, - /* P_GB_P1Q1 */ - {0x3660, 0xC2A9}, - /* P_GB_P1Q2 */ - {0x3662, 0x274F}, - /* P_GB_P1Q3 */ - {0x3664, 0xADAB}, - /* P_GB_P1Q4 */ - {0x3666, 0x8EF0}, - /* P_GB_P2Q0 */ - {0x369E, 0x09B1}, - /* P_GB_P2Q1 */ - {0x36A0, 0xAA2E}, - /* P_GB_P2Q2 */ - {0x36A2, 0xC3D3}, - /* P_GB_P2Q3 */ - {0x36A4, 0x7FAF}, - /* P_GB_P2Q4 */ - {0x36A6, 0x3F34}, - /* P_GB_P3Q0 */ - {0x36DE, 0x4C8F}, - /* P_GB_P3Q1 */ - {0x36E0, 0x886E}, - /* P_GB_P3Q2 */ - {0x36E2, 0xE831}, - /* P_GB_P3Q3 */ - {0x36E4, 0x1FD0}, - /* P_GB_P3Q4 */ - {0x36E6, 0x1192}, - /* P_GB_P4Q0 */ - {0x371E, 0xB952}, - /* P_GB_P4Q1 */ - {0x3720, 0x6DCF}, - /* P_GB_P4Q2 */ - {0x3722, 0x1B55}, - /* P_GB_P4Q3 */ - {0x3724, 0xA112}, - /* P_GB_P4Q4 */ - {0x3726, 0x82F6}, - /* POLY_ORIGIN_C */ - {0x3782, 0x0510}, - /* POLY_ORIGIN_R */ - {0x3784, 0x0390}, - /* POLY_SC_ENABLE */ - {0x3780, 0x8000}, -}; - - -struct mt9p012_reg mt9p012_regs = { - .reg_pat = &mt9p012_reg_pat[0], - .reg_pat_size = ARRAY_SIZE(mt9p012_reg_pat), - .ttbl = &mt9p012_test_tbl[0], - .ttbl_size = ARRAY_SIZE(mt9p012_test_tbl), - .lctbl = &mt9p012_lc_tbl[0], - .lctbl_size = ARRAY_SIZE(mt9p012_lc_tbl), - .rftbl = &mt9p012_rolloff_tbl[0], - .rftbl_size = ARRAY_SIZE(mt9p012_rolloff_tbl) -}; - - diff --git a/drivers/staging/dream/camera/mt9t013.c b/drivers/staging/dream/camera/mt9t013.c deleted file mode 100644 index 8fd7727ba234..000000000000 --- a/drivers/staging/dream/camera/mt9t013.c +++ /dev/null @@ -1,1497 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/uaccess.h> -#include <linux/miscdevice.h> -#include <linux/kernel.h> -#include <media/msm_camera.h> -#include <mach/gpio.h> -#include <mach/camera.h> -#include <asm/mach-types.h> -#include "mt9t013.h" - -/*============================================================= - SENSOR REGISTER DEFINES -==============================================================*/ -#define MT9T013_REG_MODEL_ID 0x0000 -#define MT9T013_MODEL_ID 0x2600 -#define REG_GROUPED_PARAMETER_HOLD 0x0104 -#define GROUPED_PARAMETER_HOLD 0x0100 -#define GROUPED_PARAMETER_UPDATE 0x0000 -#define REG_COARSE_INT_TIME 0x3012 -#define REG_VT_PIX_CLK_DIV 0x0300 -#define REG_VT_SYS_CLK_DIV 0x0302 -#define REG_PRE_PLL_CLK_DIV 0x0304 -#define REG_PLL_MULTIPLIER 0x0306 -#define REG_OP_PIX_CLK_DIV 0x0308 -#define REG_OP_SYS_CLK_DIV 0x030A -#define REG_SCALE_M 0x0404 -#define REG_FRAME_LENGTH_LINES 0x300A -#define REG_LINE_LENGTH_PCK 0x300C -#define REG_X_ADDR_START 0x3004 -#define REG_Y_ADDR_START 0x3002 -#define REG_X_ADDR_END 0x3008 -#define REG_Y_ADDR_END 0x3006 -#define REG_X_OUTPUT_SIZE 0x034C -#define REG_Y_OUTPUT_SIZE 0x034E -#define REG_FINE_INT_TIME 0x3014 -#define REG_ROW_SPEED 0x3016 -#define MT9T013_REG_RESET_REGISTER 0x301A -#define MT9T013_RESET_REGISTER_PWON 0x10CC -#define MT9T013_RESET_REGISTER_PWOFF 0x1008 /* 0x10C8 stop streaming*/ -#define REG_READ_MODE 0x3040 -#define REG_GLOBAL_GAIN 0x305E -#define REG_TEST_PATTERN_MODE 0x3070 - - -enum mt9t013_test_mode { - TEST_OFF, - TEST_1, - TEST_2, - TEST_3 -}; - -enum mt9t013_resolution { - QTR_SIZE, - FULL_SIZE, - INVALID_SIZE -}; - -enum mt9t013_reg_update { - REG_INIT, /* registers that need to be updated during initialization */ - UPDATE_PERIODIC, /* registers that needs periodic I2C writes */ - UPDATE_ALL, /* all registers will be updated */ - UPDATE_INVALID -}; - -enum mt9t013_setting { - RES_PREVIEW, - RES_CAPTURE -}; - -/* actuator's Slave Address */ -#define MT9T013_AF_I2C_ADDR 0x18 - -/* -* AF Total steps parameters -*/ -#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR 30 - -/* - * Time in milisecs for waiting for the sensor to reset. - */ -#define MT9T013_RESET_DELAY_MSECS 66 - -/* for 30 fps preview */ -#define MT9T013_DEFAULT_CLOCK_RATE 24000000 -#define MT9T013_DEFAULT_MAX_FPS 26 - - -/* FIXME: Changes from here */ -struct mt9t013_work { - struct work_struct work; -}; - -static struct mt9t013_work *mt9t013_sensorw; -static struct i2c_client *mt9t013_client; - -struct mt9t013_ctrl { - const struct msm_camera_sensor_info *sensordata; - - int sensormode; - uint32_t fps_divider; /* init to 1 * 0x00000400 */ - uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ - - uint16_t curr_lens_pos; - uint16_t init_curr_lens_pos; - uint16_t my_reg_gain; - uint32_t my_reg_line_count; - - enum mt9t013_resolution prev_res; - enum mt9t013_resolution pict_res; - enum mt9t013_resolution curr_res; - enum mt9t013_test_mode set_test; - - unsigned short imgaddr; -}; - - -static struct mt9t013_ctrl *mt9t013_ctrl; -static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue); -DECLARE_MUTEX(mt9t013_sem); - -extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */ - -static int mt9t013_i2c_rxdata(unsigned short saddr, - unsigned char *rxdata, int length) -{ - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = 2, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = length, - .buf = rxdata, - }, - }; - - if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) { - pr_err("mt9t013_i2c_rxdata failed!\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9t013_i2c_read_w(unsigned short saddr, - unsigned short raddr, unsigned short *rdata) -{ - int32_t rc = 0; - unsigned char buf[4]; - - if (!rdata) - return -EIO; - - memset(buf, 0, sizeof(buf)); - - buf[0] = (raddr & 0xFF00)>>8; - buf[1] = (raddr & 0x00FF); - - rc = mt9t013_i2c_rxdata(saddr, buf, 2); - if (rc < 0) - return rc; - - *rdata = buf[0] << 8 | buf[1]; - - if (rc < 0) - pr_err("mt9t013_i2c_read failed!\n"); - - return rc; -} - -static int32_t mt9t013_i2c_txdata(unsigned short saddr, - unsigned char *txdata, int length) -{ - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - - if (i2c_transfer(mt9t013_client->adapter, msg, 1) < 0) { - pr_err("mt9t013_i2c_txdata failed\n"); - return -EIO; - } - - return 0; -} - -static int32_t mt9t013_i2c_write_b(unsigned short saddr, - unsigned short waddr, unsigned short wdata) -{ - int32_t rc = -EIO; - unsigned char buf[2]; - - memset(buf, 0, sizeof(buf)); - buf[0] = waddr; - buf[1] = wdata; - rc = mt9t013_i2c_txdata(saddr, buf, 2); - - if (rc < 0) - pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n", - waddr, wdata); - - return rc; -} - -static int32_t mt9t013_i2c_write_w(unsigned short saddr, - unsigned short waddr, unsigned short wdata) -{ - int32_t rc = -EIO; - unsigned char buf[4]; - - memset(buf, 0, sizeof(buf)); - buf[0] = (waddr & 0xFF00)>>8; - buf[1] = (waddr & 0x00FF); - buf[2] = (wdata & 0xFF00)>>8; - buf[3] = (wdata & 0x00FF); - - rc = mt9t013_i2c_txdata(saddr, buf, 4); - - if (rc < 0) - pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", - waddr, wdata); - - return rc; -} - -static int32_t mt9t013_i2c_write_w_table( - struct mt9t013_i2c_reg_conf *reg_conf_tbl, int num_of_items_in_table) -{ - int i; - int32_t rc = -EIO; - - for (i = 0; i < num_of_items_in_table; i++) { - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - reg_conf_tbl->waddr, reg_conf_tbl->wdata); - if (rc < 0) - break; - reg_conf_tbl++; - } - - return rc; -} - -static int32_t mt9t013_test(enum mt9t013_test_mode mo) -{ - int32_t rc = 0; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - if (mo == TEST_OFF) - return 0; - else { - rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl, - mt9t013_regs.ttbl_size); - if (rc < 0) - return rc; - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_TEST_PATTERN_MODE, (uint16_t)mo); - if (rc < 0) - return rc; - } - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - return rc; -} - -static int32_t mt9t013_set_lc(void) -{ - int32_t rc; - - rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl, mt9t013_regs.lctbl_size); - if (rc < 0) - return rc; - - return rc; -} - -static int32_t mt9t013_set_default_focus(uint8_t af_step) -{ - int32_t rc = 0; - uint8_t code_val_msb, code_val_lsb; - code_val_msb = 0x01; - code_val_lsb = af_step; - - /* Write the digital code for current to the actuator */ - rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1, - code_val_msb, code_val_lsb); - - mt9t013_ctrl->curr_lens_pos = 0; - mt9t013_ctrl->init_curr_lens_pos = 0; - return rc; -} - -static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps) -{ - /* input fps is preview fps in Q8 format */ - uint32_t divider; /*Q10 */ - uint32_t pclk_mult; /*Q10 */ - - if (mt9t013_ctrl->prev_res == QTR_SIZE) { - divider = - (uint32_t)( - ((mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines * - mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck) * - 0x00000400) / - (mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines * - mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck)); - - pclk_mult = - (uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].pll_multiplier * - 0x00000400) / - (mt9t013_regs.reg_pat[RES_PREVIEW].pll_multiplier)); - - } else { - /* full size resolution used for preview. */ - divider = 0x00000400; /*1.0 */ - pclk_mult = 0x00000400; /*1.0 */ - } - - /* Verify PCLK settings and frame sizes. */ - *pfps = - (uint16_t) (fps * divider * pclk_mult / - 0x00000400 / 0x00000400); -} - -static uint16_t mt9t013_get_prev_lines_pf(void) -{ - if (mt9t013_ctrl->prev_res == QTR_SIZE) - return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines; - else - return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines; -} - -static uint16_t mt9t013_get_prev_pixels_pl(void) -{ - if (mt9t013_ctrl->prev_res == QTR_SIZE) - return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck; - else - return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck; -} - -static uint16_t mt9t013_get_pict_lines_pf(void) -{ - return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines; -} - -static uint16_t mt9t013_get_pict_pixels_pl(void) -{ - return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck; -} - -static uint32_t mt9t013_get_pict_max_exp_lc(void) -{ - uint16_t snapshot_lines_per_frame; - - if (mt9t013_ctrl->pict_res == QTR_SIZE) { - snapshot_lines_per_frame = - mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1; - } else { - snapshot_lines_per_frame = - mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1; - } - - return snapshot_lines_per_frame * 24; -} - -static int32_t mt9t013_set_fps(struct fps_cfg *fps) -{ - /* input is new fps in Q8 format */ - int32_t rc = 0; - - mt9t013_ctrl->fps_divider = fps->fps_div; - mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return -EBUSY; - - CDBG("mt9t013_set_fps: fps_div is %d, frame_rate is %d\n", - fps->fps_div, - (uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW]. - frame_length_lines * - fps->fps_div/0x00000400)); - - CDBG("mt9t013_set_fps: fps_mult is %d, frame_rate is %d\n", - fps->f_mult, - (uint16_t)(mt9t013_regs.reg_pat[RES_PREVIEW]. - line_length_pck * - fps->f_mult / 0x00000400)); - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_LINE_LENGTH_PCK, - (uint16_t) ( - mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck * - fps->f_mult / 0x00000400)); - if (rc < 0) - return rc; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - return rc; -} - -static int32_t mt9t013_write_exp_gain(uint16_t gain, uint32_t line) -{ - const uint16_t max_legal_gain = 0x01FF; - uint32_t line_length_ratio = 0x00000400; - enum mt9t013_setting setting; - int32_t rc = 0; - - if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) { - mt9t013_ctrl->my_reg_gain = gain; - mt9t013_ctrl->my_reg_line_count = (uint16_t) line; - } - - if (gain > max_legal_gain) - gain = max_legal_gain; - - /* Verify no overflow */ - if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) { - line = (uint32_t) (line * mt9t013_ctrl->fps_divider / - 0x00000400); - - setting = RES_PREVIEW; - - } else { - line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider / - 0x00000400); - - setting = RES_CAPTURE; - } - - /*Set digital gain to 1 */ - gain |= 0x0200; - - if ((mt9t013_regs.reg_pat[setting].frame_length_lines - 1) < line) { - - line_length_ratio = - (uint32_t) (line * 0x00000400) / - (mt9t013_regs.reg_pat[setting].frame_length_lines - 1); - } else - line_length_ratio = 0x00000400; - - /* There used to be PARAMETER_HOLD register write before and - * after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes - * aec oscillation. Hence removed. */ - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain); - if (rc < 0) - return rc; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_COARSE_INT_TIME, - (uint16_t)((uint32_t) line * 0x00000400 / - line_length_ratio)); - if (rc < 0) - return rc; - - return rc; -} - -static int32_t mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line) -{ - int32_t rc = 0; - - rc = mt9t013_write_exp_gain(gain, line); - if (rc < 0) - return rc; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - 0x10CC | 0x0002); - - mdelay(5); - - /* camera_timed_wait(snapshot_wait*exposure_ratio); */ - return rc; -} - -static int32_t mt9t013_setting(enum mt9t013_reg_update rupdate, - enum mt9t013_setting rt) -{ - int32_t rc = 0; - - switch (rupdate) { - case UPDATE_PERIODIC: { - - if (rt == RES_PREVIEW || rt == RES_CAPTURE) { -#if 0 - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWOFF); - if (rc < 0) - return rc; -#endif - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_VT_PIX_CLK_DIV, - mt9t013_regs.reg_pat[rt].vt_pix_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_VT_SYS_CLK_DIV, - mt9t013_regs.reg_pat[rt].vt_sys_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_PRE_PLL_CLK_DIV, - mt9t013_regs.reg_pat[rt].pre_pll_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_PLL_MULTIPLIER, - mt9t013_regs.reg_pat[rt].pll_multiplier); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_OP_PIX_CLK_DIV, - mt9t013_regs.reg_pat[rt].op_pix_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_OP_SYS_CLK_DIV, - mt9t013_regs.reg_pat[rt].op_sys_clk_div); - if (rc < 0) - return rc; - - mdelay(5); - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_ROW_SPEED, - mt9t013_regs.reg_pat[rt].row_speed); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_ADDR_START, - mt9t013_regs.reg_pat[rt].x_addr_start); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_ADDR_END, - mt9t013_regs.reg_pat[rt].x_addr_end); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_ADDR_START, - mt9t013_regs.reg_pat[rt].y_addr_start); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_ADDR_END, - mt9t013_regs.reg_pat[rt].y_addr_end); - if (rc < 0) - return rc; - - if (machine_is_sapphire()) { - if (rt == 0) - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - 0x046F); - else - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - 0x0027); - } else - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - mt9t013_regs.reg_pat[rt].read_mode); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_SCALE_M, - mt9t013_regs.reg_pat[rt].scale_m); - if (rc < 0) - return rc; - - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_OUTPUT_SIZE, - mt9t013_regs.reg_pat[rt].x_output_size); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_OUTPUT_SIZE, - mt9t013_regs.reg_pat[rt].y_output_size); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_LINE_LENGTH_PCK, - mt9t013_regs.reg_pat[rt].line_length_pck); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_FRAME_LENGTH_LINES, - (mt9t013_regs.reg_pat[rt].frame_length_lines * - mt9t013_ctrl->fps_divider / 0x00000400)); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_COARSE_INT_TIME, - mt9t013_regs.reg_pat[rt].coarse_int_time); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_FINE_INT_TIME, - mt9t013_regs.reg_pat[rt].fine_int_time); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - rc = mt9t013_test(mt9t013_ctrl->set_test); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWON); - if (rc < 0) - return rc; - - mdelay(5); - - return rc; - } - } - break; - - /*CAMSENSOR_REG_UPDATE_PERIODIC */ - case REG_INIT: { - if (rt == RES_PREVIEW || rt == RES_CAPTURE) { - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWOFF); - if (rc < 0) - /* MODE_SELECT, stop streaming */ - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_VT_PIX_CLK_DIV, - mt9t013_regs.reg_pat[rt].vt_pix_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_VT_SYS_CLK_DIV, - mt9t013_regs.reg_pat[rt].vt_sys_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_PRE_PLL_CLK_DIV, - mt9t013_regs.reg_pat[rt].pre_pll_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_PLL_MULTIPLIER, - mt9t013_regs.reg_pat[rt].pll_multiplier); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_OP_PIX_CLK_DIV, - mt9t013_regs.reg_pat[rt].op_pix_clk_div); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_OP_SYS_CLK_DIV, - mt9t013_regs.reg_pat[rt].op_sys_clk_div); - if (rc < 0) - return rc; - - mdelay(5); - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - /* additional power saving mode ok around 38.2MHz */ - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - 0x3084, 0x2409); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - 0x3092, 0x0A49); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - 0x3094, 0x4949); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - 0x3096, 0x4949); - if (rc < 0) - return rc; - - /* Set preview or snapshot mode */ - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_ROW_SPEED, - mt9t013_regs.reg_pat[rt].row_speed); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_ADDR_START, - mt9t013_regs.reg_pat[rt].x_addr_start); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_ADDR_END, - mt9t013_regs.reg_pat[rt].x_addr_end); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_ADDR_START, - mt9t013_regs.reg_pat[rt].y_addr_start); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_ADDR_END, - mt9t013_regs.reg_pat[rt].y_addr_end); - if (rc < 0) - return rc; - - if (machine_is_sapphire()) { - if (rt == 0) - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - 0x046F); - else - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - 0x0027); - } else - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_READ_MODE, - mt9t013_regs.reg_pat[rt].read_mode); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_SCALE_M, - mt9t013_regs.reg_pat[rt].scale_m); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_X_OUTPUT_SIZE, - mt9t013_regs.reg_pat[rt].x_output_size); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_Y_OUTPUT_SIZE, - mt9t013_regs.reg_pat[rt].y_output_size); - if (rc < 0) - return 0; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_LINE_LENGTH_PCK, - mt9t013_regs.reg_pat[rt].line_length_pck); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_FRAME_LENGTH_LINES, - mt9t013_regs.reg_pat[rt].frame_length_lines); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_COARSE_INT_TIME, - mt9t013_regs.reg_pat[rt].coarse_int_time); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_FINE_INT_TIME, - mt9t013_regs.reg_pat[rt].fine_int_time); - if (rc < 0) - return rc; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - /* load lens shading */ - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - /* most likely needs to be written only once. */ - rc = mt9t013_set_lc(); - if (rc < 0) - return -EBUSY; - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - if (rc < 0) - return rc; - - rc = mt9t013_test(mt9t013_ctrl->set_test); - if (rc < 0) - return rc; - - mdelay(5); - - rc = - mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWON); - if (rc < 0) - /* MODE_SELECT, stop streaming */ - return rc; - - CDBG("!!! mt9t013 !!! PowerOn is done!\n"); - mdelay(5); - return rc; - } - } /* case CAMSENSOR_REG_INIT: */ - break; - - /*CAMSENSOR_REG_INIT */ - default: - rc = -EINVAL; - break; - } /* switch (rupdate) */ - - return rc; -} - -static int32_t mt9t013_video_config(int mode, int res) -{ - int32_t rc; - - switch (res) { - case QTR_SIZE: - rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW); - if (rc < 0) - return rc; - CDBG("sensor configuration done!\n"); - break; - - case FULL_SIZE: - rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - break; - - default: - return -EINVAL; - } /* switch */ - - mt9t013_ctrl->prev_res = res; - mt9t013_ctrl->curr_res = res; - mt9t013_ctrl->sensormode = mode; - - return mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain, - mt9t013_ctrl->my_reg_line_count); -} - -static int32_t mt9t013_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - - mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res; - mt9t013_ctrl->sensormode = mode; - return rc; -} - -static int32_t mt9t013_raw_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE); - if (rc < 0) - return rc; - - mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res; - mt9t013_ctrl->sensormode = mode; - return rc; -} - -static int32_t mt9t013_power_down(void) -{ - int32_t rc = 0; - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWOFF); - if (rc >= 0) - mdelay(5); - return rc; -} - -static int32_t mt9t013_move_focus(int direction, int32_t num_steps) -{ - int16_t step_direction; - int16_t actual_step; - int16_t next_position; - int16_t break_steps[4]; - uint8_t code_val_msb, code_val_lsb; - int16_t i; - - if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR) - num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR; - else if (num_steps == 0) - return -EINVAL; - - if (direction == MOVE_NEAR) - step_direction = 4; - else if (direction == MOVE_FAR) - step_direction = -4; - else - return -EINVAL; - - if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos) - mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos; - - actual_step = - (int16_t) (step_direction * - (int16_t) num_steps); - - for (i = 0; i < 4; i++) - break_steps[i] = - actual_step / 4 * (i + 1) - actual_step / 4 * i; - - for (i = 0; i < 4; i++) { - next_position = - (int16_t) - (mt9t013_ctrl->curr_lens_pos + break_steps[i]); - - if (next_position > 255) - next_position = 255; - else if (next_position < 0) - next_position = 0; - - code_val_msb = - ((next_position >> 4) << 2) | - ((next_position << 4) >> 6); - - code_val_lsb = - ((next_position & 0x03) << 6); - - /* Writing the digital code for current to the actuator */ - if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1, - code_val_msb, code_val_lsb) < 0) - return -EBUSY; - - /* Storing the current lens Position */ - mt9t013_ctrl->curr_lens_pos = next_position; - - if (i < 3) - mdelay(1); - } /* for */ - - return 0; -} - -static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data) -{ - gpio_direction_output(data->sensor_reset, 0); - gpio_free(data->sensor_reset); - return 0; -} - -static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data) -{ - int rc; - uint16_t chipid; - - rc = gpio_request(data->sensor_reset, "mt9t013"); - if (!rc) - gpio_direction_output(data->sensor_reset, 1); - else - goto init_probe_done; - - mdelay(20); - - /* RESET the sensor image part via I2C command */ - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, 0x1009); - if (rc < 0) - goto init_probe_fail; - - /* 3. Read sensor Model ID: */ - rc = mt9t013_i2c_read_w(mt9t013_client->addr, - MT9T013_REG_MODEL_ID, &chipid); - - if (rc < 0) - goto init_probe_fail; - - CDBG("mt9t013 model_id = 0x%x\n", chipid); - - /* 4. Compare sensor ID to MT9T012VC ID: */ - if (chipid != MT9T013_MODEL_ID) { - rc = -ENODEV; - goto init_probe_fail; - } - - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - 0x3064, 0x0805); - if (rc < 0) - goto init_probe_fail; - - mdelay(MT9T013_RESET_DELAY_MSECS); - - goto init_probe_done; - - /* sensor: output enable */ -#if 0 - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - MT9T013_REG_RESET_REGISTER, - MT9T013_RESET_REGISTER_PWON); - - /* if this fails, the sensor is not the MT9T013 */ - rc = mt9t013_set_default_focus(0); -#endif - -init_probe_fail: - gpio_direction_output(data->sensor_reset, 0); - gpio_free(data->sensor_reset); -init_probe_done: - return rc; -} - -static int32_t mt9t013_poweron_af(void) -{ - int32_t rc = 0; - - /* enable AF actuator */ - CDBG("enable AF actuator, gpio = %d\n", - mt9t013_ctrl->sensordata->vcm_pwd); - rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013"); - if (!rc) { - gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0); - mdelay(20); - rc = mt9t013_set_default_focus(0); - } else - pr_err("%s, gpio_request failed (%d)!\n", __func__, rc); - return rc; -} - -static void mt9t013_poweroff_af(void) -{ - gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1); - gpio_free(mt9t013_ctrl->sensordata->vcm_pwd); -} - -int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data) -{ - int32_t rc; - - mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL); - if (!mt9t013_ctrl) { - pr_err("mt9t013_init failed!\n"); - rc = -ENOMEM; - goto init_done; - } - - mt9t013_ctrl->fps_divider = 1 * 0x00000400; - mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400; - mt9t013_ctrl->set_test = TEST_OFF; - mt9t013_ctrl->prev_res = QTR_SIZE; - mt9t013_ctrl->pict_res = FULL_SIZE; - - if (data) - mt9t013_ctrl->sensordata = data; - - /* enable mclk first */ - msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE); - mdelay(20); - - msm_camio_camif_pad_reg_reset(); - mdelay(20); - - rc = mt9t013_probe_init_sensor(data); - if (rc < 0) - goto init_fail; - - if (mt9t013_ctrl->prev_res == QTR_SIZE) - rc = mt9t013_setting(REG_INIT, RES_PREVIEW); - else - rc = mt9t013_setting(REG_INIT, RES_CAPTURE); - - if (rc >= 0) - rc = mt9t013_poweron_af(); - - if (rc < 0) - goto init_fail; - else - goto init_done; - -init_fail: - kfree(mt9t013_ctrl); -init_done: - return rc; -} - -static int mt9t013_init_client(struct i2c_client *client) -{ - /* Initialize the MSM_CAMI2C Chip */ - init_waitqueue_head(&mt9t013_wait_queue); - return 0; -} - - -static int32_t mt9t013_set_sensor_mode(int mode, int res) -{ - int32_t rc = 0; - rc = mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_HOLD); - if (rc < 0) - return rc; - - switch (mode) { - case SENSOR_PREVIEW_MODE: - rc = mt9t013_video_config(mode, res); - break; - - case SENSOR_SNAPSHOT_MODE: - rc = mt9t013_snapshot_config(mode); - break; - - case SENSOR_RAW_SNAPSHOT_MODE: - rc = mt9t013_raw_snapshot_config(mode); - break; - - default: - return -EINVAL; - } - - /* FIXME: what should we do if rc < 0? */ - if (rc >= 0) - return mt9t013_i2c_write_w(mt9t013_client->addr, - REG_GROUPED_PARAMETER_HOLD, - GROUPED_PARAMETER_UPDATE); - return rc; -} - -int mt9t013_sensor_config(void __user *argp) -{ - struct sensor_cfg_data cdata; - long rc = 0; - - if (copy_from_user(&cdata, (void *)argp, - sizeof(struct sensor_cfg_data))) - return -EFAULT; - - down(&mt9t013_sem); - - CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype); - switch (cdata.cfgtype) { - case CFG_GET_PICT_FPS: - mt9t013_get_pict_fps(cdata.cfg.gfps.prevfps, - &(cdata.cfg.gfps.pictfps)); - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_L_PF: - cdata.cfg.prevl_pf = mt9t013_get_prev_lines_pf(); - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_P_PL: - cdata.cfg.prevp_pl = mt9t013_get_prev_pixels_pl(); - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_L_PF: - cdata.cfg.pictl_pf = mt9t013_get_pict_lines_pf(); - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_P_PL: - cdata.cfg.pictp_pl = - mt9t013_get_pict_pixels_pl(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_MAX_EXP_LC: - cdata.cfg.pict_max_exp_lc = - mt9t013_get_pict_max_exp_lc(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_SET_FPS: - case CFG_SET_PICT_FPS: - rc = mt9t013_set_fps(&(cdata.cfg.fps)); - break; - - case CFG_SET_EXP_GAIN: - rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_PICT_EXP_GAIN: - rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_MODE: - rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs); - break; - - case CFG_PWR_DOWN: - rc = mt9t013_power_down(); - break; - - case CFG_MOVE_FOCUS: - rc = mt9t013_move_focus(cdata.cfg.focus.dir, - cdata.cfg.focus.steps); - break; - - case CFG_SET_DEFAULT_FOCUS: - rc = mt9t013_set_default_focus(cdata.cfg.focus.steps); - break; - - case CFG_GET_AF_MAX_STEPS: - cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR; - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_SET_EFFECT: - default: - rc = -EINVAL; - break; - } - - up(&mt9t013_sem); - return rc; -} - -int mt9t013_sensor_release(void) -{ - int rc = -EBADF; - - down(&mt9t013_sem); - - mt9t013_poweroff_af(); - mt9t013_power_down(); - - gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset, - 0); - gpio_free(mt9t013_ctrl->sensordata->sensor_reset); - - kfree(mt9t013_ctrl); - - up(&mt9t013_sem); - CDBG("mt9t013_release completed!\n"); - return rc; -} - -static int mt9t013_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - rc = -ENOTSUPP; - goto probe_failure; - } - - mt9t013_sensorw = - kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL); - - if (!mt9t013_sensorw) { - rc = -ENOMEM; - goto probe_failure; - } - - i2c_set_clientdata(client, mt9t013_sensorw); - mt9t013_init_client(client); - mt9t013_client = client; - mt9t013_client->addr = mt9t013_client->addr >> 1; - mdelay(50); - - CDBG("i2c probe ok\n"); - return 0; - -probe_failure: - kfree(mt9t013_sensorw); - mt9t013_sensorw = NULL; - pr_err("i2c probe failure %d\n", rc); - return rc; -} - -static const struct i2c_device_id mt9t013_i2c_id[] = { - { "mt9t013", 0}, - { } -}; - -static struct i2c_driver mt9t013_i2c_driver = { - .id_table = mt9t013_i2c_id, - .probe = mt9t013_i2c_probe, - .remove = __exit_p(mt9t013_i2c_remove), - .driver = { - .name = "mt9t013", - }, -}; - -static int mt9t013_sensor_probe( - const struct msm_camera_sensor_info *info, - struct msm_sensor_ctrl *s) -{ - /* We expect this driver to match with the i2c device registered - * in the board file immediately. */ - int rc = i2c_add_driver(&mt9t013_i2c_driver); - if (rc < 0 || mt9t013_client == NULL) { - rc = -ENOTSUPP; - goto probe_done; - } - - /* enable mclk first */ - msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE); - mdelay(20); - - rc = mt9t013_probe_init_sensor(info); - if (rc < 0) { - i2c_del_driver(&mt9t013_i2c_driver); - goto probe_done; - } - - s->s_init = mt9t013_sensor_open_init; - s->s_release = mt9t013_sensor_release; - s->s_config = mt9t013_sensor_config; - mt9t013_sensor_init_done(info); - -probe_done: - return rc; -} - -static int __mt9t013_probe(struct platform_device *pdev) -{ - return msm_camera_drv_start(pdev, mt9t013_sensor_probe); -} - -static struct platform_driver msm_camera_driver = { - .probe = __mt9t013_probe, - .driver = { - .name = "msm_camera_mt9t013", - .owner = THIS_MODULE, - }, -}; - -static int __init mt9t013_init(void) -{ - return platform_driver_register(&msm_camera_driver); -} - -module_init(mt9t013_init); diff --git a/drivers/staging/dream/camera/mt9t013.h b/drivers/staging/dream/camera/mt9t013.h deleted file mode 100644 index 9bce2036e3b6..000000000000 --- a/drivers/staging/dream/camera/mt9t013.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#ifndef MT9T013_H -#define MT9T013_H - -#include <linux/types.h> - -struct reg_struct { - uint16_t vt_pix_clk_div; /* 0x0300 */ - uint16_t vt_sys_clk_div; /* 0x0302 */ - uint16_t pre_pll_clk_div; /* 0x0304 */ - uint16_t pll_multiplier; /* 0x0306 */ - uint16_t op_pix_clk_div; /* 0x0308 */ - uint16_t op_sys_clk_div; /* 0x030A */ - uint16_t scale_m; /* 0x0404 */ - uint16_t row_speed; /* 0x3016 */ - uint16_t x_addr_start; /* 0x3004 */ - uint16_t x_addr_end; /* 0x3008 */ - uint16_t y_addr_start; /* 0x3002 */ - uint16_t y_addr_end; /* 0x3006 */ - uint16_t read_mode; /* 0x3040 */ - uint16_t x_output_size; /* 0x034C */ - uint16_t y_output_size; /* 0x034E */ - uint16_t line_length_pck; /* 0x300C */ - uint16_t frame_length_lines; /* 0x300A */ - uint16_t coarse_int_time; /* 0x3012 */ - uint16_t fine_int_time; /* 0x3014 */ -}; - -struct mt9t013_i2c_reg_conf { - unsigned short waddr; - unsigned short wdata; -}; - -struct mt9t013_reg { - struct reg_struct *reg_pat; - uint16_t reg_pat_size; - struct mt9t013_i2c_reg_conf *ttbl; - uint16_t ttbl_size; - struct mt9t013_i2c_reg_conf *lctbl; - uint16_t lctbl_size; - struct mt9t013_i2c_reg_conf *rftbl; - uint16_t rftbl_size; -}; - -#endif /* #define MT9T013_H */ diff --git a/drivers/staging/dream/camera/mt9t013_reg.c b/drivers/staging/dream/camera/mt9t013_reg.c deleted file mode 100644 index ba0a1d4b4d5f..000000000000 --- a/drivers/staging/dream/camera/mt9t013_reg.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2009 QUALCOMM Incorporated. - */ - -#include "mt9t013.h" -#include <linux/kernel.h> - -struct reg_struct const mt9t013_reg_pat[2] = { - { /* Preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */ - /* vt_pix_clk_div:REG=0x0300 update get_snapshot_fps - * if this change */ - 8, - - /* vt_sys_clk_div: REG=0x0302 update get_snapshot_fps - * if this change */ - 1, - - /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps - * if this change */ - 2, - - /* pll_multiplier REG=0x0306 60 for 30fps preview, 40 - * for 20fps preview - * 46 for 30fps preview, try 47/48 to increase further */ - 46, - - /* op_pix_clk_div REG=0x0308 */ - 8, - - /* op_sys_clk_div REG=0x030A */ - 1, - - /* scale_m REG=0x0404 */ - 16, - - /* row_speed REG=0x3016 */ - 0x0111, - - /* x_addr_start REG=0x3004 */ - 8, - - /* x_addr_end REG=0x3008 */ - 2053, - - /* y_addr_start REG=0x3002 */ - 8, - - /* y_addr_end REG=0x3006 */ - 1541, - - /* read_mode REG=0x3040 */ - 0x046C, - - /* x_output_size REG=0x034C */ - 1024, - - /* y_output_size REG=0x034E */ - 768, - - /* line_length_pck REG=0x300C */ - 2616, - - /* frame_length_lines REG=0x300A */ - 916, - - /* coarse_int_time REG=0x3012 */ - 16, - - /* fine_int_time REG=0x3014 */ - 1461 - }, - { /*Snapshot */ - /* vt_pix_clk_div REG=0x0300 update get_snapshot_fps - * if this change */ - 8, - - /* vt_sys_clk_div REG=0x0302 update get_snapshot_fps - * if this change */ - 1, - - /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps - * if this change */ - 2, - - /* pll_multiplier REG=0x0306 50 for 15fps snapshot, - * 40 for 10fps snapshot - * 46 for 30fps snapshot, try 47/48 to increase further */ - 46, - - /* op_pix_clk_div REG=0x0308 */ - 8, - - /* op_sys_clk_div REG=0x030A */ - 1, - - /* scale_m REG=0x0404 */ - 16, - - /* row_speed REG=0x3016 */ - 0x0111, - - /* x_addr_start REG=0x3004 */ - 8, - - /* x_addr_end REG=0x3008 */ - 2071, - - /* y_addr_start REG=0x3002 */ - 8, - - /* y_addr_end REG=0x3006 */ - 1551, - - /* read_mode REG=0x3040 */ - 0x0024, - - /* x_output_size REG=0x034C */ - 2064, - - /* y_output_size REG=0x034E */ - 1544, - - /* line_length_pck REG=0x300C */ - 2952, - - /* frame_length_lines REG=0x300A */ - 1629, - - /* coarse_int_time REG=0x3012 */ - 16, - - /* fine_int_time REG=0x3014 */ - 733 - } -}; - -struct mt9t013_i2c_reg_conf mt9t013_test_tbl[] = { - { 0x3044, 0x0544 & 0xFBFF }, - { 0x30CA, 0x0004 | 0x0001 }, - { 0x30D4, 0x9020 & 0x7FFF }, - { 0x31E0, 0x0003 & 0xFFFE }, - { 0x3180, 0x91FF & 0x7FFF }, - { 0x301A, (0x10CC | 0x8000) & 0xFFF7 }, - { 0x301E, 0x0000 }, - { 0x3780, 0x0000 }, -}; - -/* [Lens shading 85 Percent TL84] */ -struct mt9t013_i2c_reg_conf mt9t013_lc_tbl[] = { - { 0x360A, 0x0290 }, /* P_RD_P0Q0 */ - { 0x360C, 0xC92D }, /* P_RD_P0Q1 */ - { 0x360E, 0x0771 }, /* P_RD_P0Q2 */ - { 0x3610, 0xE38C }, /* P_RD_P0Q3 */ - { 0x3612, 0xD74F }, /* P_RD_P0Q4 */ - { 0x364A, 0x168C }, /* P_RD_P1Q0 */ - { 0x364C, 0xCACB }, /* P_RD_P1Q1 */ - { 0x364E, 0x8C4C }, /* P_RD_P1Q2 */ - { 0x3650, 0x0BEA }, /* P_RD_P1Q3 */ - { 0x3652, 0xDC0F }, /* P_RD_P1Q4 */ - { 0x368A, 0x70B0 }, /* P_RD_P2Q0 */ - { 0x368C, 0x200B }, /* P_RD_P2Q1 */ - { 0x368E, 0x30B2 }, /* P_RD_P2Q2 */ - { 0x3690, 0xD04F }, /* P_RD_P2Q3 */ - { 0x3692, 0xACF5 }, /* P_RD_P2Q4 */ - { 0x36CA, 0xF7C9 }, /* P_RD_P3Q0 */ - { 0x36CC, 0x2AED }, /* P_RD_P3Q1 */ - { 0x36CE, 0xA652 }, /* P_RD_P3Q2 */ - { 0x36D0, 0x8192 }, /* P_RD_P3Q3 */ - { 0x36D2, 0x3A15 }, /* P_RD_P3Q4 */ - { 0x370A, 0xDA30 }, /* P_RD_P4Q0 */ - { 0x370C, 0x2E2F }, /* P_RD_P4Q1 */ - { 0x370E, 0xBB56 }, /* P_RD_P4Q2 */ - { 0x3710, 0x8195 }, /* P_RD_P4Q3 */ - { 0x3712, 0x02F9 }, /* P_RD_P4Q4 */ - { 0x3600, 0x0230 }, /* P_GR_P0Q0 */ - { 0x3602, 0x58AD }, /* P_GR_P0Q1 */ - { 0x3604, 0x18D1 }, /* P_GR_P0Q2 */ - { 0x3606, 0x260D }, /* P_GR_P0Q3 */ - { 0x3608, 0xF530 }, /* P_GR_P0Q4 */ - { 0x3640, 0x17EB }, /* P_GR_P1Q0 */ - { 0x3642, 0x3CAB }, /* P_GR_P1Q1 */ - { 0x3644, 0x87CE }, /* P_GR_P1Q2 */ - { 0x3646, 0xC02E }, /* P_GR_P1Q3 */ - { 0x3648, 0xF48F }, /* P_GR_P1Q4 */ - { 0x3680, 0x5350 }, /* P_GR_P2Q0 */ - { 0x3682, 0x7EAF }, /* P_GR_P2Q1 */ - { 0x3684, 0x4312 }, /* P_GR_P2Q2 */ - { 0x3686, 0xC652 }, /* P_GR_P2Q3 */ - { 0x3688, 0xBC15 }, /* P_GR_P2Q4 */ - { 0x36C0, 0xB8AD }, /* P_GR_P3Q0 */ - { 0x36C2, 0xBDCD }, /* P_GR_P3Q1 */ - { 0x36C4, 0xE4B2 }, /* P_GR_P3Q2 */ - { 0x36C6, 0xB50F }, /* P_GR_P3Q3 */ - { 0x36C8, 0x5B95 }, /* P_GR_P3Q4 */ - { 0x3700, 0xFC90 }, /* P_GR_P4Q0 */ - { 0x3702, 0x8C51 }, /* P_GR_P4Q1 */ - { 0x3704, 0xCED6 }, /* P_GR_P4Q2 */ - { 0x3706, 0xB594 }, /* P_GR_P4Q3 */ - { 0x3708, 0x0A39 }, /* P_GR_P4Q4 */ - { 0x3614, 0x0230 }, /* P_BL_P0Q0 */ - { 0x3616, 0x160D }, /* P_BL_P0Q1 */ - { 0x3618, 0x08D1 }, /* P_BL_P0Q2 */ - { 0x361A, 0x98AB }, /* P_BL_P0Q3 */ - { 0x361C, 0xEA50 }, /* P_BL_P0Q4 */ - { 0x3654, 0xB4EA }, /* P_BL_P1Q0 */ - { 0x3656, 0xEA6C }, /* P_BL_P1Q1 */ - { 0x3658, 0xFE08 }, /* P_BL_P1Q2 */ - { 0x365A, 0x2C6E }, /* P_BL_P1Q3 */ - { 0x365C, 0xEB0E }, /* P_BL_P1Q4 */ - { 0x3694, 0x6DF0 }, /* P_BL_P2Q0 */ - { 0x3696, 0x3ACF }, /* P_BL_P2Q1 */ - { 0x3698, 0x3E0F }, /* P_BL_P2Q2 */ - { 0x369A, 0xB2B1 }, /* P_BL_P2Q3 */ - { 0x369C, 0xC374 }, /* P_BL_P2Q4 */ - { 0x36D4, 0xF2AA }, /* P_BL_P3Q0 */ - { 0x36D6, 0x8CCC }, /* P_BL_P3Q1 */ - { 0x36D8, 0xDEF2 }, /* P_BL_P3Q2 */ - { 0x36DA, 0xFA11 }, /* P_BL_P3Q3 */ - { 0x36DC, 0x42F5 }, /* P_BL_P3Q4 */ - { 0x3714, 0xF4F1 }, /* P_BL_P4Q0 */ - { 0x3716, 0xF6F0 }, /* P_BL_P4Q1 */ - { 0x3718, 0x8FD6 }, /* P_BL_P4Q2 */ - { 0x371A, 0xEA14 }, /* P_BL_P4Q3 */ - { 0x371C, 0x6338 }, /* P_BL_P4Q4 */ - { 0x361E, 0x0350 }, /* P_GB_P0Q0 */ - { 0x3620, 0x91AE }, /* P_GB_P0Q1 */ - { 0x3622, 0x0571 }, /* P_GB_P0Q2 */ - { 0x3624, 0x100D }, /* P_GB_P0Q3 */ - { 0x3626, 0xCA70 }, /* P_GB_P0Q4 */ - { 0x365E, 0xE6CB }, /* P_GB_P1Q0 */ - { 0x3660, 0x50ED }, /* P_GB_P1Q1 */ - { 0x3662, 0x3DAE }, /* P_GB_P1Q2 */ - { 0x3664, 0xAA4F }, /* P_GB_P1Q3 */ - { 0x3666, 0xDC50 }, /* P_GB_P1Q4 */ - { 0x369E, 0x5470 }, /* P_GB_P2Q0 */ - { 0x36A0, 0x1F6E }, /* P_GB_P2Q1 */ - { 0x36A2, 0x6671 }, /* P_GB_P2Q2 */ - { 0x36A4, 0xC010 }, /* P_GB_P2Q3 */ - { 0x36A6, 0x8DF5 }, /* P_GB_P2Q4 */ - { 0x36DE, 0x0B0C }, /* P_GB_P3Q0 */ - { 0x36E0, 0x84CE }, /* P_GB_P3Q1 */ - { 0x36E2, 0x8493 }, /* P_GB_P3Q2 */ - { 0x36E4, 0xA610 }, /* P_GB_P3Q3 */ - { 0x36E6, 0x50B5 }, /* P_GB_P3Q4 */ - { 0x371E, 0x9651 }, /* P_GB_P4Q0 */ - { 0x3720, 0x1EAB }, /* P_GB_P4Q1 */ - { 0x3722, 0xAF76 }, /* P_GB_P4Q2 */ - { 0x3724, 0xE4F4 }, /* P_GB_P4Q3 */ - { 0x3726, 0x79F8 }, /* P_GB_P4Q4 */ - { 0x3782, 0x0410 }, /* POLY_ORIGIN_C */ - { 0x3784, 0x0320 }, /* POLY_ORIGIN_R */ - { 0x3780, 0x8000 } /* POLY_SC_ENABLE */ -}; - -struct mt9t013_reg mt9t013_regs = { - .reg_pat = &mt9t013_reg_pat[0], - .reg_pat_size = ARRAY_SIZE(mt9t013_reg_pat), - .ttbl = &mt9t013_test_tbl[0], - .ttbl_size = ARRAY_SIZE(mt9t013_test_tbl), - .lctbl = &mt9t013_lc_tbl[0], - .lctbl_size = ARRAY_SIZE(mt9t013_lc_tbl), - .rftbl = &mt9t013_lc_tbl[0], /* &mt9t013_rolloff_tbl[0], */ - .rftbl_size = ARRAY_SIZE(mt9t013_lc_tbl) -}; - - diff --git a/drivers/staging/dream/camera/s5k3e2fx.c b/drivers/staging/dream/camera/s5k3e2fx.c deleted file mode 100644 index 1459903a339d..000000000000 --- a/drivers/staging/dream/camera/s5k3e2fx.c +++ /dev/null @@ -1,1307 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/uaccess.h> -#include <linux/miscdevice.h> -#include <media/msm_camera.h> -#include <mach/gpio.h> -#include <mach/camera.h> -#include "s5k3e2fx.h" - -#define S5K3E2FX_REG_MODEL_ID 0x0000 -#define S5K3E2FX_MODEL_ID 0x3E2F - -/* PLL Registers */ -#define REG_PRE_PLL_CLK_DIV 0x0305 -#define REG_PLL_MULTIPLIER_MSB 0x0306 -#define REG_PLL_MULTIPLIER_LSB 0x0307 -#define REG_VT_PIX_CLK_DIV 0x0301 -#define REG_VT_SYS_CLK_DIV 0x0303 -#define REG_OP_PIX_CLK_DIV 0x0309 -#define REG_OP_SYS_CLK_DIV 0x030B - -/* Data Format Registers */ -#define REG_CCP_DATA_FORMAT_MSB 0x0112 -#define REG_CCP_DATA_FORMAT_LSB 0x0113 - -/* Output Size */ -#define REG_X_OUTPUT_SIZE_MSB 0x034C -#define REG_X_OUTPUT_SIZE_LSB 0x034D -#define REG_Y_OUTPUT_SIZE_MSB 0x034E -#define REG_Y_OUTPUT_SIZE_LSB 0x034F - -/* Binning */ -#define REG_X_EVEN_INC 0x0381 -#define REG_X_ODD_INC 0x0383 -#define REG_Y_EVEN_INC 0x0385 -#define REG_Y_ODD_INC 0x0387 -/*Reserved register */ -#define REG_BINNING_ENABLE 0x3014 - -/* Frame Fotmat */ -#define REG_FRAME_LENGTH_LINES_MSB 0x0340 -#define REG_FRAME_LENGTH_LINES_LSB 0x0341 -#define REG_LINE_LENGTH_PCK_MSB 0x0342 -#define REG_LINE_LENGTH_PCK_LSB 0x0343 - -/* MSR setting */ -/* Reserved registers */ -#define REG_SHADE_CLK_ENABLE 0x30AC -#define REG_SEL_CCP 0x30C4 -#define REG_VPIX 0x3024 -#define REG_CLAMP_ON 0x3015 -#define REG_OFFSET 0x307E - -/* CDS timing settings */ -/* Reserved registers */ -#define REG_LD_START 0x3000 -#define REG_LD_END 0x3001 -#define REG_SL_START 0x3002 -#define REG_SL_END 0x3003 -#define REG_RX_START 0x3004 -#define REG_S1_START 0x3005 -#define REG_S1_END 0x3006 -#define REG_S1S_START 0x3007 -#define REG_S1S_END 0x3008 -#define REG_S3_START 0x3009 -#define REG_S3_END 0x300A -#define REG_CMP_EN_START 0x300B -#define REG_CLP_SL_START 0x300C -#define REG_CLP_SL_END 0x300D -#define REG_OFF_START 0x300E -#define REG_RMP_EN_START 0x300F -#define REG_TX_START 0x3010 -#define REG_TX_END 0x3011 -#define REG_STX_WIDTH 0x3012 -#define REG_TYPE1_AF_ENABLE 0x3130 -#define DRIVER_ENABLED 0x0001 -#define AUTO_START_ENABLED 0x0010 -#define REG_NEW_POSITION 0x3131 -#define REG_3152_RESERVED 0x3152 -#define REG_315A_RESERVED 0x315A -#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204 -#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205 -#define REG_FINE_INTEGRATION_TIME 0x0200 -#define REG_COARSE_INTEGRATION_TIME 0x0202 -#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203 - -/* Mode select register */ -#define S5K3E2FX_REG_MODE_SELECT 0x0100 -#define S5K3E2FX_MODE_SELECT_STREAM 0x01 /* start streaming */ -#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00 /* software standby */ -#define S5K3E2FX_REG_SOFTWARE_RESET 0x0103 -#define S5K3E2FX_SOFTWARE_RESET 0x01 -#define REG_TEST_PATTERN_MODE 0x0601 - -struct reg_struct { - uint8_t pre_pll_clk_div; /* 0x0305 */ - uint8_t pll_multiplier_msb; /* 0x0306 */ - uint8_t pll_multiplier_lsb; /* 0x0307 */ - uint8_t vt_pix_clk_div; /* 0x0301 */ - uint8_t vt_sys_clk_div; /* 0x0303 */ - uint8_t op_pix_clk_div; /* 0x0309 */ - uint8_t op_sys_clk_div; /* 0x030B */ - uint8_t ccp_data_format_msb; /* 0x0112 */ - uint8_t ccp_data_format_lsb; /* 0x0113 */ - uint8_t x_output_size_msb; /* 0x034C */ - uint8_t x_output_size_lsb; /* 0x034D */ - uint8_t y_output_size_msb; /* 0x034E */ - uint8_t y_output_size_lsb; /* 0x034F */ - uint8_t x_even_inc; /* 0x0381 */ - uint8_t x_odd_inc; /* 0x0383 */ - uint8_t y_even_inc; /* 0x0385 */ - uint8_t y_odd_inc; /* 0x0387 */ - uint8_t binning_enable; /* 0x3014 */ - uint8_t frame_length_lines_msb; /* 0x0340 */ - uint8_t frame_length_lines_lsb; /* 0x0341 */ - uint8_t line_length_pck_msb; /* 0x0342 */ - uint8_t line_length_pck_lsb; /* 0x0343 */ - uint8_t shade_clk_enable ; /* 0x30AC */ - uint8_t sel_ccp; /* 0x30C4 */ - uint8_t vpix; /* 0x3024 */ - uint8_t clamp_on; /* 0x3015 */ - uint8_t offset; /* 0x307E */ - uint8_t ld_start; /* 0x3000 */ - uint8_t ld_end; /* 0x3001 */ - uint8_t sl_start; /* 0x3002 */ - uint8_t sl_end; /* 0x3003 */ - uint8_t rx_start; /* 0x3004 */ - uint8_t s1_start; /* 0x3005 */ - uint8_t s1_end; /* 0x3006 */ - uint8_t s1s_start; /* 0x3007 */ - uint8_t s1s_end; /* 0x3008 */ - uint8_t s3_start; /* 0x3009 */ - uint8_t s3_end; /* 0x300A */ - uint8_t cmp_en_start; /* 0x300B */ - uint8_t clp_sl_start; /* 0x300C */ - uint8_t clp_sl_end; /* 0x300D */ - uint8_t off_start; /* 0x300E */ - uint8_t rmp_en_start; /* 0x300F */ - uint8_t tx_start; /* 0x3010 */ - uint8_t tx_end; /* 0x3011 */ - uint8_t stx_width; /* 0x3012 */ - uint8_t reg_3152_reserved; /* 0x3152 */ - uint8_t reg_315A_reserved; /* 0x315A */ - uint8_t analogue_gain_code_global_msb; /* 0x0204 */ - uint8_t analogue_gain_code_global_lsb; /* 0x0205 */ - uint8_t fine_integration_time; /* 0x0200 */ - uint8_t coarse_integration_time; /* 0x0202 */ - uint32_t size_h; - uint32_t blk_l; - uint32_t size_w; - uint32_t blk_p; -}; - -struct reg_struct s5k3e2fx_reg_pat[2] = { - { /* Preview */ - 0x06, /* pre_pll_clk_div REG=0x0305 */ - 0x00, /* pll_multiplier_msb REG=0x0306 */ - 0x88, /* pll_multiplier_lsb REG=0x0307 */ - 0x0a, /* vt_pix_clk_div REG=0x0301 */ - 0x01, /* vt_sys_clk_div REG=0x0303 */ - 0x0a, /* op_pix_clk_div REG=0x0309 */ - 0x01, /* op_sys_clk_div REG=0x030B */ - 0x0a, /* ccp_data_format_msb REG=0x0112 */ - 0x0a, /* ccp_data_format_lsb REG=0x0113 */ - 0x05, /* x_output_size_msb REG=0x034C */ - 0x10, /* x_output_size_lsb REG=0x034D */ - 0x03, /* y_output_size_msb REG=0x034E */ - 0xcc, /* y_output_size_lsb REG=0x034F */ - - /* enable binning for preview */ - 0x01, /* x_even_inc REG=0x0381 */ - 0x01, /* x_odd_inc REG=0x0383 */ - 0x01, /* y_even_inc REG=0x0385 */ - 0x03, /* y_odd_inc REG=0x0387 */ - 0x06, /* binning_enable REG=0x3014 */ - - 0x03, /* frame_length_lines_msb REG=0x0340 */ - 0xde, /* frame_length_lines_lsb REG=0x0341 */ - 0x0a, /* line_length_pck_msb REG=0x0342 */ - 0xac, /* line_length_pck_lsb REG=0x0343 */ - 0x81, /* shade_clk_enable REG=0x30AC */ - 0x01, /* sel_ccp REG=0x30C4 */ - 0x04, /* vpix REG=0x3024 */ - 0x00, /* clamp_on REG=0x3015 */ - 0x02, /* offset REG=0x307E */ - 0x03, /* ld_start REG=0x3000 */ - 0x9c, /* ld_end REG=0x3001 */ - 0x02, /* sl_start REG=0x3002 */ - 0x9e, /* sl_end REG=0x3003 */ - 0x05, /* rx_start REG=0x3004 */ - 0x0f, /* s1_start REG=0x3005 */ - 0x24, /* s1_end REG=0x3006 */ - 0x7c, /* s1s_start REG=0x3007 */ - 0x9a, /* s1s_end REG=0x3008 */ - 0x10, /* s3_start REG=0x3009 */ - 0x14, /* s3_end REG=0x300A */ - 0x10, /* cmp_en_start REG=0x300B */ - 0x04, /* clp_sl_start REG=0x300C */ - 0x26, /* clp_sl_end REG=0x300D */ - 0x02, /* off_start REG=0x300E */ - 0x0e, /* rmp_en_start REG=0x300F */ - 0x30, /* tx_start REG=0x3010 */ - 0x4e, /* tx_end REG=0x3011 */ - 0x1E, /* stx_width REG=0x3012 */ - 0x08, /* reg_3152_reserved REG=0x3152 */ - 0x10, /* reg_315A_reserved REG=0x315A */ - 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ - 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ - 0x02, /* fine_integration_time REG=0x0200 */ - 0x03, /* coarse_integration_time REG=0x0202 */ - 972, - 18, - 1296, - 1436 - }, - { /* Snapshot */ - 0x06, /* pre_pll_clk_div REG=0x0305 */ - 0x00, /* pll_multiplier_msb REG=0x0306 */ - 0x88, /* pll_multiplier_lsb REG=0x0307 */ - 0x0a, /* vt_pix_clk_div REG=0x0301 */ - 0x01, /* vt_sys_clk_div REG=0x0303 */ - 0x0a, /* op_pix_clk_div REG=0x0309 */ - 0x01, /* op_sys_clk_div REG=0x030B */ - 0x0a, /* ccp_data_format_msb REG=0x0112 */ - 0x0a, /* ccp_data_format_lsb REG=0x0113 */ - 0x0a, /* x_output_size_msb REG=0x034C */ - 0x30, /* x_output_size_lsb REG=0x034D */ - 0x07, /* y_output_size_msb REG=0x034E */ - 0xa8, /* y_output_size_lsb REG=0x034F */ - - /* disable binning for snapshot */ - 0x01, /* x_even_inc REG=0x0381 */ - 0x01, /* x_odd_inc REG=0x0383 */ - 0x01, /* y_even_inc REG=0x0385 */ - 0x01, /* y_odd_inc REG=0x0387 */ - 0x00, /* binning_enable REG=0x3014 */ - - 0x07, /* frame_length_lines_msb REG=0x0340 */ - 0xb6, /* frame_length_lines_lsb REG=0x0341 */ - 0x0a, /* line_length_pck_msb REG=0x0342 */ - 0xac, /* line_length_pck_lsb REG=0x0343 */ - 0x81, /* shade_clk_enable REG=0x30AC */ - 0x01, /* sel_ccp REG=0x30C4 */ - 0x04, /* vpix REG=0x3024 */ - 0x00, /* clamp_on REG=0x3015 */ - 0x02, /* offset REG=0x307E */ - 0x03, /* ld_start REG=0x3000 */ - 0x9c, /* ld_end REG=0x3001 */ - 0x02, /* sl_start REG=0x3002 */ - 0x9e, /* sl_end REG=0x3003 */ - 0x05, /* rx_start REG=0x3004 */ - 0x0f, /* s1_start REG=0x3005 */ - 0x24, /* s1_end REG=0x3006 */ - 0x7c, /* s1s_start REG=0x3007 */ - 0x9a, /* s1s_end REG=0x3008 */ - 0x10, /* s3_start REG=0x3009 */ - 0x14, /* s3_end REG=0x300A */ - 0x10, /* cmp_en_start REG=0x300B */ - 0x04, /* clp_sl_start REG=0x300C */ - 0x26, /* clp_sl_end REG=0x300D */ - 0x02, /* off_start REG=0x300E */ - 0x0e, /* rmp_en_start REG=0x300F */ - 0x30, /* tx_start REG=0x3010 */ - 0x4e, /* tx_end REG=0x3011 */ - 0x1E, /* stx_width REG=0x3012 */ - 0x08, /* reg_3152_reserved REG=0x3152 */ - 0x10, /* reg_315A_reserved REG=0x315A */ - 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ - 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ - 0x02, /* fine_integration_time REG=0x0200 */ - 0x03, /* coarse_integration_time REG=0x0202 */ - 1960, - 14, - 2608, - 124 - } -}; - -struct s5k3e2fx_work { - struct work_struct work; -}; -static struct s5k3e2fx_work *s5k3e2fx_sensorw; -static struct i2c_client *s5k3e2fx_client; - -struct s5k3e2fx_ctrl { - const struct msm_camera_sensor_info *sensordata; - - int sensormode; - uint32_t fps_divider; /* init to 1 * 0x00000400 */ - uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ - - uint16_t curr_lens_pos; - uint16_t init_curr_lens_pos; - uint16_t my_reg_gain; - uint32_t my_reg_line_count; - - enum msm_s_resolution prev_res; - enum msm_s_resolution pict_res; - enum msm_s_resolution curr_res; - enum msm_s_test_mode set_test; -}; - -struct s5k3e2fx_i2c_reg_conf { - unsigned short waddr; - unsigned char bdata; -}; - -static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl; -static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue); -DECLARE_MUTEX(s5k3e2fx_sem); - -static int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, - int length) -{ - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = 0, - .len = 2, - .buf = rxdata, - }, - { - .addr = saddr, - .flags = I2C_M_RD, - .len = length, - .buf = rxdata, - }, - }; - - if (i2c_transfer(s5k3e2fx_client->adapter, msgs, 2) < 0) { - CDBG("s5k3e2fx_i2c_rxdata failed!\n"); - return -EIO; - } - - return 0; -} - -static int32_t s5k3e2fx_i2c_txdata(unsigned short saddr, - unsigned char *txdata, int length) -{ - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - - if (i2c_transfer(s5k3e2fx_client->adapter, msg, 1) < 0) { - CDBG("s5k3e2fx_i2c_txdata failed\n"); - return -EIO; - } - - return 0; -} - -static int32_t s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr, - unsigned char bdata) -{ - int32_t rc = -EIO; - unsigned char buf[4]; - - memset(buf, 0, sizeof(buf)); - buf[0] = (waddr & 0xFF00)>>8; - buf[1] = (waddr & 0x00FF); - buf[2] = bdata; - - rc = s5k3e2fx_i2c_txdata(saddr, buf, 3); - - if (rc < 0) - CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", - waddr, bdata); - - return rc; -} - -static int32_t s5k3e2fx_i2c_write_table( - struct s5k3e2fx_i2c_reg_conf *reg_cfg_tbl, int num) -{ - int i; - int32_t rc = -EIO; - for (i = 0; i < num; i++) { - if (rc < 0) - break; - reg_cfg_tbl++; - } - - return rc; -} - -static int32_t s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr, - unsigned short *rdata) -{ - int32_t rc = 0; - unsigned char buf[4]; - - if (!rdata) - return -EIO; - - memset(buf, 0, sizeof(buf)); - - buf[0] = (raddr & 0xFF00)>>8; - buf[1] = (raddr & 0x00FF); - - rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2); - if (rc < 0) - return rc; - - *rdata = buf[0] << 8 | buf[1]; - - if (rc < 0) - CDBG("s5k3e2fx_i2c_read failed!\n"); - - return rc; -} - -static int s5k3e2fx_probe_init_done(const struct msm_camera_sensor_info *data) -{ - gpio_direction_output(data->sensor_reset, 0); - gpio_free(data->sensor_reset); - return 0; -} - -static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data) -{ - int32_t rc; - uint16_t chipid = 0; - - rc = gpio_request(data->sensor_reset, "s5k3e2fx"); - if (!rc) - gpio_direction_output(data->sensor_reset, 1); - else - goto init_probe_done; - - mdelay(20); - - CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n"); - - rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr, - S5K3E2FX_REG_MODEL_ID, &chipid); - if (rc < 0) - goto init_probe_fail; - - if (chipid != S5K3E2FX_MODEL_ID) { - CDBG("S5K3E2FX wrong model_id = 0x%x\n", chipid); - rc = -ENODEV; - goto init_probe_fail; - } - - goto init_probe_done; - -init_probe_fail: - s5k3e2fx_probe_init_done(data); -init_probe_done: - return rc; -} - -static int s5k3e2fx_init_client(struct i2c_client *client) -{ - /* Initialize the MSM_CAMI2C Chip */ - init_waitqueue_head(&s5k3e2fx_wait_queue); - return 0; -} - -static const struct i2c_device_id s5k3e2fx_i2c_id[] = { - { "s5k3e2fx", 0}, - { } -}; - -static int s5k3e2fx_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc = 0; - CDBG("s5k3e2fx_probe called!\n"); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - CDBG("i2c_check_functionality failed\n"); - goto probe_failure; - } - - s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL); - if (!s5k3e2fx_sensorw) { - CDBG("kzalloc failed.\n"); - rc = -ENOMEM; - goto probe_failure; - } - - i2c_set_clientdata(client, s5k3e2fx_sensorw); - s5k3e2fx_init_client(client); - s5k3e2fx_client = client; - - mdelay(50); - - CDBG("s5k3e2fx_probe successed! rc = %d\n", rc); - return 0; - -probe_failure: - CDBG("s5k3e2fx_probe failed! rc = %d\n", rc); - return rc; -} - -static struct i2c_driver s5k3e2fx_i2c_driver = { - .id_table = s5k3e2fx_i2c_id, - .probe = s5k3e2fx_i2c_probe, - .remove = __exit_p(s5k3e2fx_i2c_remove), - .driver = { - .name = "s5k3e2fx", - }, -}; - -static int32_t s5k3e2fx_test(enum msm_s_test_mode mo) -{ - int32_t rc = 0; - - if (mo == S_TEST_OFF) - rc = 0; - else - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, - REG_TEST_PATTERN_MODE, (uint16_t)mo); - - return rc; -} - -static int32_t s5k3e2fx_setting(enum msm_s_reg_update rupdate, - enum msm_s_setting rt) -{ - int32_t rc = 0; - uint16_t num_lperf; - - switch (rupdate) { - case S_UPDATE_PERIODIC: - if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { - - struct s5k3e2fx_i2c_reg_conf tbl_1[] = { - {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, - {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, - {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb}, - {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb}, - {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb}, - {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb}, - {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc}, - {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc}, - {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc}, - {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc}, - {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable}, - }; - - struct s5k3e2fx_i2c_reg_conf tbl_2[] = { - {REG_FRAME_LENGTH_LINES_MSB, 0}, - {REG_FRAME_LENGTH_LINES_LSB, 0}, - {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb}, - {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, - {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable}, - {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, - {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, - {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, - {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, - {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, - {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, - {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, - {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, - {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, - {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, - {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, - {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, - {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, - {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, - {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, - {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, - {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, - {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, - {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, - {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, - {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, - {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, - {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, - {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved}, - {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved}, - {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb}, - {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb}, - {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time}, - {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time}, - {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, - }; - - rc = s5k3e2fx_i2c_write_table(&tbl_1[0], - ARRAY_SIZE(tbl_1)); - if (rc < 0) - return rc; - - num_lperf = - (uint16_t)((s5k3e2fx_reg_pat[rt].frame_length_lines_msb << 8) & 0xFF00) + - s5k3e2fx_reg_pat[rt].frame_length_lines_lsb; - - num_lperf = num_lperf * s5k3e2fx_ctrl->fps_divider / 0x0400; - - tbl_2[0] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_MSB, (num_lperf & 0xFF00) >> 8}; - tbl_2[1] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_LSB, (num_lperf & 0x00FF)}; - - rc = s5k3e2fx_i2c_write_table(&tbl_2[0], - ARRAY_SIZE(tbl_2)); - if (rc < 0) - return rc; - - mdelay(5); - - rc = s5k3e2fx_test(s5k3e2fx_ctrl->set_test); - if (rc < 0) - return rc; - } - break; /* UPDATE_PERIODIC */ - - case S_REG_INIT: - if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { - - struct s5k3e2fx_i2c_reg_conf tbl_3[] = { - {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET}, - {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_SW_STANDBY}, - /* PLL setting */ - {REG_PRE_PLL_CLK_DIV, s5k3e2fx_reg_pat[rt].pre_pll_clk_div}, - {REG_PLL_MULTIPLIER_MSB, s5k3e2fx_reg_pat[rt].pll_multiplier_msb}, - {REG_PLL_MULTIPLIER_LSB, s5k3e2fx_reg_pat[rt].pll_multiplier_lsb}, - {REG_VT_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_pix_clk_div}, - {REG_VT_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_sys_clk_div}, - {REG_OP_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].op_pix_clk_div}, - {REG_OP_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].op_sys_clk_div}, - /*Data Format */ - {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, - {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, - /*Output Size */ - {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb}, - {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb}, - {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb}, - {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb}, - /* Binning */ - {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc}, - {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc }, - {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc}, - {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc}, - {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable}, - /* Frame format */ - {REG_FRAME_LENGTH_LINES_MSB, s5k3e2fx_reg_pat[rt].frame_length_lines_msb}, - {REG_FRAME_LENGTH_LINES_LSB, s5k3e2fx_reg_pat[rt].frame_length_lines_lsb}, - {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb}, - {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, - /* MSR setting */ - {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable}, - {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, - {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, - {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, - {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, - /* CDS timing setting */ - {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, - {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, - {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, - {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, - {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, - {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, - {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, - {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, - {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, - {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, - {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, - {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, - {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, - {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, - {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, - {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, - {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, - {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, - {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, - {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved}, - {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved}, - {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb}, - {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb}, - {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time}, - {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time}, - {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, - }; - - /* reset fps_divider */ - s5k3e2fx_ctrl->fps_divider = 1 * 0x0400; - rc = s5k3e2fx_i2c_write_table(&tbl_3[0], - ARRAY_SIZE(tbl_3)); - if (rc < 0) - return rc; - } - break; /* case REG_INIT: */ - - default: - rc = -EINVAL; - break; - } /* switch (rupdate) */ - - return rc; -} - -static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data) -{ - int32_t rc; - - s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL); - if (!s5k3e2fx_ctrl) { - CDBG("s5k3e2fx_init failed!\n"); - rc = -ENOMEM; - goto init_done; - } - - s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400; - s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400; - s5k3e2fx_ctrl->set_test = S_TEST_OFF; - s5k3e2fx_ctrl->prev_res = S_QTR_SIZE; - s5k3e2fx_ctrl->pict_res = S_FULL_SIZE; - - if (data) - s5k3e2fx_ctrl->sensordata = data; - - /* enable mclk first */ - msm_camio_clk_rate_set(24000000); - mdelay(20); - - msm_camio_camif_pad_reg_reset(); - mdelay(20); - - rc = s5k3e2fx_probe_init_sensor(data); - if (rc < 0) - goto init_fail1; - - if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE) - rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW); - else - rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE); - - if (rc < 0) { - CDBG("s5k3e2fx_setting failed. rc = %d\n", rc); - goto init_fail1; - } - - /* initialize AF */ - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A); - if (rc < 0) - goto init_fail1; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03); - if (rc < 0) - goto init_fail1; - - goto init_done; - -init_fail1: - s5k3e2fx_probe_init_done(data); - kfree(s5k3e2fx_ctrl); -init_done: - return rc; -} - -static int32_t s5k3e2fx_power_down(void) -{ - int32_t rc = 0; - return rc; -} - -static int s5k3e2fx_sensor_release(void) -{ - int rc = -EBADF; - - down(&s5k3e2fx_sem); - - s5k3e2fx_power_down(); - - gpio_direction_output(s5k3e2fx_ctrl->sensordata->sensor_reset, - 0); - gpio_free(s5k3e2fx_ctrl->sensordata->sensor_reset); - - kfree(s5k3e2fx_ctrl); - s5k3e2fx_ctrl = NULL; - - CDBG("s5k3e2fx_release completed\n"); - - up(&s5k3e2fx_sem); - return rc; -} - -static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps) -{ - /* input fps is preview fps in Q8 format */ - uint32_t divider; /* Q10 */ - - divider = (uint32_t) - ((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * - (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 / - ((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) * - (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p)); - - /* Verify PCLK settings and frame sizes. */ - *pfps = (uint16_t)(fps * divider / 0x00000400); -} - -static uint16_t s5k3e2fx_get_prev_lines_pf(void) -{ - return (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l); -} - -static uint16_t s5k3e2fx_get_prev_pixels_pl(void) -{ - return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p; -} - -static uint16_t s5k3e2fx_get_pict_lines_pf(void) -{ - return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; -} - -static uint16_t s5k3e2fx_get_pict_pixels_pl(void) -{ - return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; -} - -static uint32_t s5k3e2fx_get_pict_max_exp_lc(void) -{ - uint32_t snapshot_lines_per_frame; - - if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE) - snapshot_lines_per_frame = - s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l; - else - snapshot_lines_per_frame = 3961 * 3; - - return snapshot_lines_per_frame; -} - -static int32_t s5k3e2fx_set_fps(struct fps_cfg *fps) -{ - /* input is new fps in Q10 format */ - int32_t rc = 0; - - s5k3e2fx_ctrl->fps_divider = fps->fps_div; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, - REG_FRAME_LENGTH_LINES_MSB, - (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * - s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00) >> 8); - if (rc < 0) - goto set_fps_done; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, - REG_FRAME_LENGTH_LINES_LSB, - (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * - s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00)); - -set_fps_done: - return rc; -} - -static int32_t s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line) -{ - int32_t rc = 0; - - uint16_t max_legal_gain = 0x0200; - uint32_t ll_ratio; /* Q10 */ - uint16_t ll_pck, fl_lines; - uint16_t offset = 4; - uint8_t gain_msb, gain_lsb; - uint8_t intg_t_msb, intg_t_lsb; - uint8_t ll_pck_msb, ll_pck_lsb, tmp; - - struct s5k3e2fx_i2c_reg_conf tbl[2]; - - CDBG("Line:%d s5k3e2fx_write_exp_gain \n", __LINE__); - - if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) { - - s5k3e2fx_ctrl->my_reg_gain = gain; - s5k3e2fx_ctrl->my_reg_line_count = (uint16_t)line; - - fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; - - ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; - - } else { - - fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; - - ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + - s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; - } - - if (gain > max_legal_gain) - gain = max_legal_gain; - - /* in Q10 */ - line = (line * s5k3e2fx_ctrl->fps_divider); - - if (fl_lines < (line / 0x400)) - ll_ratio = (line / (fl_lines - offset)); - else - ll_ratio = 0x400; - - /* update gain registers */ - gain_msb = (gain & 0xFF00) >> 8; - gain_lsb = gain & 0x00FF; - tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB; - tbl[0].bdata = gain_msb; - tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB; - tbl[1].bdata = gain_lsb; - rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); - if (rc < 0) - goto write_gain_done; - - ll_pck = ll_pck * ll_ratio; - ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8; - ll_pck_lsb = (ll_pck / 0x400) & 0x00FF; - tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB; - tbl[0].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_msb; - tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB; - tbl[1].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_lsb; - rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); - if (rc < 0) - goto write_gain_done; - - tmp = (ll_pck * 0x400) / ll_ratio; - intg_t_msb = (tmp & 0xFF00) >> 8; - intg_t_lsb = (tmp & 0x00FF); - tbl[0].waddr = REG_COARSE_INTEGRATION_TIME; - tbl[0].bdata = intg_t_msb; - tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB; - tbl[1].bdata = intg_t_lsb; - rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); - -write_gain_done: - return rc; -} - -static int32_t s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line) -{ - int32_t rc = 0; - - CDBG("Line:%d s5k3e2fx_set_pict_exp_gain \n", __LINE__); - - rc = - s5k3e2fx_write_exp_gain(gain, line); - - return rc; -} - -static int32_t s5k3e2fx_video_config(int mode, int res) -{ - int32_t rc; - - switch (res) { - case S_QTR_SIZE: - rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW); - if (rc < 0) - return rc; - - CDBG("s5k3e2fx sensor configuration done!\n"); - break; - - case S_FULL_SIZE: - rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); - if (rc < 0) - return rc; - - break; - - default: - return 0; - } /* switch */ - - s5k3e2fx_ctrl->prev_res = res; - s5k3e2fx_ctrl->curr_res = res; - s5k3e2fx_ctrl->sensormode = mode; - - rc = - s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain, - s5k3e2fx_ctrl->my_reg_line_count); - - return rc; -} - -static int32_t s5k3e2fx_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); - if (rc < 0) - return rc; - - s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; - s5k3e2fx_ctrl->sensormode = mode; - - return rc; -} - -static int32_t s5k3e2fx_raw_snapshot_config(int mode) -{ - int32_t rc = 0; - - rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); - if (rc < 0) - return rc; - - s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; - s5k3e2fx_ctrl->sensormode = mode; - - return rc; -} - -static int32_t s5k3e2fx_set_sensor_mode(int mode, int res) -{ - int32_t rc = 0; - - switch (mode) { - case SENSOR_PREVIEW_MODE: - rc = s5k3e2fx_video_config(mode, res); - break; - - case SENSOR_SNAPSHOT_MODE: - rc = s5k3e2fx_snapshot_config(mode); - break; - - case SENSOR_RAW_SNAPSHOT_MODE: - rc = s5k3e2fx_raw_snapshot_config(mode); - break; - - default: - rc = -EINVAL; - break; - } - - return rc; -} - -static int32_t s5k3e2fx_set_default_focus(void) -{ - int32_t rc = 0; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, - 0x3131, 0); - if (rc < 0) - return rc; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, - 0x3132, 0); - if (rc < 0) - return rc; - - s5k3e2fx_ctrl->curr_lens_pos = 0; - - return rc; -} - -static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps) -{ - int32_t rc = 0; - int32_t i; - int16_t step_direction; - int16_t actual_step; - int16_t next_pos, pos_offset; - int16_t init_code = 50; - uint8_t next_pos_msb, next_pos_lsb; - int16_t s_move[5]; - uint32_t gain; /* Q10 format */ - - if (direction == MOVE_NEAR) - step_direction = 20; - else if (direction == MOVE_FAR) - step_direction = -20; - else { - CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__); - return -EINVAL; - } - - actual_step = step_direction * (int16_t)num_steps; - pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos; - gain = ((actual_step << 10) / 5) >> 10; - - for (i = 0; i <= 4; i++) - s_move[i] = gain; - - /* Ring Damping Code */ - for (i = 0; i <= 4; i++) { - next_pos = (int16_t)(pos_offset + s_move[i]); - - if (next_pos > (738 + init_code)) - next_pos = 738 + init_code; - else if (next_pos < 0) - next_pos = 0; - - CDBG("next_position in damping mode = %d\n", next_pos); - /* Writing the Values to the actuator */ - if (next_pos == init_code) - next_pos = 0x00; - - next_pos_msb = next_pos >> 8; - next_pos_lsb = next_pos & 0x00FF; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, next_pos_msb); - if (rc < 0) - break; - - rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, next_pos_lsb); - if (rc < 0) - break; - - pos_offset = next_pos; - s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code; - if (i < 4) - mdelay(3); - } - - return rc; -} - -static int s5k3e2fx_sensor_config(void __user *argp) -{ - struct sensor_cfg_data cdata; - long rc = 0; - - if (copy_from_user(&cdata, - (void *)argp, - sizeof(struct sensor_cfg_data))) - return -EFAULT; - - down(&s5k3e2fx_sem); - - CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); - switch (cdata.cfgtype) { - case CFG_GET_PICT_FPS: - s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps, - &(cdata.cfg.gfps.pictfps)); - - if (copy_to_user((void *)argp, &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_L_PF: - cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PREV_P_PL: - cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_L_PF: - cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_P_PL: - cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_GET_PICT_MAX_EXP_LC: - cdata.cfg.pict_max_exp_lc = - s5k3e2fx_get_pict_max_exp_lc(); - - if (copy_to_user((void *)argp, - &cdata, - sizeof(struct sensor_cfg_data))) - rc = -EFAULT; - break; - - case CFG_SET_FPS: - case CFG_SET_PICT_FPS: - rc = s5k3e2fx_set_fps(&(cdata.cfg.fps)); - break; - - case CFG_SET_EXP_GAIN: - rc = - s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_PICT_EXP_GAIN: - CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); - rc = - s5k3e2fx_set_pict_exp_gain( - cdata.cfg.exp_gain.gain, - cdata.cfg.exp_gain.line); - break; - - case CFG_SET_MODE: - rc = - s5k3e2fx_set_sensor_mode( - cdata.mode, cdata.rs); - break; - - case CFG_PWR_DOWN: - rc = s5k3e2fx_power_down(); - break; - - case CFG_MOVE_FOCUS: - rc = - s5k3e2fx_move_focus( - cdata.cfg.focus.dir, - cdata.cfg.focus.steps); - break; - - case CFG_SET_DEFAULT_FOCUS: - rc = - s5k3e2fx_set_default_focus(); - break; - - case CFG_GET_AF_MAX_STEPS: - case CFG_SET_EFFECT: - case CFG_SET_LENS_SHADING: - default: - rc = -EINVAL; - break; - } - - up(&s5k3e2fx_sem); - return rc; -} - -static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info, - struct msm_sensor_ctrl *s) -{ - int rc = 0; - - rc = i2c_add_driver(&s5k3e2fx_i2c_driver); - if (rc < 0 || s5k3e2fx_client == NULL) { - rc = -ENOTSUPP; - goto probe_fail; - } - - msm_camio_clk_rate_set(24000000); - mdelay(20); - - rc = s5k3e2fx_probe_init_sensor(info); - if (rc < 0) - goto probe_fail; - - s->s_init = s5k3e2fx_sensor_open_init; - s->s_release = s5k3e2fx_sensor_release; - s->s_config = s5k3e2fx_sensor_config; - s5k3e2fx_probe_init_done(info); - - return rc; - -probe_fail: - CDBG("SENSOR PROBE FAILS!\n"); - return rc; -} - -static int __s5k3e2fx_probe(struct platform_device *pdev) -{ - return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe); -} - -static struct platform_driver msm_camera_driver = { - .probe = __s5k3e2fx_probe, - .driver = { - .name = "msm_camera_s5k3e2fx", - .owner = THIS_MODULE, - }, -}; - -static int __init s5k3e2fx_init(void) -{ - return platform_driver_register(&msm_camera_driver); -} - -module_init(s5k3e2fx_init); - diff --git a/drivers/staging/dream/camera/s5k3e2fx.h b/drivers/staging/dream/camera/s5k3e2fx.h deleted file mode 100644 index 69bc75084457..000000000000 --- a/drivers/staging/dream/camera/s5k3e2fx.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#ifndef CAMSENSOR_S5K3E2FX -#define CAMSENSOR_S5K3E2FX - -#include <mach/board.h> -#endif /* CAMSENSOR_S5K3E2FX */ diff --git a/drivers/staging/dream/generic_gpio.c b/drivers/staging/dream/generic_gpio.c deleted file mode 100644 index fe24d38345d0..000000000000 --- a/drivers/staging/dream/generic_gpio.c +++ /dev/null @@ -1,274 +0,0 @@ -/* arch/arm/mach-msm/generic_gpio.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <asm/gpio.h> -#include "gpio_chip.h" - -#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5) - -struct gpio_state { - unsigned long flags; - int refcount; -}; - -static DEFINE_SPINLOCK(gpio_chips_lock); -static LIST_HEAD(gpio_chip_list); -static struct gpio_chip **gpio_chip_array; -static unsigned long gpio_chip_array_size; - -int register_gpio_chip(struct gpio_chip *new_gpio_chip) -{ - int err = 0; - struct gpio_chip *gpio_chip; - int i; - unsigned long irq_flags; - unsigned int chip_array_start_index, chip_array_end_index; - - new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL); - if (new_gpio_chip->state == NULL) { - printk(KERN_ERR "register_gpio_chip: failed to allocate state\n"); - return -ENOMEM; - } - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start); - chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end); - if (chip_array_end_index >= gpio_chip_array_size) { - struct gpio_chip **new_gpio_chip_array; - unsigned long new_gpio_chip_array_size = chip_array_end_index + 1; - - new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC); - if (new_gpio_chip_array == NULL) { - printk(KERN_ERR "register_gpio_chip: failed to allocate array\n"); - err = -ENOMEM; - goto failed; - } - for (i = 0; i < gpio_chip_array_size; i++) - new_gpio_chip_array[i] = gpio_chip_array[i]; - for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++) - new_gpio_chip_array[i] = NULL; - gpio_chip_array = new_gpio_chip_array; - gpio_chip_array_size = new_gpio_chip_array_size; - } - list_for_each_entry(gpio_chip, &gpio_chip_list, list) { - if (gpio_chip->start > new_gpio_chip->end) { - list_add_tail(&new_gpio_chip->list, &gpio_chip->list); - goto added; - } - if (gpio_chip->end >= new_gpio_chip->start) { - printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n", - new_gpio_chip->start, new_gpio_chip->end, - gpio_chip->start, gpio_chip->end); - err = -EBUSY; - goto failed; - } - } - list_add_tail(&new_gpio_chip->list, &gpio_chip_list); -added: - for (i = chip_array_start_index; i <= chip_array_end_index; i++) { - if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start) - gpio_chip_array[i] = new_gpio_chip; - } -failed: - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - if (err) - kfree(new_gpio_chip->state); - return err; -} - -static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio) -{ - unsigned long i; - struct gpio_chip *chip; - - i = GPIO_NUM_TO_CHIP_INDEX(gpio); - if (i >= gpio_chip_array_size) - return NULL; - chip = gpio_chip_array[i]; - if (chip == NULL) - return NULL; - list_for_each_entry_from(chip, &gpio_chip_list, list) { - if (gpio < chip->start) - return NULL; - if (gpio <= chip->end) - return chip; - } - return NULL; -} - -static int request_gpio(unsigned int gpio, unsigned long flags) -{ - int err = 0; - struct gpio_chip *chip; - unsigned long irq_flags; - unsigned long chip_index; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip == NULL) { - err = -EINVAL; - goto err; - } - chip_index = gpio - chip->start; - if (chip->state[chip_index].refcount == 0) { - chip->configure(chip, gpio, flags); - chip->state[chip_index].flags = flags; - chip->state[chip_index].refcount++; - } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED)) - chip->state[chip_index].refcount++; - else - err = -EBUSY; -err: - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return err; -} - -int gpio_request(unsigned gpio, const char *label) -{ - return request_gpio(gpio, 0); -} -EXPORT_SYMBOL(gpio_request); - -void gpio_free(unsigned gpio) -{ - struct gpio_chip *chip; - unsigned long irq_flags; - unsigned long chip_index; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip) { - chip_index = gpio - chip->start; - chip->state[chip_index].refcount--; - } - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); -} -EXPORT_SYMBOL(gpio_free); - -static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip && chip->get_irq_num) - ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return ret; -} - -int gpio_to_irq(unsigned gpio) -{ - int ret, irq; - ret = gpio_get_irq_num(gpio, &irq, NULL); - if (ret) - return ret; - return irq; -} -EXPORT_SYMBOL(gpio_to_irq); - -int gpio_configure(unsigned int gpio, unsigned long flags) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip) - ret = chip->configure(chip, gpio, flags); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return ret; -} -EXPORT_SYMBOL(gpio_configure); - -int gpio_direction_input(unsigned gpio) -{ - return gpio_configure(gpio, GPIOF_INPUT); -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned gpio, int value) -{ - gpio_set_value(gpio, value); - return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT); -} -EXPORT_SYMBOL(gpio_direction_output); - -int gpio_get_value(unsigned gpio) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip && chip->read) - ret = chip->read(chip, gpio); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return ret; -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned gpio, int on) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip && chip->write) - ret = chip->write(chip, gpio, on); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_read_detect_status(unsigned int gpio) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip && chip->read_detect_status) - ret = chip->read_detect_status(chip, gpio); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return ret; -} -EXPORT_SYMBOL(gpio_read_detect_status); - -int gpio_clear_detect_status(unsigned int gpio) -{ - int ret = -ENOTSUPP; - struct gpio_chip *chip; - unsigned long irq_flags; - - spin_lock_irqsave(&gpio_chips_lock, irq_flags); - chip = get_gpio_chip_locked(gpio); - if (chip && chip->clear_detect_status) - ret = chip->clear_detect_status(chip, gpio); - spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); - return ret; -} -EXPORT_SYMBOL(gpio_clear_detect_status); diff --git a/drivers/staging/dream/gpio_axis.c b/drivers/staging/dream/gpio_axis.c deleted file mode 100644 index eb54724b1d3a..000000000000 --- a/drivers/staging/dream/gpio_axis.c +++ /dev/null @@ -1,181 +0,0 @@ -/* drivers/input/misc/gpio_axis.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/gpio_event.h> -#include <linux/interrupt.h> - -struct gpio_axis_state { - struct input_dev *input_dev; - struct gpio_event_axis_info *info; - uint32_t pos; -}; - -uint16_t gpio_axis_4bit_gray_map_table[] = { - [0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */ - [0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */ - [0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */ - [0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */ - [0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */ - [0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */ - [0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */ - [0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */ -}; -uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in) -{ - return gpio_axis_4bit_gray_map_table[in]; -} - -uint16_t gpio_axis_5bit_singletrack_map_table[] = { - [0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /* 10000 10100 11100 */ - [0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /* 11110 11010 11000 */ - [0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /* 01000 01010 01110 */ - [0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /* 01111 01101 01100 */ - [0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /* 00100 00101 00111 */ - [0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /* 10111 10110 00110 */ - [0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /* 00010 10010 10011 */ - [0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /* 11011 01011 00011 */ - [0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001 */ - [0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001 */ -}; -uint16_t gpio_axis_5bit_singletrack_map( - struct gpio_event_axis_info *info, uint16_t in) -{ - return gpio_axis_5bit_singletrack_map_table[in]; -} - -static void gpio_event_update_axis(struct gpio_axis_state *as, int report) -{ - struct gpio_event_axis_info *ai = as->info; - int i; - int change; - uint16_t state = 0; - uint16_t pos; - uint16_t old_pos = as->pos; - for (i = ai->count - 1; i >= 0; i--) - state = (state << 1) | gpio_get_value(ai->gpio[i]); - pos = ai->map(ai, state); - if (ai->flags & GPIOEAF_PRINT_RAW) - pr_info("axis %d-%d raw %x, pos %d -> %d\n", - ai->type, ai->code, state, old_pos, pos); - if (report && pos != old_pos) { - if (ai->type == EV_REL) { - change = (ai->decoded_size + pos - old_pos) % - ai->decoded_size; - if (change > ai->decoded_size / 2) - change -= ai->decoded_size; - if (change == ai->decoded_size / 2) { - if (ai->flags & GPIOEAF_PRINT_EVENT) - pr_info("axis %d-%d unknown direction, " - "pos %d -> %d\n", ai->type, - ai->code, old_pos, pos); - change = 0; /* no closest direction */ - } - if (ai->flags & GPIOEAF_PRINT_EVENT) - pr_info("axis %d-%d change %d\n", - ai->type, ai->code, change); - input_report_rel(as->input_dev, ai->code, change); - } else { - if (ai->flags & GPIOEAF_PRINT_EVENT) - pr_info("axis %d-%d now %d\n", - ai->type, ai->code, pos); - input_event(as->input_dev, ai->type, ai->code, pos); - } - input_sync(as->input_dev); - } - as->pos = pos; -} - -static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id) -{ - struct gpio_axis_state *as = dev_id; - gpio_event_update_axis(as, 1); - return IRQ_HANDLED; -} - -int gpio_event_axis_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func) -{ - int ret; - int i; - int irq; - struct gpio_event_axis_info *ai; - struct gpio_axis_state *as; - - ai = container_of(info, struct gpio_event_axis_info, info); - if (func == GPIO_EVENT_FUNC_SUSPEND) { - for (i = 0; i < ai->count; i++) - disable_irq(gpio_to_irq(ai->gpio[i])); - return 0; - } - if (func == GPIO_EVENT_FUNC_RESUME) { - for (i = 0; i < ai->count; i++) - enable_irq(gpio_to_irq(ai->gpio[i])); - return 0; - } - - if (func == GPIO_EVENT_FUNC_INIT) { - *data = as = kmalloc(sizeof(*as), GFP_KERNEL); - if (as == NULL) { - ret = -ENOMEM; - goto err_alloc_axis_state_failed; - } - as->input_dev = input_dev; - as->info = ai; - - input_set_capability(input_dev, ai->type, ai->code); - if (ai->type == EV_ABS) { - input_set_abs_params(input_dev, ai->code, 0, - ai->decoded_size - 1, 0, 0); - } - for (i = 0; i < ai->count; i++) { - ret = gpio_request(ai->gpio[i], "gpio_event_axis"); - if (ret < 0) - goto err_request_gpio_failed; - ret = gpio_direction_input(ai->gpio[i]); - if (ret < 0) - goto err_gpio_direction_input_failed; - ret = irq = gpio_to_irq(ai->gpio[i]); - if (ret < 0) - goto err_get_irq_num_failed; - ret = request_irq(irq, gpio_axis_irq_handler, - IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, - "gpio_event_axis", as); - if (ret < 0) - goto err_request_irq_failed; - } - gpio_event_update_axis(as, 0); - return 0; - } - - ret = 0; - as = *data; - for (i = ai->count - 1; i >= 0; i--) { - free_irq(gpio_to_irq(ai->gpio[i]), as); -err_request_irq_failed: -err_get_irq_num_failed: -err_gpio_direction_input_failed: - gpio_free(ai->gpio[i]); -err_request_gpio_failed: - ; - } - kfree(as); - *data = NULL; -err_alloc_axis_state_failed: - return ret; -} diff --git a/drivers/staging/dream/gpio_event.c b/drivers/staging/dream/gpio_event.c deleted file mode 100644 index 97a511d11f49..000000000000 --- a/drivers/staging/dream/gpio_event.c +++ /dev/null @@ -1,224 +0,0 @@ -/* drivers/input/misc/gpio_event.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/input.h> -#include <linux/gpio_event.h> -#include <linux/hrtimer.h> -#include <linux/platform_device.h> - -struct gpio_event { - struct input_dev *input_dev; - const struct gpio_event_platform_data *info; - void *state[0]; -}; - -static int gpio_input_event( - struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - int i; - int ret = 0; - int tmp_ret; - struct gpio_event_info **ii; - struct gpio_event *ip = input_get_drvdata(dev); - - for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) { - if ((*ii)->event) { - tmp_ret = (*ii)->event(ip->input_dev, *ii, - &ip->state[i], type, code, value); - if (tmp_ret) - ret = tmp_ret; - } - } - return ret; -} - -static int gpio_event_call_all_func(struct gpio_event *ip, int func) -{ - int i; - int ret; - struct gpio_event_info **ii; - - if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) { - ii = ip->info->info; - for (i = 0; i < ip->info->info_count; i++, ii++) { - if ((*ii)->func == NULL) { - ret = -ENODEV; - pr_err("gpio_event_probe: Incomplete pdata, " - "no function\n"); - goto err_no_func; - } - ret = (*ii)->func(ip->input_dev, *ii, &ip->state[i], - func); - if (ret) { - pr_err("gpio_event_probe: function failed\n"); - goto err_func_failed; - } - } - return 0; - } - - ret = 0; - i = ip->info->info_count; - ii = ip->info->info + i; - while (i > 0) { - i--; - ii--; - (*ii)->func(ip->input_dev, *ii, &ip->state[i], func & ~1); -err_func_failed: -err_no_func: - ; - } - return ret; -} - -#ifdef CONFIG_HAS_EARLYSUSPEND -void gpio_event_suspend(struct early_suspend *h) -{ - struct gpio_event *ip; - ip = container_of(h, struct gpio_event, early_suspend); - gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND); - ip->info->power(ip->info, 0); -} - -void gpio_event_resume(struct early_suspend *h) -{ - struct gpio_event *ip; - ip = container_of(h, struct gpio_event, early_suspend); - ip->info->power(ip->info, 1); - gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME); -} -#endif - -static int __init gpio_event_probe(struct platform_device *pdev) -{ - int err; - struct gpio_event *ip; - struct input_dev *input_dev; - struct gpio_event_platform_data *event_info; - - event_info = pdev->dev.platform_data; - if (event_info == NULL) { - pr_err("gpio_event_probe: No pdata\n"); - return -ENODEV; - } - if (event_info->name == NULL || - event_info->info == NULL || - event_info->info_count == 0) { - pr_err("gpio_event_probe: Incomplete pdata\n"); - return -ENODEV; - } - ip = kzalloc(sizeof(*ip) + - sizeof(ip->state[0]) * event_info->info_count, GFP_KERNEL); - if (ip == NULL) { - err = -ENOMEM; - pr_err("gpio_event_probe: Failed to allocate private data\n"); - goto err_kp_alloc_failed; - } - platform_set_drvdata(pdev, ip); - - input_dev = input_allocate_device(); - if (input_dev == NULL) { - err = -ENOMEM; - pr_err("gpio_event_probe: Failed to allocate input device\n"); - goto err_input_dev_alloc_failed; - } - input_set_drvdata(input_dev, ip); - ip->input_dev = input_dev; - ip->info = event_info; - if (event_info->power) { -#ifdef CONFIG_HAS_EARLYSUSPEND - ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - ip->early_suspend.suspend = gpio_event_suspend; - ip->early_suspend.resume = gpio_event_resume; - register_early_suspend(&ip->early_suspend); -#endif - ip->info->power(ip->info, 1); - } - - input_dev->name = ip->info->name; - input_dev->event = gpio_input_event; - - err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT); - if (err) - goto err_call_all_func_failed; - - err = input_register_device(input_dev); - if (err) { - pr_err("gpio_event_probe: Unable to register %s input device\n", - input_dev->name); - goto err_input_register_device_failed; - } - - return 0; - -err_input_register_device_failed: - gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); -err_call_all_func_failed: - if (event_info->power) { -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&ip->early_suspend); -#endif - ip->info->power(ip->info, 0); - } - input_free_device(input_dev); -err_input_dev_alloc_failed: - kfree(ip); -err_kp_alloc_failed: - return err; -} - -static int gpio_event_remove(struct platform_device *pdev) -{ - struct gpio_event *ip = platform_get_drvdata(pdev); - - gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); - if (ip->info->power) { -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&ip->early_suspend); -#endif - ip->info->power(ip->info, 0); - } - input_unregister_device(ip->input_dev); - kfree(ip); - return 0; -} - -static struct platform_driver gpio_event_driver = { - .probe = gpio_event_probe, - .remove = gpio_event_remove, - .driver = { - .name = GPIO_EVENT_DEV_NAME, - }, -}; - -static int __devinit gpio_event_init(void) -{ - return platform_driver_register(&gpio_event_driver); -} - -static void __exit gpio_event_exit(void) -{ - platform_driver_unregister(&gpio_event_driver); -} - -module_init(gpio_event_init); -module_exit(gpio_event_exit); - -MODULE_DESCRIPTION("GPIO Event Driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/dream/gpio_input.c b/drivers/staging/dream/gpio_input.c deleted file mode 100644 index ca29e5eb070a..000000000000 --- a/drivers/staging/dream/gpio_input.c +++ /dev/null @@ -1,337 +0,0 @@ -/* drivers/input/misc/gpio_input.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/gpio.h> -#include <linux/gpio_event.h> -#include <linux/hrtimer.h> -#include <linux/input.h> -#include <linux/interrupt.h> -#include <linux/slab.h> - -enum { - DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */ - DEBOUNCE_PRESSED = BIT(1), - DEBOUNCE_NOTPRESSED = BIT(2), - DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */ - DEBOUNCE_POLL = BIT(4), /* Stable polling state */ - - DEBOUNCE_UNKNOWN = - DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED, -}; - -struct gpio_key_state { - struct gpio_input_state *ds; - uint8_t debounce; -}; - -struct gpio_input_state { - struct input_dev *input_dev; - const struct gpio_event_input_info *info; - struct hrtimer timer; - int use_irq; - int debounce_count; - spinlock_t irq_lock; - struct gpio_key_state key_state[0]; -}; - -static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) -{ - int i; - int pressed; - struct gpio_input_state *ds = - container_of(timer, struct gpio_input_state, timer); - unsigned gpio_flags = ds->info->flags; - unsigned npolarity; - int nkeys = ds->info->keymap_size; - const struct gpio_event_direct_entry *key_entry; - struct gpio_key_state *key_state; - unsigned long irqflags; - uint8_t debounce; - -#if 0 - key_entry = kp->keys_info->keymap; - key_state = kp->key_state; - for (i = 0; i < nkeys; i++, key_entry++, key_state++) - pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, - gpio_read_detect_status(key_entry->gpio)); -#endif - key_entry = ds->info->keymap; - key_state = ds->key_state; - spin_lock_irqsave(&ds->irq_lock, irqflags); - for (i = 0; i < nkeys; i++, key_entry++, key_state++) { - debounce = key_state->debounce; - if (debounce & DEBOUNCE_WAIT_IRQ) - continue; - if (key_state->debounce & DEBOUNCE_UNSTABLE) { - debounce = key_state->debounce = DEBOUNCE_UNKNOWN; - enable_irq(gpio_to_irq(key_entry->gpio)); - pr_info("gpio_keys_scan_keys: key %x-%x, %d " - "(%d) continue debounce\n", - ds->info->type, key_entry->code, - i, key_entry->gpio); - } - npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); - pressed = gpio_get_value(key_entry->gpio) ^ npolarity; - if (debounce & DEBOUNCE_POLL) { - if (pressed == !(debounce & DEBOUNCE_PRESSED)) { - ds->debounce_count++; - key_state->debounce = DEBOUNCE_UNKNOWN; - if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) - pr_info("gpio_keys_scan_keys: key %x-" - "%x, %d (%d) start debounce\n", - ds->info->type, key_entry->code, - i, key_entry->gpio); - } - continue; - } - if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { - if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) - pr_info("gpio_keys_scan_keys: key %x-%x, %d " - "(%d) debounce pressed 1\n", - ds->info->type, key_entry->code, - i, key_entry->gpio); - key_state->debounce = DEBOUNCE_PRESSED; - continue; - } - if (!pressed && (debounce & DEBOUNCE_PRESSED)) { - if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) - pr_info("gpio_keys_scan_keys: key %x-%x, %d " - "(%d) debounce pressed 0\n", - ds->info->type, key_entry->code, - i, key_entry->gpio); - key_state->debounce = DEBOUNCE_NOTPRESSED; - continue; - } - /* key is stable */ - ds->debounce_count--; - if (ds->use_irq) - key_state->debounce |= DEBOUNCE_WAIT_IRQ; - else - key_state->debounce |= DEBOUNCE_POLL; - if (gpio_flags & GPIOEDF_PRINT_KEYS) - pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " - "changed to %d\n", ds->info->type, - key_entry->code, i, key_entry->gpio, pressed); - input_event(ds->input_dev, ds->info->type, - key_entry->code, pressed); - } - -#if 0 - key_entry = kp->keys_info->keymap; - key_state = kp->key_state; - for (i = 0; i < nkeys; i++, key_entry++, key_state++) { - pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, - gpio_read_detect_status(key_entry->gpio)); - } -#endif - - if (ds->debounce_count) - hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL); - else if (!ds->use_irq) - hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL); - - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - - return HRTIMER_NORESTART; -} - -static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) -{ - struct gpio_key_state *ks = dev_id; - struct gpio_input_state *ds = ks->ds; - int keymap_index = ks - ds->key_state; - const struct gpio_event_direct_entry *key_entry; - unsigned long irqflags; - int pressed; - - if (!ds->use_irq) - return IRQ_HANDLED; - - key_entry = &ds->info->keymap[keymap_index]; - - if (ds->info->debounce_time.tv64) { - spin_lock_irqsave(&ds->irq_lock, irqflags); - if (ks->debounce & DEBOUNCE_WAIT_IRQ) { - ks->debounce = DEBOUNCE_UNKNOWN; - if (ds->debounce_count++ == 0) { - hrtimer_start( - &ds->timer, ds->info->debounce_time, - HRTIMER_MODE_REL); - } - if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) - pr_info("gpio_event_input_irq_handler: " - "key %x-%x, %d (%d) start debounce\n", - ds->info->type, key_entry->code, - keymap_index, key_entry->gpio); - } else { - disable_irq(irq); - ks->debounce = DEBOUNCE_UNSTABLE; - } - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - } else { - pressed = gpio_get_value(key_entry->gpio) ^ - !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); - if (ds->info->flags & GPIOEDF_PRINT_KEYS) - pr_info("gpio_event_input_irq_handler: key %x-%x, %d " - "(%d) changed to %d\n", - ds->info->type, key_entry->code, keymap_index, - key_entry->gpio, pressed); - input_event(ds->input_dev, ds->info->type, - key_entry->code, pressed); - } - return IRQ_HANDLED; -} - -static int gpio_event_input_request_irqs(struct gpio_input_state *ds) -{ - int i; - int err; - unsigned int irq; - unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; - - for (i = 0; i < ds->info->keymap_size; i++) { - err = irq = gpio_to_irq(ds->info->keymap[i].gpio); - if (err < 0) - goto err_gpio_get_irq_num_failed; - err = request_irq(irq, gpio_event_input_irq_handler, - req_flags, "gpio_keys", &ds->key_state[i]); - if (err) { - pr_err("gpio_event_input_request_irqs: request_irq " - "failed for input %d, irq %d\n", - ds->info->keymap[i].gpio, irq); - goto err_request_irq_failed; - } - enable_irq_wake(irq); - } - return 0; - - for (i = ds->info->keymap_size - 1; i >= 0; i--) { - free_irq(gpio_to_irq(ds->info->keymap[i].gpio), - &ds->key_state[i]); -err_request_irq_failed: -err_gpio_get_irq_num_failed: - ; - } - return err; -} - -int gpio_event_input_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func) -{ - int ret; - int i; - unsigned long irqflags; - struct gpio_event_input_info *di; - struct gpio_input_state *ds = *data; - - di = container_of(info, struct gpio_event_input_info, info); - - if (func == GPIO_EVENT_FUNC_SUSPEND) { - spin_lock_irqsave(&ds->irq_lock, irqflags); - if (ds->use_irq) - for (i = 0; i < di->keymap_size; i++) - disable_irq(gpio_to_irq(di->keymap[i].gpio)); - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - hrtimer_cancel(&ds->timer); - return 0; - } - if (func == GPIO_EVENT_FUNC_RESUME) { - spin_lock_irqsave(&ds->irq_lock, irqflags); - if (ds->use_irq) - for (i = 0; i < di->keymap_size; i++) - enable_irq(gpio_to_irq(di->keymap[i].gpio)); - hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - return 0; - } - - if (func == GPIO_EVENT_FUNC_INIT) { - if (ktime_to_ns(di->poll_time) <= 0) - di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); - - *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * - di->keymap_size, GFP_KERNEL); - if (ds == NULL) { - ret = -ENOMEM; - pr_err("gpio_event_input_func: " - "Failed to allocate private data\n"); - goto err_ds_alloc_failed; - } - ds->debounce_count = di->keymap_size; - ds->input_dev = input_dev; - ds->info = di; - spin_lock_init(&ds->irq_lock); - - for (i = 0; i < di->keymap_size; i++) { - input_set_capability(input_dev, di->type, - di->keymap[i].code); - ds->key_state[i].ds = ds; - ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; - } - - for (i = 0; i < di->keymap_size; i++) { - ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); - if (ret) { - pr_err("gpio_event_input_func: gpio_request " - "failed for %d\n", di->keymap[i].gpio); - goto err_gpio_request_failed; - } - ret = gpio_direction_input(di->keymap[i].gpio); - if (ret) { - pr_err("gpio_event_input_func: " - "gpio_direction_input failed for %d\n", - di->keymap[i].gpio); - goto err_gpio_configure_failed; - } - } - - ret = gpio_event_input_request_irqs(ds); - - spin_lock_irqsave(&ds->irq_lock, irqflags); - ds->use_irq = ret == 0; - - pr_info("GPIO Input Driver: Start gpio inputs for %s in %s " - "mode\n", - input_dev->name, ret == 0 ? "interrupt" : "polling"); - - hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ds->timer.function = gpio_event_input_timer_func; - hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - return 0; - } - - ret = 0; - spin_lock_irqsave(&ds->irq_lock, irqflags); - hrtimer_cancel(&ds->timer); - if (ds->use_irq) { - for (i = di->keymap_size - 1; i >= 0; i--) { - free_irq(gpio_to_irq(di->keymap[i].gpio), - &ds->key_state[i]); - } - } - spin_unlock_irqrestore(&ds->irq_lock, irqflags); - - for (i = di->keymap_size - 1; i >= 0; i--) { -err_gpio_configure_failed: - gpio_free(di->keymap[i].gpio); -err_gpio_request_failed: - ; - } - kfree(ds); -err_ds_alloc_failed: - return ret; -} diff --git a/drivers/staging/dream/gpio_matrix.c b/drivers/staging/dream/gpio_matrix.c deleted file mode 100644 index b377ee1f5a5f..000000000000 --- a/drivers/staging/dream/gpio_matrix.c +++ /dev/null @@ -1,399 +0,0 @@ -/* drivers/input/misc/gpio_matrix.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/gpio_event.h> -#include <linux/hrtimer.h> -#include <linux/interrupt.h> - -struct gpio_kp { - struct input_dev *input_dev; - struct gpio_event_matrix_info *keypad_info; - struct hrtimer timer; - int current_output; - unsigned int use_irq:1; - unsigned int key_state_changed:1; - unsigned int last_key_state_changed:1; - unsigned int some_keys_pressed:2; - unsigned long keys_pressed[0]; -}; - -static void clear_phantom_key(struct gpio_kp *kp, int out, int in) -{ - struct gpio_event_matrix_info *mi = kp->keypad_info; - int key_index = out * mi->ninputs + in; - unsigned short keycode = mi->keymap[key_index];; - - if (!test_bit(keycode, kp->input_dev->key)) { - if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) - pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " - "cleared\n", keycode, out, in, - mi->output_gpios[out], mi->input_gpios[in]); - __clear_bit(key_index, kp->keys_pressed); - } else { - if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) - pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " - "not cleared\n", keycode, out, in, - mi->output_gpios[out], mi->input_gpios[in]); - } -} - -static int restore_keys_for_input(struct gpio_kp *kp, int out, int in) -{ - int rv = 0; - int key_index; - - key_index = out * kp->keypad_info->ninputs + in; - while (out < kp->keypad_info->noutputs) { - if (test_bit(key_index, kp->keys_pressed)) { - rv = 1; - clear_phantom_key(kp, out, in); - } - key_index += kp->keypad_info->ninputs; - out++; - } - return rv; -} - -static void remove_phantom_keys(struct gpio_kp *kp) -{ - int out, in, inp; - int key_index; - - if (kp->some_keys_pressed < 3) - return; - - for (out = 0; out < kp->keypad_info->noutputs; out++) { - inp = -1; - key_index = out * kp->keypad_info->ninputs; - for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) { - if (test_bit(key_index, kp->keys_pressed)) { - if (inp == -1) { - inp = in; - continue; - } - if (inp >= 0) { - if (!restore_keys_for_input(kp, out + 1, - inp)) - break; - clear_phantom_key(kp, out, inp); - inp = -2; - } - restore_keys_for_input(kp, out, in); - } - } - } -} - -static void report_key(struct gpio_kp *kp, int key_index, int out, int in) -{ - struct gpio_event_matrix_info *mi = kp->keypad_info; - int pressed = test_bit(key_index, kp->keys_pressed); - unsigned short keycode = mi->keymap[key_index]; - if (pressed != test_bit(keycode, kp->input_dev->key)) { - if (keycode == KEY_RESERVED) { - if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) - pr_info("gpiomatrix: unmapped key, %d-%d " - "(%d-%d) changed to %d\n", - out, in, mi->output_gpios[out], - mi->input_gpios[in], pressed); - } else { - if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS) - pr_info("gpiomatrix: key %x, %d-%d (%d-%d) " - "changed to %d\n", keycode, - out, in, mi->output_gpios[out], - mi->input_gpios[in], pressed); - input_report_key(kp->input_dev, keycode, pressed); - } - } -} - -static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer) -{ - int out, in; - int key_index; - int gpio; - struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer); - struct gpio_event_matrix_info *mi = kp->keypad_info; - unsigned gpio_keypad_flags = mi->flags; - unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH); - - out = kp->current_output; - if (out == mi->noutputs) { - out = 0; - kp->last_key_state_changed = kp->key_state_changed; - kp->key_state_changed = 0; - kp->some_keys_pressed = 0; - } else { - key_index = out * mi->ninputs; - for (in = 0; in < mi->ninputs; in++, key_index++) { - gpio = mi->input_gpios[in]; - if (gpio_get_value(gpio) ^ !polarity) { - if (kp->some_keys_pressed < 3) - kp->some_keys_pressed++; - kp->key_state_changed |= !__test_and_set_bit( - key_index, kp->keys_pressed); - } else - kp->key_state_changed |= __test_and_clear_bit( - key_index, kp->keys_pressed); - } - gpio = mi->output_gpios[out]; - if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) - gpio_set_value(gpio, !polarity); - else - gpio_direction_input(gpio); - out++; - } - kp->current_output = out; - if (out < mi->noutputs) { - gpio = mi->output_gpios[out]; - if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) - gpio_set_value(gpio, polarity); - else - gpio_direction_output(gpio, polarity); - hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL); - return HRTIMER_NORESTART; - } - if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) { - if (kp->key_state_changed) { - hrtimer_start(&kp->timer, mi->debounce_delay, - HRTIMER_MODE_REL); - return HRTIMER_NORESTART; - } - kp->key_state_changed = kp->last_key_state_changed; - } - if (kp->key_state_changed) { - if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) - remove_phantom_keys(kp); - key_index = 0; - for (out = 0; out < mi->noutputs; out++) - for (in = 0; in < mi->ninputs; in++, key_index++) - report_key(kp, key_index, out, in); - } - if (!kp->use_irq || kp->some_keys_pressed) { - hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL); - return HRTIMER_NORESTART; - } - - /* No keys are pressed, reenable interrupt */ - for (out = 0; out < mi->noutputs; out++) { - if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) - gpio_set_value(mi->output_gpios[out], polarity); - else - gpio_direction_output(mi->output_gpios[out], polarity); - } - for (in = 0; in < mi->ninputs; in++) - enable_irq(gpio_to_irq(mi->input_gpios[in])); - return HRTIMER_NORESTART; -} - -static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id) -{ - int i; - struct gpio_kp *kp = dev_id; - struct gpio_event_matrix_info *mi = kp->keypad_info; - unsigned gpio_keypad_flags = mi->flags; - - if (!kp->use_irq) /* ignore interrupt while registering the handler */ - return IRQ_HANDLED; - - for (i = 0; i < mi->ninputs; i++) - disable_irq(gpio_to_irq(mi->input_gpios[i])); - for (i = 0; i < mi->noutputs; i++) { - if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) - gpio_set_value(mi->output_gpios[i], - !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH)); - else - gpio_direction_input(mi->output_gpios[i]); - } - hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); - return IRQ_HANDLED; -} - -static int gpio_keypad_request_irqs(struct gpio_kp *kp) -{ - int i; - int err; - unsigned int irq; - unsigned long request_flags; - struct gpio_event_matrix_info *mi = kp->keypad_info; - - switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { - default: - request_flags = IRQF_TRIGGER_FALLING; - break; - case GPIOKPF_ACTIVE_HIGH: - request_flags = IRQF_TRIGGER_RISING; - break; - case GPIOKPF_LEVEL_TRIGGERED_IRQ: - request_flags = IRQF_TRIGGER_LOW; - break; - case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: - request_flags = IRQF_TRIGGER_HIGH; - break; - } - - for (i = 0; i < mi->ninputs; i++) { - err = irq = gpio_to_irq(mi->input_gpios[i]); - if (err < 0) - goto err_gpio_get_irq_num_failed; - err = request_irq(irq, gpio_keypad_irq_handler, request_flags, - "gpio_kp", kp); - if (err) { - pr_err("gpiomatrix: request_irq failed for input %d, " - "irq %d\n", mi->input_gpios[i], irq); - goto err_request_irq_failed; - } - err = set_irq_wake(irq, 1); - if (err) { - pr_err("gpiomatrix: set_irq_wake failed for input %d, " - "irq %d\n", mi->input_gpios[i], irq); - } - disable_irq(irq); - } - return 0; - - for (i = mi->noutputs - 1; i >= 0; i--) { - free_irq(gpio_to_irq(mi->input_gpios[i]), kp); -err_request_irq_failed: -err_gpio_get_irq_num_failed: - ; - } - return err; -} - -int gpio_event_matrix_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func) -{ - int i; - int err; - int key_count; - struct gpio_kp *kp; - struct gpio_event_matrix_info *mi; - - mi = container_of(info, struct gpio_event_matrix_info, info); - if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) { - /* TODO: disable scanning */ - return 0; - } - - if (func == GPIO_EVENT_FUNC_INIT) { - if (mi->keymap == NULL || - mi->input_gpios == NULL || - mi->output_gpios == NULL) { - err = -ENODEV; - pr_err("gpiomatrix: Incomplete pdata\n"); - goto err_invalid_platform_data; - } - key_count = mi->ninputs * mi->noutputs; - - *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) * - BITS_TO_LONGS(key_count), GFP_KERNEL); - if (kp == NULL) { - err = -ENOMEM; - pr_err("gpiomatrix: Failed to allocate private data\n"); - goto err_kp_alloc_failed; - } - kp->input_dev = input_dev; - kp->keypad_info = mi; - set_bit(EV_KEY, input_dev->evbit); - for (i = 0; i < key_count; i++) { - if (mi->keymap[i]) - set_bit(mi->keymap[i] & KEY_MAX, - input_dev->keybit); - } - - for (i = 0; i < mi->noutputs; i++) { - if (gpio_cansleep(mi->output_gpios[i])) { - pr_err("gpiomatrix: unsupported output gpio %d," - " can sleep\n", mi->output_gpios[i]); - err = -EINVAL; - goto err_request_output_gpio_failed; - } - err = gpio_request(mi->output_gpios[i], "gpio_kp_out"); - if (err) { - pr_err("gpiomatrix: gpio_request failed for " - "output %d\n", mi->output_gpios[i]); - goto err_request_output_gpio_failed; - } - if (mi->flags & GPIOKPF_DRIVE_INACTIVE) - err = gpio_direction_output(mi->output_gpios[i], - !(mi->flags & GPIOKPF_ACTIVE_HIGH)); - else - err = gpio_direction_input(mi->output_gpios[i]); - if (err) { - pr_err("gpiomatrix: gpio_configure failed for " - "output %d\n", mi->output_gpios[i]); - goto err_output_gpio_configure_failed; - } - } - for (i = 0; i < mi->ninputs; i++) { - err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); - if (err) { - pr_err("gpiomatrix: gpio_request failed for " - "input %d\n", mi->input_gpios[i]); - goto err_request_input_gpio_failed; - } - err = gpio_direction_input(mi->input_gpios[i]); - if (err) { - pr_err("gpiomatrix: gpio_direction_input failed" - " for input %d\n", mi->input_gpios[i]); - goto err_gpio_direction_input_failed; - } - } - kp->current_output = mi->noutputs; - kp->key_state_changed = 1; - - hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - kp->timer.function = gpio_keypad_timer_func; - err = gpio_keypad_request_irqs(kp); - kp->use_irq = err == 0; - - pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for %s " - "in %s mode\n", input_dev->name, - kp->use_irq ? "interrupt" : "polling"); - - hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); - - return 0; - } - - err = 0; - kp = *data; - - if (kp->use_irq) - for (i = mi->noutputs - 1; i >= 0; i--) - free_irq(gpio_to_irq(mi->input_gpios[i]), kp); - - hrtimer_cancel(&kp->timer); - for (i = mi->noutputs - 1; i >= 0; i--) { -err_gpio_direction_input_failed: - gpio_free(mi->input_gpios[i]); -err_request_input_gpio_failed: - ; - } - for (i = mi->noutputs - 1; i >= 0; i--) { -err_output_gpio_configure_failed: - gpio_free(mi->output_gpios[i]); -err_request_output_gpio_failed: - ; - } - kfree(kp); -err_kp_alloc_failed: -err_invalid_platform_data: - return err; -} diff --git a/drivers/staging/dream/gpio_output.c b/drivers/staging/dream/gpio_output.c deleted file mode 100644 index 6f8453c97bd2..000000000000 --- a/drivers/staging/dream/gpio_output.c +++ /dev/null @@ -1,84 +0,0 @@ -/* drivers/input/misc/gpio_output.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/gpio.h> -#include <linux/gpio_event.h> - -int gpio_event_output_event( - struct input_dev *input_dev, struct gpio_event_info *info, void **data, - unsigned int type, unsigned int code, int value) -{ - int i; - struct gpio_event_output_info *oi; - oi = container_of(info, struct gpio_event_output_info, info); - if (type != oi->type) - return 0; - if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) - value = !value; - for (i = 0; i < oi->keymap_size; i++) - if (code == oi->keymap[i].code) - gpio_set_value(oi->keymap[i].gpio, value); - return 0; -} - -int gpio_event_output_func( - struct input_dev *input_dev, struct gpio_event_info *info, void **data, - int func) -{ - int ret; - int i; - struct gpio_event_output_info *oi; - oi = container_of(info, struct gpio_event_output_info, info); - - if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) - return 0; - - if (func == GPIO_EVENT_FUNC_INIT) { - int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); - for (i = 0; i < oi->keymap_size; i++) - input_set_capability(input_dev, oi->type, - oi->keymap[i].code); - - for (i = 0; i < oi->keymap_size; i++) { - ret = gpio_request(oi->keymap[i].gpio, - "gpio_event_output"); - if (ret) { - pr_err("gpio_event_output_func: gpio_request " - "failed for %d\n", oi->keymap[i].gpio); - goto err_gpio_request_failed; - } - ret = gpio_direction_output(oi->keymap[i].gpio, - output_level); - if (ret) { - pr_err("gpio_event_output_func: " - "gpio_direction_output failed for %d\n", - oi->keymap[i].gpio); - goto err_gpio_direction_output_failed; - } - } - return 0; - } - - ret = 0; - for (i = oi->keymap_size - 1; i >= 0; i--) { -err_gpio_direction_output_failed: - gpio_free(oi->keymap[i].gpio); -err_gpio_request_failed: - ; - } - return ret; -} - diff --git a/drivers/staging/dream/include/linux/android_pmem.h b/drivers/staging/dream/include/linux/android_pmem.h deleted file mode 100644 index 2fc05d7d335b..000000000000 --- a/drivers/staging/dream/include/linux/android_pmem.h +++ /dev/null @@ -1,80 +0,0 @@ -/* drivers/staging/dream/include/linux/android_pmem.h - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ANDROID_PMEM_H_ -#define _ANDROID_PMEM_H_ - -#define PMEM_IOCTL_MAGIC 'p' -#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int) -#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int) -#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int) -#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int) -/* This ioctl will allocate pmem space, backing the file, it will fail - * if the file already has an allocation, pass it the len as the argument - * to the ioctl */ -#define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int) -/* This will connect a one pmem file to another, pass the file that is already - * backed in memory as the argument to the ioctl - */ -#define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int) -/* Returns the total size of the pmem region it is sent to as a pmem_region - * struct (with offset set to 0). - */ -#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int) -/* Revokes gpu registers and resets the gpu. Pass a pointer to the - * start of the mapped gpu regs (the vaddr returned by mmap) as the argument. - */ -#define HW3D_REVOKE_GPU _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int) -#define HW3D_GRANT_GPU _IOW(PMEM_IOCTL_MAGIC, 9, unsigned int) -#define HW3D_WAIT_FOR_INTERRUPT _IOW(PMEM_IOCTL_MAGIC, 10, unsigned int) - -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *end, struct file **filp); -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *end); -void put_pmem_file(struct file* file); -void flush_pmem_file(struct file *file, unsigned long start, unsigned long len); - -struct android_pmem_platform_data -{ - const char* name; - /* starting physical address of memory region */ - unsigned long start; - /* size of memory region */ - unsigned long size; - /* set to indicate the region should not be managed with an allocator */ - unsigned no_allocator; - /* set to indicate maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - /* The MSM7k has bits to enable a write buffer in the bus controller*/ - unsigned buffered; -}; - -struct pmem_region { - unsigned long offset; - unsigned long len; -}; - -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)); - -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation); - -#endif //_ANDROID_PPP_H_ - diff --git a/drivers/staging/dream/include/linux/gpio_event.h b/drivers/staging/dream/include/linux/gpio_event.h deleted file mode 100644 index ffc5da392ad7..000000000000 --- a/drivers/staging/dream/include/linux/gpio_event.h +++ /dev/null @@ -1,154 +0,0 @@ -/* drivers/staging/dream/include/linux/gpio_event.h - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_GPIO_EVENT_H -#define _LINUX_GPIO_EVENT_H - -#include <linux/input.h> - -enum { - GPIO_EVENT_FUNC_UNINIT = 0x0, - GPIO_EVENT_FUNC_INIT = 0x1, - GPIO_EVENT_FUNC_SUSPEND = 0x2, - GPIO_EVENT_FUNC_RESUME = 0x3, -}; -struct gpio_event_info { - int (*func)(struct input_dev *input_dev, - struct gpio_event_info *info, - void **data, int func); - int (*event)(struct input_dev *input_dev, - struct gpio_event_info *info, - void **data, unsigned int type, - unsigned int code, int value); /* out events */ -}; - -struct gpio_event_platform_data { - const char *name; - struct gpio_event_info **info; - size_t info_count; - int (*power)(const struct gpio_event_platform_data *pdata, bool on); -}; - -#define GPIO_EVENT_DEV_NAME "gpio-event" - -/* Key matrix */ - -enum gpio_event_matrix_flags { - /* unset: drive active output low, set: drive active output high */ - GPIOKPF_ACTIVE_HIGH = 1U << 0, - GPIOKPF_DEBOUNCE = 1U << 1, - GPIOKPF_REMOVE_SOME_PHANTOM_KEYS = 1U << 2, - GPIOKPF_REMOVE_PHANTOM_KEYS = GPIOKPF_REMOVE_SOME_PHANTOM_KEYS | - GPIOKPF_DEBOUNCE, - GPIOKPF_DRIVE_INACTIVE = 1U << 3, - GPIOKPF_LEVEL_TRIGGERED_IRQ = 1U << 4, - GPIOKPF_PRINT_UNMAPPED_KEYS = 1U << 16, - GPIOKPF_PRINT_MAPPED_KEYS = 1U << 17, - GPIOKPF_PRINT_PHANTOM_KEYS = 1U << 18, -}; - -extern int gpio_event_matrix_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func); -struct gpio_event_matrix_info { - /* initialize to gpio_event_matrix_func */ - struct gpio_event_info info; - /* size must be ninputs * noutputs */ - const unsigned short *keymap; - unsigned int *input_gpios; - unsigned int *output_gpios; - unsigned int ninputs; - unsigned int noutputs; - /* time to wait before reading inputs after driving each output */ - ktime_t settle_time; - /* time to wait before scanning the keypad a second time */ - ktime_t debounce_delay; - ktime_t poll_time; - unsigned flags; -}; - -/* Directly connected inputs and outputs */ - -enum gpio_event_direct_flags { - GPIOEDF_ACTIVE_HIGH = 1U << 0, -/* GPIOEDF_USE_DOWN_IRQ = 1U << 1, */ -/* GPIOEDF_USE_IRQ = (1U << 2) | GPIOIDF_USE_DOWN_IRQ, */ - GPIOEDF_PRINT_KEYS = 1U << 8, - GPIOEDF_PRINT_KEY_DEBOUNCE = 1U << 9, -}; - -struct gpio_event_direct_entry { - uint32_t gpio:23; - uint32_t code:9; -}; - -/* inputs */ -extern int gpio_event_input_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func); -struct gpio_event_input_info { - /* initialize to gpio_event_input_func */ - struct gpio_event_info info; - ktime_t debounce_time; - ktime_t poll_time; - uint16_t flags; - uint16_t type; - const struct gpio_event_direct_entry *keymap; - size_t keymap_size; -}; - -/* outputs */ -extern int gpio_event_output_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func); -extern int gpio_event_output_event(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, - unsigned int type, unsigned int code, int value); -struct gpio_event_output_info { - /* initialize to gpio_event_output_func and gpio_event_output_event */ - struct gpio_event_info info; - uint16_t flags; - uint16_t type; - const struct gpio_event_direct_entry *keymap; - size_t keymap_size; -}; - - -/* axes */ - -enum gpio_event_axis_flags { - GPIOEAF_PRINT_UNKNOWN_DIRECTION = 1U << 16, - GPIOEAF_PRINT_RAW = 1U << 17, - GPIOEAF_PRINT_EVENT = 1U << 18, -}; - -extern int gpio_event_axis_func(struct input_dev *input_dev, - struct gpio_event_info *info, void **data, int func); -struct gpio_event_axis_info { - /* initialize to gpio_event_axis_func */ - struct gpio_event_info info; - uint8_t count; - uint8_t type; /* EV_REL or EV_ABS */ - uint16_t code; - uint16_t decoded_size; - uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in); - uint32_t *gpio; - uint32_t flags; -}; -#define gpio_axis_2bit_gray_map gpio_axis_4bit_gray_map -#define gpio_axis_3bit_gray_map gpio_axis_4bit_gray_map -uint16_t gpio_axis_4bit_gray_map( - struct gpio_event_axis_info *info, uint16_t in); -uint16_t gpio_axis_5bit_singletrack_map( - struct gpio_event_axis_info *info, uint16_t in); - -#endif diff --git a/drivers/staging/dream/include/linux/msm_adsp.h b/drivers/staging/dream/include/linux/msm_adsp.h deleted file mode 100644 index e775f3e94f1d..000000000000 --- a/drivers/staging/dream/include/linux/msm_adsp.h +++ /dev/null @@ -1,84 +0,0 @@ -/* drivers/staging/dream/include/linux/msm_adsp.h - * - * Copyright (c) QUALCOMM Incorporated - * Copyright (C) 2007 Google, Inc. - * Author: Iliyan Malchev <ibm@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef __LINUX_MSM_ADSP_H -#define __LINUX_MSM_ADSP_H - -#include <linux/types.h> -#include <linux/ioctl.h> - -#define ADSP_IOCTL_MAGIC 'q' - -/* ADSP_IOCTL_WRITE_COMMAND */ -struct adsp_command_t { - uint16_t queue; - uint32_t len; /* bytes */ - uint8_t *data; -}; - -/* ADSP_IOCTL_GET_EVENT */ -struct adsp_event_t { - uint16_t type; /* 1 == event (RPC), 0 == message (adsp) */ - uint32_t timeout_ms; /* -1 for infinite, 0 for immediate return */ - uint16_t msg_id; - uint16_t flags; /* 1 == 16--bit event, 0 == 32-bit event */ - uint32_t len; /* size in, number of bytes out */ - uint8_t *data; -}; - -#define ADSP_IOCTL_ENABLE \ - _IOR(ADSP_IOCTL_MAGIC, 1, unsigned) - -#define ADSP_IOCTL_DISABLE \ - _IOR(ADSP_IOCTL_MAGIC, 2, unsigned) - -#define ADSP_IOCTL_DISABLE_ACK \ - _IOR(ADSP_IOCTL_MAGIC, 3, unsigned) - -#define ADSP_IOCTL_WRITE_COMMAND \ - _IOR(ADSP_IOCTL_MAGIC, 4, struct adsp_command_t *) - -#define ADSP_IOCTL_GET_EVENT \ - _IOWR(ADSP_IOCTL_MAGIC, 5, struct adsp_event_data_t *) - -#define ADSP_IOCTL_SET_CLKRATE \ - _IOR(ADSP_IOCTL_MAGIC, 6, unsigned) - -#define ADSP_IOCTL_DISABLE_EVENT_RSP \ - _IOR(ADSP_IOCTL_MAGIC, 10, unsigned) - -struct adsp_pmem_info { - int fd; - void *vaddr; -}; - -#define ADSP_IOCTL_REGISTER_PMEM \ - _IOW(ADSP_IOCTL_MAGIC, 13, unsigned) - -#define ADSP_IOCTL_UNREGISTER_PMEM \ - _IOW(ADSP_IOCTL_MAGIC, 14, unsigned) - -/* Cause any further GET_EVENT ioctls to fail (-ENODEV) - * until the device is closed and reopened. Useful for - * terminating event dispatch threads - */ -#define ADSP_IOCTL_ABORT_EVENT_READ \ - _IOW(ADSP_IOCTL_MAGIC, 15, unsigned) - -#define ADSP_IOCTL_LINK_TASK \ - _IOW(ADSP_IOCTL_MAGIC, 16, unsigned) - -#endif diff --git a/drivers/staging/dream/include/linux/msm_audio.h b/drivers/staging/dream/include/linux/msm_audio.h deleted file mode 100644 index cfbdaa0d98b2..000000000000 --- a/drivers/staging/dream/include/linux/msm_audio.h +++ /dev/null @@ -1,115 +0,0 @@ -/* drivers/staging/dream/include/linux/msm_audio.h - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __LINUX_MSM_AUDIO_H -#define __LINUX_MSM_AUDIO_H - -#include <linux/types.h> -#include <linux/ioctl.h> -#include <asm/sizes.h> - -/* PCM Audio */ - -#define AUDIO_IOCTL_MAGIC 'a' - -#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned) -#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned) -#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned) -#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned) -#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned) -#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned) -#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned) -#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned) -#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned) -#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned) -#define AUDIO_SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned) -#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned) -#define AUDIO_SET_AGC _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned) -#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned) -#define AUDIO_SET_TX_IIR _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned) -#define AUDIO_PAUSE _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned) -#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned) -#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned) -#define AUDIO_SWITCH_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned) - -#define AUDIO_MAX_COMMON_IOCTL_NUM 100 - -#define AUDIO_MAX_COMMON_IOCTL_NUM 100 - -struct msm_audio_config { - uint32_t buffer_size; - uint32_t buffer_count; - uint32_t channel_count; - uint32_t sample_rate; - uint32_t type; - uint32_t unused[3]; -}; - -struct msm_audio_stats { - uint32_t byte_count; - uint32_t sample_count; - uint32_t unused[2]; -}; - -/* Audio routing */ - -#define SND_IOCTL_MAGIC 's' - -#define SND_MUTE_UNMUTED 0 -#define SND_MUTE_MUTED 1 - -struct msm_snd_device_config { - uint32_t device; - uint32_t ear_mute; - uint32_t mic_mute; -}; - -#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *) - -#define SND_METHOD_VOICE 0 - -struct msm_snd_volume_config { - uint32_t device; - uint32_t method; - uint32_t volume; -}; - -#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *) - -/* Returns the number of SND endpoints supported. */ - -#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *) - -struct msm_snd_endpoint { - int id; /* input and output */ - char name[64]; /* output only */ -}; - -/* Takes an index between 0 and one less than the number returned by - * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a - * SND endpoint. On input, the .id field contains the number of the - * endpoint, and on exit it contains the SND index, while .name contains - * the description of the endpoint. - */ - -#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *) - -struct msm_audio_pcm_config { - uint32_t pcm_feedback; /* 0 - disable > 0 - enable */ - uint32_t buffer_count; /* Number of buffers to allocate */ - uint32_t buffer_size; /* Size of buffer for capturing of - PCM samples */ -}; -#endif diff --git a/drivers/staging/dream/include/linux/msm_rpcrouter.h b/drivers/staging/dream/include/linux/msm_rpcrouter.h deleted file mode 100644 index 64845fb481f1..000000000000 --- a/drivers/staging/dream/include/linux/msm_rpcrouter.h +++ /dev/null @@ -1,47 +0,0 @@ -/* drivers/staging/dream/include/linux/msm_rpcrouter.h - * - * Copyright (c) QUALCOMM Incorporated - * Copyright (C) 2007 Google, Inc. - * Author: San Mehat <san@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef __LINUX_MSM_RPCROUTER_H -#define __LINUX_MSM_RPCROUTER_H - -#include <linux/types.h> -#include <linux/ioctl.h> - -#define RPC_ROUTER_VERSION_V1 0x00010000 - -struct rpcrouter_ioctl_server_args { - uint32_t prog; - uint32_t vers; -}; - -#define RPC_ROUTER_IOCTL_MAGIC (0xC1) - -#define RPC_ROUTER_IOCTL_GET_VERSION \ - _IOR(RPC_ROUTER_IOCTL_MAGIC, 0, unsigned int) - -#define RPC_ROUTER_IOCTL_GET_MTU \ - _IOR(RPC_ROUTER_IOCTL_MAGIC, 1, unsigned int) - -#define RPC_ROUTER_IOCTL_REGISTER_SERVER \ - _IOWR(RPC_ROUTER_IOCTL_MAGIC, 2, unsigned int) - -#define RPC_ROUTER_IOCTL_UNREGISTER_SERVER \ - _IOWR(RPC_ROUTER_IOCTL_MAGIC, 3, unsigned int) - -#define RPC_ROUTER_IOCTL_GET_MINOR_VERSION \ - _IOW(RPC_ROUTER_IOCTL_MAGIC, 4, unsigned int) - -#endif diff --git a/drivers/staging/dream/include/linux/wakelock.h b/drivers/staging/dream/include/linux/wakelock.h deleted file mode 100644 index 93c31a4d1ca7..000000000000 --- a/drivers/staging/dream/include/linux/wakelock.h +++ /dev/null @@ -1,91 +0,0 @@ -/* drivers/staging/dream/include/linux/wakelock.h - * - * Copyright (C) 2007-2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_WAKELOCK_H -#define _LINUX_WAKELOCK_H - -#include <linux/list.h> -#include <linux/ktime.h> - -/* A wake_lock prevents the system from entering suspend or other low power - * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock - * prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power - * states that cause large interrupt latencies or that disable a set of - * interrupts will not entered from idle until the wake_locks are released. - */ - -enum { - WAKE_LOCK_SUSPEND, /* Prevent suspend */ - WAKE_LOCK_IDLE, /* Prevent low power idle */ - WAKE_LOCK_TYPE_COUNT -}; - -struct wake_lock { -#ifdef CONFIG_HAS_WAKELOCK - struct list_head link; - int flags; - const char *name; - unsigned long expires; -#ifdef CONFIG_WAKELOCK_STAT - struct { - int count; - int expire_count; - int wakeup_count; - ktime_t total_time; - ktime_t prevent_suspend_time; - ktime_t max_time; - ktime_t last_time; - } stat; -#endif -#endif -}; - -#ifdef CONFIG_HAS_WAKELOCK - -void wake_lock_init(struct wake_lock *lock, int type, const char *name); -void wake_lock_destroy(struct wake_lock *lock); -void wake_lock(struct wake_lock *lock); -void wake_lock_timeout(struct wake_lock *lock, long timeout); -void wake_unlock(struct wake_lock *lock); - -/* wake_lock_active returns a non-zero value if the wake_lock is currently - * locked. If the wake_lock has a timeout, it does not check the timeout - * but if the timeout had aready been checked it will return 0. - */ -int wake_lock_active(struct wake_lock *lock); - -/* has_wake_lock returns 0 if no wake locks of the specified type are active, - * and non-zero if one or more wake locks are held. Specifically it returns - * -1 if one or more wake locks with no timeout are active or the - * number of jiffies until all active wake locks time out. - */ -long has_wake_lock(int type); - -#else - -static inline void wake_lock_init(struct wake_lock *lock, int type, - const char *name) {} -static inline void wake_lock_destroy(struct wake_lock *lock) {} -static inline void wake_lock(struct wake_lock *lock) {} -static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) {} -static inline void wake_unlock(struct wake_lock *lock) {} - -static inline int wake_lock_active(struct wake_lock *lock) { return 0; } -static inline long has_wake_lock(int type) { return 0; } - -#endif - -#endif - diff --git a/drivers/staging/dream/include/mach/camera.h b/drivers/staging/dream/include/mach/camera.h deleted file mode 100644 index c20f0423abd4..000000000000 --- a/drivers/staging/dream/include/mach/camera.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ - -#ifndef __ASM__ARCH_CAMERA_H -#define __ASM__ARCH_CAMERA_H - -#include <linux/list.h> -#include <linux/poll.h> -#include <linux/cdev.h> -#include <linux/platform_device.h> -#include "linux/types.h" - -#include <mach/board.h> -#include <media/msm_camera.h> - -#ifdef CONFIG_MSM_CAMERA_DEBUG -#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args) -#else -#define CDBG(fmt, args...) do { } while (0) -#endif - -#define MSM_CAMERA_MSG 0 -#define MSM_CAMERA_EVT 1 -#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4 -#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS 3 -#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16 -#define NUM_AF_STAT_OUTPUT_BUFFERS 3 - -enum msm_queue { - MSM_CAM_Q_CTRL, /* control command or control command status */ - MSM_CAM_Q_VFE_EVT, /* adsp event */ - MSM_CAM_Q_VFE_MSG, /* adsp message */ - MSM_CAM_Q_V4L2_REQ, /* v4l2 request */ -}; - -enum vfe_resp_msg { - VFE_EVENT, - VFE_MSG_GENERAL, - VFE_MSG_SNAPSHOT, - VFE_MSG_OUTPUT1, - VFE_MSG_OUTPUT2, - VFE_MSG_STATS_AF, - VFE_MSG_STATS_WE, -}; - -struct msm_vfe_phy_info { - uint32_t sbuf_phy; - uint32_t y_phy; - uint32_t cbcr_phy; -}; - -struct msm_vfe_resp { - enum vfe_resp_msg type; - struct msm_vfe_evt_msg evt_msg; - struct msm_vfe_phy_info phy; - void *extdata; - int32_t extlen; -}; - -struct msm_vfe_callback { - void (*vfe_resp)(struct msm_vfe_resp *, - enum msm_queue, void *syncdata); - void* (*vfe_alloc)(int, void *syncdata); -}; - -struct msm_camvfe_fn { - int (*vfe_init)(struct msm_vfe_callback *, struct platform_device *); - int (*vfe_enable)(struct camera_enable_cmd *); - int (*vfe_config)(struct msm_vfe_cfg_cmd *, void *); - int (*vfe_disable)(struct camera_enable_cmd *, - struct platform_device *dev); - void (*vfe_release)(struct platform_device *); -}; - -struct msm_sensor_ctrl { - int (*s_init)(const struct msm_camera_sensor_info *); - int (*s_release)(void); - int (*s_config)(void __user *); -}; - -struct msm_sync { - /* These two queues are accessed from a process context only. */ - struct hlist_head frame; /* most-frequently accessed */ - struct hlist_head stats; - - /* The message queue is used by the control thread to send commands - * to the config thread, and also by the DSP to send messages to the - * config thread. Thus it is the only queue that is accessed from - * both interrupt and process context. - */ - spinlock_t msg_event_q_lock; - struct list_head msg_event_q; - wait_queue_head_t msg_event_wait; - - /* This queue contains preview frames. It is accessed by the DSP (in - * in interrupt context, and by the frame thread. - */ - spinlock_t prev_frame_q_lock; - struct list_head prev_frame_q; - wait_queue_head_t prev_frame_wait; - int unblock_poll_frame; - - /* This queue contains snapshot frames. It is accessed by the DSP (in - * interrupt context, and by the control thread. - */ - spinlock_t pict_frame_q_lock; - struct list_head pict_frame_q; - wait_queue_head_t pict_frame_wait; - - struct msm_camera_sensor_info *sdata; - struct msm_camvfe_fn vfefn; - struct msm_sensor_ctrl sctrl; - struct platform_device *pdev; - uint8_t opencnt; - void *cropinfo; - int croplen; - unsigned pict_pp; - - const char *apps_id; - - struct mutex lock; - struct list_head list; -}; - -#define MSM_APPS_ID_V4L2 "msm_v4l2" -#define MSM_APPS_ID_PROP "msm_qct" - -struct msm_device { - struct msm_sync *sync; /* most-frequently accessed */ - struct device *device; - struct cdev cdev; - /* opened is meaningful only for the config and frame nodes, - * which may be opened only once. - */ - atomic_t opened; -}; - -struct msm_control_device_queue { - spinlock_t ctrl_status_q_lock; - struct list_head ctrl_status_q; - wait_queue_head_t ctrl_status_wait; -}; - -struct msm_control_device { - struct msm_device *pmsm; - - /* This queue used by the config thread to send responses back to the - * control thread. It is accessed only from a process context. - */ - struct msm_control_device_queue ctrl_q; -}; - -/* this structure is used in kernel */ -struct msm_queue_cmd { - struct list_head list; - enum msm_queue type; - void *command; -}; - -struct register_address_value_pair { - uint16_t register_address; - uint16_t register_value; -}; - -struct msm_pmem_region { - struct hlist_node list; - int type; - void *vaddr; - unsigned long paddr; - unsigned long len; - struct file *file; - uint32_t y_off; - uint32_t cbcr_off; - int fd; - uint8_t active; -}; - -struct axidata { - uint32_t bufnum1; - uint32_t bufnum2; - struct msm_pmem_region *region; -}; - -#ifdef CONFIG_MSM_CAMERA_FLASH -int msm_camera_flash_set_led_state(unsigned led_state); -#else -static inline int msm_camera_flash_set_led_state(unsigned led_state) -{ - return -ENOTSUPP; -} -#endif - -/* Below functions are added for V4L2 kernel APIs */ -struct msm_v4l2_driver { - struct msm_sync *sync; - int (*open)(struct msm_sync *, const char *apps_id); - int (*release)(struct msm_sync *); - int (*ctrl)(struct msm_sync *, struct msm_ctrl_cmd *); - int (*reg_pmem)(struct msm_sync *, struct msm_pmem_info *); - int (*get_frame) (struct msm_sync *, struct msm_frame *); - int (*put_frame) (struct msm_sync *, struct msm_frame *); - int (*get_pict) (struct msm_sync *, struct msm_ctrl_cmd *); - unsigned int (*drv_poll) (struct msm_sync *, struct file *, - struct poll_table_struct *); -}; - -int msm_v4l2_register(struct msm_v4l2_driver *); -int msm_v4l2_unregister(struct msm_v4l2_driver *); - -void msm_camvfe_init(void); -int msm_camvfe_check(void *); -void msm_camvfe_fn_init(struct msm_camvfe_fn *, void *); -int msm_camera_drv_start(struct platform_device *dev, - int (*sensor_probe)(const struct msm_camera_sensor_info *, - struct msm_sensor_ctrl *)); - -enum msm_camio_clk_type { - CAMIO_VFE_MDC_CLK, - CAMIO_MDC_CLK, - CAMIO_VFE_CLK, - CAMIO_VFE_AXI_CLK, - - CAMIO_MAX_CLK -}; - -enum msm_camio_clk_src_type { - MSM_CAMIO_CLK_SRC_INTERNAL, - MSM_CAMIO_CLK_SRC_EXTERNAL, - MSM_CAMIO_CLK_SRC_MAX -}; - -enum msm_s_test_mode { - S_TEST_OFF, - S_TEST_1, - S_TEST_2, - S_TEST_3 -}; - -enum msm_s_resolution { - S_QTR_SIZE, - S_FULL_SIZE, - S_INVALID_SIZE -}; - -enum msm_s_reg_update { - /* Sensor egisters that need to be updated during initialization */ - S_REG_INIT, - /* Sensor egisters that needs periodic I2C writes */ - S_UPDATE_PERIODIC, - /* All the sensor Registers will be updated */ - S_UPDATE_ALL, - /* Not valid update */ - S_UPDATE_INVALID -}; - -enum msm_s_setting { - S_RES_PREVIEW, - S_RES_CAPTURE -}; - -int msm_camio_enable(struct platform_device *dev); - -int msm_camio_clk_enable(enum msm_camio_clk_type clk); -int msm_camio_clk_disable(enum msm_camio_clk_type clk); -int msm_camio_clk_config(uint32_t freq); -void msm_camio_clk_rate_set(int rate); -void msm_camio_clk_axi_rate_set(int rate); - -void msm_camio_camif_pad_reg_reset(void); -void msm_camio_camif_pad_reg_reset_2(void); - -void msm_camio_vfe_blk_reset(void); - -void msm_camio_clk_sel(enum msm_camio_clk_src_type); -void msm_camio_disable(struct platform_device *); -int msm_camio_probe_on(struct platform_device *); -int msm_camio_probe_off(struct platform_device *); -#endif diff --git a/drivers/staging/dream/include/mach/msm_adsp.h b/drivers/staging/dream/include/mach/msm_adsp.h deleted file mode 100644 index a081683328a3..000000000000 --- a/drivers/staging/dream/include/mach/msm_adsp.h +++ /dev/null @@ -1,112 +0,0 @@ -/* include/asm-arm/arch-msm/msm_adsp.h - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM__ARCH_MSM_ADSP_H -#define __ASM__ARCH_MSM_ADSP_H - -struct msm_adsp_module; - -struct msm_adsp_ops { - /* event is called from interrupt context when a message - * arrives from the DSP. Use the provided function pointer - * to copy the message into a local buffer. Do NOT call - * it multiple times. - */ - void (*event)(void *driver_data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)); -}; - -/* Get, Put, Enable, and Disable are synchronous and must only - * be called from thread context. Enable and Disable will block - * up to one second in the event of a fatal DSP error but are - * much faster otherwise. - */ -int msm_adsp_get(const char *name, struct msm_adsp_module **module, - struct msm_adsp_ops *ops, void *driver_data); -void msm_adsp_put(struct msm_adsp_module *module); -int msm_adsp_enable(struct msm_adsp_module *module); -int msm_adsp_disable(struct msm_adsp_module *module); -int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate); - -/* Write is safe to call from interrupt context. - */ -int msm_adsp_write(struct msm_adsp_module *module, - unsigned queue_id, - void *data, size_t len); - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -/* Command Queue Indexes */ -#define QDSP_lpmCommandQueue 0 -#define QDSP_mpuAfeQueue 1 -#define QDSP_mpuGraphicsCmdQueue 2 -#define QDSP_mpuModmathCmdQueue 3 -#define QDSP_mpuVDecCmdQueue 4 -#define QDSP_mpuVDecPktQueue 5 -#define QDSP_mpuVEncCmdQueue 6 -#define QDSP_rxMpuDecCmdQueue 7 -#define QDSP_rxMpuDecPktQueue 8 -#define QDSP_txMpuEncQueue 9 -#define QDSP_uPAudPPCmd1Queue 10 -#define QDSP_uPAudPPCmd2Queue 11 -#define QDSP_uPAudPPCmd3Queue 12 -#define QDSP_uPAudPlay0BitStreamCtrlQueue 13 -#define QDSP_uPAudPlay1BitStreamCtrlQueue 14 -#define QDSP_uPAudPlay2BitStreamCtrlQueue 15 -#define QDSP_uPAudPlay3BitStreamCtrlQueue 16 -#define QDSP_uPAudPlay4BitStreamCtrlQueue 17 -#define QDSP_uPAudPreProcCmdQueue 18 -#define QDSP_uPAudRecBitStreamQueue 19 -#define QDSP_uPAudRecCmdQueue 20 -#define QDSP_uPDiagQueue 21 -#define QDSP_uPJpegActionCmdQueue 22 -#define QDSP_uPJpegCfgCmdQueue 23 -#define QDSP_uPVocProcQueue 24 -#define QDSP_vfeCommandQueue 25 -#define QDSP_vfeCommandScaleQueue 26 -#define QDSP_vfeCommandTableQueue 27 -#define QDSP_MAX_NUM_QUEUES 28 -#else -/* Command Queue Indexes */ -#define QDSP_lpmCommandQueue 0 -#define QDSP_mpuAfeQueue 1 -#define QDSP_mpuGraphicsCmdQueue 2 -#define QDSP_mpuModmathCmdQueue 3 -#define QDSP_mpuVDecCmdQueue 4 -#define QDSP_mpuVDecPktQueue 5 -#define QDSP_mpuVEncCmdQueue 6 -#define QDSP_rxMpuDecCmdQueue 7 -#define QDSP_rxMpuDecPktQueue 8 -#define QDSP_txMpuEncQueue 9 -#define QDSP_uPAudPPCmd1Queue 10 -#define QDSP_uPAudPPCmd2Queue 11 -#define QDSP_uPAudPPCmd3Queue 12 -#define QDSP_uPAudPlay0BitStreamCtrlQueue 13 -#define QDSP_uPAudPlay1BitStreamCtrlQueue 14 -#define QDSP_uPAudPlay2BitStreamCtrlQueue 15 -#define QDSP_uPAudPlay3BitStreamCtrlQueue 16 -#define QDSP_uPAudPlay4BitStreamCtrlQueue 17 -#define QDSP_uPAudPreProcCmdQueue 18 -#define QDSP_uPAudRecBitStreamQueue 19 -#define QDSP_uPAudRecCmdQueue 20 -#define QDSP_uPJpegActionCmdQueue 21 -#define QDSP_uPJpegCfgCmdQueue 22 -#define QDSP_uPVocProcQueue 23 -#define QDSP_vfeCommandQueue 24 -#define QDSP_vfeCommandScaleQueue 25 -#define QDSP_vfeCommandTableQueue 26 -#define QDSP_QUEUE_MAX 26 -#endif - -#endif diff --git a/drivers/staging/dream/include/mach/msm_rpcrouter.h b/drivers/staging/dream/include/mach/msm_rpcrouter.h deleted file mode 100644 index 9724ece1c97c..000000000000 --- a/drivers/staging/dream/include/mach/msm_rpcrouter.h +++ /dev/null @@ -1,179 +0,0 @@ -/** include/asm-arm/arch-msm/msm_rpcrouter.h - * - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2009 QUALCOMM Incorporated - * Author: San Mehat <san@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM__ARCH_MSM_RPCROUTER_H -#define __ASM__ARCH_MSM_RPCROUTER_H - -#include <linux/types.h> -#include <linux/list.h> -#include <linux/platform_device.h> - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -/* RPC API version structure - * Version bit 31 : 1->hashkey versioning, - * 0->major-minor (backward compatible) versioning - * hashkey versioning: - * Version bits 31-0 hashkey - * major-minor (backward compatible) versioning - * Version bits 30-28 reserved (no match) - * Version bits 27-16 major (must match) - * Version bits 15-0 minor (greater or equal) - */ -#define RPC_VERSION_MODE_MASK 0x80000000 -#define RPC_VERSION_MAJOR_MASK 0x0fff0000 -#define RPC_VERSION_MAJOR_OFFSET 16 -#define RPC_VERSION_MINOR_MASK 0x0000ffff - -#define MSM_RPC_VERS(major, minor) \ - ((uint32_t)((((major) << RPC_VERSION_MAJOR_OFFSET) & \ - RPC_VERSION_MAJOR_MASK) | \ - ((minor) & RPC_VERSION_MINOR_MASK))) -#define MSM_RPC_GET_MAJOR(vers) (((vers) & RPC_VERSION_MAJOR_MASK) >> \ - RPC_VERSION_MAJOR_OFFSET) -#define MSM_RPC_GET_MINOR(vers) ((vers) & RPC_VERSION_MINOR_MASK) -#else -#define MSM_RPC_VERS(major, minor) (major) -#define MSM_RPC_GET_MAJOR(vers) (vers) -#define MSM_RPC_GET_MINOR(vers) 0 -#endif - -struct msm_rpc_endpoint; - -struct rpcsvr_platform_device -{ - struct platform_device base; - uint32_t prog; - uint32_t vers; -}; - -#define RPC_DATA_IN 0 -/* - * Structures for sending / receiving direct RPC requests - * XXX: Any cred/verif lengths > 0 not supported - */ - -struct rpc_request_hdr -{ - uint32_t xid; - uint32_t type; /* 0 */ - uint32_t rpc_vers; /* 2 */ - uint32_t prog; - uint32_t vers; - uint32_t procedure; - uint32_t cred_flavor; - uint32_t cred_length; - uint32_t verf_flavor; - uint32_t verf_length; -}; - -typedef struct -{ - uint32_t low; - uint32_t high; -} rpc_reply_progmismatch_data; - -typedef struct -{ -} rpc_denied_reply_hdr; - -typedef struct -{ - uint32_t verf_flavor; - uint32_t verf_length; - uint32_t accept_stat; -#define RPC_ACCEPTSTAT_SUCCESS 0 -#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1 -#define RPC_ACCEPTSTAT_PROG_MISMATCH 2 -#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3 -#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4 -#define RPC_ACCEPTSTAT_SYSTEM_ERR 5 -#define RPC_ACCEPTSTAT_PROG_LOCKED 6 - /* - * Following data is dependant on accept_stat - * If ACCEPTSTAT == PROG_MISMATCH then there is a - * 'rpc_reply_progmismatch_data' structure following the header. - * Otherwise the data is procedure specific - */ -} rpc_accepted_reply_hdr; - -struct rpc_reply_hdr -{ - uint32_t xid; - uint32_t type; - uint32_t reply_stat; -#define RPCMSG_REPLYSTAT_ACCEPTED 0 -#define RPCMSG_REPLYSTAT_DENIED 1 - union { - rpc_accepted_reply_hdr acc_hdr; - rpc_denied_reply_hdr dny_hdr; - } data; -}; - -/* flags for msm_rpc_connect() */ -#define MSM_RPC_UNINTERRUPTIBLE 0x0001 - -/* use IS_ERR() to check for failure */ -struct msm_rpc_endpoint *msm_rpc_open(void); -/* Connect with the specified server version */ -struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags); -uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept); -/* check if server version can handle client requested version */ -int msm_rpc_is_compatible_version(uint32_t server_version, - uint32_t client_version); - -int msm_rpc_close(struct msm_rpc_endpoint *ept); -int msm_rpc_write(struct msm_rpc_endpoint *ept, - void *data, int len); -int msm_rpc_read(struct msm_rpc_endpoint *ept, - void **data, unsigned len, long timeout); -void msm_rpc_setup_req(struct rpc_request_hdr *hdr, - uint32_t prog, uint32_t vers, uint32_t proc); -int msm_rpc_register_server(struct msm_rpc_endpoint *ept, - uint32_t prog, uint32_t vers); -int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, - uint32_t prog, uint32_t vers); - -/* simple blocking rpc call - * - * request is mandatory and must have a rpc_request_hdr - * at the start. The header will be filled out for you. - * - * reply provides a buffer for replies of reply_max_size - */ -int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, - void *request, int request_size, - void *reply, int reply_max_size, - long timeout); -int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc, - void *request, int request_size, - long timeout); - -struct msm_rpc_server -{ - struct list_head list; - uint32_t flags; - - uint32_t prog; - uint32_t vers; - - int (*rpc_call)(struct msm_rpc_server *server, - struct rpc_request_hdr *req, unsigned len); -}; - -int msm_rpc_create_server(struct msm_rpc_server *server); - -#endif diff --git a/drivers/staging/dream/include/mach/msm_smd.h b/drivers/staging/dream/include/mach/msm_smd.h deleted file mode 100644 index bdf7731ab680..000000000000 --- a/drivers/staging/dream/include/mach/msm_smd.h +++ /dev/null @@ -1,107 +0,0 @@ -/* linux/include/asm-arm/arch-msm/msm_smd.h - * - * Copyright (C) 2007 Google, Inc. - * Author: Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM_ARCH_MSM_SMD_H -#define __ASM_ARCH_MSM_SMD_H - -typedef struct smd_channel smd_channel_t; - -/* warning: notify() may be called before open returns */ -int smd_open(const char *name, smd_channel_t **ch, void *priv, - void (*notify)(void *priv, unsigned event)); - -#define SMD_EVENT_DATA 1 -#define SMD_EVENT_OPEN 2 -#define SMD_EVENT_CLOSE 3 - -int smd_close(smd_channel_t *ch); - -/* passing a null pointer for data reads and discards */ -int smd_read(smd_channel_t *ch, void *data, int len); - -/* Write to stream channels may do a partial write and return -** the length actually written. -** Write to packet channels will never do a partial write -- -** it will return the requested length written or an error. -*/ -int smd_write(smd_channel_t *ch, const void *data, int len); - -int smd_write_avail(smd_channel_t *ch); -int smd_read_avail(smd_channel_t *ch); - -/* Returns the total size of the current packet being read. -** Returns 0 if no packets available or a stream channel. -*/ -int smd_cur_packet_size(smd_channel_t *ch); - -/* used for tty unthrottling and the like -- causes the notify() -** callback to be called from the same lock context as is used -** when it is called from channel updates -*/ -void smd_kick(smd_channel_t *ch); - - -#if 0 -/* these are interruptable waits which will block you until the specified -** number of bytes are readable or writable. -*/ -int smd_wait_until_readable(smd_channel_t *ch, int bytes); -int smd_wait_until_writable(smd_channel_t *ch, int bytes); -#endif - -typedef enum -{ - SMD_PORT_DS = 0, - SMD_PORT_DIAG, - SMD_PORT_RPC_CALL, - SMD_PORT_RPC_REPLY, - SMD_PORT_BT, - SMD_PORT_CONTROL, - SMD_PORT_MEMCPY_SPARE1, - SMD_PORT_DATA1, - SMD_PORT_DATA2, - SMD_PORT_DATA3, - SMD_PORT_DATA4, - SMD_PORT_DATA5, - SMD_PORT_DATA6, - SMD_PORT_DATA7, - SMD_PORT_DATA8, - SMD_PORT_DATA9, - SMD_PORT_DATA10, - SMD_PORT_DATA11, - SMD_PORT_DATA12, - SMD_PORT_DATA13, - SMD_PORT_DATA14, - SMD_PORT_DATA15, - SMD_PORT_DATA16, - SMD_PORT_DATA17, - SMD_PORT_DATA18, - SMD_PORT_DATA19, - SMD_PORT_DATA20, - SMD_PORT_GPS_NMEA, - SMD_PORT_BRIDGE_1, - SMD_PORT_BRIDGE_2, - SMD_PORT_BRIDGE_3, - SMD_PORT_BRIDGE_4, - SMD_PORT_BRIDGE_5, - SMD_PORT_LOOPBACK, - SMD_PORT_CS_APPS_MODEM, - SMD_PORT_CS_APPS_DSP, - SMD_PORT_CS_MODEM_DSP, - SMD_NUM_PORTS, -} smd_port_id_type; - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h deleted file mode 100644 index 0b6a31259bb0..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef QDSP5AUDPLAYCMDI_H -#define QDSP5AUDPLAYCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - Q D S P 5 A U D I O P L A Y T A S K C O M M A N D S - -GENERAL DESCRIPTION - Command Interface for AUDPLAYTASK on QDSP5 - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - - audplay_cmd_dec_data_avail - Send buffer to AUDPLAY task - - -Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaycmdi.h#2 $ - -===========================================================================*/ - -#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL 0x0000 -#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN \ - sizeof(audplay_cmd_bitstream_data_avail) - -/* Type specification of dec_data_avail message sent to AUDPLAYTASK -*/ -typedef struct { - /*command ID*/ - unsigned int cmd_id; - - /* Decoder ID for which message is being sent */ - unsigned int decoder_id; - - /* Start address of data in ARM global memory */ - unsigned int buf_ptr; - - /* Number of 16-bit words of bit-stream data contiguously available at the - * above-mentioned address. */ - unsigned int buf_size; - - /* Partition number used by audPlayTask to communicate with DSP's RTOS - * kernel */ - unsigned int partition_number; -} __attribute__((packed)) audplay_cmd_bitstream_data_avail; - -#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003 -#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \ - sizeof(struct audplay_cmd_hpcm_buf_cfg) - -struct audplay_cmd_hpcm_buf_cfg { - unsigned int cmd_id; - unsigned int hostpcm_config; - unsigned int feedback_frequency; - unsigned int byte_swap; - unsigned int max_buffers; - unsigned int partition_number; -} __attribute__((packed)); - -#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004 -#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \ - sizeof(struct audplay_cmd_buffer_update) - -struct audplay_cmd_buffer_refresh { - unsigned int cmd_id; - unsigned int num_buffers; - unsigned int buf_read_count; - unsigned int buf0_address; - unsigned int buf0_length; - unsigned int buf1_address; - unsigned int buf1_length; -} __attribute__((packed)); -#endif /* QDSP5AUDPLAYCMD_H */ diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h deleted file mode 100644 index c63034b8bf13..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef QDSP5AUDPLAYMSG_H -#define QDSP5AUDPLAYMSG_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - Q D S P 5 A U D I O P L A Y T A S K M S G - -GENERAL DESCRIPTION - Message sent by AUDPLAY task - -REFERENCES - None - - -Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaymsg.h#3 $ - -===========================================================================*/ -#define AUDPLAY_MSG_DEC_NEEDS_DATA 0x0001 -#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN \ - sizeof(audplay_msg_dec_needs_data) - -typedef struct{ - /* reserved*/ - unsigned int dec_id; - - /* The read pointer offset of external memory until which the - * bitstream has been DMAed in. */ - unsigned int adecDataReadPtrOffset; - - /* The buffer size of external memory. */ - unsigned int adecDataBufSize; - - unsigned int bitstream_free_len; - unsigned int bitstream_write_ptr; - unsigned int bitstarem_buf_start; - unsigned int bitstream_buf_len; -} __attribute__((packed)) audplay_msg_dec_needs_data; - -#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004 -#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \ - sizeof(struct audplay_msg_buffer_update) - -struct audplay_msg_buffer_update { - unsigned int buffer_write_count; - unsigned int num_of_buffer; - unsigned int buf0_address; - unsigned int buf0_length; - unsigned int buf1_address; - unsigned int buf1_length; -} __attribute__((packed)); -#endif /* QDSP5AUDPLAYMSG_H */ diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h deleted file mode 100644 index 8bee9c62980b..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h +++ /dev/null @@ -1,914 +0,0 @@ -#ifndef QDSP5AUDPPCMDI_H -#define QDSP5AUDPPCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - A U D I O P O S T P R O C E S S I N G I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by AUDPP Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppcmdi.h#2 $ - -===========================================================================*/ - -/* - * ARM to AUDPPTASK Commands - * - * ARM uses three command queues to communicate with AUDPPTASK - * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands - * Location : MEMA - * Buffer Size : 6 words - * No of buffers in a queue : 20 for gaming audio and 5 for other images - * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier - * Location : MEMA - * Buffer Size : 23 - * No of buffers in a queue : 2 - * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands - * Location : MEMA - * Buffer Size : 145 - * No of buffers in a queue : 3 - */ - -/* - * Commands Related to uPAudPPCmd1Queue - */ - -/* - * Command Structure to enable or disable the active decoders - */ - -#define AUDPP_CMD_CFG_DEC_TYPE 0x0001 -#define AUDPP_CMD_CFG_DEC_TYPE_LEN sizeof(audpp_cmd_cfg_dec_type) - -/* Enable the decoder */ -#define AUDPP_CMD_DEC_TYPE_M 0x000F - -#define AUDPP_CMD_ENA_DEC_V 0x4000 -#define AUDPP_CMD_DIS_DEC_V 0x0000 -#define AUDPP_CMD_DEC_STATE_M 0x4000 - -#define AUDPP_CMD_UPDATDE_CFG_DEC 0x8000 -#define AUDPP_CMD_DONT_UPDATE_CFG_DEC 0x0000 - - -/* Type specification of cmd_cfg_dec */ - -typedef struct { - unsigned short cmd_id; - unsigned short dec0_cfg; - unsigned short dec1_cfg; - unsigned short dec2_cfg; - unsigned short dec3_cfg; - unsigned short dec4_cfg; -} __attribute__((packed)) audpp_cmd_cfg_dec_type; - -/* - * Command Structure to Pause , Resume and flushes the selected audio decoders - */ - -#define AUDPP_CMD_DEC_CTRL 0x0002 -#define AUDPP_CMD_DEC_CTRL_LEN sizeof(audpp_cmd_dec_ctrl) - -/* Decoder control commands for pause, resume and flush */ -#define AUDPP_CMD_FLUSH_V 0x2000 - -#define AUDPP_CMD_PAUSE_V 0x4000 -#define AUDPP_CMD_RESUME_V 0x0000 - -#define AUDPP_CMD_UPDATE_V 0x8000 -#define AUDPP_CMD_IGNORE_V 0x0000 - - -/* Type Spec for decoder control command*/ - -typedef struct { - unsigned short cmd_id; - unsigned short dec0_ctrl; - unsigned short dec1_ctrl; - unsigned short dec2_ctrl; - unsigned short dec3_ctrl; - unsigned short dec4_ctrl; -} __attribute__((packed)) audpp_cmd_dec_ctrl; - -/* - * Command Structure to Configure the AVSync FeedBack Mechanism - */ - -#define AUDPP_CMD_AVSYNC 0x0003 -#define AUDPP_CMD_AVSYNC_LEN sizeof(audpp_cmd_avsync) - -typedef struct { - unsigned short cmd_id; - unsigned short object_number; - unsigned short interrupt_interval_lsw; - unsigned short interrupt_interval_msw; -} __attribute__((packed)) audpp_cmd_avsync; - -/* - * Command Structure to enable or disable(sleep) the AUDPPTASK - */ - -#define AUDPP_CMD_CFG 0x0004 -#define AUDPP_CMD_CFG_LEN sizeof(audpp_cmd_cfg) - -#define AUDPP_CMD_CFG_SLEEP 0x0000 -#define AUDPP_CMD_CFG_ENABLE 0xFFFF - -typedef struct { - unsigned short cmd_id; - unsigned short cfg; -} __attribute__((packed)) audpp_cmd_cfg; - -/* - * Command Structure to Inject or drop the specified no of samples - */ - -#define AUDPP_CMD_ADJUST_SAMP 0x0005 -#define AUDPP_CMD_ADJUST_SAMP_LEN sizeof(audpp_cmd_adjust_samp) - -#define AUDPP_CMD_SAMP_DROP -1 -#define AUDPP_CMD_SAMP_INSERT 0x0001 - -#define AUDPP_CMD_NUM_SAMPLES 0x0001 - -typedef struct { - unsigned short cmd_id; - unsigned short object_no; - signed short sample_insert_or_drop; - unsigned short num_samples; -} __attribute__((packed)) audpp_cmd_adjust_samp; - -/* - * Command Structure to Configure AVSync Feedback Mechanism - */ - -#define AUDPP_CMD_AVSYNC_CMD_2 0x0006 -#define AUDPP_CMD_AVSYNC_CMD_2_LEN sizeof(audpp_cmd_avsync_cmd_2) - -typedef struct { - unsigned short cmd_id; - unsigned short object_number; - unsigned short interrupt_interval_lsw; - unsigned short interrupt_interval_msw; - unsigned short sample_counter_dlsw; - unsigned short sample_counter_dmsw; - unsigned short sample_counter_msw; - unsigned short byte_counter_dlsw; - unsigned short byte_counter_dmsw; - unsigned short byte_counter_msw; -} __attribute__((packed)) audpp_cmd_avsync_cmd_2; - -/* - * Command Structure to Configure AVSync Feedback Mechanism - */ - -#define AUDPP_CMD_AVSYNC_CMD_3 0x0007 -#define AUDPP_CMD_AVSYNC_CMD_3_LEN sizeof(audpp_cmd_avsync_cmd_3) - -typedef struct { - unsigned short cmd_id; - unsigned short object_number; - unsigned short interrupt_interval_lsw; - unsigned short interrupt_interval_msw; - unsigned short sample_counter_dlsw; - unsigned short sample_counter_dmsw; - unsigned short sample_counter_msw; - unsigned short byte_counter_dlsw; - unsigned short byte_counter_dmsw; - unsigned short byte_counter_msw; -} __attribute__((packed)) audpp_cmd_avsync_cmd_3; - -#define AUDPP_CMD_ROUTING_MODE 0x0008 -#define AUDPP_CMD_ROUTING_MODE_LEN \ -sizeof(struct audpp_cmd_routing_mode) - -struct audpp_cmd_routing_mode { - unsigned short cmd_id; - unsigned short object_number; - unsigned short routing_mode; -} __attribute__((packed)); - -/* - * Commands Related to uPAudPPCmd2Queue - */ - -/* - * Command Structure to configure Per decoder Parameters (Common) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS 0x0000 -#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN \ - sizeof(audpp_cmd_cfg_adec_params_common) - -#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM 0x4000 -#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM 0x0000 - -#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM 0x8000 -#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM 0x0000 - -/* Sampling frequency*/ -#define AUDPP_CMD_SAMP_RATE_96000 0x0000 -#define AUDPP_CMD_SAMP_RATE_88200 0x0001 -#define AUDPP_CMD_SAMP_RATE_64000 0x0002 -#define AUDPP_CMD_SAMP_RATE_48000 0x0003 -#define AUDPP_CMD_SAMP_RATE_44100 0x0004 -#define AUDPP_CMD_SAMP_RATE_32000 0x0005 -#define AUDPP_CMD_SAMP_RATE_24000 0x0006 -#define AUDPP_CMD_SAMP_RATE_22050 0x0007 -#define AUDPP_CMD_SAMP_RATE_16000 0x0008 -#define AUDPP_CMD_SAMP_RATE_12000 0x0009 -#define AUDPP_CMD_SAMP_RATE_11025 0x000A -#define AUDPP_CMD_SAMP_RATE_8000 0x000B - - -/* - * Type specification of cmd_adec_cfg sent to all decoder - */ - -typedef struct { - unsigned short cmd_id; - unsigned short length; - unsigned short dec_id; - unsigned short status_msg_flag; - unsigned short decoder_frame_counter_msg_period; - unsigned short input_sampling_frequency; -} __attribute__((packed)) audpp_cmd_cfg_adec_params_common; - -/* - * Command Structure to configure Per decoder Parameters (Wav) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN \ - sizeof(audpp_cmd_cfg_adec_params_wav) - - -#define AUDPP_CMD_WAV_STEREO_CFG_MONO 0x0001 -#define AUDPP_CMD_WAV_STEREO_CFG_STEREO 0x0002 - -#define AUDPP_CMD_WAV_PCM_WIDTH_8 0x0000 -#define AUDPP_CMD_WAV_PCM_WIDTH_16 0x0001 -#define AUDPP_CMD_WAV_PCM_WIDTH_32 0x0002 - -typedef struct { - audpp_cmd_cfg_adec_params_common common; - unsigned short stereo_cfg; - unsigned short pcm_width; - unsigned short sign; -} __attribute__((packed)) audpp_cmd_cfg_adec_params_wav; - -/* - * Command Structure to configure Per decoder Parameters (ADPCM) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN \ - sizeof(audpp_cmd_cfg_adec_params_adpcm) - - -#define AUDPP_CMD_ADPCM_STEREO_CFG_MONO 0x0001 -#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO 0x0002 - -typedef struct { - audpp_cmd_cfg_adec_params_common common; - unsigned short stereo_cfg; - unsigned short block_size; -} __attribute__((packed)) audpp_cmd_cfg_adec_params_adpcm; - -/* - * Command Structure to configure Per decoder Parameters (MP3) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN \ - sizeof(audpp_cmd_cfg_adec_params_mp3) - -typedef struct { - audpp_cmd_cfg_adec_params_common common; -} __attribute__((packed)) audpp_cmd_cfg_adec_params_mp3; - - -/* - * Command Structure to configure Per decoder Parameters (AAC) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN \ - sizeof(audpp_cmd_cfg_adec_params_aac) - - -#define AUDPP_CMD_AAC_FORMAT_ADTS -1 -#define AUDPP_CMD_AAC_FORMAT_RAW 0x0000 -#define AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW 0x0001 -#define AUDPP_CMD_AAC_FORMAT_LOAS 0x0002 - -#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC 0x0002 -#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP 0x0004 -#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC 0x0011 - -#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON 0x0001 -#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF 0x0000 - -#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON 0x0001 -#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF 0x0000 - -typedef struct { - audpp_cmd_cfg_adec_params_common common; - signed short format; - unsigned short audio_object; - unsigned short ep_config; - unsigned short aac_section_data_resilience_flag; - unsigned short aac_scalefactor_data_resilience_flag; - unsigned short aac_spectral_data_resilience_flag; - unsigned short sbr_on_flag; - unsigned short sbr_ps_on_flag; - unsigned short dual_mono_mode; - unsigned short channel_configuration; -} __attribute__((packed)) audpp_cmd_cfg_adec_params_aac; - -/* - * Command Structure to configure Per decoder Parameters (V13K) - */ - -#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN \ - sizeof(struct audpp_cmd_cfg_adec_params_v13k) - - -#define AUDPP_CMD_STEREO_CFG_MONO 0x0001 -#define AUDPP_CMD_STEREO_CFG_STEREO 0x0002 - -struct audpp_cmd_cfg_adec_params_v13k { - audpp_cmd_cfg_adec_params_common common; - unsigned short stereo_cfg; -} __attribute__((packed)); - -#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \ - sizeof(struct audpp_cmd_cfg_adec_params_evrc) - -struct audpp_cmd_cfg_adec_params_evrc { - audpp_cmd_cfg_adec_params_common common; - unsigned short stereo_cfg; -} __attribute__ ((packed)); - -/* - * Command Structure to configure the HOST PCM interface - */ - -#define AUDPP_CMD_PCM_INTF 0x0001 -#define AUDPP_CMD_PCM_INTF_2 0x0002 -#define AUDPP_CMD_PCM_INTF_LEN sizeof(audpp_cmd_pcm_intf) - -#define AUDPP_CMD_PCM_INTF_MONO_V 0x0001 -#define AUDPP_CMD_PCM_INTF_STEREO_V 0x0002 - -/* These two values differentiate the two types of commands that could be issued - * Interface configuration command and Buffer update command */ - -#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V 0x0000 -#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V -1 - -#define AUDPP_CMD_PCM_INTF_RX_ENA_M 0x000F -#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V 0x0008 -#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V 0x0004 - -/* These flags control the enabling and disabling of the interface together - * with host interface bit mask. */ - -#define AUDPP_CMD_PCM_INTF_ENA_V -1 -#define AUDPP_CMD_PCM_INTF_DIS_V 0x0000 - - -#define AUDPP_CMD_PCM_INTF_FULL_DUPLEX 0x0 -#define AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP 0x1 - - -#define AUDPP_CMD_PCM_INTF_OBJECT_NUM 0x5 -#define AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM 0x6 - - -typedef struct { - unsigned short cmd_id; - unsigned short object_num; - signed short config; - unsigned short intf_type; - - /* DSP -> ARM Configuration */ - unsigned short read_buf1LSW; - unsigned short read_buf1MSW; - unsigned short read_buf1_len; - - unsigned short read_buf2LSW; - unsigned short read_buf2MSW; - unsigned short read_buf2_len; - /* 0:HOST_PCM_INTF disable - ** 0xFFFF: HOST_PCM_INTF enable - */ - signed short dsp_to_arm_flag; - unsigned short partition_number; - - /* ARM -> DSP Configuration */ - unsigned short write_buf1LSW; - unsigned short write_buf1MSW; - unsigned short write_buf1_len; - - unsigned short write_buf2LSW; - unsigned short write_buf2MSW; - unsigned short write_buf2_len; - - /* 0:HOST_PCM_INTF disable - ** 0xFFFF: HOST_PCM_INTF enable - */ - signed short arm_to_rx_flag; - unsigned short weight_decoder_to_rx; - unsigned short weight_arm_to_rx; - - unsigned short partition_number_arm_to_dsp; - unsigned short sample_rate; - unsigned short channel_mode; -} __attribute__((packed)) audpp_cmd_pcm_intf; - -/* - ** BUFFER UPDATE COMMAND - */ -#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN \ - sizeof(audpp_cmd_pcm_intf_send_buffer) - -typedef struct { - unsigned short cmd_id; - unsigned short host_pcm_object; - /* set config = 0xFFFF for configuration*/ - signed short config; - unsigned short intf_type; - unsigned short dsp_to_arm_buf_id; - unsigned short arm_to_dsp_buf_id; - unsigned short arm_to_dsp_buf_len; -} __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer; - - -/* - * Commands Related to uPAudPPCmd3Queue - */ - -/* - * Command Structure to configure post processing params (Commmon) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS 0x0000 -#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN \ - sizeof(audpp_cmd_cfg_object_params_common) - -#define AUDPP_CMD_OBJ0_UPDATE 0x8000 -#define AUDPP_CMD_OBJ0_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_OBJ1_UPDATE 0x8000 -#define AUDPP_CMD_OBJ1_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_OBJ2_UPDATE 0x8000 -#define AUDPP_CMD_OBJ2_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_OBJ3_UPDATE 0x8000 -#define AUDPP_CMD_OBJ3_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_OBJ4_UPDATE 0x8000 -#define AUDPP_CMD_OBJ4_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_HPCM_UPDATE 0x8000 -#define AUDPP_CMD_HPCM_DONT_UPDATE 0x0000 - -#define AUDPP_CMD_COMMON_CFG_UPDATE 0x8000 -#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE 0x0000 - -typedef struct { - unsigned short cmd_id; - unsigned short obj0_cfg; - unsigned short obj1_cfg; - unsigned short obj2_cfg; - unsigned short obj3_cfg; - unsigned short obj4_cfg; - unsigned short host_pcm_obj_cfg; - unsigned short comman_cfg; - unsigned short command_type; -} __attribute__((packed)) audpp_cmd_cfg_object_params_common; - -/* - * Command Structure to configure post processing params (Volume) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN \ - sizeof(audpp_cmd_cfg_object_params_volume) - -typedef struct { - audpp_cmd_cfg_object_params_common common; - unsigned short volume; - unsigned short pan; -} __attribute__((packed)) audpp_cmd_cfg_object_params_volume; - -/* - * Command Structure to configure post processing params (PCM Filter) --DOUBT - */ - -typedef struct { - unsigned short numerator_b0_filter_lsw; - unsigned short numerator_b0_filter_msw; - unsigned short numerator_b1_filter_lsw; - unsigned short numerator_b1_filter_msw; - unsigned short numerator_b2_filter_lsw; - unsigned short numerator_b2_filter_msw; -} __attribute__((packed)) numerator; - -typedef struct { - unsigned short denominator_a0_filter_lsw; - unsigned short denominator_a0_filter_msw; - unsigned short denominator_a1_filter_lsw; - unsigned short denominator_a1_filter_msw; -} __attribute__((packed)) denominator; - -typedef struct { - unsigned short shift_factor_0; -} __attribute__((packed)) shift_factor; - -typedef struct { - unsigned short pan_filter_0; -} __attribute__((packed)) pan; - -typedef struct { - numerator numerator_filter; - denominator denominator_filter; - shift_factor shift_factor_filter; - pan pan_filter; -} __attribute__((packed)) filter_1; - -typedef struct { - numerator numerator_filter[2]; - denominator denominator_filter[2]; - shift_factor shift_factor_filter[2]; - pan pan_filter[2]; -} __attribute__((packed)) filter_2; - -typedef struct { - numerator numerator_filter[3]; - denominator denominator_filter[3]; - shift_factor shift_factor_filter[3]; - pan pan_filter[3]; -} __attribute__((packed)) filter_3; - -typedef struct { - numerator numerator_filter[4]; - denominator denominator_filter[4]; - shift_factor shift_factor_filter[4]; - pan pan_filter[4]; -} __attribute__((packed)) filter_4; - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN \ - sizeof(audpp_cmd_cfg_object_params_pcm) - - -typedef struct { - audpp_cmd_cfg_object_params_common common; - unsigned short active_flag; - unsigned short num_bands; - union { - filter_1 filter_1_params; - filter_2 filter_2_params; - filter_3 filter_3_params; - filter_4 filter_4_params; - } __attribute__((packed)) params_filter; -} __attribute__((packed)) audpp_cmd_cfg_object_params_pcm; - - -/* - * Command Structure to configure post processing parameters (equalizer) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN \ - sizeof(audpp_cmd_cfg_object_params_eqalizer) - -typedef struct { - unsigned short numerator_coeff_0_lsw; - unsigned short numerator_coeff_0_msw; - unsigned short numerator_coeff_1_lsw; - unsigned short numerator_coeff_1_msw; - unsigned short numerator_coeff_2_lsw; - unsigned short numerator_coeff_2_msw; -} __attribute__((packed)) eq_numerator; - -typedef struct { - unsigned short denominator_coeff_0_lsw; - unsigned short denominator_coeff_0_msw; - unsigned short denominator_coeff_1_lsw; - unsigned short denominator_coeff_1_msw; -} __attribute__((packed)) eq_denominator; - -typedef struct { - unsigned short shift_factor; -} __attribute__((packed)) eq_shiftfactor; - -typedef struct { - eq_numerator numerator; - eq_denominator denominator; - eq_shiftfactor shiftfactor; -} __attribute__((packed)) eq_coeff_1; - -typedef struct { - eq_numerator numerator[2]; - eq_denominator denominator[2]; - eq_shiftfactor shiftfactor[2]; -} __attribute__((packed)) eq_coeff_2; - -typedef struct { - eq_numerator numerator[3]; - eq_denominator denominator[3]; - eq_shiftfactor shiftfactor[3]; -} __attribute__((packed)) eq_coeff_3; - -typedef struct { - eq_numerator numerator[4]; - eq_denominator denominator[4]; - eq_shiftfactor shiftfactor[4]; -} __attribute__((packed)) eq_coeff_4; - -typedef struct { - eq_numerator numerator[5]; - eq_denominator denominator[5]; - eq_shiftfactor shiftfactor[5]; -} __attribute__((packed)) eq_coeff_5; - -typedef struct { - eq_numerator numerator[6]; - eq_denominator denominator[6]; - eq_shiftfactor shiftfactor[6]; -} __attribute__((packed)) eq_coeff_6; - -typedef struct { - eq_numerator numerator[7]; - eq_denominator denominator[7]; - eq_shiftfactor shiftfactor[7]; -} __attribute__((packed)) eq_coeff_7; - -typedef struct { - eq_numerator numerator[8]; - eq_denominator denominator[8]; - eq_shiftfactor shiftfactor[8]; -} __attribute__((packed)) eq_coeff_8; - -typedef struct { - eq_numerator numerator[9]; - eq_denominator denominator[9]; - eq_shiftfactor shiftfactor[9]; -} __attribute__((packed)) eq_coeff_9; - -typedef struct { - eq_numerator numerator[10]; - eq_denominator denominator[10]; - eq_shiftfactor shiftfactor[10]; -} __attribute__((packed)) eq_coeff_10; - -typedef struct { - eq_numerator numerator[11]; - eq_denominator denominator[11]; - eq_shiftfactor shiftfactor[11]; -} __attribute__((packed)) eq_coeff_11; - -typedef struct { - eq_numerator numerator[12]; - eq_denominator denominator[12]; - eq_shiftfactor shiftfactor[12]; -} __attribute__((packed)) eq_coeff_12; - - -typedef struct { - audpp_cmd_cfg_object_params_common common; - unsigned short eq_flag; - unsigned short num_bands; - union { - eq_coeff_1 eq_coeffs_1; - eq_coeff_2 eq_coeffs_2; - eq_coeff_3 eq_coeffs_3; - eq_coeff_4 eq_coeffs_4; - eq_coeff_5 eq_coeffs_5; - eq_coeff_6 eq_coeffs_6; - eq_coeff_7 eq_coeffs_7; - eq_coeff_8 eq_coeffs_8; - eq_coeff_9 eq_coeffs_9; - eq_coeff_10 eq_coeffs_10; - eq_coeff_11 eq_coeffs_11; - eq_coeff_12 eq_coeffs_12; - } __attribute__((packed)) eq_coeff; -} __attribute__((packed)) audpp_cmd_cfg_object_params_eqalizer; - - -/* - * Command Structure to configure post processing parameters (ADRC) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN \ - sizeof(audpp_cmd_cfg_object_params_adrc) - - -#define AUDPP_CMD_ADRC_FLAG_DIS 0x0000 -#define AUDPP_CMD_ADRC_FLAG_ENA -1 - -typedef struct { - audpp_cmd_cfg_object_params_common common; - signed short adrc_flag; - unsigned short compression_th; - unsigned short compression_slope; - unsigned short rms_time; - unsigned short attack_const_lsw; - unsigned short attack_const_msw; - unsigned short release_const_lsw; - unsigned short release_const_msw; - unsigned short adrc_system_delay; -} __attribute__((packed)) audpp_cmd_cfg_object_params_adrc; - -/* - * Command Structure to configure post processing parameters(Spectrum Analizer) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN \ - sizeof(audpp_cmd_cfg_object_params_spectram) - - -typedef struct { - audpp_cmd_cfg_object_params_common common; - unsigned short sample_interval; - unsigned short num_coeff; -} __attribute__((packed)) audpp_cmd_cfg_object_params_spectram; - -/* - * Command Structure to configure post processing parameters (QConcert) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN \ - sizeof(audpp_cmd_cfg_object_params_qconcert) - - -#define AUDPP_CMD_QCON_ENA_FLAG_ENA -1 -#define AUDPP_CMD_QCON_ENA_FLAG_DIS 0x0000 - -#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE -1 -#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT 0x0000 -#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE 0x0001 -#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP 0x0002 - -#define AUDPP_CMD_QCON_GAIN_UNIT 0x7FFF -#define AUDPP_CMD_QCON_GAIN_SIX_DB 0x4027 - - -#define AUDPP_CMD_QCON_EXPANSION_MAX 0x7FFF - - -typedef struct { - audpp_cmd_cfg_object_params_common common; - signed short enable_flag; - signed short output_mode; - signed short gain; - signed short expansion; - signed short delay; - unsigned short stages_per_mode; -} __attribute__((packed)) audpp_cmd_cfg_object_params_qconcert; - -/* - * Command Structure to configure post processing parameters (Side Chain) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN \ - sizeof(audpp_cmd_cfg_object_params_sidechain) - - -#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS 0x0000 -#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA -1 - -typedef struct { - audpp_cmd_cfg_object_params_common common; - signed short active_flag; - unsigned short num_bands; - union { - filter_1 filter_1_params; - filter_2 filter_2_params; - filter_3 filter_3_params; - filter_4 filter_4_params; - } __attribute__((packed)) params_filter; -} __attribute__((packed)) audpp_cmd_cfg_object_params_sidechain; - - -/* - * Command Structure to configure post processing parameters (QAFX) - */ - -#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN \ - sizeof(audpp_cmd_cfg_object_params_qafx) - -#define AUDPP_CMD_QAFX_ENA_DISA 0x0000 -#define AUDPP_CMD_QAFX_ENA_ENA_CFG -1 -#define AUDPP_CMD_QAFX_ENA_DIS_CFG 0x0001 - -#define AUDPP_CMD_QAFX_CMD_TYPE_ENV 0x0100 -#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ 0x0010 -#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY 0x1000 - -#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE 0x0100 -#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS 0x0101 -#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI 0x0102 -#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL 0X0103 -#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES 0x0107 - -#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ 0x0010 -#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL 0x0011 -#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST 0x0012 -#define AUDPP_CMD_QAFX_CMDS_OBJ_POS 0x0013 -#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL 0x0014 - - -typedef struct { - audpp_cmd_cfg_object_params_common common; - signed short enable; - unsigned short command_type; - unsigned short num_commands; - unsigned short commands; -} __attribute__((packed)) audpp_cmd_cfg_object_params_qafx; - -/* - * Command Structure to enable , disable or configure the reverberation effect - * (Common) - */ - -#define AUDPP_CMD_REVERB_CONFIG 0x0001 -#define AUDPP_CMD_REVERB_CONFIG_COMMON_LEN \ - sizeof(audpp_cmd_reverb_config_common) - -#define AUDPP_CMD_ENA_ENA 0xFFFF -#define AUDPP_CMD_ENA_DIS 0x0000 -#define AUDPP_CMD_ENA_CFG 0x0001 - -#define AUDPP_CMD_CMD_TYPE_ENV 0x0104 -#define AUDPP_CMD_CMD_TYPE_OBJ 0x0015 -#define AUDPP_CMD_CMD_TYPE_QUERY 0x1000 - - -typedef struct { - unsigned short cmd_id; - unsigned short enable; - unsigned short cmd_type; -} __attribute__((packed)) audpp_cmd_reverb_config_common; - -/* - * Command Structure to enable , disable or configure the reverberation effect - * (ENV-0x0104) - */ - -#define AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN \ - sizeof(audpp_cmd_reverb_config_env_104) - -typedef struct { - audpp_cmd_reverb_config_common common; - unsigned short env_gain; - unsigned short decay_msw; - unsigned short decay_lsw; - unsigned short decay_timeratio_msw; - unsigned short decay_timeratio_lsw; - unsigned short delay_time; - unsigned short reverb_gain; - unsigned short reverb_delay; -} __attribute__((packed)) audpp_cmd_reverb_config_env_104; - -/* - * Command Structure to enable , disable or configure the reverberation effect - * (ENV-0x0015) - */ - -#define AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN \ - sizeof(audpp_cmd_reverb_config_env_15) - -typedef struct { - audpp_cmd_reverb_config_common common; - unsigned short object_num; - unsigned short absolute_gain; -} __attribute__((packed)) audpp_cmd_reverb_config_env_15; - - -#endif /* QDSP5AUDPPCMDI_H */ - diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h deleted file mode 100644 index 44fea224001a..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h +++ /dev/null @@ -1,318 +0,0 @@ -#ifndef QDSP5AUDPPMSG_H -#define QDSP5AUDPPMSG_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - Q D S P 5 A U D I O P O S T P R O C E S S I N G M S G - -GENERAL DESCRIPTION - Messages sent by AUDPPTASK to ARM - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - - $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppmsg.h#4 $ - -===========================================================================*/ - -/* - * AUDPPTASK uses audPPuPRlist to send messages to the ARM - * Location : MEMA - * Buffer Size : 45 - * No of Buffers in a queue : 5 for gaming audio and 1 for other images - */ - -/* - * MSG to Informs the ARM os Success/Failure of bringing up the decoder - */ - -#define AUDPP_MSG_STATUS_MSG 0x0001 -#define AUDPP_MSG_STATUS_MSG_LEN \ - sizeof(audpp_msg_status_msg) - -#define AUDPP_MSG_STATUS_SLEEP 0x0000 -#define AUDPP_MSG__STATUS_INIT 0x0001 -#define AUDPP_MSG_MSG_STATUS_CFG 0x0002 -#define AUDPP_MSG_STATUS_PLAY 0x0003 - -#define AUDPP_MSG_REASON_MIPS 0x0000 -#define AUDPP_MSG_REASON_MEM 0x0001 - -typedef struct{ - unsigned short dec_id; - unsigned short status; - unsigned short reason; -} __attribute__((packed)) audpp_msg_status_msg; - -/* - * MSG to communicate the spectrum analyzer output bands to the ARM - */ -#define AUDPP_MSG_SPA_BANDS 0x0002 -#define AUDPP_MSG_SPA_BANDS_LEN \ - sizeof(audpp_msg_spa_bands) - -typedef struct { - unsigned short current_object; - unsigned short spa_band_1; - unsigned short spa_band_2; - unsigned short spa_band_3; - unsigned short spa_band_4; - unsigned short spa_band_5; - unsigned short spa_band_6; - unsigned short spa_band_7; - unsigned short spa_band_8; - unsigned short spa_band_9; - unsigned short spa_band_10; - unsigned short spa_band_11; - unsigned short spa_band_12; - unsigned short spa_band_13; - unsigned short spa_band_14; - unsigned short spa_band_15; - unsigned short spa_band_16; - unsigned short spa_band_17; - unsigned short spa_band_18; - unsigned short spa_band_19; - unsigned short spa_band_20; - unsigned short spa_band_21; - unsigned short spa_band_22; - unsigned short spa_band_23; - unsigned short spa_band_24; - unsigned short spa_band_25; - unsigned short spa_band_26; - unsigned short spa_band_27; - unsigned short spa_band_28; - unsigned short spa_band_29; - unsigned short spa_band_30; - unsigned short spa_band_31; - unsigned short spa_band_32; -} __attribute__((packed)) audpp_msg_spa_bands; - -/* - * MSG to communicate the PCM I/O buffer status to ARM - */ -#define AUDPP_MSG_HOST_PCM_INTF_MSG 0x0003 -#define AUDPP_MSG_HOST_PCM_INTF_MSG_LEN \ - sizeof(audpp_msg_host_pcm_intf_msg) - -#define AUDPP_MSG_HOSTPCM_ID_TX_ARM 0x0000 -#define AUDPP_MSG_HOSTPCM_ID_ARM_TX 0x0001 -#define AUDPP_MSG_HOSTPCM_ID_RX_ARM 0x0002 -#define AUDPP_MSG_HOSTPCM_ID_ARM_RX 0x0003 - -#define AUDPP_MSG_SAMP_FREQ_INDX_96000 0x0000 -#define AUDPP_MSG_SAMP_FREQ_INDX_88200 0x0001 -#define AUDPP_MSG_SAMP_FREQ_INDX_64000 0x0002 -#define AUDPP_MSG_SAMP_FREQ_INDX_48000 0x0003 -#define AUDPP_MSG_SAMP_FREQ_INDX_44100 0x0004 -#define AUDPP_MSG_SAMP_FREQ_INDX_32000 0x0005 -#define AUDPP_MSG_SAMP_FREQ_INDX_24000 0x0006 -#define AUDPP_MSG_SAMP_FREQ_INDX_22050 0x0007 -#define AUDPP_MSG_SAMP_FREQ_INDX_16000 0x0008 -#define AUDPP_MSG_SAMP_FREQ_INDX_12000 0x0009 -#define AUDPP_MSG_SAMP_FREQ_INDX_11025 0x000A -#define AUDPP_MSG_SAMP_FREQ_INDX_8000 0x000B - -#define AUDPP_MSG_CHANNEL_MODE_MONO 0x0001 -#define AUDPP_MSG_CHANNEL_MODE_STEREO 0x0002 - -typedef struct{ - unsigned short obj_num; - unsigned short numbers_of_samples; - unsigned short host_pcm_id; - unsigned short buf_indx; - unsigned short samp_freq_indx; - unsigned short channel_mode; -} __attribute__((packed)) audpp_msg_host_pcm_intf_msg; - - -/* - * MSG to communicate 3D position of the source and listener , source volume - * source rolloff, source orientation - */ - -#define AUDPP_MSG_QAFX_POS 0x0004 -#define AUDPP_MSG_QAFX_POS_LEN \ - sizeof(audpp_msg_qafx_pos) - -typedef struct { - unsigned short current_object; - unsigned short x_pos_lis_msw; - unsigned short x_pos_lis_lsw; - unsigned short y_pos_lis_msw; - unsigned short y_pos_lis_lsw; - unsigned short z_pos_lis_msw; - unsigned short z_pos_lis_lsw; - unsigned short x_fwd_msw; - unsigned short x_fwd_lsw; - unsigned short y_fwd_msw; - unsigned short y_fwd_lsw; - unsigned short z_fwd_msw; - unsigned short z_fwd_lsw; - unsigned short x_up_msw; - unsigned short x_up_lsw; - unsigned short y_up_msw; - unsigned short y_up_lsw; - unsigned short z_up_msw; - unsigned short z_up_lsw; - unsigned short x_vel_lis_msw; - unsigned short x_vel_lis_lsw; - unsigned short y_vel_lis_msw; - unsigned short y_vel_lis_lsw; - unsigned short z_vel_lis_msw; - unsigned short z_vel_lis_lsw; - unsigned short threed_enable_flag; - unsigned short volume; - unsigned short x_pos_source_msw; - unsigned short x_pos_source_lsw; - unsigned short y_pos_source_msw; - unsigned short y_pos_source_lsw; - unsigned short z_pos_source_msw; - unsigned short z_pos_source_lsw; - unsigned short max_dist_0_msw; - unsigned short max_dist_0_lsw; - unsigned short min_dist_0_msw; - unsigned short min_dist_0_lsw; - unsigned short roll_off_factor; - unsigned short mute_after_max_flag; - unsigned short x_vel_source_msw; - unsigned short x_vel_source_lsw; - unsigned short y_vel_source_msw; - unsigned short y_vel_source_lsw; - unsigned short z_vel_source_msw; - unsigned short z_vel_source_lsw; -} __attribute__((packed)) audpp_msg_qafx_pos; - -/* - * MSG to provide AVSYNC feedback from DSP to ARM - */ - -#define AUDPP_MSG_AVSYNC_MSG 0x0005 -#define AUDPP_MSG_AVSYNC_MSG_LEN \ - sizeof(audpp_msg_avsync_msg) - -typedef struct { - unsigned short active_flag; - unsigned short num_samples_counter0_HSW; - unsigned short num_samples_counter0_MSW; - unsigned short num_samples_counter0_LSW; - unsigned short num_bytes_counter0_HSW; - unsigned short num_bytes_counter0_MSW; - unsigned short num_bytes_counter0_LSW; - unsigned short samp_freq_obj_0; - unsigned short samp_freq_obj_1; - unsigned short samp_freq_obj_2; - unsigned short samp_freq_obj_3; - unsigned short samp_freq_obj_4; - unsigned short samp_freq_obj_5; - unsigned short samp_freq_obj_6; - unsigned short samp_freq_obj_7; - unsigned short samp_freq_obj_8; - unsigned short samp_freq_obj_9; - unsigned short samp_freq_obj_10; - unsigned short samp_freq_obj_11; - unsigned short samp_freq_obj_12; - unsigned short samp_freq_obj_13; - unsigned short samp_freq_obj_14; - unsigned short samp_freq_obj_15; - unsigned short num_samples_counter4_HSW; - unsigned short num_samples_counter4_MSW; - unsigned short num_samples_counter4_LSW; - unsigned short num_bytes_counter4_HSW; - unsigned short num_bytes_counter4_MSW; - unsigned short num_bytes_counter4_LSW; -} __attribute__((packed)) audpp_msg_avsync_msg; - -/* - * MSG to provide PCM DMA Missed feedback from the DSP to ARM - */ - -#define AUDPP_MSG_PCMDMAMISSED 0x0006 -#define AUDPP_MSG_PCMDMAMISSED_LEN \ - sizeof(audpp_msg_pcmdmamissed); - -typedef struct{ - /* - ** Bit 0 0 = PCM DMA not missed for object 0 - ** 1 = PCM DMA missed for object0 - ** Bit 1 0 = PCM DMA not missed for object 1 - ** 1 = PCM DMA missed for object1 - ** Bit 2 0 = PCM DMA not missed for object 2 - ** 1 = PCM DMA missed for object2 - ** Bit 3 0 = PCM DMA not missed for object 3 - ** 1 = PCM DMA missed for object3 - ** Bit 4 0 = PCM DMA not missed for object 4 - ** 1 = PCM DMA missed for object4 - */ - unsigned short pcmdmamissed; -} __attribute__((packed)) audpp_msg_pcmdmamissed; - -/* - * MSG to AUDPP enable or disable feedback form DSP to ARM - */ - -#define AUDPP_MSG_CFG_MSG 0x0007 -#define AUDPP_MSG_CFG_MSG_LEN \ - sizeof(audpp_msg_cfg_msg) - -#define AUDPP_MSG_ENA_ENA 0xFFFF -#define AUDPP_MSG_ENA_DIS 0x0000 - -typedef struct{ - /* Enabled - 0xffff - ** Disabled - 0 - */ - unsigned short enabled; -} __attribute__((packed)) audpp_msg_cfg_msg; - -/* - * MSG to communicate the reverb per object volume - */ - -#define AUDPP_MSG_QREVERB_VOLUME 0x0008 -#define AUDPP_MSG_QREVERB_VOLUME_LEN \ - sizeof(audpp_msg_qreverb_volume) - - -typedef struct { - unsigned short obj_0_gain; - unsigned short obj_1_gain; - unsigned short obj_2_gain; - unsigned short obj_3_gain; - unsigned short obj_4_gain; - unsigned short hpcm_obj_volume; -} __attribute__((packed)) audpp_msg_qreverb_volume; - -#define AUDPP_MSG_ROUTING_ACK 0x0009 -#define AUDPP_MSG_ROUTING_ACK_LEN \ - sizeof(struct audpp_msg_routing_ack) - -struct audpp_msg_routing_ack { - unsigned short dec_id; - unsigned short routing_mode; -} __attribute__((packed)); - -#define AUDPP_MSG_FLUSH_ACK 0x000A - -#endif /* QDSP5AUDPPMSG_H */ diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h deleted file mode 100644 index 06d33d571583..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h +++ /dev/null @@ -1,256 +0,0 @@ -#ifndef QDSP5AUDPREPROCCMDI_H -#define QDSP5AUDPREPROCCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - A U D I O P R E P R O C E S S I N G I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by AUDPREPROC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreproccmdi.h#2 $ - -===========================================================================*/ - -/* - * AUDIOPREPROC COMMANDS: - * ARM uses uPAudPreProcCmdQueue to communicate with AUDPREPROCTASK - * Location : MEMB - * Buffer size : 51 - * Number of buffers in a queue : 3 - */ - -/* - * Command to configure the parameters of AGC - */ - -#define AUDPREPROC_CMD_CFG_AGC_PARAMS 0x0000 -#define AUDPREPROC_CMD_CFG_AGC_PARAMS_LEN \ - sizeof(audpreproc_cmd_cfg_agc_params) - -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE 0x0009 -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH 0x000A -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE 0x000B -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH 0x000C -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG 0x000D -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN 0x000E -#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG 0x000F - -#define AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA -1 -#define AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS 0x0000 - -#define AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_ADP_GAIN -1 -#define AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_STATIC_GAIN 0x0000 - -#define AUDPREPROC_CMD_PARAM_MASK_RMS_TAY 0x0004 -#define AUDPREPROC_CMD_PARAM_MASK_RELEASEK 0x0005 -#define AUDPREPROC_CMD_PARAM_MASK_DELAY 0x0006 -#define AUDPREPROC_CMD_PARAM_MASK_ATTACKK 0x0007 -#define AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW 0x0008 -#define AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST 0x0009 -#define AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK 0x000A -#define AUDPREPROC_CMD_PARAM_MASK_AIG_MIN 0x000B -#define AUDPREPROC_CMD_PARAM_MASK_AIG_MAX 0x000C -#define AUDPREPROC_CMD_PARAM_MASK_LEAK_UP 0x000D -#define AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN 0x000E -#define AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK 0x000F - -typedef struct { - unsigned short cmd_id; - unsigned short tx_agc_param_mask; - unsigned short tx_agc_enable_flag; - unsigned short static_gain; - signed short adaptive_gain_flag; - unsigned short expander_th; - unsigned short expander_slope; - unsigned short compressor_th; - unsigned short compressor_slope; - unsigned short param_mask; - unsigned short aig_attackk; - unsigned short aig_leak_down; - unsigned short aig_leak_up; - unsigned short aig_max; - unsigned short aig_min; - unsigned short aig_releasek; - unsigned short aig_leakrate_fast; - unsigned short aig_leakrate_slow; - unsigned short attackk_msw; - unsigned short attackk_lsw; - unsigned short delay; - unsigned short releasek_msw; - unsigned short releasek_lsw; - unsigned short rms_tav; -} __attribute__((packed)) audpreproc_cmd_cfg_agc_params; - - -/* - * Command to configure the params of Advanved AGC - */ - -#define AUDPREPROC_CMD_CFG_AGC_PARAMS_2 0x0001 -#define AUDPREPROC_CMD_CFG_AGC_PARAMS_2_LEN \ - sizeof(audpreproc_cmd_cfg_agc_params_2) - -#define AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_ENA -1; -#define AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_DIS 0x0000; - -typedef struct { - unsigned short cmd_id; - unsigned short agc_param_mask; - signed short tx_agc_enable_flag; - unsigned short comp_static_gain; - unsigned short exp_th; - unsigned short exp_slope; - unsigned short comp_th; - unsigned short comp_slope; - unsigned short comp_rms_tav; - unsigned short comp_samp_mask; - unsigned short comp_attackk_msw; - unsigned short comp_attackk_lsw; - unsigned short comp_releasek_msw; - unsigned short comp_releasek_lsw; - unsigned short comp_delay; - unsigned short comp_makeup_gain; -} __attribute__((packed)) audpreproc_cmd_cfg_agc_params_2; - -/* - * Command to configure params for ns - */ - -#define AUDPREPROC_CMD_CFG_NS_PARAMS 0x0002 -#define AUDPREPROC_CMD_CFG_NS_PARAMS_LEN \ - sizeof(audpreproc_cmd_cfg_ns_params) - -#define AUDPREPROC_CMD_EC_MODE_NEW_NLMS_ENA 0x0001 -#define AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_DES_ENA 0x0002 -#define AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA 0x0004 -#define AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_CNI_ENA 0x0008 -#define AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS 0x0000 - -#define AUDPREPROC_CMD_EC_MODE_NEW_NLES_ENA 0x0010 -#define AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA 0x0020 -#define AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA 0x0040 -#define AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_PCD_ENA 0x0080 -#define AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_FEHI_ENA 0x0100 -#define AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_NEHI_ENA 0x0200 -#define AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_NLPP_ENA 0x0400 -#define AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_FNE_ENA 0x0800 -#define AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS 0x0000 -#define AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_ENA 0x1000 -#define AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS 0x0000 - -typedef struct { - unsigned short cmd_id; - unsigned short ec_mode_new; - unsigned short dens_gamma_n; - unsigned short dens_nfe_block_size; - unsigned short dens_limit_ns; - unsigned short dens_limit_ns_d; - unsigned short wb_gamma_e; - unsigned short wb_gamma_n; -} __attribute__((packed)) audpreproc_cmd_cfg_ns_params; - -/* - * Command to configure parameters for IIR tuning filter - */ - -#define AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS 0x0003 -#define AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS_LEN \ - sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params) - -#define AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS 0x0000 -#define AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA 0x0001 - -typedef struct { - unsigned short cmd_id; - unsigned short active_flag; - unsigned short num_bands; - unsigned short numerator_coeff_b0_filter0_lsw; - unsigned short numerator_coeff_b0_filter0_msw; - unsigned short numerator_coeff_b1_filter0_lsw; - unsigned short numerator_coeff_b1_filter0_msw; - unsigned short numerator_coeff_b2_filter0_lsw; - unsigned short numerator_coeff_b2_filter0_msw; - unsigned short numerator_coeff_b0_filter1_lsw; - unsigned short numerator_coeff_b0_filter1_msw; - unsigned short numerator_coeff_b1_filter1_lsw; - unsigned short numerator_coeff_b1_filter1_msw; - unsigned short numerator_coeff_b2_filter1_lsw; - unsigned short numerator_coeff_b2_filter1_msw; - unsigned short numerator_coeff_b0_filter2_lsw; - unsigned short numerator_coeff_b0_filter2_msw; - unsigned short numerator_coeff_b1_filter2_lsw; - unsigned short numerator_coeff_b1_filter2_msw; - unsigned short numerator_coeff_b2_filter2_lsw; - unsigned short numerator_coeff_b2_filter2_msw; - unsigned short numerator_coeff_b0_filter3_lsw; - unsigned short numerator_coeff_b0_filter3_msw; - unsigned short numerator_coeff_b1_filter3_lsw; - unsigned short numerator_coeff_b1_filter3_msw; - unsigned short numerator_coeff_b2_filter3_lsw; - unsigned short numerator_coeff_b2_filter3_msw; - unsigned short denominator_coeff_a0_filter0_lsw; - unsigned short denominator_coeff_a0_filter0_msw; - unsigned short denominator_coeff_a1_filter0_lsw; - unsigned short denominator_coeff_a1_filter0_msw; - unsigned short denominator_coeff_a0_filter1_lsw; - unsigned short denominator_coeff_a0_filter1_msw; - unsigned short denominator_coeff_a1_filter1_lsw; - unsigned short denominator_coeff_a1_filter1_msw; - unsigned short denominator_coeff_a0_filter2_lsw; - unsigned short denominator_coeff_a0_filter2_msw; - unsigned short denominator_coeff_a1_filter2_lsw; - unsigned short denominator_coeff_a1_filter2_msw; - unsigned short denominator_coeff_a0_filter3_lsw; - unsigned short denominator_coeff_a0_filter3_msw; - unsigned short denominator_coeff_a1_filter3_lsw; - unsigned short denominator_coeff_a1_filter3_msw; - - unsigned short shift_factor_filter0; - unsigned short shift_factor_filter1; - unsigned short shift_factor_filter2; - unsigned short shift_factor_filter3; - - unsigned short channel_selected0; - unsigned short channel_selected1; - unsigned short channel_selected2; - unsigned short channel_selected3; -} __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params; - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h deleted file mode 100644 index f40e41e76737..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef QDSP5AUDPREPROCMSG_H -#define QDSP5AUDPREPROCMSG_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - A U D I O P R E P R O C E S S I N G M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of messages - that are rcvd by AUDPREPROC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - - $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreprocmsg.h#3 $ - -===========================================================================*/ - -/* - * ADSPREPROCTASK Messages - * AUDPREPROCTASK uses audPreProcUpRlist to communicate with ARM - * Location : MEMA - * Message Length : 2 - */ - -/* - * Message to indicate particular feature has been enabled or disabled - */ - - -#define AUDPREPROC_MSG_CMD_CFG_DONE_MSG 0x0000 -#define AUDPREPROC_MSG_CMD_CFG_DONE_MSG_LEN \ - sizeof(audpreproc_msg_cmd_cfg_done_msg) - -#define AUDPREPROC_MSG_TYPE_AGC 0x0000 -#define AUDPREPROC_MSG_TYPE_NOISE_REDUCTION 0x0001 -#define AUDPREPROC_MSG_TYPE_IIR_FILTER 0x0002 - - -#define AUDPREPROC_MSG_STATUS_FLAG_ENA -1 -#define AUDPREPROC_MSG_STATUS_FLAG_DIS 0x0000 - -typedef struct { - unsigned short type; - signed short status_flag; -} __attribute__((packed)) audpreproc_msg_cmd_cfg_done_msg; - - -/* - * Message to indicate particular feature has selected for wrong samp freq - */ - -#define AUDPREPROC_MSG_ERROR_MSG_ID 0x0001 -#define AUDPREPROC_MSG_ERROR_MSG_ID_LEN \ - sizeof(audpreproc_msg_error_msg_id) - -#define AUDPREPROC_MSG_ERR_INDEX_NS 0x0000 - -typedef struct { - unsigned short err_index; -} __attribute__((packed)) audpreproc_msg_error_msg_id; - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h deleted file mode 100644 index d03ee024ae91..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef QDSP5AUDRECCMDI_H -#define QDSP5AUDRECCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - A U D I O R E C O R D I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by AUDREC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ - -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - - $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audreccmdi.h#3 $ - -============================================================================*/ - -/* - * AUDRECTASK COMMANDS - * ARM uses 2 queues to communicate with the AUDRECTASK - * 1.uPAudRecCmdQueue - * Location :MEMC - * Buffer Size : 8 - * No of Buffers in a queue : 3 - * 2.audRecUpBitStreamQueue - * Location : MEMC - * Buffer Size : 4 - * No of buffers in a queue : 2 - */ - -/* - * Commands on uPAudRecCmdQueue - */ - -/* - * Command to initiate and terminate the audio recording section - */ - -#define AUDREC_CMD_CFG 0x0000 -#define AUDREC_CMD_CFG_LEN sizeof(audrec_cmd_cfg) - -#define AUDREC_CMD_TYPE_0_INDEX_WAV 0x0000 -#define AUDREC_CMD_TYPE_0_INDEX_AAC 0x0001 - -#define AUDREC_CMD_TYPE_0_ENA 0x4000 -#define AUDREC_CMD_TYPE_0_DIS 0x0000 - -#define AUDREC_CMD_TYPE_0_NOUPDATE 0x0000 -#define AUDREC_CMD_TYPE_0_UPDATE 0x8000 - -#define AUDREC_CMD_TYPE_1_INDEX_SBC 0x0002 - -#define AUDREC_CMD_TYPE_1_ENA 0x4000 -#define AUDREC_CMD_TYPE_1_DIS 0x0000 - -#define AUDREC_CMD_TYPE_1_NOUPDATE 0x0000 -#define AUDREC_CMD_TYPE_1_UPDATE 0x8000 - -typedef struct { - unsigned short cmd_id; - unsigned short type_0; - unsigned short type_1; -} __attribute__((packed)) audrec_cmd_cfg; - - -/* - * Command to configure the recording parameters for RecType0(AAC/WAV) encoder - */ - -#define AUDREC_CMD_AREC0PARAM_CFG 0x0001 -#define AUDREC_CMD_AREC0PARAM_CFG_LEN \ - sizeof(audrec_cmd_arec0param_cfg) - -#define AUDREC_CMD_SAMP_RATE_INDX_8000 0x000B -#define AUDREC_CMD_SAMP_RATE_INDX_11025 0x000A -#define AUDREC_CMD_SAMP_RATE_INDX_12000 0x0009 -#define AUDREC_CMD_SAMP_RATE_INDX_16000 0x0008 -#define AUDREC_CMD_SAMP_RATE_INDX_22050 0x0007 -#define AUDREC_CMD_SAMP_RATE_INDX_24000 0x0006 -#define AUDREC_CMD_SAMP_RATE_INDX_32000 0x0005 -#define AUDREC_CMD_SAMP_RATE_INDX_44100 0x0004 -#define AUDREC_CMD_SAMP_RATE_INDX_48000 0x0003 - -#define AUDREC_CMD_STEREO_MODE_MONO 0x0000 -#define AUDREC_CMD_STEREO_MODE_STEREO 0x0001 - -typedef struct { - unsigned short cmd_id; - unsigned short ptr_to_extpkt_buffer_msw; - unsigned short ptr_to_extpkt_buffer_lsw; - unsigned short buf_len; - unsigned short samp_rate_index; - unsigned short stereo_mode; - unsigned short rec_quality; -} __attribute__((packed)) audrec_cmd_arec0param_cfg; - -/* - * Command to configure the recording parameters for RecType1(SBC) encoder - */ - -#define AUDREC_CMD_AREC1PARAM_CFG 0x0002 -#define AUDREC_CMD_AREC1PARAM_CFG_LEN \ - sizeof(audrec_cmd_arec1param_cfg) - -#define AUDREC_CMD_PARAM_BUF_BLOCKS_4 0x0000 -#define AUDREC_CMD_PARAM_BUF_BLOCKS_8 0x0001 -#define AUDREC_CMD_PARAM_BUF_BLOCKS_12 0x0002 -#define AUDREC_CMD_PARAM_BUF_BLOCKS_16 0x0003 - -#define AUDREC_CMD_PARAM_BUF_SUB_BANDS_8 0x0010 -#define AUDREC_CMD_PARAM_BUF_MODE_MONO 0x0000 -#define AUDREC_CMD_PARAM_BUF_MODE_DUAL 0x0040 -#define AUDREC_CMD_PARAM_BUF_MODE_STEREO 0x0050 -#define AUDREC_CMD_PARAM_BUF_MODE_JSTEREO 0x0060 -#define AUDREC_CMD_PARAM_BUF_LOUDNESS 0x0000 -#define AUDREC_CMD_PARAM_BUF_SNR 0x0100 -#define AUDREC_CMD_PARAM_BUF_BASIC_VER 0x0000 - -typedef struct { - unsigned short cmd_id; - unsigned short ptr_to_extpkt_buffer_msw; - unsigned short ptr_to_extpkt_buffer_lsw; - unsigned short buf_len; - unsigned short param_buf; - unsigned short bit_rate_0; - unsigned short bit_rate_1; -} __attribute__((packed)) audrec_cmd_arec1param_cfg; - - -/* - * Commands on audRecUpBitStreamQueue - */ - -/* - * Command to indicate the current packet read count - */ - -#define AUDREC_CMD_PACKET_EXT_PTR 0x0000 -#define AUDREC_CMD_PACKET_EXT_PTR_LEN \ - sizeof(audrec_cmd_packet_ext_ptr) - -#define AUDREC_CMD_TYPE_0 0x0000 -#define AUDREC_CMD_TYPE_1 0x0001 - -typedef struct { - unsigned short cmd_id; - unsigned short type; - unsigned short curr_rec_count_msw; - unsigned short curr_rec_count_lsw; -} __attribute__((packed)) audrec_cmd_packet_ext_ptr; - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h deleted file mode 100644 index bb6eb5093cf5..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef QDSP5AUDRECMSGI_H -#define QDSP5AUDRECMSGI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - A U D I O R E C O R D M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of messages - that are sent by AUDREC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ - -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - - $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audrecmsg.h#3 $ - -============================================================================*/ - -/* - * AUDRECTASK MESSAGES - * AUDRECTASK uses audRecUpRlist to communicate with ARM - * Location : MEMC - * Buffer size : 4 - * No of buffers in a queue : 2 - */ - -/* - * Message to notify that config command is done - */ - -#define AUDREC_MSG_CMD_CFG_DONE_MSG 0x0002 -#define AUDREC_MSG_CMD_CFG_DONE_MSG_LEN \ - sizeof(audrec_msg_cmd_cfg_done_msg) - - -#define AUDREC_MSG_CFG_DONE_TYPE_0_ENA 0x4000 -#define AUDREC_MSG_CFG_DONE_TYPE_0_DIS 0x0000 - -#define AUDREC_MSG_CFG_DONE_TYPE_0_NO_UPDATE 0x0000 -#define AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE 0x8000 - -#define AUDREC_MSG_CFG_DONE_TYPE_1_ENA 0x4000 -#define AUDREC_MSG_CFG_DONE_TYPE_1_DIS 0x0000 - -#define AUDREC_MSG_CFG_DONE_TYPE_1_NO_UPDATE 0x0000 -#define AUDREC_MSG_CFG_DONE_TYPE_1_UPDATE 0x8000 - -typedef struct { - unsigned short type_0; - unsigned short type_1; -} __attribute__((packed))audrec_msg_cmd_cfg_done_msg; - - -/* - * Message to notify arec0/1 cfg done and recording params revd by task - */ - -#define AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG 0x0003 -#define AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG_LEN \ - sizeof(audrec_msg_cmd_arec_param_cfg_done_msg) - -#define AUDREC_MSG_AREC_PARAM_TYPE_0 0x0000 -#define AUDREC_MSG_AREC_PARAM_TYPE_1 0x0001 - -typedef struct { - unsigned short type; -} __attribute__((packed))audrec_msg_cmd_arec_param_cfg_done_msg; - - -/* - * Message to notify no more buffers are available in ext mem to DME - */ - -#define AUDREC_MSG_FATAL_ERR_MSG 0x0004 -#define AUDREC_MSG_FATAL_ERR_MSG_LEN \ - sizeof(audrec_msg_fatal_err_msg) - -#define AUDREC_MSG_FATAL_ERR_TYPE_0 0x0000 -#define AUDREC_MSG_FATAL_ERR_TYPE_1 0x0001 - -typedef struct { - unsigned short type; -} __attribute__((packed))audrec_msg_fatal_err_msg; - -/* - * Message to notify DME deliverd the encoded pkt to ext pkt buffer - */ - -#define AUDREC_MSG_PACKET_READY_MSG 0x0005 -#define AUDREC_MSG_PACKET_READY_MSG_LEN \ - sizeof(audrec_msg_packet_ready_msg) - -#define AUDREC_MSG_PACKET_READY_TYPE_0 0x0000 -#define AUDREC_MSG_PACKET_READY_TYPE_1 0x0001 - -typedef struct { - unsigned short type; - unsigned short pkt_counter_msw; - unsigned short pkt_counter_lsw; - unsigned short pkt_read_cnt_msw; - unsigned short pkt_read_cnt_lsw; -} __attribute__((packed))audrec_msg_packet_ready_msg; - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h deleted file mode 100644 index 574ad6bbcade..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h +++ /dev/null @@ -1,376 +0,0 @@ -#ifndef QDSP5VIDJPEGCMDI_H -#define QDSP5VIDJPEGCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - J P E G I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by JPEG Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: -when who what, where, why --------- --- ---------------------------------------------------------- -06/09/08 sv initial version -===========================================================================*/ - -/* - * ARM to JPEG configuration commands are passed through the - * uPJpegCfgCmdQueue - */ - -/* - * Command to configure JPEG Encoder - */ - -#define JPEG_CMD_ENC_CFG 0x0000 -#define JPEG_CMD_ENC_CFG_LEN sizeof(jpeg_cmd_enc_cfg) - -#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_0 0x0000 -#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_90 0x0100 -#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_180 0x0200 -#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_270 0x0300 -#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M 0x0003 -#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2 0x0000 -#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V1 0x0001 -#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H1V2 0x0002 - -#define JPEG_CMD_IP_SIZE_CFG_LUMA_HEIGHT_M 0x0000FFFF -#define JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M 0xFFFF0000 -#define JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_ENA 0x0001 -#define JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_DIS 0x0000 - -#define JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M 0xFFFF - -typedef struct { - unsigned int cmd_id; - unsigned int process_cfg; - unsigned int ip_size_cfg; - unsigned int op_size_cfg; - unsigned int frag_cfg; - unsigned int frag_cfg_part[16]; - - unsigned int part_num; - - unsigned int op_buf_0_cfg_part1; - unsigned int op_buf_0_cfg_part2; - unsigned int op_buf_1_cfg_part1; - unsigned int op_buf_1_cfg_part2; - - unsigned int luma_qunt_table[32]; - unsigned int chroma_qunt_table[32]; - - unsigned int upsamp_ip_size_cfg; - unsigned int upsamp_ip_frame_off; - unsigned int upsamp_pp_filter_coeff[64]; -} __attribute__((packed)) jpeg_cmd_enc_cfg; - -/* - * Command to configure JPEG Decoder - */ - -#define JPEG_CMD_DEC_CFG 0x0001 -#define JPEG_CMD_DEC_CFG_LEN sizeof(jpeg_cmd_dec_cfg) - -#define JPEG_CMD_DEC_OP_DATA_FORMAT_M 0x0001 -#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2 0x0000 -#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V1 0x0001 - -#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_8 0x000000 -#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_4 0x010000 -#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_2 0x020000 -#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_1 0x030000 - -#define JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_NOT_FINAL 0x0000 -#define JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_FINAL 0x0001 - - -typedef struct { - unsigned int cmd_id; - unsigned int img_dimension_cfg; - unsigned int op_data_format; - unsigned int restart_interval; - unsigned int ip_buf_partition_num; - unsigned int ip_stream_buf_cfg_part1; - unsigned int ip_stream_buf_cfg_part2; - unsigned int ip_stream_buf_cfg_part3; - unsigned int op_stream_buf_0_cfg_part1; - unsigned int op_stream_buf_0_cfg_part2; - unsigned int op_stream_buf_0_cfg_part3; - unsigned int op_stream_buf_1_cfg_part1; - unsigned int op_stream_buf_1_cfg_part2; - unsigned int op_stream_buf_1_cfg_part3; - unsigned int luma_qunt_table_0_3; - unsigned int luma_qunt_table_4_7; - unsigned int luma_qunt_table_8_11; - unsigned int luma_qunt_table_12_15; - unsigned int luma_qunt_table_16_19; - unsigned int luma_qunt_table_20_23; - unsigned int luma_qunt_table_24_27; - unsigned int luma_qunt_table_28_31; - unsigned int luma_qunt_table_32_35; - unsigned int luma_qunt_table_36_39; - unsigned int luma_qunt_table_40_43; - unsigned int luma_qunt_table_44_47; - unsigned int luma_qunt_table_48_51; - unsigned int luma_qunt_table_52_55; - unsigned int luma_qunt_table_56_59; - unsigned int luma_qunt_table_60_63; - unsigned int chroma_qunt_table_0_3; - unsigned int chroma_qunt_table_4_7; - unsigned int chroma_qunt_table_8_11; - unsigned int chroma_qunt_table_12_15; - unsigned int chroma_qunt_table_16_19; - unsigned int chroma_qunt_table_20_23; - unsigned int chroma_qunt_table_24_27; - unsigned int chroma_qunt_table_28_31; - unsigned int chroma_qunt_table_32_35; - unsigned int chroma_qunt_table_36_39; - unsigned int chroma_qunt_table_40_43; - unsigned int chroma_qunt_table_44_47; - unsigned int chroma_qunt_table_48_51; - unsigned int chroma_qunt_table_52_55; - unsigned int chroma_qunt_table_56_59; - unsigned int chroma_qunt_table_60_63; - unsigned int luma_dc_hm_code_cnt_table_0_3; - unsigned int luma_dc_hm_code_cnt_table_4_7; - unsigned int luma_dc_hm_code_cnt_table_8_11; - unsigned int luma_dc_hm_code_cnt_table_12_15; - unsigned int luma_dc_hm_code_val_table_0_3; - unsigned int luma_dc_hm_code_val_table_4_7; - unsigned int luma_dc_hm_code_val_table_8_11; - unsigned int chroma_dc_hm_code_cnt_table_0_3; - unsigned int chroma_dc_hm_code_cnt_table_4_7; - unsigned int chroma_dc_hm_code_cnt_table_8_11; - unsigned int chroma_dc_hm_code_cnt_table_12_15; - unsigned int chroma_dc_hm_code_val_table_0_3; - unsigned int chroma_dc_hm_code_val_table_4_7; - unsigned int chroma_dc_hm_code_val_table_8_11; - unsigned int luma_ac_hm_code_cnt_table_0_3; - unsigned int luma_ac_hm_code_cnt_table_4_7; - unsigned int luma_ac_hm_code_cnt_table_8_11; - unsigned int luma_ac_hm_code_cnt_table_12_15; - unsigned int luma_ac_hm_code_val_table_0_3; - unsigned int luma_ac_hm_code_val_table_4_7; - unsigned int luma_ac_hm_code_val_table_8_11; - unsigned int luma_ac_hm_code_val_table_12_15; - unsigned int luma_ac_hm_code_val_table_16_19; - unsigned int luma_ac_hm_code_val_table_20_23; - unsigned int luma_ac_hm_code_val_table_24_27; - unsigned int luma_ac_hm_code_val_table_28_31; - unsigned int luma_ac_hm_code_val_table_32_35; - unsigned int luma_ac_hm_code_val_table_36_39; - unsigned int luma_ac_hm_code_val_table_40_43; - unsigned int luma_ac_hm_code_val_table_44_47; - unsigned int luma_ac_hm_code_val_table_48_51; - unsigned int luma_ac_hm_code_val_table_52_55; - unsigned int luma_ac_hm_code_val_table_56_59; - unsigned int luma_ac_hm_code_val_table_60_63; - unsigned int luma_ac_hm_code_val_table_64_67; - unsigned int luma_ac_hm_code_val_table_68_71; - unsigned int luma_ac_hm_code_val_table_72_75; - unsigned int luma_ac_hm_code_val_table_76_79; - unsigned int luma_ac_hm_code_val_table_80_83; - unsigned int luma_ac_hm_code_val_table_84_87; - unsigned int luma_ac_hm_code_val_table_88_91; - unsigned int luma_ac_hm_code_val_table_92_95; - unsigned int luma_ac_hm_code_val_table_96_99; - unsigned int luma_ac_hm_code_val_table_100_103; - unsigned int luma_ac_hm_code_val_table_104_107; - unsigned int luma_ac_hm_code_val_table_108_111; - unsigned int luma_ac_hm_code_val_table_112_115; - unsigned int luma_ac_hm_code_val_table_116_119; - unsigned int luma_ac_hm_code_val_table_120_123; - unsigned int luma_ac_hm_code_val_table_124_127; - unsigned int luma_ac_hm_code_val_table_128_131; - unsigned int luma_ac_hm_code_val_table_132_135; - unsigned int luma_ac_hm_code_val_table_136_139; - unsigned int luma_ac_hm_code_val_table_140_143; - unsigned int luma_ac_hm_code_val_table_144_147; - unsigned int luma_ac_hm_code_val_table_148_151; - unsigned int luma_ac_hm_code_val_table_152_155; - unsigned int luma_ac_hm_code_val_table_156_159; - unsigned int luma_ac_hm_code_val_table_160_161; - unsigned int chroma_ac_hm_code_cnt_table_0_3; - unsigned int chroma_ac_hm_code_cnt_table_4_7; - unsigned int chroma_ac_hm_code_cnt_table_8_11; - unsigned int chroma_ac_hm_code_cnt_table_12_15; - unsigned int chroma_ac_hm_code_val_table_0_3; - unsigned int chroma_ac_hm_code_val_table_4_7; - unsigned int chroma_ac_hm_code_val_table_8_11; - unsigned int chroma_ac_hm_code_val_table_12_15; - unsigned int chroma_ac_hm_code_val_table_16_19; - unsigned int chroma_ac_hm_code_val_table_20_23; - unsigned int chroma_ac_hm_code_val_table_24_27; - unsigned int chroma_ac_hm_code_val_table_28_31; - unsigned int chroma_ac_hm_code_val_table_32_35; - unsigned int chroma_ac_hm_code_val_table_36_39; - unsigned int chroma_ac_hm_code_val_table_40_43; - unsigned int chroma_ac_hm_code_val_table_44_47; - unsigned int chroma_ac_hm_code_val_table_48_51; - unsigned int chroma_ac_hm_code_val_table_52_55; - unsigned int chroma_ac_hm_code_val_table_56_59; - unsigned int chroma_ac_hm_code_val_table_60_63; - unsigned int chroma_ac_hm_code_val_table_64_67; - unsigned int chroma_ac_hm_code_val_table_68_71; - unsigned int chroma_ac_hm_code_val_table_72_75; - unsigned int chroma_ac_hm_code_val_table_76_79; - unsigned int chroma_ac_hm_code_val_table_80_83; - unsigned int chroma_ac_hm_code_val_table_84_87; - unsigned int chroma_ac_hm_code_val_table_88_91; - unsigned int chroma_ac_hm_code_val_table_92_95; - unsigned int chroma_ac_hm_code_val_table_96_99; - unsigned int chroma_ac_hm_code_val_table_100_103; - unsigned int chroma_ac_hm_code_val_table_104_107; - unsigned int chroma_ac_hm_code_val_table_108_111; - unsigned int chroma_ac_hm_code_val_table_112_115; - unsigned int chroma_ac_hm_code_val_table_116_119; - unsigned int chroma_ac_hm_code_val_table_120_123; - unsigned int chroma_ac_hm_code_val_table_124_127; - unsigned int chroma_ac_hm_code_val_table_128_131; - unsigned int chroma_ac_hm_code_val_table_132_135; - unsigned int chroma_ac_hm_code_val_table_136_139; - unsigned int chroma_ac_hm_code_val_table_140_143; - unsigned int chroma_ac_hm_code_val_table_144_147; - unsigned int chroma_ac_hm_code_val_table_148_151; - unsigned int chroma_ac_hm_code_val_table_152_155; - unsigned int chroma_ac_hm_code_val_table_156_159; - unsigned int chroma_ac_hm_code_val_table_160_161; -} __attribute__((packed)) jpeg_cmd_dec_cfg; - - -/* - * ARM to JPEG configuration commands are passed through the - * uPJpegActionCmdQueue - */ - -/* - * Command to start the encode process - */ - -#define JPEG_CMD_ENC_ENCODE 0x0000 -#define JPEG_CMD_ENC_ENCODE_LEN sizeof(jpeg_cmd_enc_encode) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) jpeg_cmd_enc_encode; - - -/* - * Command to transition from current state of encoder to IDLE state - */ - -#define JPEG_CMD_ENC_IDLE 0x0001 -#define JPEG_CMD_ENC_IDLE_LEN sizeof(jpeg_cmd_enc_idle) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) jpeg_cmd_enc_idle; - - -/* - * Command to inform the encoder that another buffer is ready - */ - -#define JPEG_CMD_ENC_OP_CONSUMED 0x0002 -#define JPEG_CMD_ENC_OP_CONSUMED_LEN sizeof(jpeg_cmd_enc_op_consumed) - - -typedef struct { - unsigned int cmd_id; - unsigned int op_buf_addr; - unsigned int op_buf_size; -} __attribute__((packed)) jpeg_cmd_enc_op_consumed; - - -/* - * Command to start the decoding process - */ - -#define JPEG_CMD_DEC_DECODE 0x0003 -#define JPEG_CMD_DEC_DECODE_LEN sizeof(jpeg_cmd_dec_decode) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) jpeg_cmd_dec_decode; - - -/* - * Command to transition from the current state of decoder to IDLE - */ - -#define JPEG_CMD_DEC_IDLE 0x0004 -#define JPEG_CMD_DEC_IDLE_LEN sizeof(jpeg_cmd_dec_idle) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) jpeg_cmd_dec_idle; - - -/* - * Command to inform that an op buffer is ready for use - */ - -#define JPEG_CMD_DEC_OP_CONSUMED 0x0005 -#define JPEG_CMD_DEC_OP_CONSUMED_LEN sizeof(jpeg_cmd_dec_op_consumed) - - -typedef struct { - unsigned int cmd_id; - unsigned int luma_op_buf_addr; - unsigned int luma_op_buf_size; - unsigned int chroma_op_buf_addr; -} __attribute__((packed)) jpeg_cmd_dec_op_consumed; - - -/* - * Command to pass a new ip buffer to the jpeg decoder - */ - -#define JPEG_CMD_DEC_IP 0x0006 -#define JPEG_CMD_DEC_IP_LEN sizeof(jpeg_cmd_dec_ip_len) - -#define JPEG_CMD_EOI_INDICATOR_NOT_END 0x0000 -#define JPEG_CMD_EOI_INDICATOR_END 0x0001 - -typedef struct { - unsigned int cmd_id; - unsigned int ip_buf_addr; - unsigned int ip_buf_size; - unsigned int eoi_indicator; -} __attribute__((packed)) jpeg_cmd_dec_ip; - - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h deleted file mode 100644 index d11aa3fbccb6..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef QDSP5VIDJPEGMSGI_H -#define QDSP5VIDJPEGMSGI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - J P E G I N T E R N A L M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of messages - that are sent by JPEG Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -05/10/08 sv initial version -===========================================================================*/ - -/* - * Messages from JPEG task to ARM through jpeguPMsgQueue - */ - -/* - * Message is ACK for CMD_JPEGE_ENCODE cmd - */ - -#define JPEG_MSG_ENC_ENCODE_ACK 0x0000 -#define JPEG_MSG_ENC_ENCODE_ACK_LEN \ - sizeof(jpeg_msg_enc_encode_ack) - -typedef struct { -} __attribute__((packed)) jpeg_msg_enc_encode_ack; - - -/* - * Message informs the up when op buffer is ready for consumption and - * when encoding is complete or errors - */ - -#define JPEG_MSG_ENC_OP_PRODUCED 0x0001 -#define JPEG_MSG_ENC_OP_PRODUCED_LEN \ - sizeof(jpeg_msg_enc_op_produced) - -#define JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_PROGRESS 0x0000 -#define JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_COMPLETE 0x0001 -#define JPEG_MSGOP_OP_BUF_STATUS_ENC_ERR 0x10000 - -typedef struct { - unsigned int op_buf_addr; - unsigned int op_buf_size; - unsigned int op_buf_status; -} __attribute__((packed)) jpeg_msg_enc_op_produced; - - -/* - * Message to ack CMD_JPEGE_IDLE - */ - -#define JPEG_MSG_ENC_IDLE_ACK 0x0002 -#define JPEG_MSG_ENC_IDLE_ACK_LEN sizeof(jpeg_msg_enc_idle_ack) - - -typedef struct { -} __attribute__ ((packed)) jpeg_msg_enc_idle_ack; - - -/* - * Message to indicate the illegal command - */ - -#define JPEG_MSG_ENC_ILLEGAL_COMMAND 0x0003 -#define JPEG_MSG_ENC_ILLEGAL_COMMAND_LEN \ - sizeof(jpeg_msg_enc_illegal_command) - -typedef struct { - unsigned int status; -} __attribute__((packed)) jpeg_msg_enc_illegal_command; - - -/* - * Message to ACK CMD_JPEGD_DECODE - */ - -#define JPEG_MSG_DEC_DECODE_ACK 0x0004 -#define JPEG_MSG_DEC_DECODE_ACK_LEN \ - sizeof(jpeg_msg_dec_decode_ack) - - -typedef struct { -} __attribute__((packed)) jpeg_msg_dec_decode_ack; - - -/* - * Message to inform up that an op buffer is ready for consumption and when - * decoding is complete or an error occurs - */ - -#define JPEG_MSG_DEC_OP_PRODUCED 0x0005 -#define JPEG_MSG_DEC_OP_PRODUCED_LEN \ - sizeof(jpeg_msg_dec_op_produced) - -#define JPEG_MSG_DEC_OP_BUF_STATUS_PROGRESS 0x0000 -#define JPEG_MSG_DEC_OP_BUF_STATUS_DONE 0x0001 - -typedef struct { - unsigned int luma_op_buf_addr; - unsigned int chroma_op_buf_addr; - unsigned int num_mcus; - unsigned int op_buf_status; -} __attribute__((packed)) jpeg_msg_dec_op_produced; - -/* - * Message to ack CMD_JPEGD_IDLE cmd - */ - -#define JPEG_MSG_DEC_IDLE_ACK 0x0006 -#define JPEG_MSG_DEC_IDLE_ACK_LEN sizeof(jpeg_msg_dec_idle_ack) - - -typedef struct { -} __attribute__((packed)) jpeg_msg_dec_idle_ack; - - -/* - * Message to indicate illegal cmd was received - */ - -#define JPEG_MSG_DEC_ILLEGAL_COMMAND 0x0007 -#define JPEG_MSG_DEC_ILLEGAL_COMMAND_LEN \ - sizeof(jpeg_msg_dec_illegal_command) - - -typedef struct { - unsigned int status; -} __attribute__((packed)) jpeg_msg_dec_illegal_command; - -/* - * Message to request up for the next segment of ip bit stream - */ - -#define JPEG_MSG_DEC_IP_REQUEST 0x0008 -#define JPEG_MSG_DEC_IP_REQUEST_LEN \ - sizeof(jpeg_msg_dec_ip_request) - - -typedef struct { -} __attribute__((packed)) jpeg_msg_dec_ip_request; - - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h deleted file mode 100644 index 6c76e2c20cf4..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef QDSP5LPMCMDI_H -#define QDSP5LPMCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - L P M I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by LPM Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -06/12/08 sv initial version -===========================================================================*/ - - -/* - * Command to start LPM processing based on the config params - */ - -#define LPM_CMD_START 0x0000 -#define LPM_CMD_START_LEN sizeof(lpm_cmd_start) - -#define LPM_CMD_SPATIAL_FILTER_PART_OPMODE_0 0x00000000 -#define LPM_CMD_SPATIAL_FILTER_PART_OPMODE_1 0x00010000 -typedef struct { - unsigned int cmd_id; - unsigned int ip_data_cfg_part1; - unsigned int ip_data_cfg_part2; - unsigned int ip_data_cfg_part3; - unsigned int ip_data_cfg_part4; - unsigned int op_data_cfg_part1; - unsigned int op_data_cfg_part2; - unsigned int op_data_cfg_part3; - unsigned int spatial_filter_part[32]; -} __attribute__((packed)) lpm_cmd_start; - - - -/* - * Command to stop LPM processing - */ - -#define LPM_CMD_IDLE 0x0001 -#define LPM_CMD_IDLE_LEN sizeof(lpm_cmd_idle) - -typedef struct { - unsigned int cmd_id; -} __attribute__((packed)) lpm_cmd_idle; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h deleted file mode 100644 index 3d1039d6ba42..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef QDSP5LPMMSGI_H -#define QDSP5LPMMSGI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - L P M I N T E R N A L M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by LPM Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -06/12/08 sv initial version -===========================================================================*/ - -/* - * Message to acknowledge CMD_LPM_IDLE command - */ - -#define LPM_MSG_IDLE_ACK 0x0000 -#define LPM_MSG_IDLE_ACK_LEN sizeof(lpm_msg_idle_ack) - -typedef struct { -} __attribute__((packed)) lpm_msg_idle_ack; - - -/* - * Message to acknowledge CMD_LPM_START command - */ - - -#define LPM_MSG_START_ACK 0x0001 -#define LPM_MSG_START_ACK_LEN sizeof(lpm_msg_start_ack) - - -typedef struct { -} __attribute__((packed)) lpm_msg_start_ack; - - -/* - * Message to notify the ARM that LPM processing is complete - */ - -#define LPM_MSG_DONE 0x0002 -#define LPM_MSG_DONE_LEN sizeof(lpm_msg_done) - -typedef struct { -} __attribute__((packed)) lpm_msg_done; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h deleted file mode 100644 index 3a32ee99c6e4..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef QDSP5VIDDECCMDI_H -#define QDSP5VIDDECCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - V I D E O D E C O D E R I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by VIDDEC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdeccmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -05/10/08 ac initial version -===========================================================================*/ - - -/* - * Command to inform VIDDEC that new subframe packet is ready - */ - -#define VIDDEC_CMD_SUBFRAME_PKT 0x0000 -#define VIDDEC_CMD_SUBFRAME_PKT_LEN \ - sizeof(viddec_cmd_subframe_pkt) - -#define VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DM 0x0000 -#define VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DMA 0x0001 - -#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_CONTI 0x0000 -#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST 0x0001 -#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_LAST 0x0002 -#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST_AND_LAST 0x0003 - -#define VIDDEC_CMD_CODEC_SELECTION_WORD_MPEG_4 0x0000 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_P0 0x0001 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_264 0x0002 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_p3 0x0003 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_RV9 0x0004 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_WMV9 0x0005 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_SMCDB 0x0006 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_QFRE 0x0007 -#define VIDDEC_CMD_CODEC_SELECTION_WORD_VLD 0x0008 - -typedef struct { - unsigned short cmd_id; - unsigned short packet_seq_number; - unsigned short codec_instance_id; - unsigned short subframe_packet_size_high; - unsigned short subframe_packet_size_low; - unsigned short subframe_packet_high; - unsigned short subframe_packet_low; - unsigned short subframe_packet_partition; - unsigned short statistics_packet_size_high; - unsigned short statistics_packet_size_low; - unsigned short statistics_packet_high; - unsigned short statistics_packet_low; - unsigned short statistics_partition; - unsigned short subframe_info_1; - unsigned short subframe_info_0; - unsigned short codec_selection_word; - unsigned short num_mbs; -} __attribute__((packed)) viddec_cmd_subframe_pkt; - - -/* - * Command to inform VIDDEC task that post processing is required for the frame - */ - -#define VIDDEC_CMD_PP_ENABLE 0x0001 -#define VIDDEC_CMD_PP_ENABLE_LEN \ - sizeof(viddec_cmd_pp_enable) - -#define VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DM 0x0000 -#define VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DMA 0x0001 - -typedef struct { - unsigned short cmd_id; - unsigned short packet_seq_num; - unsigned short codec_instance_id; - unsigned short postproc_info_0; - unsigned short codec_selection_word; - unsigned short pp_output_addr_high; - unsigned short pp_output_addr_low; - unsigned short postproc_info_1; - unsigned short load_sharing_packet_size_high; - unsigned short load_sharing_packet_size_low; - unsigned short load_sharing_packet_high; - unsigned short load_sharing_packet_low; - unsigned short load_sharing_partition; - unsigned short pp_param_0; - unsigned short pp_param_1; - unsigned short pp_param_2; - unsigned short pp_param_3; -} __attribute__((packed)) viddec_cmd_pp_enable; - - -/* - * FRAME Header Packet : It is at the start of new frame - */ - -#define VIDDEC_CMD_FRAME_HEADER_PACKET 0x0002 -#define VIDDEC_CMD_FRAME_HEADER_PACKET_LEN \ - sizeof(viddec_cmd_frame_header_packet) - -#define VIDDEC_CMD_FRAME_INFO_0_ERROR_SKIP 0x0000 -#define VIDDEC_CMD_FRAME_INFO_0_ERROR_BLACK 0x0800 - -typedef struct { - unsigned short packet_id; - unsigned short x_dimension; - unsigned short y_dimension; - unsigned short line_width; - unsigned short frame_info_0; - unsigned short frame_buffer_0_high; - unsigned short frame_buffer_0_low; - unsigned short frame_buffer_1_high; - unsigned short frame_buffer_1_low; - unsigned short frame_buffer_2_high; - unsigned short frame_buffer_2_low; - unsigned short frame_buffer_3_high; - unsigned short frame_buffer_3_low; - unsigned short frame_buffer_4_high; - unsigned short frame_buffer_4_low; - unsigned short frame_buffer_5_high; - unsigned short frame_buffer_5_low; - unsigned short frame_buffer_6_high; - unsigned short frame_buffer_6_low; - unsigned short frame_buffer_7_high; - unsigned short frame_buffer_7_low; - unsigned short frame_buffer_8_high; - unsigned short frame_buffer_8_low; - unsigned short frame_buffer_9_high; - unsigned short frame_buffer_9_low; - unsigned short frame_buffer_10_high; - unsigned short frame_buffer_10_low; - unsigned short frame_buffer_11_high; - unsigned short frame_buffer_11_low; - unsigned short frame_buffer_12_high; - unsigned short frame_buffer_12_low; - unsigned short frame_buffer_13_high; - unsigned short frame_buffer_13_low; - unsigned short frame_buffer_14_high; - unsigned short frame_buffer_14_low; - unsigned short frame_buffer_15_high; - unsigned short frame_buffer_15_low; - unsigned short output_frame_buffer_high; - unsigned short output_frame_buffer_low; - unsigned short end_of_packet_marker; -} __attribute__((packed)) viddec_cmd_frame_header_packet; - - -/* - * SLICE HEADER PACKET - * I-Slice and P-Slice - */ - -#define VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE 0x0003 -#define VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE_LEN \ - sizeof(viddec_cmd_slice_header_pkt_islice) - -#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_PSLICE 0x0000 -#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_BSLICE 0x0100 -#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_ISLICE 0x0200 -#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SPSLICE 0x0300 -#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SISLICE 0x0400 -#define VIDDEC_CMD_ISLICE_INFO_1_NOPADDING 0x0000 -#define VIDDEC_CMD_ISLICE_INFO_1_PADDING 0x0800 - -#define VIDDEC_CMD_ISLICE_EOP_MARKER 0x7FFF - -typedef struct { - unsigned short cmd_id; - unsigned short packet_id; - unsigned short slice_info_0; - unsigned short slice_info_1; - unsigned short slice_info_2; - unsigned short num_bytes_in_rbsp_high; - unsigned short num_bytes_in_rbsp_low; - unsigned short num_bytes_in_rbsp_consumed; - unsigned short end_of_packet_marker; -} __attribute__((packed)) viddec_cmd_slice_header_pkt_islice; - - -#define VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE 0x0003 -#define VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE_LEN \ - sizeof(viddec_cmd_slice_header_pkt_pslice) - - -typedef struct { - unsigned short cmd_id; - unsigned short packet_id; - unsigned short slice_info_0; - unsigned short slice_info_1; - unsigned short slice_info_2; - unsigned short slice_info_3; - unsigned short refidx_l0_map_tab_info_0; - unsigned short refidx_l0_map_tab_info_1; - unsigned short refidx_l0_map_tab_info_2; - unsigned short refidx_l0_map_tab_info_3; - unsigned short num_bytes_in_rbsp_high; - unsigned short num_bytes_in_rbsp_low; - unsigned short num_bytes_in_rbsp_consumed; - unsigned short end_of_packet_marker; -} __attribute__((packed)) viddec_cmd_slice_header_pkt_pslice; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h deleted file mode 100644 index c1744c1644dd..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef QDSP5VIDDECMSGI_H -#define QDSP5VIDDECMSGI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - V I D E O D E C O D E R I N T E R N A L M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of messages - that are sent by VIDDEC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdecmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -05/10/08 ac initial version -===========================================================================*/ - -/* - * Message to inform ARM which VDEC_SUBFRAME_PKT_CMD processed by VIDDEC TASK - */ - -#define VIDDEC_MSG_SUBF_DONE 0x0000 -#define VIDDEC_MSG_SUBF_DONE_LEN \ - sizeof(viddec_msg_subf_done) - -typedef struct { - unsigned short packet_seq_number; - unsigned short codec_instance_id; -} __attribute__((packed)) viddec_msg_subf_done; - - -/* - * Message to inform ARM one frame has been decoded - */ - -#define VIDDEC_MSG_FRAME_DONE 0x0001 -#define VIDDEC_MSG_FRAME_DONE_LEN \ - sizeof(viddec_msg_frame_done) - -typedef struct { - unsigned short packet_seq_number; - unsigned short codec_instance_id; -} __attribute__((packed)) viddec_msg_frame_done; - - -/* - * Message to inform ARM that post processing frame has been decoded - */ - -#define VIDDEC_MSG_PP_ENABLE_CMD_DONE 0x0002 -#define VIDDEC_MSG_PP_ENABLE_CMD_DONE_LEN \ - sizeof(viddec_msg_pp_enable_cmd_done) - -typedef struct { - unsigned short packet_seq_number; - unsigned short codec_instance_id; -} __attribute__((packed)) viddec_msg_pp_enable_cmd_done; - - -/* - * Message to inform ARM that one post processing frame has been decoded - */ - - -#define VIDDEC_MSG_PP_FRAME_DONE 0x0003 -#define VIDDEC_MSG_PP_FRAME_DONE_LEN \ - sizeof(viddec_msg_pp_frame_done) - -#define VIDDEC_MSG_DISP_WORTHY_DISP 0x0000 -#define VIDDEC_MSG_DISP_WORTHY_DISP_NONE 0xFFFF - - -typedef struct { - unsigned short packet_seq_number; - unsigned short codec_instance_id; - unsigned short display_worthy; -} __attribute__((packed)) viddec_msg_pp_frame_done; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h deleted file mode 100644 index 819544d186da..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef QDSP5VIDENCCMDI_H -#define QDSP5VIDENCCMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - V I D E O E N C O D E R I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by VIDENC Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 2008 by QUALCOMM, Incorporated. -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -09/25/08 umeshp initial version -===========================================================================*/ - - #define VIDENC_CMD_CFG 0x0000 - #define VIDENC_CMD_ACTIVE 0x0001 - #define VIDENC_CMD_IDLE 0x0002 - #define VIDENC_CMD_FRAME_START 0x0003 - #define VIDENC_CMD_STATUS_QUERY 0x0004 - #define VIDENC_CMD_RC_CFG 0x0005 - #define VIDENC_CMD_DIS_CFG 0x0006 - #define VIDENC_CMD_DIS 0x0007 - #define VIDENC_CMD_INTRA_REFRESH 0x0008 - #define VIDENC_CMD_DIGITAL_ZOOM 0x0009 - - -/* - * Command to pass the frame message information to VIDENC - */ - - -#define VIDENC_CMD_FRAME_START_LEN \ - sizeof(videnc_cmd_frame_start) - -typedef struct { - unsigned short cmd_id; - unsigned short frame_info; - unsigned short frame_rho_budget_word_high; - unsigned short frame_rho_budget_word_low; - unsigned short input_luma_addr_high; - unsigned short input_luma_addr_low; - unsigned short input_chroma_addr_high; - unsigned short input_chroma_addr_low; - unsigned short ref_vop_buf_ptr_high; - unsigned short ref_vop_buf_ptr_low; - unsigned short enc_pkt_buf_ptr_high; - unsigned short enc_pkt_buf_ptr_low; - unsigned short enc_pkt_buf_size_high; - unsigned short enc_pkt_buf_size_low; - unsigned short unfilt_recon_vop_buf_ptr_high; - unsigned short unfilt_recon_vop_buf_ptr_low; - unsigned short filt_recon_vop_buf_ptr_high; - unsigned short filt_recon_vop_buf_ptr_low; -} __attribute__((packed)) videnc_cmd_frame_start; - -/* - * Command to pass the frame-level digital stabilization parameters to VIDENC - */ - - -#define VIDENC_CMD_DIS_LEN \ - sizeof(videnc_cmd_dis) - -typedef struct { - unsigned short cmd_id; - unsigned short vfe_out_prev_luma_addr_high; - unsigned short vfe_out_prev_luma_addr_low; - unsigned short stabilization_info; -} __attribute__((packed)) videnc_cmd_dis; - -/* - * Command to pass the codec related parameters to VIDENC - */ - - -#define VIDENC_CMD_CFG_LEN \ - sizeof(videnc_cmd_cfg) - -typedef struct { - unsigned short cmd_id; - unsigned short cfg_info_0; - unsigned short cfg_info_1; - unsigned short four_mv_threshold; - unsigned short ise_fse_mv_cost_fac; - unsigned short venc_frame_dim; - unsigned short venc_DM_partition; -} __attribute__((packed)) videnc_cmd_cfg; - -/* - * Command to start the video encoding - */ - - -#define VIDENC_CMD_ACTIVE_LEN \ - sizeof(videnc_cmd_active) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) videnc_cmd_active; - -/* - * Command to stop the video encoding - */ - - -#define VIDENC_CMD_IDLE_LEN \ - sizeof(videnc_cmd_idle) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) videnc_cmd_idle; - -/* - * Command to query staus of VIDENC - */ - - -#define VIDENC_CMD_STATUS_QUERY_LEN \ - sizeof(videnc_cmd_status_query) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) videnc_cmd_status_query; - -/* - * Command to set rate control for a frame - */ - - -#define VIDENC_CMD_RC_CFG_LEN \ - sizeof(videnc_cmd_rc_cfg) - -typedef struct { - unsigned short cmd_id; - unsigned short max_frame_qp_delta; - unsigned short max_min_frame_qp; -} __attribute__((packed)) videnc_cmd_rc_cfg; - -/* - * Command to set intra-refreshing - */ - - -#define VIDENC_CMD_INTRA_REFRESH_LEN \ - sizeof(videnc_cmd_intra_refresh) - -typedef struct { - unsigned short cmd_id; - unsigned short num_mb_refresh; - unsigned short mb_index[15]; -} __attribute__((packed)) videnc_cmd_intra_refresh; - -/* - * Command to pass digital zoom information to the VIDENC - */ -#define VIDENC_CMD_DIGITAL_ZOOM_LEN \ - sizeof(videnc_cmd_digital_zoom) - -typedef struct { - unsigned short cmd_id; - unsigned short digital_zoom_en; - unsigned short luma_frame_shift_X; - unsigned short luma_frame_shift_Y; - unsigned short up_ip_luma_rows; - unsigned short up_ip_luma_cols; - unsigned short up_ip_chroma_rows; - unsigned short up_ip_chroma_cols; - unsigned short luma_ph_incr_V_low; - unsigned short luma_ph_incr_V_high; - unsigned short luma_ph_incr_H_low; - unsigned short luma_ph_incr_H_high; - unsigned short chroma_ph_incr_V_low; - unsigned short chroma_ph_incr_V_high; - unsigned short chroma_ph_incr_H_low; - unsigned short chroma_ph_incr_H_high; -} __attribute__((packed)) videnc_cmd_digital_zoom; - -/* - * Command to configure digital stabilization parameters - */ - -#define VIDENC_CMD_DIS_CFG_LEN \ - sizeof(videnc_cmd_dis_cfg) - -typedef struct { - unsigned short cmd_id; - unsigned short image_stab_subf_start_row_col; - unsigned short image_stab_subf_dim; - unsigned short image_stab_info_0; -} __attribute__((packed)) videnc_cmd_dis_cfg; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h deleted file mode 100644 index 55e8fc2269f7..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h +++ /dev/null @@ -1,910 +0,0 @@ -#ifndef QDSP5VFECMDI_H -#define QDSP5VFECMDI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - V F E I N T E R N A L C O M M A N D S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are accepted by VFE Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfecmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -06/12/08 sv initial version -===========================================================================*/ - -/****************************************************************************** - * Commands through vfeCommandScaleQueue - *****************************************************************************/ - -/* - * Command to program scaler for op1 . max op of scaler is VGA - */ - - -#define VFE_CMD_SCALE_OP1_CFG 0x0000 -#define VFE_CMD_SCALE_OP1_CFG_LEN \ - sizeof(vfe_cmd_scale_op1_cfg) - -#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_STANDARD 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_CASCADED 0x0001 -#define VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_ENA 0x0002 -#define VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_ENA 0x0004 -#define VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_ENA 0x0008 -#define VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_ENA 0x0010 -#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_STANDARD 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_CASCADED 0x0020 -#define VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_ENA 0x0040 -#define VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_ENA 0x0080 - -#define VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS 0x80000000 -#define VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS 0x80000000 - -typedef struct { - unsigned int cmd_id; - unsigned int scale_op1_sel; - unsigned int y_scaler_cfg_part1; - unsigned int y_scaler_cfg_part2; - unsigned int cbcr_scaler_cfg_part1; - unsigned int cbcr_scaler_cfg_part2; - unsigned int cbcr_scaler_cfg_part3; - unsigned int pp_y_scaler_cfg_part1; - unsigned int pp_y_scaler_cfg_part2; - unsigned int y_scaler_v_coeff_bank_part1[16]; - unsigned int y_scaler_v_coeff_bank_part2[16]; - unsigned int y_scaler_h_coeff_bank_part1[16]; - unsigned int y_scaler_h_coeff_bank_part2[16]; -} __attribute__((packed)) vfe_cmd_scale_op1_cfg; - - -/* - * Command to program scaler for op2 - */ - -#define VFE_CMD_SCALE_OP2_CFG 0x0001 -#define VFE_CMD_SCALE_OP2_CFG_LEN \ - sizeof(vfe_cmd_scale_op2_cfg) - -#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_STANDARD 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_CASCADED 0x0001 -#define VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_ENA 0x0002 -#define VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_ENA 0x0004 -#define VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_ENA 0x0008 -#define VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_ENA 0x0010 -#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_STANDARD 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_CASCADED 0x0020 -#define VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_ENA 0x0040 -#define VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_DIS 0x0000 -#define VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_ENA 0x0080 - -#define VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS 0x80000000 -#define VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS 0x80000000 - -typedef struct { - unsigned int cmd_id; - unsigned int scale_op2_sel; - unsigned int y_scaler_cfg_part1; - unsigned int y_scaler_cfg_part2; - unsigned int cbcr_scaler_cfg_part1; - unsigned int cbcr_scaler_cfg_part2; - unsigned int cbcr_scaler_cfg_part3; - unsigned int pp_y_scaler_cfg_part1; - unsigned int pp_y_scaler_cfg_part2; - unsigned int y_scaler_v_coeff_bank_part1[16]; - unsigned int y_scaler_v_coeff_bank_part2[16]; - unsigned int y_scaler_h_coeff_bank_part1[16]; - unsigned int y_scaler_h_coeff_bank_part2[16]; -} __attribute__((packed)) vfe_cmd_scale_op2_cfg; - - -/****************************************************************************** - * Commands through vfeCommandTableQueue - *****************************************************************************/ - -/* - * Command to program the AXI ip paths - */ - -#define VFE_CMD_AXI_IP_CFG 0x0000 -#define VFE_CMD_AXI_IP_CFG_LEN sizeof(vfe_cmd_axi_ip_cfg) - -#define VFE_CMD_IP_SEL_IP_FORMAT_8 0x0000 -#define VFE_CMD_IP_SEL_IP_FORMAT_10 0x0001 -#define VFE_CMD_IP_SEL_IP_FORMAT_12 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int ip_sel; - unsigned int ip_cfg_part1; - unsigned int ip_cfg_part2; - unsigned int ip_unpack_cfg_part[6]; - unsigned int ip_buf_addr[8]; -} __attribute__ ((packed)) vfe_cmd_axi_ip_cfg; - - -/* - * Command to program axi op paths - */ - -#define VFE_CMD_AXI_OP_CFG 0x0001 -#define VFE_CMD_AXI_OP_CFG_LEN sizeof(vfe_cmd_axi_op_cfg) - -#define VFE_CMD_OP_SEL_OP1 0x0000 -#define VFE_CMD_OP_SEL_OP2 0x0001 -#define VFE_CMD_OP_SEL_OP1_OP2 0x0002 -#define VFE_CMD_OP_SEL_CTOA 0x0003 -#define VFE_CMD_OP_SEL_CTOA_OP1 0x0004 -#define VFE_CMD_OP_SEL_CTOA_OP2 0x0005 -#define VFE_CMD_OP_SEL_OP_FORMAT_8 0x0000 -#define VFE_CMD_OP_SEL_OP_FORMAT_10 0x0008 -#define VFE_CMD_OP_SEL_OP_FORMAT_12 0x0010 - - -typedef struct { - unsigned int cmd_id; - unsigned int op_sel; - unsigned int op1_y_cfg_part1; - unsigned int op1_y_cfg_part2; - unsigned int op1_cbcr_cfg_part1; - unsigned int op1_cbcr_cfg_part2; - unsigned int op2_y_cfg_part1; - unsigned int op2_y_cfg_part2; - unsigned int op2_cbcr_cfg_part1; - unsigned int op2_cbcr_cfg_part2; - unsigned int op1_buf1_addr[16]; - unsigned int op2_buf1_addr[16]; -} __attribute__((packed)) vfe_cmd_axi_op_cfg; - - - - -/* - * Command to program the roll off correction module - */ - -#define VFE_CMD_ROLLOFF_CFG 0x0002 -#define VFE_CMD_ROLLOFF_CFG_LEN \ - sizeof(vfe_cmd_rolloff_cfg) - - -typedef struct { - unsigned int cmd_id; - unsigned int correction_opt_center_pos; - unsigned int radius_square_entry[32]; - unsigned int red_table_entry[32]; - unsigned int green_table_entry[32]; - unsigned int blue_table_entry[32]; -} __attribute__((packed)) vfe_cmd_rolloff_cfg; - -/* - * Command to program RGB gamma table - */ - -#define VFE_CMD_RGB_GAMMA_CFG 0x0003 -#define VFE_CMD_RGB_GAMMA_CFG_LEN \ - sizeof(vfe_cmd_rgb_gamma_cfg) - -#define VFE_CMD_RGB_GAMMA_SEL_LINEAR 0x0000 -#define VFE_CMD_RGB_GAMMA_SEL_PW_LINEAR 0x0001 -typedef struct { - unsigned int cmd_id; - unsigned int rgb_gamma_sel; - unsigned int rgb_gamma_entry[256]; -} __attribute__((packed)) vfe_cmd_rgb_gamma_cfg; - - -/* - * Command to program luma gamma table for the noise reduction path - */ - -#define VFE_CMD_Y_GAMMA_CFG 0x0004 -#define VFE_CMD_Y_GAMMA_CFG_LEN \ - sizeof(vfe_cmd_y_gamma_cfg) - -#define VFE_CMD_Y_GAMMA_SEL_LINEAR 0x0000 -#define VFE_CMD_Y_GAMMA_SEL_PW_LINEAR 0x0001 - -typedef struct { - unsigned int cmd_id; - unsigned int y_gamma_sel; - unsigned int y_gamma_entry[256]; -} __attribute__((packed)) vfe_cmd_y_gamma_cfg; - - - -/****************************************************************************** - * Commands through vfeCommandQueue - *****************************************************************************/ - -/* - * Command to reset the VFE to a known good state.All previously programmed - * Params will be lost - */ - - -#define VFE_CMD_RESET 0x0000 -#define VFE_CMD_RESET_LEN sizeof(vfe_cmd_reset) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) vfe_cmd_reset; - - -/* - * Command to start VFE processing based on the config params - */ - - -#define VFE_CMD_START 0x0001 -#define VFE_CMD_START_LEN sizeof(vfe_cmd_start) - -#define VFE_CMD_STARTUP_PARAMS_SRC_CAMIF 0x0000 -#define VFE_CMD_STARTUP_PARAMS_SRC_AXI 0x0001 -#define VFE_CMD_STARTUP_PARAMS_MODE_CONTINUOUS 0x0000 -#define VFE_CMD_STARTUP_PARAMS_MODE_SNAPSHOT 0x0002 - -#define VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_ENA 0x0001 -#define VFE_CMD_IMAGE_PL_ROLLOFF_CORR_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_ROLLOFF_CORR_ENA 0x0002 -#define VFE_CMD_IMAGE_PL_WHITE_BAL_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_WHITE_BAL_ENA 0x0004 -#define VFE_CMD_IMAGE_PL_RGB_GAMMA_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_RGB_GAMMA_ENA 0x0008 -#define VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_ENA 0x0010 -#define VFE_CMD_IMAGE_PL_ADP_FILTER_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_ADP_FILTER_ENA 0x0020 -#define VFE_CMD_IMAGE_PL_CHROMA_SAMP_DIS 0x0000 -#define VFE_CMD_IMAGE_PL_CHROMA_SAMP_ENA 0x0040 - - -typedef struct { - unsigned int cmd_id; - unsigned int startup_params; - unsigned int image_pipeline; - unsigned int frame_dimension; -} __attribute__((packed)) vfe_cmd_start; - - -/* - * Command to halt all processing - */ - -#define VFE_CMD_STOP 0x0002 -#define VFE_CMD_STOP_LEN sizeof(vfe_cmd_stop) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) vfe_cmd_stop; - - -/* - * Command to commit the params that have been programmed to take - * effect on the next frame - */ - -#define VFE_CMD_UPDATE 0x0003 -#define VFE_CMD_UPDATE_LEN sizeof(vfe_cmd_update) - - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) vfe_cmd_update; - - -/* - * Command to program CAMIF module - */ - -#define VFE_CMD_CAMIF_CFG 0x0004 -#define VFE_CMD_CAMIF_CFG_LEN sizeof(vfe_cmd_camif_cfg) - -#define VFE_CMD_CFG_VSYNC_SYNC_EDGE_HIGH 0x0000 -#define VFE_CMD_CFG_VSYNC_SYNC_EDGE_LOW 0x0002 -#define VFE_CMD_CFG_HSYNC_SYNC_EDGE_HIGH 0x0000 -#define VFE_CMD_CFG_HSYNC_SYNC_EDGE_LOW 0x0004 -#define VFE_CMD_CFG_SYNC_MODE_APS 0x0000 -#define VFE_CMD_CFG_SYNC_MODE_EFS 0X0008 -#define VFE_CMD_CFG_SYNC_MODE_ELS 0x0010 -#define VFE_CMD_CFG_SYNC_MODE_RVD 0x0018 -#define VFE_CMD_CFG_VFE_SUBSAMP_EN_DIS 0x0000 -#define VFE_CMD_CFG_VFE_SUBSAMP_EN_ENA 0x0020 -#define VFE_CMD_CFG_BUS_SUBSAMP_EN_DIS 0x0000 -#define VFE_CMD_CFG_BUS_SUBSAMP_EN_ENA 0x0080 -#define VFE_CMD_CFG_IRQ_SUBSAMP_EN_DIS 0x0000 -#define VFE_CMD_CFG_IRQ_SUBSAMP_EN_ENA 0x0800 - -#define VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_16 0x0000 -#define VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_12 0x0010 - -#define VFE_CMD_EPOCH_IRQ_1_DIS 0x0000 -#define VFE_CMD_EPOCH_IRQ_1_ENA 0x4000 -#define VFE_CMD_EPOCH_IRQ_2_DIS 0x0000 -#define VFE_CMD_EPOCH_IRQ_2_ENA 0x8000 - -typedef struct { - unsigned int cmd_id; - unsigned int cfg; - unsigned int efs_cfg; - unsigned int frame_cfg; - unsigned int window_width_cfg; - unsigned int window_height_cfg; - unsigned int subsamp1_cfg; - unsigned int subsamp2_cfg; - unsigned int epoch_irq; -} __attribute__((packed)) vfe_cmd_camif_cfg; - - - -/* - * Command to program the black level module - */ - -#define VFE_CMD_BLACK_LVL_CFG 0x0005 -#define VFE_CMD_BLACK_LVL_CFG_LEN sizeof(vfe_cmd_black_lvl_cfg) - -#define VFE_CMD_BL_SEL_MANUAL 0x0000 -#define VFE_CMD_BL_SEL_AUTO 0x0001 - -typedef struct { - unsigned int cmd_id; - unsigned int black_lvl_sel; - unsigned int cfg_part[3]; -} __attribute__((packed)) vfe_cmd_black_lvl_cfg; - - -/* - * Command to program the active region by cropping the region of interest - */ - -#define VFE_CMD_ACTIVE_REGION_CFG 0x0006 -#define VFE_CMD_ACTIVE_REGION_CFG_LEN \ - sizeof(vfe_cmd_active_region_cfg) - - -typedef struct { - unsigned int cmd_id; - unsigned int cfg_part1; - unsigned int cfg_part2; -} __attribute__((packed)) vfe_cmd_active_region_cfg; - - - -/* - * Command to program the defective pixel correction(DPC) , - * adaptive bayer filter (ABF) and demosaic modules - */ - -#define VFE_CMD_DEMOSAIC_CFG 0x0007 -#define VFE_CMD_DEMOSAIC_CFG_LEN sizeof(vfe_cmd_demosaic_cfg) - -#define VFE_CMD_DEMOSAIC_PART1_ABF_EN_DIS 0x0000 -#define VFE_CMD_DEMOSAIC_PART1_ABF_EN_ENA 0x0001 -#define VFE_CMD_DEMOSAIC_PART1_DPC_EN_DIS 0x0000 -#define VFE_CMD_DEMOSAIC_PART1_DPC_EN_ENA 0x0002 -#define VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_OFF 0x0000 -#define VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_ON 0x0004 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1 0x00000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_2 0x10000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_4 0x20000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_8 0x30000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_2 0x50000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_4 0x60000000 -#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_8 0x70000000 - -typedef struct { - unsigned int cmd_id; - unsigned int demosaic_part1; - unsigned int demosaic_part2; - unsigned int demosaic_part3; - unsigned int demosaic_part4; - unsigned int demosaic_part5; -} __attribute__((packed)) vfe_cmd_demosaic_cfg; - - -/* - * Command to program the ip format - */ - -#define VFE_CMD_IP_FORMAT_CFG 0x0008 -#define VFE_CMD_IP_FORMAT_CFG_LEN \ - sizeof(vfe_cmd_ip_format_cfg) - -#define VFE_CMD_IP_FORMAT_SEL_RGRG 0x0000 -#define VFE_CMD_IP_FORMAT_SEL_GRGR 0x0001 -#define VFE_CMD_IP_FORMAT_SEL_BGBG 0x0002 -#define VFE_CMD_IP_FORMAT_SEL_GBGB 0x0003 -#define VFE_CMD_IP_FORMAT_SEL_YCBYCR 0x0004 -#define VFE_CMD_IP_FORMAT_SEL_YCRYCB 0x0005 -#define VFE_CMD_IP_FORMAT_SEL_CBYCRY 0x0006 -#define VFE_CMD_IP_FORMAT_SEL_CRYCBY 0x0007 -#define VFE_CMD_IP_FORMAT_SEL_NO_CHROMA 0x0000 -#define VFE_CMD_IP_FORMAT_SEL_CHROMA 0x0008 - - -typedef struct { - unsigned int cmd_id; - unsigned int ip_format_sel; - unsigned int balance_gains_part1; - unsigned int balance_gains_part2; -} __attribute__((packed)) vfe_cmd_ip_format_cfg; - - - -/* - * Command to program max and min allowed op values - */ - -#define VFE_CMD_OP_CLAMP_CFG 0x0009 -#define VFE_CMD_OP_CLAMP_CFG_LEN \ - sizeof(vfe_cmd_op_clamp_cfg) - -typedef struct { - unsigned int cmd_id; - unsigned int op_clamp_max; - unsigned int op_clamp_min; -} __attribute__((packed)) vfe_cmd_op_clamp_cfg; - - -/* - * Command to program chroma sub sample module - */ - -#define VFE_CMD_CHROMA_SUBSAMPLE_CFG 0x000A -#define VFE_CMD_CHROMA_SUBSAMPLE_CFG_LEN \ - sizeof(vfe_cmd_chroma_subsample_cfg) - -#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_INTERESTIAL_SAMPS 0x0000 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_COSITED_SAMPS 0x0001 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_INTERESTIAL_SAMPS 0x0000 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_COSITED_SAMPS 0x0002 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_DIS 0x0000 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_ENA 0x0004 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_DIS 0x0000 -#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_ENA 0x0008 - -typedef struct { - unsigned int cmd_id; - unsigned int chroma_subsamp_sel; -} __attribute__((packed)) vfe_cmd_chroma_subsample_cfg; - - -/* - * Command to program the white balance module - */ - -#define VFE_CMD_WHITE_BALANCE_CFG 0x000B -#define VFE_CMD_WHITE_BALANCE_CFG_LEN \ - sizeof(vfe_cmd_white_balance_cfg) - -typedef struct { - unsigned int cmd_id; - unsigned int white_balance_gains; -} __attribute__((packed)) vfe_cmd_white_balance_cfg; - - -/* - * Command to program the color processing module - */ - -#define VFE_CMD_COLOR_PROCESS_CFG 0x000C -#define VFE_CMD_COLOR_PROCESS_CFG_LEN \ - sizeof(vfe_cmd_color_process_cfg) - -#define VFE_CMD_COLOR_CORRE_PART7_Q7_FACTORS 0x0000 -#define VFE_CMD_COLOR_CORRE_PART7_Q8_FACTORS 0x0001 -#define VFE_CMD_COLOR_CORRE_PART7_Q9_FACTORS 0x0002 -#define VFE_CMD_COLOR_CORRE_PART7_Q10_FACTORS 0x0003 - -typedef struct { - unsigned int cmd_id; - unsigned int color_correction_part1; - unsigned int color_correction_part2; - unsigned int color_correction_part3; - unsigned int color_correction_part4; - unsigned int color_correction_part5; - unsigned int color_correction_part6; - unsigned int color_correction_part7; - unsigned int chroma_enhance_part1; - unsigned int chroma_enhance_part2; - unsigned int chroma_enhance_part3; - unsigned int chroma_enhance_part4; - unsigned int chroma_enhance_part5; - unsigned int luma_calc_part1; - unsigned int luma_calc_part2; -} __attribute__((packed)) vfe_cmd_color_process_cfg; - - -/* - * Command to program adaptive filter module - */ - -#define VFE_CMD_ADP_FILTER_CFG 0x000D -#define VFE_CMD_ADP_FILTER_CFG_LEN \ - sizeof(vfe_cmd_adp_filter_cfg) - -#define VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_DIS 0x0000 -#define VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_ENA 0x0001 -#define VFE_CMD_ASF_CFG_PART_NO_SHARP_MODE 0x0000 -#define VFE_CMD_ASF_CFG_PART_SINGLE_FILTER 0x0002 -#define VFE_CMD_ASF_CFG_PART_DUAL_FILTER 0x0004 -#define VFE_CMD_ASF_CFG_PART_SHARP_MODE 0x0007 - -typedef struct { - unsigned int cmd_id; - unsigned int asf_cfg_part[7]; -} __attribute__((packed)) vfe_cmd_adp_filter_cfg; - - -/* - * Command to program for frame skip pattern for op1 and op2 - */ - -#define VFE_CMD_FRAME_SKIP_CFG 0x000E -#define VFE_CMD_FRAME_SKIP_CFG_LEN \ - sizeof(vfe_cmd_frame_skip_cfg) - -typedef struct { - unsigned int cmd_id; - unsigned int frame_skip_pattern_op1; - unsigned int frame_skip_pattern_op2; -} __attribute__((packed)) vfe_cmd_frame_skip_cfg; - - -/* - * Command to program field-of-view crop for digital zoom - */ - -#define VFE_CMD_FOV_CROP 0x000F -#define VFE_CMD_FOV_CROP_LEN sizeof(vfe_cmd_fov_crop) - -typedef struct { - unsigned int cmd_id; - unsigned int fov_crop_part1; - unsigned int fov_crop_part2; -} __attribute__((packed)) vfe_cmd_fov_crop; - - - -/* - * Command to program auto focus(AF) statistics module - */ - -#define VFE_CMD_STATS_AUTOFOCUS_CFG 0x0010 -#define VFE_CMD_STATS_AUTOFOCUS_CFG_LEN \ - sizeof(vfe_cmd_stats_autofocus_cfg) - -#define VFE_CMD_AF_STATS_SEL_STATS_DIS 0x0000 -#define VFE_CMD_AF_STATS_SEL_STATS_ENA 0x0001 -#define VFE_CMD_AF_STATS_SEL_PRI_FIXED 0x0000 -#define VFE_CMD_AF_STATS_SEL_PRI_VAR 0x0002 -#define VFE_CMD_AF_STATS_CFG_PART_METRIC_SUM 0x00000000 -#define VFE_CMD_AF_STATS_CFG_PART_METRIC_MAX 0x00200000 - -typedef struct { - unsigned int cmd_id; - unsigned int af_stats_sel; - unsigned int af_stats_cfg_part[8]; - unsigned int af_stats_op_buf_hdr; - unsigned int af_stats_op_buf[3]; -} __attribute__((packed)) vfe_cmd_stats_autofocus_cfg; - - -/* - * Command to program White balance(wb) and exposure (exp) - * statistics module - */ - -#define VFE_CMD_STATS_WB_EXP_CFG 0x0011 -#define VFE_CMD_STATS_WB_EXP_CFG_LEN \ - sizeof(vfe_cmd_stats_wb_exp_cfg) - -#define VFE_CMD_WB_EXP_STATS_SEL_STATS_DIS 0x0000 -#define VFE_CMD_WB_EXP_STATS_SEL_STATS_ENA 0x0001 -#define VFE_CMD_WB_EXP_STATS_SEL_PRI_FIXED 0x0000 -#define VFE_CMD_WB_EXP_STATS_SEL_PRI_VAR 0x0002 - -#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_8_8 0x0000 -#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_16_16 0x0001 -#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_8_8 0x0000 -#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_4_4 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int wb_exp_stats_sel; - unsigned int wb_exp_stats_cfg_part1; - unsigned int wb_exp_stats_cfg_part2; - unsigned int wb_exp_stats_cfg_part3; - unsigned int wb_exp_stats_cfg_part4; - unsigned int wb_exp_stats_op_buf_hdr; - unsigned int wb_exp_stats_op_buf[3]; -} __attribute__((packed)) vfe_cmd_stats_wb_exp_cfg; - - -/* - * Command to program histogram(hg) stats module - */ - -#define VFE_CMD_STATS_HG_CFG 0x0012 -#define VFE_CMD_STATS_HG_CFG_LEN \ - sizeof(vfe_cmd_stats_hg_cfg) - -#define VFE_CMD_HG_STATS_SEL_PRI_FIXED 0x0000 -#define VFE_CMD_HG_STATS_SEL_PRI_VAR 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int hg_stats_sel; - unsigned int hg_stats_cfg_part1; - unsigned int hg_stats_cfg_part2; - unsigned int hg_stats_op_buf_hdr; - unsigned int hg_stats_op_buf; -} __attribute__((packed)) vfe_cmd_stats_hg_cfg; - - -/* - * Command to acknowledge last MSG_VFE_OP1 message - */ - -#define VFE_CMD_OP1_ACK 0x0013 -#define VFE_CMD_OP1_ACK_LEN sizeof(vfe_cmd_op1_ack) - -typedef struct { - unsigned int cmd_id; - unsigned int op1_buf_y_addr; - unsigned int op1_buf_cbcr_addr; -} __attribute__((packed)) vfe_cmd_op1_ack; - - - -/* - * Command to acknowledge last MSG_VFE_OP2 message - */ - -#define VFE_CMD_OP2_ACK 0x0014 -#define VFE_CMD_OP2_ACK_LEN sizeof(vfe_cmd_op2_ack) - -typedef struct { - unsigned int cmd_id; - unsigned int op2_buf_y_addr; - unsigned int op2_buf_cbcr_addr; -} __attribute__((packed)) vfe_cmd_op2_ack; - - - -/* - * Command to acknowledge MSG_VFE_STATS_AUTOFOCUS msg - */ - -#define VFE_CMD_STATS_AF_ACK 0x0015 -#define VFE_CMD_STATS_AF_ACK_LEN sizeof(vfe_cmd_stats_af_ack) - - -typedef struct { - unsigned int cmd_id; - unsigned int af_stats_op_buf; -} __attribute__((packed)) vfe_cmd_stats_af_ack; - - -/* - * Command to acknowledge MSG_VFE_STATS_WB_EXP msg - */ - -#define VFE_CMD_STATS_WB_EXP_ACK 0x0016 -#define VFE_CMD_STATS_WB_EXP_ACK_LEN sizeof(vfe_cmd_stats_wb_exp_ack) - -typedef struct { - unsigned int cmd_id; - unsigned int wb_exp_stats_op_buf; -} __attribute__((packed)) vfe_cmd_stats_wb_exp_ack; - - -/* - * Command to acknowledge MSG_VFE_EPOCH1 message - */ - -#define VFE_CMD_EPOCH1_ACK 0x0017 -#define VFE_CMD_EPOCH1_ACK_LEN sizeof(vfe_cmd_epoch1_ack) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) vfe_cmd_epoch1_ack; - - -/* - * Command to acknowledge MSG_VFE_EPOCH2 message - */ - -#define VFE_CMD_EPOCH2_ACK 0x0018 -#define VFE_CMD_EPOCH2_ACK_LEN sizeof(vfe_cmd_epoch2_ack) - -typedef struct { - unsigned short cmd_id; -} __attribute__((packed)) vfe_cmd_epoch2_ack; - - - -/* - * Command to configure, enable or disable synchronous timer1 - */ - -#define VFE_CMD_SYNC_TIMER1_CFG 0x0019 -#define VFE_CMD_SYNC_TIMER1_CFG_LEN \ - sizeof(vfe_cmd_sync_timer1_cfg) - -#define VFE_CMD_SYNC_T1_CFG_PART1_TIMER_DIS 0x0000 -#define VFE_CMD_SYNC_T1_CFG_PART1_TIMER_ENA 0x0001 -#define VFE_CMD_SYNC_T1_CFG_PART1_POL_HIGH 0x0000 -#define VFE_CMD_SYNC_T1_CFG_PART1_POL_LOW 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int sync_t1_cfg_part1; - unsigned int sync_t1_h_sync_countdown; - unsigned int sync_t1_pclk_countdown; - unsigned int sync_t1_duration; -} __attribute__((packed)) vfe_cmd_sync_timer1_cfg; - - -/* - * Command to configure, enable or disable synchronous timer1 - */ - -#define VFE_CMD_SYNC_TIMER2_CFG 0x001A -#define VFE_CMD_SYNC_TIMER2_CFG_LEN \ - sizeof(vfe_cmd_sync_timer2_cfg) - -#define VFE_CMD_SYNC_T2_CFG_PART1_TIMER_DIS 0x0000 -#define VFE_CMD_SYNC_T2_CFG_PART1_TIMER_ENA 0x0001 -#define VFE_CMD_SYNC_T2_CFG_PART1_POL_HIGH 0x0000 -#define VFE_CMD_SYNC_T2_CFG_PART1_POL_LOW 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int sync_t2_cfg_part1; - unsigned int sync_t2_h_sync_countdown; - unsigned int sync_t2_pclk_countdown; - unsigned int sync_t2_duration; -} __attribute__((packed)) vfe_cmd_sync_timer2_cfg; - - -/* - * Command to configure and start asynchronous timer1 - */ - -#define VFE_CMD_ASYNC_TIMER1_START 0x001B -#define VFE_CMD_ASYNC_TIMER1_START_LEN \ - sizeof(vfe_cmd_async_timer1_start) - -#define VFE_CMD_ASYNC_T1_POLARITY_A_HIGH 0x0000 -#define VFE_CMD_ASYNC_T1_POLARITY_A_LOW 0x0001 -#define VFE_CMD_ASYNC_T1_POLARITY_B_HIGH 0x0000 -#define VFE_CMD_ASYNC_T1_POLARITY_B_LOW 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int async_t1a_cfg; - unsigned int async_t1b_cfg; - unsigned int async_t1_polarity; -} __attribute__((packed)) vfe_cmd_async_timer1_start; - - -/* - * Command to configure and start asynchronous timer2 - */ - -#define VFE_CMD_ASYNC_TIMER2_START 0x001C -#define VFE_CMD_ASYNC_TIMER2_START_LEN \ - sizeof(vfe_cmd_async_timer2_start) - -#define VFE_CMD_ASYNC_T2_POLARITY_A_HIGH 0x0000 -#define VFE_CMD_ASYNC_T2_POLARITY_A_LOW 0x0001 -#define VFE_CMD_ASYNC_T2_POLARITY_B_HIGH 0x0000 -#define VFE_CMD_ASYNC_T2_POLARITY_B_LOW 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int async_t2a_cfg; - unsigned int async_t2b_cfg; - unsigned int async_t2_polarity; -} __attribute__((packed)) vfe_cmd_async_timer2_start; - - -/* - * Command to program partial configurations of auto focus(af) - */ - -#define VFE_CMD_STATS_AF_UPDATE 0x001D -#define VFE_CMD_STATS_AF_UPDATE_LEN \ - sizeof(vfe_cmd_stats_af_update) - -#define VFE_CMD_AF_UPDATE_PART1_WINDOW_ONE 0x00000000 -#define VFE_CMD_AF_UPDATE_PART1_WINDOW_MULTI 0x80000000 - -typedef struct { - unsigned int cmd_id; - unsigned int af_update_part1; - unsigned int af_update_part2; -} __attribute__((packed)) vfe_cmd_stats_af_update; - - -/* - * Command to program partial cfg of wb and exp - */ - -#define VFE_CMD_STATS_WB_EXP_UPDATE 0x001E -#define VFE_CMD_STATS_WB_EXP_UPDATE_LEN \ - sizeof(vfe_cmd_stats_wb_exp_update) - -#define VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_8_8 0x0000 -#define VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_16_16 0x0001 -#define VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_8_8 0x0000 -#define VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_4_4 0x0002 - -typedef struct { - unsigned int cmd_id; - unsigned int wb_exp_update_part1; - unsigned int wb_exp_update_part2; - unsigned int wb_exp_update_part3; - unsigned int wb_exp_update_part4; -} __attribute__((packed)) vfe_cmd_stats_wb_exp_update; - - - -/* - * Command to re program the CAMIF FRAME CONFIG settings - */ - -#define VFE_CMD_UPDATE_CAMIF_FRAME_CFG 0x001F -#define VFE_CMD_UPDATE_CAMIF_FRAME_CFG_LEN \ - sizeof(vfe_cmd_update_camif_frame_cfg) - -typedef struct { - unsigned int cmd_id; - unsigned int camif_frame_cfg; -} __attribute__((packed)) vfe_cmd_update_camif_frame_cfg; - - -#endif diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h deleted file mode 100644 index 0053cfb65ba1..000000000000 --- a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef QDSP5VFEMSGI_H -#define QDSP5VFEMSGI_H - -/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* - - V F E I N T E R N A L M E S S A G E S - -GENERAL DESCRIPTION - This file contains defintions of format blocks of commands - that are sent by VFE Task - -REFERENCES - None - -EXTERNALIZED FUNCTIONS - None - -Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated. - -This software is licensed under the terms of the GNU General Public -License version 2, as published by the Free Software Foundation, and -may be copied, distributed, and modified under those terms. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/ -/*=========================================================================== - - EDIT HISTORY FOR FILE - -This section contains comments describing changes made to this file. -Notice that changes are listed in reverse chronological order. - -$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfemsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $ -Revision History: - -when who what, where, why --------- --- ---------------------------------------------------------- -06/12/08 sv initial version -===========================================================================*/ - - -/* - * Message to acknowledge CMD_VFE_REST command - */ - -#define VFE_MSG_RESET_ACK 0x0000 -#define VFE_MSG_RESET_ACK_LEN sizeof(vfe_msg_reset_ack) - -typedef struct { -} __attribute__((packed)) vfe_msg_reset_ack; - - -/* - * Message to acknowledge CMD_VFE_START command - */ - -#define VFE_MSG_START_ACK 0x0001 -#define VFE_MSG_START_ACK_LEN sizeof(vfe_msg_start_ack) - -typedef struct { -} __attribute__((packed)) vfe_msg_start_ack; - -/* - * Message to acknowledge CMD_VFE_STOP command - */ - -#define VFE_MSG_STOP_ACK 0x0002 -#define VFE_MSG_STOP_ACK_LEN sizeof(vfe_msg_stop_ack) - -typedef struct { -} __attribute__((packed)) vfe_msg_stop_ack; - - -/* - * Message to acknowledge CMD_VFE_UPDATE command - */ - -#define VFE_MSG_UPDATE_ACK 0x0003 -#define VFE_MSG_UPDATE_ACK_LEN sizeof(vfe_msg_update_ack) - -typedef struct { -} __attribute__((packed)) vfe_msg_update_ack; - - -/* - * Message to notify the ARM that snapshot processing is complete - * and that the VFE is now STATE_VFE_IDLE - */ - -#define VFE_MSG_SNAPSHOT_DONE 0x0004 -#define VFE_MSG_SNAPSHOT_DONE_LEN \ - sizeof(vfe_msg_snapshot_done) - -typedef struct { -} __attribute__((packed)) vfe_msg_snapshot_done; - - - -/* - * Message to notify ARM that illegal cmd was received and - * system is in the IDLE state - */ - -#define VFE_MSG_ILLEGAL_CMD 0x0005 -#define VFE_MSG_ILLEGAL_CMD_LEN \ - sizeof(vfe_msg_illegal_cmd) - -typedef struct { - unsigned int status; -} __attribute__((packed)) vfe_msg_illegal_cmd; - - -/* - * Message to notify ARM that op1 buf is full and ready - */ - -#define VFE_MSG_OP1 0x0006 -#define VFE_MSG_OP1_LEN sizeof(vfe_msg_op1) - -typedef struct { - unsigned int op1_buf_y_addr; - unsigned int op1_buf_cbcr_addr; - unsigned int black_level_even_col; - unsigned int black_level_odd_col; - unsigned int defect_pixels_detected; - unsigned int asf_max_edge; -} __attribute__((packed)) vfe_msg_op1; - - -/* - * Message to notify ARM that op2 buf is full and ready - */ - -#define VFE_MSG_OP2 0x0007 -#define VFE_MSG_OP2_LEN sizeof(vfe_msg_op2) - -typedef struct { - unsigned int op2_buf_y_addr; - unsigned int op2_buf_cbcr_addr; - unsigned int black_level_even_col; - unsigned int black_level_odd_col; - unsigned int defect_pixels_detected; - unsigned int asf_max_edge; -} __attribute__((packed)) vfe_msg_op2; - - -/* - * Message to notify ARM that autofocus(af) stats are ready - */ - -#define VFE_MSG_STATS_AF 0x0008 -#define VFE_MSG_STATS_AF_LEN sizeof(vfe_msg_stats_af) - -typedef struct { - unsigned int af_stats_op_buffer; -} __attribute__((packed)) vfe_msg_stats_af; - - -/* - * Message to notify ARM that white balance(wb) and exposure (exp) - * stats are ready - */ - -#define VFE_MSG_STATS_WB_EXP 0x0009 -#define VFE_MSG_STATS_WB_EXP_LEN \ - sizeof(vfe_msg_stats_wb_exp) - -typedef struct { - unsigned int wb_exp_stats_op_buf; -} __attribute__((packed)) vfe_msg_stats_wb_exp; - - -/* - * Message to notify the ARM that histogram(hg) stats are ready - */ - -#define VFE_MSG_STATS_HG 0x000A -#define VFE_MSG_STATS_HG_LEN sizeof(vfe_msg_stats_hg) - -typedef struct { - unsigned int hg_stats_op_buf; -} __attribute__((packed)) vfe_msg_stats_hg; - - -/* - * Message to notify the ARM that epoch1 event occurred in the CAMIF - */ - -#define VFE_MSG_EPOCH1 0x000B -#define VFE_MSG_EPOCH1_LEN sizeof(vfe_msg_epoch1) - -typedef struct { -} __attribute__((packed)) vfe_msg_epoch1; - - -/* - * Message to notify the ARM that epoch2 event occurred in the CAMIF - */ - -#define VFE_MSG_EPOCH2 0x000C -#define VFE_MSG_EPOCH2_LEN sizeof(vfe_msg_epoch2) - -typedef struct { -} __attribute__((packed)) vfe_msg_epoch2; - - -/* - * Message to notify the ARM that sync timer1 op is completed - */ - -#define VFE_MSG_SYNC_T1_DONE 0x000D -#define VFE_MSG_SYNC_T1_DONE_LEN sizeof(vfe_msg_sync_t1_done) - -typedef struct { -} __attribute__((packed)) vfe_msg_sync_t1_done; - - -/* - * Message to notify the ARM that sync timer2 op is completed - */ - -#define VFE_MSG_SYNC_T2_DONE 0x000E -#define VFE_MSG_SYNC_T2_DONE_LEN sizeof(vfe_msg_sync_t2_done) - -typedef struct { -} __attribute__((packed)) vfe_msg_sync_t2_done; - - -/* - * Message to notify the ARM that async t1 operation completed - */ - -#define VFE_MSG_ASYNC_T1_DONE 0x000F -#define VFE_MSG_ASYNC_T1_DONE_LEN sizeof(vfe_msg_async_t1_done) - -typedef struct { -} __attribute__((packed)) vfe_msg_async_t1_done; - - - -/* - * Message to notify the ARM that async t2 operation completed - */ - -#define VFE_MSG_ASYNC_T2_DONE 0x0010 -#define VFE_MSG_ASYNC_T2_DONE_LEN sizeof(vfe_msg_async_t2_done) - -typedef struct { -} __attribute__((packed)) vfe_msg_async_t2_done; - - - -/* - * Message to notify the ARM that an error has occurred - */ - -#define VFE_MSG_ERROR 0x0011 -#define VFE_MSG_ERROR_LEN sizeof(vfe_msg_error) - -#define VFE_MSG_ERR_COND_NO_CAMIF_ERR 0x0000 -#define VFE_MSG_ERR_COND_CAMIF_ERR 0x0001 -#define VFE_MSG_ERR_COND_OP1_Y_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_OP1_Y_BUS_OF 0x0002 -#define VFE_MSG_ERR_COND_OP1_CBCR_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_OP1_CBCR_BUS_OF 0x0004 -#define VFE_MSG_ERR_COND_OP2_Y_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_OP2_Y_BUS_OF 0x0008 -#define VFE_MSG_ERR_COND_OP2_CBCR_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_OP2_CBCR_BUS_OF 0x0010 -#define VFE_MSG_ERR_COND_AF_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_AF_BUS_OF 0x0020 -#define VFE_MSG_ERR_COND_WB_EXP_NO_BUS_OF 0x0000 -#define VFE_MSG_ERR_COND_WB_EXP_BUS_OF 0x0040 -#define VFE_MSG_ERR_COND_NO_AXI_ERR 0x0000 -#define VFE_MSG_ERR_COND_AXI_ERR 0x0080 - -#define VFE_MSG_CAMIF_STS_IDLE 0x0000 -#define VFE_MSG_CAMIF_STS_CAPTURE_DATA 0x0001 - -typedef struct { - unsigned int err_cond; - unsigned int camif_sts; -} __attribute__((packed)) vfe_msg_error; - - -#endif diff --git a/drivers/staging/dream/include/media/msm_camera.h b/drivers/staging/dream/include/media/msm_camera.h deleted file mode 100644 index 09812d62cc1e..000000000000 --- a/drivers/staging/dream/include/media/msm_camera.h +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2008-2009 QUALCOMM Incorporated. - */ -#ifndef __LINUX_MSM_CAMERA_H -#define __LINUX_MSM_CAMERA_H - -#include <linux/types.h> -#include <asm/sizes.h> -#include <linux/ioctl.h> - -#define MSM_CAM_IOCTL_MAGIC 'm' - -#define MSM_CAM_IOCTL_GET_SENSOR_INFO \ - _IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *) - -#define MSM_CAM_IOCTL_REGISTER_PMEM \ - _IOW(MSM_CAM_IOCTL_MAGIC, 2, struct msm_pmem_info *) - -#define MSM_CAM_IOCTL_UNREGISTER_PMEM \ - _IOW(MSM_CAM_IOCTL_MAGIC, 3, unsigned) - -#define MSM_CAM_IOCTL_CTRL_COMMAND \ - _IOW(MSM_CAM_IOCTL_MAGIC, 4, struct msm_ctrl_cmd *) - -#define MSM_CAM_IOCTL_CONFIG_VFE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 5, struct msm_camera_vfe_cfg_cmd *) - -#define MSM_CAM_IOCTL_GET_STATS \ - _IOR(MSM_CAM_IOCTL_MAGIC, 6, struct msm_camera_stats_event_ctrl *) - -#define MSM_CAM_IOCTL_GETFRAME \ - _IOR(MSM_CAM_IOCTL_MAGIC, 7, struct msm_camera_get_frame *) - -#define MSM_CAM_IOCTL_ENABLE_VFE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 8, struct camera_enable_cmd *) - -#define MSM_CAM_IOCTL_CTRL_CMD_DONE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 9, struct camera_cmd *) - -#define MSM_CAM_IOCTL_CONFIG_CMD \ - _IOW(MSM_CAM_IOCTL_MAGIC, 10, struct camera_cmd *) - -#define MSM_CAM_IOCTL_DISABLE_VFE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 11, struct camera_enable_cmd *) - -#define MSM_CAM_IOCTL_PAD_REG_RESET2 \ - _IOW(MSM_CAM_IOCTL_MAGIC, 12, struct camera_enable_cmd *) - -#define MSM_CAM_IOCTL_VFE_APPS_RESET \ - _IOW(MSM_CAM_IOCTL_MAGIC, 13, struct camera_enable_cmd *) - -#define MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER \ - _IOW(MSM_CAM_IOCTL_MAGIC, 14, struct camera_enable_cmd *) - -#define MSM_CAM_IOCTL_RELEASE_STATS_BUFFER \ - _IOW(MSM_CAM_IOCTL_MAGIC, 15, struct msm_stats_buf *) - -#define MSM_CAM_IOCTL_AXI_CONFIG \ - _IOW(MSM_CAM_IOCTL_MAGIC, 16, struct msm_camera_vfe_cfg_cmd *) - -#define MSM_CAM_IOCTL_GET_PICTURE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 17, struct msm_camera_ctrl_cmd *) - -#define MSM_CAM_IOCTL_SET_CROP \ - _IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *) - -#define MSM_CAM_IOCTL_PICT_PP \ - _IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *) - -#define MSM_CAM_IOCTL_PICT_PP_DONE \ - _IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *) - -#define MSM_CAM_IOCTL_SENSOR_IO_CFG \ - _IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *) - -#define MSM_CAMERA_LED_OFF 0 -#define MSM_CAMERA_LED_LOW 1 -#define MSM_CAMERA_LED_HIGH 2 - -#define MSM_CAM_IOCTL_FLASH_LED_CFG \ - _IOW(MSM_CAM_IOCTL_MAGIC, 22, unsigned *) - -#define MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME \ - _IO(MSM_CAM_IOCTL_MAGIC, 23) - -#define MSM_CAM_IOCTL_CTRL_COMMAND_2 \ - _IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *) - -#define MAX_SENSOR_NUM 3 -#define MAX_SENSOR_NAME 32 - -#define MSM_CAM_CTRL_CMD_DONE 0 -#define MSM_CAM_SENSOR_VFE_CMD 1 - -/***************************************************** - * structure - *****************************************************/ - -/* define five type of structures for userspace <==> kernel - * space communication: - * command 1 - 2 are from userspace ==> kernel - * command 3 - 4 are from kernel ==> userspace - * - * 1. control command: control command(from control thread), - * control status (from config thread); - */ -struct msm_ctrl_cmd { - uint16_t type; - uint16_t length; - void *value; - uint16_t status; - uint32_t timeout_ms; - int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */ -}; - -struct msm_vfe_evt_msg { - unsigned short type; /* 1 == event (RPC), 0 == message (adsp) */ - unsigned short msg_id; - unsigned int len; /* size in, number of bytes out */ - void *data; -}; - -#define MSM_CAM_RESP_CTRL 0 -#define MSM_CAM_RESP_STAT_EVT_MSG 1 -#define MSM_CAM_RESP_V4L2 2 -#define MSM_CAM_RESP_MAX 3 - -/* this one is used to send ctrl/status up to config thread */ -struct msm_stats_event_ctrl { - /* 0 - ctrl_cmd from control thread, - * 1 - stats/event kernel, - * 2 - V4L control or read request */ - int resptype; - int timeout_ms; - struct msm_ctrl_cmd ctrl_cmd; - /* struct vfe_event_t stats_event; */ - struct msm_vfe_evt_msg stats_event; -}; - -/* 2. config command: config command(from config thread); */ -struct msm_camera_cfg_cmd { - /* what to config: - * 1 - sensor config, 2 - vfe config */ - uint16_t cfg_type; - - /* sensor config type */ - uint16_t cmd_type; - uint16_t queue; - uint16_t length; - void *value; -}; - -#define CMD_GENERAL 0 -#define CMD_AXI_CFG_OUT1 1 -#define CMD_AXI_CFG_SNAP_O1_AND_O2 2 -#define CMD_AXI_CFG_OUT2 3 -#define CMD_PICT_T_AXI_CFG 4 -#define CMD_PICT_M_AXI_CFG 5 -#define CMD_RAW_PICT_AXI_CFG 6 -#define CMD_STATS_AXI_CFG 7 -#define CMD_STATS_AF_AXI_CFG 8 -#define CMD_FRAME_BUF_RELEASE 9 -#define CMD_PREV_BUF_CFG 10 -#define CMD_SNAP_BUF_RELEASE 11 -#define CMD_SNAP_BUF_CFG 12 -#define CMD_STATS_DISABLE 13 -#define CMD_STATS_ENABLE 14 -#define CMD_STATS_AF_ENABLE 15 -#define CMD_STATS_BUF_RELEASE 16 -#define CMD_STATS_AF_BUF_RELEASE 17 -#define UPDATE_STATS_INVALID 18 - -/* vfe config command: config command(from config thread)*/ -struct msm_vfe_cfg_cmd { - int cmd_type; - uint16_t length; - void *value; -}; - -#define MAX_CAMERA_ENABLE_NAME_LEN 32 -struct camera_enable_cmd { - char name[MAX_CAMERA_ENABLE_NAME_LEN]; -}; - -#define MSM_PMEM_OUTPUT1 0 -#define MSM_PMEM_OUTPUT2 1 -#define MSM_PMEM_OUTPUT1_OUTPUT2 2 -#define MSM_PMEM_THUMBAIL 3 -#define MSM_PMEM_MAINIMG 4 -#define MSM_PMEM_RAW_MAINIMG 5 -#define MSM_PMEM_AEC_AWB 6 -#define MSM_PMEM_AF 7 -#define MSM_PMEM_MAX 8 - -#define FRAME_PREVIEW_OUTPUT1 0 -#define FRAME_PREVIEW_OUTPUT2 1 -#define FRAME_SNAPSHOT 2 -#define FRAME_THUMBAIL 3 -#define FRAME_RAW_SNAPSHOT 4 -#define FRAME_MAX 5 - -struct msm_pmem_info { - int type; - int fd; - void *vaddr; - uint32_t y_off; - uint32_t cbcr_off; - uint8_t active; -}; - -struct outputCfg { - uint32_t height; - uint32_t width; - - uint32_t window_height_firstline; - uint32_t window_height_lastline; -}; - -#define OUTPUT_1 0 -#define OUTPUT_2 1 -#define OUTPUT_1_AND_2 2 -#define CAMIF_TO_AXI_VIA_OUTPUT_2 3 -#define OUTPUT_1_AND_CAMIF_TO_AXI_VIA_OUTPUT_2 4 -#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 5 -#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 6 - -#define MSM_FRAME_PREV_1 0 -#define MSM_FRAME_PREV_2 1 -#define MSM_FRAME_ENC 2 - -struct msm_frame { - int path; - unsigned long buffer; - uint32_t y_off; - uint32_t cbcr_off; - int fd; - - void *cropinfo; - int croplen; -}; - -#define STAT_AEAW 0 -#define STAT_AF 1 -#define STAT_MAX 2 - -struct msm_stats_buf { - int type; - unsigned long buffer; - int fd; -}; - -#define MSM_V4L2_VID_CAP_TYPE 0 -#define MSM_V4L2_STREAM_ON 1 -#define MSM_V4L2_STREAM_OFF 2 -#define MSM_V4L2_SNAPSHOT 3 -#define MSM_V4L2_QUERY_CTRL 4 -#define MSM_V4L2_GET_CTRL 5 -#define MSM_V4L2_SET_CTRL 6 -#define MSM_V4L2_QUERY 7 -#define MSM_V4L2_MAX 8 - -struct crop_info { - void *info; - int len; -}; - -struct msm_postproc { - int ftnum; - struct msm_frame fthumnail; - int fmnum; - struct msm_frame fmain; -}; - -struct msm_snapshot_pp_status { - void *status; -}; - -#define CFG_SET_MODE 0 -#define CFG_SET_EFFECT 1 -#define CFG_START 2 -#define CFG_PWR_UP 3 -#define CFG_PWR_DOWN 4 -#define CFG_WRITE_EXPOSURE_GAIN 5 -#define CFG_SET_DEFAULT_FOCUS 6 -#define CFG_MOVE_FOCUS 7 -#define CFG_REGISTER_TO_REAL_GAIN 8 -#define CFG_REAL_TO_REGISTER_GAIN 9 -#define CFG_SET_FPS 10 -#define CFG_SET_PICT_FPS 11 -#define CFG_SET_BRIGHTNESS 12 -#define CFG_SET_CONTRAST 13 -#define CFG_SET_ZOOM 14 -#define CFG_SET_EXPOSURE_MODE 15 -#define CFG_SET_WB 16 -#define CFG_SET_ANTIBANDING 17 -#define CFG_SET_EXP_GAIN 18 -#define CFG_SET_PICT_EXP_GAIN 19 -#define CFG_SET_LENS_SHADING 20 -#define CFG_GET_PICT_FPS 21 -#define CFG_GET_PREV_L_PF 22 -#define CFG_GET_PREV_P_PL 23 -#define CFG_GET_PICT_L_PF 24 -#define CFG_GET_PICT_P_PL 25 -#define CFG_GET_AF_MAX_STEPS 26 -#define CFG_GET_PICT_MAX_EXP_LC 27 -#define CFG_MAX 28 - -#define MOVE_NEAR 0 -#define MOVE_FAR 1 - -#define SENSOR_PREVIEW_MODE 0 -#define SENSOR_SNAPSHOT_MODE 1 -#define SENSOR_RAW_SNAPSHOT_MODE 2 - -#define SENSOR_QTR_SIZE 0 -#define SENSOR_FULL_SIZE 1 -#define SENSOR_INVALID_SIZE 2 - -#define CAMERA_EFFECT_OFF 0 -#define CAMERA_EFFECT_MONO 1 -#define CAMERA_EFFECT_NEGATIVE 2 -#define CAMERA_EFFECT_SOLARIZE 3 -#define CAMERA_EFFECT_PASTEL 4 -#define CAMERA_EFFECT_MOSAIC 5 -#define CAMERA_EFFECT_RESIZE 6 -#define CAMERA_EFFECT_SEPIA 7 -#define CAMERA_EFFECT_POSTERIZE 8 -#define CAMERA_EFFECT_WHITEBOARD 9 -#define CAMERA_EFFECT_BLACKBOARD 10 -#define CAMERA_EFFECT_AQUA 11 -#define CAMERA_EFFECT_MAX 12 - -struct sensor_pict_fps { - uint16_t prevfps; - uint16_t pictfps; -}; - -struct exp_gain_cfg { - uint16_t gain; - uint32_t line; -}; - -struct focus_cfg { - int32_t steps; - int dir; -}; - -struct fps_cfg { - uint16_t f_mult; - uint16_t fps_div; - uint32_t pict_fps_div; -}; - -struct sensor_cfg_data { - int cfgtype; - int mode; - int rs; - uint8_t max_steps; - - union { - int8_t effect; - uint8_t lens_shading; - uint16_t prevl_pf; - uint16_t prevp_pl; - uint16_t pictl_pf; - uint16_t pictp_pl; - uint32_t pict_max_exp_lc; - uint16_t p_fps; - struct sensor_pict_fps gfps; - struct exp_gain_cfg exp_gain; - struct focus_cfg focus; - struct fps_cfg fps; - } cfg; -}; - -#define GET_NAME 0 -#define GET_PREVIEW_LINE_PER_FRAME 1 -#define GET_PREVIEW_PIXELS_PER_LINE 2 -#define GET_SNAPSHOT_LINE_PER_FRAME 3 -#define GET_SNAPSHOT_PIXELS_PER_LINE 4 -#define GET_SNAPSHOT_FPS 5 -#define GET_SNAPSHOT_MAX_EP_LINE_CNT 6 - -struct msm_camsensor_info { - char name[MAX_SENSOR_NAME]; - uint8_t flash_enabled; -}; -#endif /* __LINUX_MSM_CAMERA_H */ diff --git a/drivers/staging/dream/pmem.c b/drivers/staging/dream/pmem.c deleted file mode 100644 index 4d3d300bb736..000000000000 --- a/drivers/staging/dream/pmem.c +++ /dev/null @@ -1,1333 +0,0 @@ -/* drivers/android/pmem.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/miscdevice.h> -#include <linux/platform_device.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/mm.h> -#include <linux/list.h> -#include <linux/debugfs.h> -#include <linux/android_pmem.h> -#include <linux/mempolicy.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/uaccess.h> -#include <asm/cacheflush.h> - -#define PMEM_MAX_DEVICES 10 -#define PMEM_MAX_ORDER 128 -#define PMEM_MIN_ALLOC PAGE_SIZE - -#define PMEM_DEBUG 1 - -/* indicates that a refernce to this file has been taken via get_pmem_file, - * the file should not be released until put_pmem_file is called */ -#define PMEM_FLAGS_BUSY 0x1 -/* indicates that this is a suballocation of a larger master range */ -#define PMEM_FLAGS_CONNECTED (0x1 << 1) -/* indicates this is a master and not a sub allocation and that it is mmaped */ -#define PMEM_FLAGS_MASTERMAP (0x1 << 2) -/* submap and unsubmap flags indicate: - * 00: subregion has never been mmaped - * 10: subregion has been mmaped, reference to the mm was taken - * 11: subretion has ben released, refernece to the mm still held - * 01: subretion has been released, reference to the mm has been released - */ -#define PMEM_FLAGS_SUBMAP (0x1 << 3) -#define PMEM_FLAGS_UNSUBMAP (0x1 << 4) - - -struct pmem_data { - /* in alloc mode: an index into the bitmap - * in no_alloc mode: the size of the allocation */ - int index; - /* see flags above for descriptions */ - unsigned int flags; - /* protects this data field, if the mm_mmap sem will be held at the - * same time as this sem, the mm sem must be taken first (as this is - * the order for vma_open and vma_close ops */ - struct rw_semaphore sem; - /* info about the mmaping process */ - struct vm_area_struct *vma; - /* task struct of the mapping process */ - struct task_struct *task; - /* process id of teh mapping process */ - pid_t pid; - /* file descriptor of the master */ - int master_fd; - /* file struct of the master */ - struct file *master_file; - /* a list of currently available regions if this is a suballocation */ - struct list_head region_list; - /* a linked list of data so we can access them for debugging */ - struct list_head list; -#if PMEM_DEBUG - int ref; -#endif -}; - -struct pmem_bits { - unsigned allocated:1; /* 1 if allocated, 0 if free */ - unsigned order:7; /* size of the region in pmem space */ -}; - -struct pmem_region_node { - struct pmem_region region; - struct list_head list; -}; - -#define PMEM_DEBUG_MSGS 0 -#if PMEM_DEBUG_MSGS -#define DLOG(fmt, args...) \ - do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ - ##args); } \ - while (0) -#else -#define DLOG(x...) do {} while (0) -#endif - -struct pmem_info { - struct miscdevice dev; - /* physical start address of the remaped pmem space */ - unsigned long base; - /* vitual start address of the remaped pmem space */ - unsigned char __iomem *vbase; - /* total size of the pmem space */ - unsigned long size; - /* number of entries in the pmem space */ - unsigned long num_entries; - /* pfn of the garbage page in memory */ - unsigned long garbage_pfn; - /* index of the garbage page in the pmem space */ - int garbage_index; - /* the bitmap for the region indicating which entries are allocated - * and which are free */ - struct pmem_bits *bitmap; - /* indicates the region should not be managed with an allocator */ - unsigned no_allocator; - /* indicates maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - unsigned buffered; - /* in no_allocator mode the first mapper gets the whole space and sets - * this flag */ - unsigned allocated; - /* for debugging, creates a list of pmem file structs, the - * data_list_sem should be taken before pmem_data->sem if both are - * needed */ - struct semaphore data_list_sem; - struct list_head data_list; - /* pmem_sem protects the bitmap array - * a write lock should be held when modifying entries in bitmap - * a read lock should be held when reading data from bits or - * dereferencing a pointer into bitmap - * - * pmem_data->sem protects the pmem data of a particular file - * Many of the function that require the pmem_data->sem have a non- - * locking version for when the caller is already holding that sem. - * - * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER: - * down(pmem_data->sem) => down(bitmap_sem) - */ - struct rw_semaphore bitmap_sem; - - long (*ioctl)(struct file *, unsigned int, unsigned long); - int (*release)(struct inode *, struct file *); -}; - -static struct pmem_info pmem[PMEM_MAX_DEVICES]; -static int id_count; - -#define PMEM_IS_FREE(id, index) (!(pmem[id].bitmap[index].allocated)) -#define PMEM_ORDER(id, index) pmem[id].bitmap[index].order -#define PMEM_BUDDY_INDEX(id, index) (index ^ (1 << PMEM_ORDER(id, index))) -#define PMEM_NEXT_INDEX(id, index) (index + (1 << PMEM_ORDER(id, index))) -#define PMEM_OFFSET(index) (index * PMEM_MIN_ALLOC) -#define PMEM_START_ADDR(id, index) (PMEM_OFFSET(index) + pmem[id].base) -#define PMEM_LEN(id, index) ((1 << PMEM_ORDER(id, index)) * PMEM_MIN_ALLOC) -#define PMEM_END_ADDR(id, index) (PMEM_START_ADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_START_VADDR(id, index) (PMEM_OFFSET(id, index) + pmem[id].vbase) -#define PMEM_END_VADDR(id, index) (PMEM_START_VADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED) -#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) -#define PMEM_IS_SUBMAP(data) ((data->flags & PMEM_FLAGS_SUBMAP) && \ - (!(data->flags & PMEM_FLAGS_UNSUBMAP))) - -static int pmem_release(struct inode *, struct file *); -static int pmem_mmap(struct file *, struct vm_area_struct *); -static int pmem_open(struct inode *, struct file *); -static long pmem_ioctl(struct file *, unsigned int, unsigned long); - -const struct file_operations pmem_fops = { - .release = pmem_release, - .mmap = pmem_mmap, - .open = pmem_open, - .unlocked_ioctl = pmem_ioctl, - .llseek = noop_llseek, -}; - -static int get_id(struct file *file) -{ - return MINOR(file->f_dentry->d_inode->i_rdev); -} - -static int is_pmem_file(struct file *file) -{ - int id; - - if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode)) - return 0; - id = get_id(file); - if (unlikely(id >= PMEM_MAX_DEVICES)) - return 0; - if (unlikely(file->f_dentry->d_inode->i_rdev != - MKDEV(MISC_MAJOR, pmem[id].dev.minor))) - return 0; - return 1; -} - -static int has_allocation(struct file *file) -{ - struct pmem_data *data; - /* check is_pmem_file first if not accessed via pmem_file_ops */ - - if (unlikely(!file->private_data)) - return 0; - data = file->private_data; - if (unlikely(data->index < 0)) - return 0; - return 1; -} - -static int is_master_owner(struct file *file) -{ - struct file *master_file; - struct pmem_data *data; - int put_needed, ret = 0; - - if (!is_pmem_file(file) || !has_allocation(file)) - return 0; - data = file->private_data; - if (PMEM_FLAGS_MASTERMAP & data->flags) - return 1; - master_file = fget_light(data->master_fd, &put_needed); - if (master_file && data->master_file == master_file) - ret = 1; - fput_light(master_file, put_needed); - return ret; -} - -static int pmem_free(int id, int index) -{ - /* caller should hold the write lock on pmem_sem! */ - int buddy, curr = index; - DLOG("index %d\n", index); - - if (pmem[id].no_allocator) { - pmem[id].allocated = 0; - return 0; - } - /* clean up the bitmap, merging any buddies */ - pmem[id].bitmap[curr].allocated = 0; - /* find a slots buddy Buddy# = Slot# ^ (1 << order) - * if the buddy is also free merge them - * repeat until the buddy is not free or end of the bitmap is reached - */ - do { - buddy = PMEM_BUDDY_INDEX(id, curr); - if (PMEM_IS_FREE(id, buddy) && - PMEM_ORDER(id, buddy) == PMEM_ORDER(id, curr)) { - PMEM_ORDER(id, buddy)++; - PMEM_ORDER(id, curr)++; - curr = min(buddy, curr); - } else { - break; - } - } while (curr < pmem[id].num_entries); - - return 0; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data); - -static int pmem_release(struct inode *inode, struct file *file) -{ - struct pmem_data *data = file->private_data; - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - int id = get_id(file), ret = 0; - - - down(&pmem[id].data_list_sem); - /* if this file is a master, revoke all the memory in the connected - * files */ - if (PMEM_FLAGS_MASTERMAP & data->flags) { - struct pmem_data *sub_data; - list_for_each(elt, &pmem[id].data_list) { - sub_data = list_entry(elt, struct pmem_data, list); - down_read(&sub_data->sem); - if (PMEM_IS_SUBMAP(sub_data) && - file == sub_data->master_file) { - up_read(&sub_data->sem); - pmem_revoke(file, sub_data); - } else - up_read(&sub_data->sem); - } - } - list_del(&data->list); - up(&pmem[id].data_list_sem); - - - down_write(&data->sem); - - /* if its not a conencted file and it has an allocation, free it */ - if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) { - down_write(&pmem[id].bitmap_sem); - ret = pmem_free(id, data->index); - up_write(&pmem[id].bitmap_sem); - } - - /* if this file is a submap (mapped, connected file), downref the - * task struct */ - if (PMEM_FLAGS_SUBMAP & data->flags) - if (data->task) { - put_task_struct(data->task); - data->task = NULL; - } - - file->private_data = NULL; - - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - list_del(elt); - kfree(region_node); - } - BUG_ON(!list_empty(&data->region_list)); - - up_write(&data->sem); - kfree(data); - if (pmem[id].release) - ret = pmem[id].release(inode, file); - - return ret; -} - -static int pmem_open(struct inode *inode, struct file *file) -{ - struct pmem_data *data; - int id = get_id(file); - int ret = 0; - - DLOG("current %u file %p(%d)\n", current->pid, file, file_count(file)); - /* setup file->private_data to indicate its unmapped */ - /* you can only open a pmem device one time */ - if (file->private_data != NULL) - return -1; - data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL); - if (!data) { - printk("pmem: unable to allocate memory for pmem metadata."); - return -1; - } - data->flags = 0; - data->index = -1; - data->task = NULL; - data->vma = NULL; - data->pid = 0; - data->master_file = NULL; -#if PMEM_DEBUG - data->ref = 0; -#endif - INIT_LIST_HEAD(&data->region_list); - init_rwsem(&data->sem); - - file->private_data = data; - INIT_LIST_HEAD(&data->list); - - down(&pmem[id].data_list_sem); - list_add(&data->list, &pmem[id].data_list); - up(&pmem[id].data_list_sem); - return ret; -} - -static unsigned long pmem_order(unsigned long len) -{ - int i; - - len = (len + PMEM_MIN_ALLOC - 1)/PMEM_MIN_ALLOC; - len--; - for (i = 0; i < sizeof(len)*8; i++) - if (len >> i == 0) - break; - return i; -} - -static int pmem_allocate(int id, unsigned long len) -{ - /* caller should hold the write lock on pmem_sem! */ - /* return the corresponding pdata[] entry */ - int curr = 0; - int end = pmem[id].num_entries; - int best_fit = -1; - unsigned long order = pmem_order(len); - - if (pmem[id].no_allocator) { - DLOG("no allocator"); - if ((len > pmem[id].size) || pmem[id].allocated) - return -1; - pmem[id].allocated = 1; - return len; - } - - if (order > PMEM_MAX_ORDER) - return -1; - DLOG("order %lx\n", order); - - /* look through the bitmap: - * if you find a free slot of the correct order use it - * otherwise, use the best fit (smallest with size > order) slot - */ - while (curr < end) { - if (PMEM_IS_FREE(id, curr)) { - if (PMEM_ORDER(id, curr) == (unsigned char)order) { - /* set the not free bit and clear others */ - best_fit = curr; - break; - } - if (PMEM_ORDER(id, curr) > (unsigned char)order && - (best_fit < 0 || - PMEM_ORDER(id, curr) < PMEM_ORDER(id, best_fit))) - best_fit = curr; - } - curr = PMEM_NEXT_INDEX(id, curr); - } - - /* if best_fit < 0, there are no suitable slots, - * return an error - */ - if (best_fit < 0) { - printk("pmem: no space left to allocate!\n"); - return -1; - } - - /* now partition the best fit: - * split the slot into 2 buddies of order - 1 - * repeat until the slot is of the correct order - */ - while (PMEM_ORDER(id, best_fit) > (unsigned char)order) { - int buddy; - PMEM_ORDER(id, best_fit) -= 1; - buddy = PMEM_BUDDY_INDEX(id, best_fit); - PMEM_ORDER(id, buddy) = PMEM_ORDER(id, best_fit); - } - pmem[id].bitmap[best_fit].allocated = 1; - return best_fit; -} - -static pgprot_t phys_mem_access_prot(struct file *file, pgprot_t vma_prot) -{ - int id = get_id(file); -#ifdef pgprot_noncached - if (pmem[id].cached == 0 || file->f_flags & O_SYNC) - return pgprot_noncached(vma_prot); -#endif -#ifdef pgprot_ext_buffered - else if (pmem[id].buffered) - return pgprot_ext_buffered(vma_prot); -#endif - return vma_prot; -} - -static unsigned long pmem_start_addr(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return PMEM_START_ADDR(id, 0); - else - return PMEM_START_ADDR(id, data->index); - -} - -static void *pmem_start_vaddr(int id, struct pmem_data *data) -{ - return pmem_start_addr(id, data) - pmem[id].base + pmem[id].vbase; -} - -static unsigned long pmem_len(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return data->index; - else - return PMEM_LEN(id, data->index); -} - -static int pmem_map_garbage(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int i, garbage_pages = len >> PAGE_SHIFT; - - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE; - for (i = 0; i < garbage_pages; i++) { - if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE), - pmem[id].garbage_pfn)) - return -EAGAIN; - } - return 0; -} - -static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int garbage_pages; - DLOG("unmap offset %lx len %lx\n", offset, len); - - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - - garbage_pages = len >> PAGE_SHIFT; - zap_page_range(vma, vma->vm_start + offset, len, NULL); - pmem_map_garbage(id, vma, data, offset, len); - return 0; -} - -static int pmem_map_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - DLOG("map offset %lx len %lx\n", offset, len); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset)); - - if (io_remap_pfn_range(vma, vma->vm_start + offset, - (pmem_start_addr(id, data) + offset) >> PAGE_SHIFT, - len, vma->vm_page_prot)) { - return -EAGAIN; - } - return 0; -} - -static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - /* hold the mm semp for the vma you are modifying when you call this */ - BUG_ON(!vma); - zap_page_range(vma, vma->vm_start + offset, len, NULL); - return pmem_map_pfn_range(id, vma, data, offset, len); -} - -static void pmem_vma_open(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - int id = get_id(file); - /* this should never be called as we don't support copying pmem - * ranges via fork */ - BUG_ON(!has_allocation(file)); - down_write(&data->sem); - /* remap the garbage pages, forkers don't get access to the data */ - pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end); - up_write(&data->sem); -} - -static void pmem_vma_close(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - - DLOG("current %u ppid %u file %p count %d\n", current->pid, - current->parent->pid, file, file_count(file)); - if (unlikely(!is_pmem_file(file) || !has_allocation(file))) { - printk(KERN_WARNING "pmem: something is very wrong, you are " - "closing a vm backing an allocation that doesn't " - "exist!\n"); - return; - } - down_write(&data->sem); - if (data->vma == vma) { - data->vma = NULL; - if ((data->flags & PMEM_FLAGS_CONNECTED) && - (data->flags & PMEM_FLAGS_SUBMAP)) - data->flags |= PMEM_FLAGS_UNSUBMAP; - } - /* the kernel is going to free this vma now anyway */ - up_write(&data->sem); -} - -static struct vm_operations_struct vm_ops = { - .open = pmem_vma_open, - .close = pmem_vma_close, -}; - -static int pmem_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct pmem_data *data; - int index; - unsigned long vma_size = vma->vm_end - vma->vm_start; - int ret = 0, id = get_id(file); - - if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: mmaps must be at offset zero, aligned" - " and a multiple of pages_size.\n"); -#endif - return -EINVAL; - } - - data = file->private_data; - down_write(&data->sem); - /* check this file isn't already mmaped, for submaps check this file - * has never been mmaped */ - if ((data->flags & PMEM_FLAGS_MASTERMAP) || - (data->flags & PMEM_FLAGS_SUBMAP) || - (data->flags & PMEM_FLAGS_UNSUBMAP)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: you can only mmap a pmem file once, " - "this file is already mmaped. %x\n", data->flags); -#endif - ret = -EINVAL; - goto error; - } - /* if file->private_data == unalloced, alloc*/ - if (data && data->index == -1) { - down_write(&pmem[id].bitmap_sem); - index = pmem_allocate(id, vma->vm_end - vma->vm_start); - up_write(&pmem[id].bitmap_sem); - data->index = index; - } - /* either no space was available or an error occured */ - if (!has_allocation(file)) { - ret = -EINVAL; - printk("pmem: could not find allocation for map.\n"); - goto error; - } - - if (pmem_len(id, data) < vma_size) { -#if PMEM_DEBUG - printk(KERN_WARNING "pmem: mmap size [%lu] does not match" - "size of backing region [%lu].\n", vma_size, - pmem_len(id, data)); -#endif - ret = -EINVAL; - goto error; - } - - vma->vm_pgoff = pmem_start_addr(id, data) >> PAGE_SHIFT; - vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_page_prot); - - if (data->flags & PMEM_FLAGS_CONNECTED) { - struct pmem_region_node *region_node; - struct list_head *elt; - if (pmem_map_garbage(id, vma, data, 0, vma_size)) { - printk("pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - DLOG("remapping file: %p %lx %lx\n", file, - region_node->region.offset, - region_node->region.len); - if (pmem_remap_pfn_range(id, vma, data, - region_node->region.offset, - region_node->region.len)) { - ret = -EAGAIN; - goto error; - } - } - data->flags |= PMEM_FLAGS_SUBMAP; - get_task_struct(current->group_leader); - data->task = current->group_leader; - data->vma = vma; -#if PMEM_DEBUG - data->pid = current->pid; -#endif - DLOG("submmapped file %p vma %p pid %u\n", file, vma, - current->pid); - } else { - if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) { - printk(KERN_INFO "pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - data->flags |= PMEM_FLAGS_MASTERMAP; - data->pid = current->pid; - } - vma->vm_ops = &vm_ops; -error: - up_write(&data->sem); - return ret; -} - -/* the following are the api for accessing pmem regions by other drivers - * from inside the kernel */ -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *len) -{ - struct pmem_data *data; - if (!is_pmem_file(file) || !has_allocation(file)) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from invalid" - "file.\n"); -#endif - return -1; - } - data = file->private_data; - down_read(&data->sem); - if (data->vma) { - *start = data->vma->vm_start; - *len = data->vma->vm_end - data->vma->vm_start; - } else { - *start = 0; - *len = 0; - } - up_read(&data->sem); - return 0; -} - -int get_pmem_addr(struct file *file, unsigned long *start, - unsigned long *vstart, unsigned long *len) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file) || !has_allocation(file)) - return -1; - - data = file->private_data; - if (data->index == -1) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from file with no " - "allocation.\n"); - return -1; -#endif - } - id = get_id(file); - - down_read(&data->sem); - *start = pmem_start_addr(id, data); - *len = pmem_len(id, data); - *vstart = (unsigned long)pmem_start_vaddr(id, data); - up_read(&data->sem); -#if PMEM_DEBUG - down_write(&data->sem); - data->ref++; - up_write(&data->sem); -#endif - return 0; -} - -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *len, struct file **filp) -{ - struct file *file; - - file = fget(fd); - if (unlikely(file == NULL)) { - printk(KERN_INFO "pmem: requested data from file descriptor " - "that doesn't exist."); - return -1; - } - - if (get_pmem_addr(file, start, vstart, len)) - goto end; - - if (filp) - *filp = file; - return 0; -end: - fput(file); - return -1; -} - -void put_pmem_file(struct file *file) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file)) - return; - id = get_id(file); - data = file->private_data; -#if PMEM_DEBUG - down_write(&data->sem); - if (data->ref == 0) { - printk("pmem: pmem_put > pmem_get %s (pid %d)\n", - pmem[id].dev.name, data->pid); - BUG(); - } - data->ref--; - up_write(&data->sem); -#endif - fput(file); -} - -void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len) -{ - struct pmem_data *data; - int id; - void *vaddr; - struct pmem_region_node *region_node; - struct list_head *elt; - void *flush_start, *flush_end; - - if (!is_pmem_file(file) || !has_allocation(file)) - return; - - id = get_id(file); - data = file->private_data; - if (!pmem[id].cached) - return; - - down_read(&data->sem); - vaddr = pmem_start_vaddr(id, data); - /* if this isn't a submmapped file, flush the whole thing */ - if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) { - dmac_flush_range(vaddr, vaddr + pmem_len(id, data)); - goto end; - } - /* otherwise, flush the region of the file we are drawing */ - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - if ((offset >= region_node->region.offset) && - ((offset + len) <= (region_node->region.offset + - region_node->region.len))) { - flush_start = vaddr + region_node->region.offset; - flush_end = flush_start + region_node->region.len; - dmac_flush_range(flush_start, flush_end); - break; - } - } -end: - up_read(&data->sem); -} - -static int pmem_connect(unsigned long connect, struct file *file) -{ - struct pmem_data *data = file->private_data; - struct pmem_data *src_data; - struct file *src_file; - int ret = 0, put_needed; - - down_write(&data->sem); - /* retrieve the src file and check it is a pmem file with an alloc */ - src_file = fget_light(connect, &put_needed); - DLOG("connect %p to %p\n", file, src_file); - if (!src_file) { - printk(KERN_INFO "pmem: src file not found!\n"); - ret = -EINVAL; - goto err_no_file; - } - if (unlikely(!is_pmem_file(src_file) || !has_allocation(src_file))) { - printk(KERN_INFO "pmem: src file is not a pmem file or has no " - "alloc!\n"); - ret = -EINVAL; - goto err_bad_file; - } - src_data = src_file->private_data; - - if (has_allocation(file) && (data->index != src_data->index)) { - printk(KERN_INFO "pmem: file is already mapped but doesn't " - "match this src_file!\n"); - ret = -EINVAL; - goto err_bad_file; - } - data->index = src_data->index; - data->flags |= PMEM_FLAGS_CONNECTED; - data->master_fd = connect; - data->master_file = src_file; - -err_bad_file: - fput_light(src_file, put_needed); -err_no_file: - up_write(&data->sem); - return ret; -} - -static void pmem_unlock_data_and_mm(struct pmem_data *data, - struct mm_struct *mm) -{ - up_write(&data->sem); - if (mm != NULL) { - up_write(&mm->mmap_sem); - mmput(mm); - } -} - -static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data, - struct mm_struct **locked_mm) -{ - int ret = 0; - struct mm_struct *mm = NULL; - *locked_mm = NULL; -lock_mm: - down_read(&data->sem); - if (PMEM_IS_SUBMAP(data)) { - mm = get_task_mm(data->task); - if (!mm) { -#if PMEM_DEBUG - printk(KERN_DEBUG "pmem: can't remap task is gone!\n"); -#endif - up_read(&data->sem); - return -1; - } - } - up_read(&data->sem); - - if (mm) - down_write(&mm->mmap_sem); - - down_write(&data->sem); - /* check that the file didn't get mmaped before we could take the - * data sem, this should be safe b/c you can only submap each file - * once */ - if (PMEM_IS_SUBMAP(data) && !mm) { - pmem_unlock_data_and_mm(data, mm); - up_write(&data->sem); - goto lock_mm; - } - /* now check that vma.mm is still there, it could have been - * deleted by vma_close before we could get the data->sem */ - if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) { - /* might as well release this */ - if (data->flags & PMEM_FLAGS_SUBMAP) { - put_task_struct(data->task); - data->task = NULL; - /* lower the submap flag to show the mm is gone */ - data->flags &= ~(PMEM_FLAGS_SUBMAP); - } - pmem_unlock_data_and_mm(data, mm); - return -1; - } - *locked_mm = mm; - return ret; -} - -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation) -{ - int ret; - struct pmem_region_node *region_node; - struct mm_struct *mm = NULL; - struct list_head *elt, *elt2; - int id = get_id(file); - struct pmem_data *data = file->private_data; - - /* pmem region must be aligned on a page boundry */ - if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) || - !PMEM_IS_PAGE_ALIGNED(region->len))) { -#if PMEM_DEBUG - printk(KERN_DEBUG "pmem: request for unaligned pmem " - "suballocation %lx %lx\n", region->offset, region->len); -#endif - return -EINVAL; - } - - /* if userspace requests a region of len 0, there's nothing to do */ - if (region->len == 0) - return 0; - - /* lock the mm and data */ - ret = pmem_lock_data_and_mm(file, data, &mm); - if (ret) - return 0; - - /* only the owner of the master file can remap the client fds - * that back in it */ - if (!is_master_owner(file)) { -#if PMEM_DEBUG - printk("pmem: remap requested from non-master process\n"); -#endif - ret = -EINVAL; - goto err; - } - - /* check that the requested range is within the src allocation */ - if (unlikely((region->offset > pmem_len(id, data)) || - (region->len > pmem_len(id, data)) || - (region->offset + region->len > pmem_len(id, data)))) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: suballoc doesn't fit in src_file!\n"); -#endif - ret = -EINVAL; - goto err; - } - - if (operation == PMEM_MAP) { - region_node = kmalloc(sizeof(struct pmem_region_node), - GFP_KERNEL); - if (!region_node) { - ret = -ENOMEM; -#if PMEM_DEBUG - printk(KERN_INFO "No space to allocate metadata!"); -#endif - goto err; - } - region_node->region = *region; - list_add(®ion_node->list, &data->region_list); - } else if (operation == PMEM_UNMAP) { - int found = 0; - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - if (region->len == 0 || - (region_node->region.offset == region->offset && - region_node->region.len == region->len)) { - list_del(elt); - kfree(region_node); - found = 1; - } - } - if (!found) { -#if PMEM_DEBUG - printk("pmem: Unmap region does not map any mapped " - "region!"); -#endif - ret = -EINVAL; - goto err; - } - } - - if (data->vma && PMEM_IS_SUBMAP(data)) { - if (operation == PMEM_MAP) - ret = pmem_remap_pfn_range(id, data->vma, data, - region->offset, region->len); - else if (operation == PMEM_UNMAP) - ret = pmem_unmap_pfn_range(id, data->vma, data, - region->offset, region->len); - } - -err: - pmem_unlock_data_and_mm(data, mm); - return ret; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data) -{ - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - struct mm_struct *mm = NULL; - int id = get_id(file); - int ret = 0; - - data->master_file = NULL; - ret = pmem_lock_data_and_mm(file, data, &mm); - /* if lock_data_and_mm fails either the task that mapped the fd, or - * the vma that mapped it have already gone away, nothing more - * needs to be done */ - if (ret) - return; - /* unmap everything */ - /* delete the regions and region list nothing is mapped any more */ - if (data->vma) - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - pmem_unmap_pfn_range(id, data->vma, data, - region_node->region.offset, - region_node->region.len); - list_del(elt); - kfree(region_node); - } - /* delete the master file */ - pmem_unlock_data_and_mm(data, mm); -} - -static void pmem_get_size(struct pmem_region *region, struct file *file) -{ - struct pmem_data *data = file->private_data; - int id = get_id(file); - - if (!has_allocation(file)) { - region->offset = 0; - region->len = 0; - return; - } else { - region->offset = pmem_start_addr(id, data); - region->len = pmem_len(id, data); - } - DLOG("offset %lx len %lx\n", region->offset, region->len); -} - - -static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct pmem_data *data; - int id = get_id(file); - - switch (cmd) { - case PMEM_GET_PHYS: - { - struct pmem_region region; - DLOG("get_phys\n"); - if (!has_allocation(file)) { - region.offset = 0; - region.len = 0; - } else { - data = file->private_data; - region.offset = pmem_start_addr(id, data); - region.len = pmem_len(id, data); - } - printk(KERN_INFO "pmem: request for physical address " - "of pmem region from process %d.\n", current->pid); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_MAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = file->private_data; - return pmem_remap(®ion, file, PMEM_MAP); - } - break; - case PMEM_UNMAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = file->private_data; - return pmem_remap(®ion, file, PMEM_UNMAP); - break; - } - case PMEM_GET_SIZE: - { - struct pmem_region region; - DLOG("get_size\n"); - pmem_get_size(®ion, file); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_GET_TOTAL_SIZE: - { - struct pmem_region region; - DLOG("get total size\n"); - region.offset = 0; - get_id(file); - region.len = pmem[id].size; - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_ALLOCATE: - { - if (has_allocation(file)) - return -EINVAL; - data = file->private_data; - data->index = pmem_allocate(id, arg); - break; - } - case PMEM_CONNECT: - DLOG("connect\n"); - return pmem_connect(arg, file); - break; - default: - if (pmem[id].ioctl) - return pmem[id].ioctl(file, cmd, arg); - return -EINVAL; - } - return 0; -} - -#if PMEM_DEBUG -static ssize_t debug_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t debug_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct list_head *elt, *elt2; - struct pmem_data *data; - struct pmem_region_node *region_node; - int id = (int)file->private_data; - const int debug_bufmax = 4096; - static char buffer[4096]; - int n = 0; - - DLOG("debug open\n"); - n = scnprintf(buffer, debug_bufmax, - "pid #: mapped regions (offset, len) (offset,len)...\n"); - - down(&pmem[id].data_list_sem); - list_for_each(elt, &pmem[id].data_list) { - data = list_entry(elt, struct pmem_data, list); - down_read(&data->sem); - n += scnprintf(buffer + n, debug_bufmax - n, "pid %u:", - data->pid); - list_for_each(elt2, &data->region_list) { - region_node = list_entry(elt2, struct pmem_region_node, - list); - n += scnprintf(buffer + n, debug_bufmax - n, - "(%lx,%lx) ", - region_node->region.offset, - region_node->region.len); - } - n += scnprintf(buffer + n, debug_bufmax - n, "\n"); - up_read(&data->sem); - } - up(&pmem[id].data_list_sem); - - n++; - buffer[n] = 0; - return simple_read_from_buffer(buf, count, ppos, buffer, n); -} - -static struct file_operations debug_fops = { - .read = debug_read, - .open = debug_open, - .llseek = default_llseek, -}; -#endif - -#if 0 -static struct miscdevice pmem_dev = { - .name = "pmem", - .fops = &pmem_fops, -}; -#endif - -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)) -{ - int err = 0; - int i, index = 0; - int id = id_count; - id_count++; - - pmem[id].no_allocator = pdata->no_allocator; - pmem[id].cached = pdata->cached; - pmem[id].buffered = pdata->buffered; - pmem[id].base = pdata->start; - pmem[id].size = pdata->size; - pmem[id].ioctl = ioctl; - pmem[id].release = release; - init_rwsem(&pmem[id].bitmap_sem); - sema_init(&pmem[id].data_list_sem, 1); - INIT_LIST_HEAD(&pmem[id].data_list); - pmem[id].dev.name = pdata->name; - pmem[id].dev.minor = id; - pmem[id].dev.fops = &pmem_fops; - printk(KERN_INFO "%s: %d init\n", pdata->name, pdata->cached); - - err = misc_register(&pmem[id].dev); - if (err) { - printk(KERN_ALERT "Unable to register pmem driver!\n"); - goto err_cant_register_device; - } - pmem[id].num_entries = pmem[id].size / PMEM_MIN_ALLOC; - - pmem[id].bitmap = kcalloc(pmem[id].num_entries, - sizeof(struct pmem_bits), GFP_KERNEL); - if (!pmem[id].bitmap) - goto err_no_mem_for_metadata; - - for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--) { - if ((pmem[id].num_entries) & 1<<i) { - PMEM_ORDER(id, index) = i; - index = PMEM_NEXT_INDEX(id, index); - } - } - - if (pmem[id].cached) - pmem[id].vbase = ioremap_cached(pmem[id].base, - pmem[id].size); -#ifdef ioremap_ext_buffered - else if (pmem[id].buffered) - pmem[id].vbase = ioremap_ext_buffered(pmem[id].base, - pmem[id].size); -#endif - else - pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size); - - if (pmem[id].vbase == 0) - goto error_cant_remap; - - pmem[id].garbage_pfn = page_to_pfn(alloc_page(GFP_KERNEL)); - if (pmem[id].no_allocator) - pmem[id].allocated = 0; - -#if PMEM_DEBUG - debugfs_create_file(pdata->name, S_IFREG | S_IRUGO, NULL, (void *)id, - &debug_fops); -#endif - return 0; -error_cant_remap: - kfree(pmem[id].bitmap); -err_no_mem_for_metadata: - misc_deregister(&pmem[id].dev); -err_cant_register_device: - return -1; -} - -static int pmem_probe(struct platform_device *pdev) -{ - struct android_pmem_platform_data *pdata; - - if (!pdev || !pdev->dev.platform_data) { - printk(KERN_ALERT "Unable to probe pmem!\n"); - return -1; - } - pdata = pdev->dev.platform_data; - return pmem_setup(pdata, NULL, NULL); -} - - -static int pmem_remove(struct platform_device *pdev) -{ - int id = pdev->id; - __free_page(pfn_to_page(pmem[id].garbage_pfn)); - misc_deregister(&pmem[id].dev); - return 0; -} - -static struct platform_driver pmem_driver = { - .probe = pmem_probe, - .remove = pmem_remove, - .driver = { .name = "android_pmem" } -}; - - -static int __init pmem_init(void) -{ - return platform_driver_register(&pmem_driver); -} - -static void __exit pmem_exit(void) -{ - platform_driver_unregister(&pmem_driver); -} - -module_init(pmem_init); -module_exit(pmem_exit); - diff --git a/drivers/staging/dream/qdsp5/Makefile b/drivers/staging/dream/qdsp5/Makefile deleted file mode 100644 index 44ae6b4b47ec..000000000000 --- a/drivers/staging/dream/qdsp5/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ccflags-y:=-Idrivers/staging/dream/include -obj-y += adsp.o -ifeq ($(CONFIG_MSM_AMSS_VERSION_6350),y) -obj-y += adsp_info.o -obj-y += audio_evrc.o audio_qcelp.o audio_amrnb.o audio_aac.o -else -obj-y += adsp_6225.o -endif - -obj-y += adsp_driver.o -obj-y += adsp_video_verify_cmd.o -obj-y += adsp_videoenc_verify_cmd.o -obj-y += adsp_jpeg_verify_cmd.o adsp_jpeg_patch_event.o -obj-y += adsp_vfe_verify_cmd.o adsp_vfe_patch_event.o -obj-y += adsp_lpm_verify_cmd.o -obj-y += audio_out.o audio_in.o audio_mp3.o audmgr.o audpp.o -obj-y += snd.o - diff --git a/drivers/staging/dream/qdsp5/adsp.c b/drivers/staging/dream/qdsp5/adsp.c deleted file mode 100644 index f1e9d81674e8..000000000000 --- a/drivers/staging/dream/qdsp5/adsp.c +++ /dev/null @@ -1,1159 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp.c - * - * Register/Interrupt access for userspace aDSP library. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * Author: Iliyan Malchev <ibm@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -/* TODO: - * - move shareable rpc code outside of adsp.c - * - general solution for virt->phys patchup - * - queue IDs should be relative to modules - * - disallow access to non-associated queues - */ - -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/wait.h> - -static inline void prevent_suspend(void) -{ -} -static inline void allow_suspend(void) -{ -} - -#include <linux/io.h> -#include <mach/msm_iomap.h> -#include "adsp.h" - -#define INT_ADSP INT_ADSP_A9_A11 - -static struct adsp_info adsp_info; -static struct msm_rpc_endpoint *rpc_cb_server_client; -static struct msm_adsp_module *adsp_modules; -static int adsp_open_count; -static DEFINE_MUTEX(adsp_open_lock); - -/* protect interactions with the ADSP command/message queue */ -static spinlock_t adsp_cmd_lock; - -static uint32_t current_image = -1; - -void adsp_set_image(struct adsp_info *info, uint32_t image) -{ - current_image = image; -} - -/* - * Checks whether the module_id is available in the - * module_entries table.If module_id is available returns `0`. - * If module_id is not available returns `-ENXIO`. - */ -#if CONFIG_MSM_AMSS_VERSION >= 6350 -static int32_t adsp_validate_module(uint32_t module_id) -{ - uint32_t *ptr; - uint32_t module_index; - uint32_t num_mod_entries; - - ptr = adsp_info.init_info_ptr->module_entries; - num_mod_entries = adsp_info.init_info_ptr->module_table_size; - - for (module_index = 0; module_index < num_mod_entries; module_index++) - if (module_id == ptr[module_index]) - return 0; - - return -ENXIO; -} -#else -static inline int32_t adsp_validate_module(uint32_t module_id) { return 0; } -#endif - -uint32_t adsp_get_module(struct adsp_info *info, uint32_t task) -{ - BUG_ON(current_image == -1UL); - return info->task_to_module[current_image][task]; -} - -uint32_t adsp_get_queue_offset(struct adsp_info *info, uint32_t queue_id) -{ - BUG_ON(current_image == -1UL); - return info->queue_offset[current_image][queue_id]; -} - -static int rpc_adsp_rtos_app_to_modem(uint32_t cmd, uint32_t module, - struct msm_adsp_module *adsp_module) -{ - int rc; - struct rpc_adsp_rtos_app_to_modem_args_t rpc_req; - struct rpc_reply_hdr *rpc_rsp; - - msm_rpc_setup_req(&rpc_req.hdr, - RPC_ADSP_RTOS_ATOM_PROG, - msm_rpc_get_vers(adsp_module->rpc_client), - RPC_ADSP_RTOS_APP_TO_MODEM_PROC); - - rpc_req.gotit = cpu_to_be32(1); - rpc_req.cmd = cpu_to_be32(cmd); - rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS); - rpc_req.module = cpu_to_be32(module); - rc = msm_rpc_write(adsp_module->rpc_client, &rpc_req, sizeof(rpc_req)); - if (rc < 0) { - pr_err("adsp: could not send RPC request: %d\n", rc); - return rc; - } - - rc = msm_rpc_read(adsp_module->rpc_client, - (void **)&rpc_rsp, -1, (5*HZ)); - if (rc < 0) { - pr_err("adsp: error receiving RPC reply: %d (%d)\n", - rc, -ERESTARTSYS); - return rc; - } - - if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) { - pr_err("adsp: RPC call was denied!\n"); - kfree(rpc_rsp); - return -EPERM; - } - - if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) != - RPC_ACCEPTSTAT_SUCCESS) { - pr_err("adsp error: RPC call was not successful (%d)\n", - be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat)); - kfree(rpc_rsp); - return -EINVAL; - } - - kfree(rpc_rsp); - return 0; -} - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -static int get_module_index(uint32_t id) -{ - int mod_idx; - for (mod_idx = 0; mod_idx < adsp_info.module_count; mod_idx++) - if (adsp_info.module[mod_idx].id == id) - return mod_idx; - - return -ENXIO; -} -#endif - -static struct msm_adsp_module *find_adsp_module_by_id( - struct adsp_info *info, uint32_t id) -{ - if (id > info->max_module_id) { - return NULL; - } else { -#if CONFIG_MSM_AMSS_VERSION >= 6350 - id = get_module_index(id); - if (id < 0) - return NULL; -#endif - return info->id_to_module[id]; - } -} - -static struct msm_adsp_module *find_adsp_module_by_name( - struct adsp_info *info, const char *name) -{ - unsigned n; - for (n = 0; n < info->module_count; n++) - if (!strcmp(name, adsp_modules[n].name)) - return adsp_modules + n; - return NULL; -} - -static int adsp_rpc_init(struct msm_adsp_module *adsp_module) -{ - /* remove the original connect once compatible support is complete */ - adsp_module->rpc_client = msm_rpc_connect( - RPC_ADSP_RTOS_ATOM_PROG, - RPC_ADSP_RTOS_ATOM_VERS, - MSM_RPC_UNINTERRUPTIBLE); - - if (IS_ERR(adsp_module->rpc_client)) { - int rc = PTR_ERR(adsp_module->rpc_client); - adsp_module->rpc_client = 0; - pr_err("adsp: could not open rpc client: %d\n", rc); - return rc; - } - - return 0; -} - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -/* - * Send RPC_ADSP_RTOS_CMD_GET_INIT_INFO cmd to ARM9 and get - * queue offsets and module entries (init info) as part of the event. - */ -static void msm_get_init_info(void) -{ - int rc; - struct rpc_adsp_rtos_app_to_modem_args_t rpc_req; - - adsp_info.init_info_rpc_client = msm_rpc_connect( - RPC_ADSP_RTOS_ATOM_PROG, - RPC_ADSP_RTOS_ATOM_VERS, - MSM_RPC_UNINTERRUPTIBLE); - if (IS_ERR(adsp_info.init_info_rpc_client)) { - rc = PTR_ERR(adsp_info.init_info_rpc_client); - adsp_info.init_info_rpc_client = 0; - pr_err("adsp: could not open rpc client: %d\n", rc); - return; - } - - msm_rpc_setup_req(&rpc_req.hdr, - RPC_ADSP_RTOS_ATOM_PROG, - msm_rpc_get_vers(adsp_info.init_info_rpc_client), - RPC_ADSP_RTOS_APP_TO_MODEM_PROC); - - rpc_req.gotit = cpu_to_be32(1); - rpc_req.cmd = cpu_to_be32(RPC_ADSP_RTOS_CMD_GET_INIT_INFO); - rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS); - rpc_req.module = 0; - - rc = msm_rpc_write(adsp_info.init_info_rpc_client, - &rpc_req, sizeof(rpc_req)); - if (rc < 0) - pr_err("adsp: could not send RPC request: %d\n", rc); -} -#endif - -int msm_adsp_get(const char *name, struct msm_adsp_module **out, - struct msm_adsp_ops *ops, void *driver_data) -{ - struct msm_adsp_module *module; - int rc = 0; - -#if CONFIG_MSM_AMSS_VERSION >= 6350 - static uint32_t init_info_cmd_sent; - if (!init_info_cmd_sent) { - msm_get_init_info(); - init_waitqueue_head(&adsp_info.init_info_wait); - rc = wait_event_timeout(adsp_info.init_info_wait, - adsp_info.init_info_state == ADSP_STATE_INIT_INFO, - 5 * HZ); - if (!rc) { - pr_info("adsp: INIT_INFO failed\n"); - return -ETIMEDOUT; - } - init_info_cmd_sent++; - } -#endif - - module = find_adsp_module_by_name(&adsp_info, name); - if (!module) - return -ENODEV; - - mutex_lock(&module->lock); - pr_info("adsp: opening module %s\n", module->name); - if (module->open_count++ == 0 && module->clk) - clk_enable(module->clk); - - mutex_lock(&adsp_open_lock); - if (adsp_open_count++ == 0) { - enable_irq(INT_ADSP); - prevent_suspend(); - } - mutex_unlock(&adsp_open_lock); - - if (module->ops) { - rc = -EBUSY; - goto done; - } - - rc = adsp_rpc_init(module); - if (rc) - goto done; - - module->ops = ops; - module->driver_data = driver_data; - *out = module; - rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_REGISTER_APP, - module->id, module); - if (rc) { - module->ops = NULL; - module->driver_data = NULL; - *out = NULL; - pr_err("adsp: REGISTER_APP failed\n"); - goto done; - } - - pr_info("adsp: module %s has been registered\n", module->name); - -done: - mutex_lock(&adsp_open_lock); - if (rc && --adsp_open_count == 0) { - disable_irq(INT_ADSP); - allow_suspend(); - } - if (rc && --module->open_count == 0 && module->clk) - clk_disable(module->clk); - mutex_unlock(&adsp_open_lock); - mutex_unlock(&module->lock); - return rc; -} -EXPORT_SYMBOL(msm_adsp_get); - -static int msm_adsp_disable_locked(struct msm_adsp_module *module); - -void msm_adsp_put(struct msm_adsp_module *module) -{ - unsigned long flags; - - mutex_lock(&module->lock); - if (--module->open_count == 0 && module->clk) - clk_disable(module->clk); - if (module->ops) { - pr_info("adsp: closing module %s\n", module->name); - - /* lock to ensure a dsp event cannot be delivered - * during or after removal of the ops and driver_data - */ - spin_lock_irqsave(&adsp_cmd_lock, flags); - module->ops = NULL; - module->driver_data = NULL; - spin_unlock_irqrestore(&adsp_cmd_lock, flags); - - if (module->state != ADSP_STATE_DISABLED) { - pr_info("adsp: disabling module %s\n", module->name); - msm_adsp_disable_locked(module); - } - - msm_rpc_close(module->rpc_client); - module->rpc_client = 0; - if (--adsp_open_count == 0) { - disable_irq(INT_ADSP); - allow_suspend(); - pr_info("adsp: disable interrupt\n"); - } - } else { - pr_info("adsp: module %s is already closed\n", module->name); - } - mutex_unlock(&module->lock); -} -EXPORT_SYMBOL(msm_adsp_put); - -/* this should be common code with rpc_servers.c */ -static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client, - uint32_t xid, uint32_t accept_status) -{ - int rc = 0; - uint8_t reply_buf[sizeof(struct rpc_reply_hdr)]; - struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf; - - reply->xid = cpu_to_be32(xid); - reply->type = cpu_to_be32(1); /* reply */ - reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED); - - reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status); - reply->data.acc_hdr.verf_flavor = 0; - reply->data.acc_hdr.verf_length = 0; - - rc = msm_rpc_write(rpc_cb_server_client, reply_buf, sizeof(reply_buf)); - if (rc < 0) - pr_err("adsp: could not write RPC response: %d\n", rc); - return rc; -} - -int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr, - void *cmd_buf, size_t cmd_size) -{ - uint32_t ctrl_word; - uint32_t dsp_q_addr; - uint32_t dsp_addr; - uint32_t cmd_id = 0; - int cnt = 0; - int ret_status = 0; - unsigned long flags; - struct adsp_info *info = module->info; - - spin_lock_irqsave(&adsp_cmd_lock, flags); - - if (module->state != ADSP_STATE_ENABLED) { - spin_unlock_irqrestore(&adsp_cmd_lock, flags); - pr_err("adsp: module %s not enabled before write\n", - module->name); - return -ENODEV; - } - if (adsp_validate_module(module->id)) { - spin_unlock_irqrestore(&adsp_cmd_lock, flags); - pr_info("adsp: module id validation failed %s %d\n", - module->name, module->id); - return -ENXIO; - } - dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr); - dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M; - - /* Poll until the ADSP is ready to accept a command. - * Wait for 100us, return error if it's not responding. - * If this returns an error, we need to disable ALL modules and - * then retry. - */ - while (((ctrl_word = readl(info->write_ctrl)) & - ADSP_RTOS_WRITE_CTRL_WORD_READY_M) != - ADSP_RTOS_WRITE_CTRL_WORD_READY_V) { - if (cnt > 100) { - pr_err("adsp: timeout waiting for DSP write ready\n"); - ret_status = -EIO; - goto fail; - } - pr_warning("adsp: waiting for DSP write ready\n"); - udelay(1); - cnt++; - } - - /* Set the mutex bits */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M); - ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V; - - /* Clear the command bits */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M); - - /* Set the queue address bits */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M); - ctrl_word |= dsp_q_addr; - - writel(ctrl_word, info->write_ctrl); - - /* Generate an interrupt to the DSP. This notifies the DSP that - * we are about to send a command on this particular queue. The - * DSP will in response change its state. - */ - writel(1, info->send_irq); - - /* Poll until the adsp responds to the interrupt; this does not - * generate an interrupt from the adsp. This should happen within - * 5ms. - */ - cnt = 0; - while ((readl(info->write_ctrl) & - ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) == - ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) { - if (cnt > 5000) { - pr_err("adsp: timeout waiting for adsp ack\n"); - ret_status = -EIO; - goto fail; - } - udelay(1); - cnt++; - } - - /* Read the ctrl word */ - ctrl_word = readl(info->write_ctrl); - - if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) != - ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) { - ret_status = -EAGAIN; - goto fail; - } - - /* Ctrl word status bits were 00, no error in the ctrl word */ - - /* Get the DSP buffer address */ - dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) + - (uint32_t)MSM_AD5_BASE; - - if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) { - uint16_t *buf_ptr = (uint16_t *) cmd_buf; - uint16_t *dsp_addr16 = (uint16_t *)dsp_addr; - cmd_size /= sizeof(uint16_t); - - /* Save the command ID */ - cmd_id = (uint32_t) buf_ptr[0]; - - /* Copy the command to DSP memory */ - cmd_size++; - while (--cmd_size) - *dsp_addr16++ = *buf_ptr++; - } else { - uint32_t *buf_ptr = (uint32_t *) cmd_buf; - uint32_t *dsp_addr32 = (uint32_t *)dsp_addr; - cmd_size /= sizeof(uint32_t); - - /* Save the command ID */ - cmd_id = buf_ptr[0]; - - cmd_size++; - while (--cmd_size) - *dsp_addr32++ = *buf_ptr++; - } - - /* Set the mutex bits */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M); - ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V; - - /* Set the command bits to write done */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M); - ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V; - - /* Set the queue address bits */ - ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M); - ctrl_word |= dsp_q_addr; - - writel(ctrl_word, info->write_ctrl); - - /* Generate an interrupt to the DSP. It does not respond with - * an interrupt, and we do not need to wait for it to - * acknowledge, because it will hold the mutex lock until it's - * ready to receive more commands again. - */ - writel(1, info->send_irq); - - module->num_commands++; - -fail: - spin_unlock_irqrestore(&adsp_cmd_lock, flags); - return ret_status; -} -EXPORT_SYMBOL(msm_adsp_write); - -int msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr, - void *cmd_buf, size_t cmd_size) -{ - int rc, retries = 0; - do { - rc = __msm_adsp_write(module, dsp_queue_addr, cmd_buf, cmd_size); - if (rc == -EAGAIN) - udelay(10); - } while(rc == -EAGAIN && retries++ < 100); - if (retries > 50) - pr_warning("adsp: %s command took %d attempts: rc %d\n", - module->name, retries, rc); - return rc; -} - -#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS -static void *modem_event_addr; -#if CONFIG_MSM_AMSS_VERSION >= 6350 -static void read_modem_event(void *buf, size_t len) -{ - uint32_t *dptr = buf; - struct rpc_adsp_rtos_modem_to_app_args_t *sptr; - struct adsp_rtos_mp_mtoa_type *pkt_ptr; - - sptr = modem_event_addr; - pkt_ptr = &sptr->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet; - - dptr[0] = be32_to_cpu(sptr->mtoa_pkt.mp_mtoa_header.event); - dptr[1] = be32_to_cpu(pkt_ptr->module); - dptr[2] = be32_to_cpu(pkt_ptr->image); -} -#else -static void read_modem_event(void *buf, size_t len) -{ - uint32_t *dptr = buf; - struct rpc_adsp_rtos_modem_to_app_args_t *sptr = - modem_event_addr; - dptr[0] = be32_to_cpu(sptr->event); - dptr[1] = be32_to_cpu(sptr->module); - dptr[2] = be32_to_cpu(sptr->image); -} -#endif /* CONFIG_MSM_AMSS_VERSION >= 6350 */ -#endif /* CONFIG_MSM_ADSP_REPORT_EVENTS */ - -static void handle_adsp_rtos_mtoa_app(struct rpc_request_hdr *req) -{ - struct rpc_adsp_rtos_modem_to_app_args_t *args = - (struct rpc_adsp_rtos_modem_to_app_args_t *)req; - uint32_t event; - uint32_t proc_id; - uint32_t module_id; - uint32_t image; - struct msm_adsp_module *module; -#if CONFIG_MSM_AMSS_VERSION >= 6350 - struct adsp_rtos_mp_mtoa_type *pkt_ptr = - &args->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet; - - event = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.event); - proc_id = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.proc_id); - module_id = be32_to_cpu(pkt_ptr->module); - image = be32_to_cpu(pkt_ptr->image); - - if (be32_to_cpu(args->mtoa_pkt.desc_field) == RPC_ADSP_RTOS_INIT_INFO) { - struct queue_to_offset_type *qptr; - struct queue_to_offset_type *qtbl; - uint32_t *mptr; - uint32_t *mtbl; - uint32_t q_idx; - uint32_t num_entries; - uint32_t entries_per_image; - struct adsp_rtos_mp_mtoa_init_info_type *iptr; - struct adsp_rtos_mp_mtoa_init_info_type *sptr; - int32_t i_no, e_idx; - - pr_info("adsp:INIT_INFO Event\n"); - sptr = &args->mtoa_pkt.adsp_rtos_mp_mtoa_data. - mp_mtoa_init_packet; - - iptr = adsp_info.init_info_ptr; - iptr->image_count = be32_to_cpu(sptr->image_count); - iptr->num_queue_offsets = be32_to_cpu(sptr->num_queue_offsets); - num_entries = iptr->num_queue_offsets; - qptr = &sptr->queue_offsets_tbl[0][0]; - for (i_no = 0; i_no < iptr->image_count; i_no++) { - qtbl = &iptr->queue_offsets_tbl[i_no][0]; - for (e_idx = 0; e_idx < num_entries; e_idx++) { - qtbl[e_idx].offset = be32_to_cpu(qptr->offset); - qtbl[e_idx].queue = be32_to_cpu(qptr->queue); - q_idx = be32_to_cpu(qptr->queue); - iptr->queue_offsets[i_no][q_idx] = - qtbl[e_idx].offset; - qptr++; - } - } - - num_entries = be32_to_cpu(sptr->num_task_module_entries); - iptr->num_task_module_entries = num_entries; - entries_per_image = num_entries / iptr->image_count; - mptr = &sptr->task_to_module_tbl[0][0]; - for (i_no = 0; i_no < iptr->image_count; i_no++) { - mtbl = &iptr->task_to_module_tbl[i_no][0]; - for (e_idx = 0; e_idx < entries_per_image; e_idx++) { - mtbl[e_idx] = be32_to_cpu(*mptr); - mptr++; - } - } - - iptr->module_table_size = be32_to_cpu(sptr->module_table_size); - mptr = &sptr->module_entries[0]; - for (i_no = 0; i_no < iptr->module_table_size; i_no++) - iptr->module_entries[i_no] = be32_to_cpu(mptr[i_no]); - adsp_info.init_info_state = ADSP_STATE_INIT_INFO; - rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid, - RPC_ACCEPTSTAT_SUCCESS); - wake_up(&adsp_info.init_info_wait); - - return; - } -#else - event = be32_to_cpu(args->event); - proc_id = be32_to_cpu(args->proc_id); - module_id = be32_to_cpu(args->module); - image = be32_to_cpu(args->image); -#endif - - pr_info("adsp: rpc event=%d, proc_id=%d, module=%d, image=%d\n", - event, proc_id, module_id, image); - - module = find_adsp_module_by_id(&adsp_info, module_id); - if (!module) { - pr_err("adsp: module %d is not supported!\n", module_id); - rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid, - RPC_ACCEPTSTAT_GARBAGE_ARGS); - return; - } - - mutex_lock(&module->lock); - switch (event) { - case RPC_ADSP_RTOS_MOD_READY: - pr_info("adsp: module %s: READY\n", module->name); - module->state = ADSP_STATE_ENABLED; - wake_up(&module->state_wait); - adsp_set_image(module->info, image); - break; - case RPC_ADSP_RTOS_MOD_DISABLE: - pr_info("adsp: module %s: DISABLED\n", module->name); - module->state = ADSP_STATE_DISABLED; - wake_up(&module->state_wait); - break; - case RPC_ADSP_RTOS_SERVICE_RESET: - pr_info("adsp: module %s: SERVICE_RESET\n", module->name); - module->state = ADSP_STATE_DISABLED; - wake_up(&module->state_wait); - break; - case RPC_ADSP_RTOS_CMD_SUCCESS: - pr_info("adsp: module %s: CMD_SUCCESS\n", module->name); - break; - case RPC_ADSP_RTOS_CMD_FAIL: - pr_info("adsp: module %s: CMD_FAIL\n", module->name); - break; -#if CONFIG_MSM_AMSS_VERSION >= 6350 - case RPC_ADSP_RTOS_DISABLE_FAIL: - pr_info("adsp: module %s: DISABLE_FAIL\n", module->name); - break; -#endif - default: - pr_info("adsp: unknown event %d\n", event); - rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid, - RPC_ACCEPTSTAT_GARBAGE_ARGS); - mutex_unlock(&module->lock); - return; - } - rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid, - RPC_ACCEPTSTAT_SUCCESS); - mutex_unlock(&module->lock); -#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS - modem_event_addr = (uint32_t *)req; - module->ops->event(module->driver_data, EVENT_MSG_ID, - EVENT_LEN, read_modem_event); -#endif -} - -static int handle_adsp_rtos_mtoa(struct rpc_request_hdr *req) -{ - switch (req->procedure) { - case RPC_ADSP_RTOS_MTOA_NULL_PROC: - rpc_send_accepted_void_reply(rpc_cb_server_client, - req->xid, - RPC_ACCEPTSTAT_SUCCESS); - break; - case RPC_ADSP_RTOS_MODEM_TO_APP_PROC: - handle_adsp_rtos_mtoa_app(req); - break; - default: - pr_err("adsp: unknowned proc %d\n", req->procedure); - rpc_send_accepted_void_reply( - rpc_cb_server_client, req->xid, - RPC_ACCEPTSTAT_PROC_UNAVAIL); - break; - } - return 0; -} - -/* this should be common code with rpc_servers.c */ -static int adsp_rpc_thread(void *data) -{ - void *buffer; - struct rpc_request_hdr *req; - int rc; - - do { - rc = msm_rpc_read(rpc_cb_server_client, &buffer, -1, -1); - if (rc < 0) { - pr_err("adsp: could not read rpc: %d\n", rc); - break; - } - req = (struct rpc_request_hdr *)buffer; - - req->type = be32_to_cpu(req->type); - req->xid = be32_to_cpu(req->xid); - req->rpc_vers = be32_to_cpu(req->rpc_vers); - req->prog = be32_to_cpu(req->prog); - req->vers = be32_to_cpu(req->vers); - req->procedure = be32_to_cpu(req->procedure); - - if (req->type != 0) - goto bad_rpc; - if (req->rpc_vers != 2) - goto bad_rpc; - if (req->prog != RPC_ADSP_RTOS_MTOA_PROG) - goto bad_rpc; - if (req->vers != RPC_ADSP_RTOS_MTOA_VERS) - goto bad_rpc; - - handle_adsp_rtos_mtoa(req); - kfree(buffer); - continue; - -bad_rpc: - pr_err("adsp: bogus rpc from modem\n"); - kfree(buffer); - } while (1); - - do_exit(0); -} - -static size_t read_event_size; -static void *read_event_addr; - -static void read_event_16(void *buf, size_t len) -{ - uint16_t *dst = buf; - uint16_t *src = read_event_addr; - len /= 2; - if (len > read_event_size) - len = read_event_size; - while (len--) - *dst++ = *src++; -} - -static void read_event_32(void *buf, size_t len) -{ - uint32_t *dst = buf; - uint32_t *src = read_event_addr; - len /= 2; - if (len > read_event_size) - len = read_event_size; - while (len--) - *dst++ = *src++; -} - -static int adsp_rtos_read_ctrl_word_cmd_tast_to_h_v( - struct adsp_info *info, void *dsp_addr) -{ - struct msm_adsp_module *module; - unsigned rtos_task_id; - unsigned msg_id; - unsigned msg_length; - void (*func)(void *, size_t); - - if (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) { - uint32_t *dsp_addr32 = dsp_addr; - uint32_t tmp = *dsp_addr32++; - rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8; - msg_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M); - read_event_size = tmp >> 16; - read_event_addr = dsp_addr32; - msg_length = read_event_size * sizeof(uint32_t); - func = read_event_32; - } else { - uint16_t *dsp_addr16 = dsp_addr; - uint16_t tmp = *dsp_addr16++; - rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8; - msg_id = tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M; - read_event_size = *dsp_addr16++; - read_event_addr = dsp_addr16; - msg_length = read_event_size * sizeof(uint16_t); - func = read_event_16; - } - - if (rtos_task_id > info->max_task_id) { - pr_err("adsp: bogus task id %d\n", rtos_task_id); - return 0; - } - module = find_adsp_module_by_id(info, - adsp_get_module(info, rtos_task_id)); - - if (!module) { - pr_err("adsp: no module for task id %d\n", rtos_task_id); - return 0; - } - - module->num_events++; - - if (!module->ops) { - pr_err("adsp: module %s is not open\n", module->name); - return 0; - } - - module->ops->event(module->driver_data, msg_id, msg_length, func); - return 0; -} - -static int adsp_get_event(struct adsp_info *info) -{ - uint32_t ctrl_word; - uint32_t ready; - void *dsp_addr; - uint32_t cmd_type; - int cnt; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&adsp_cmd_lock, flags); - - /* Whenever the DSP has a message, it updates this control word - * and generates an interrupt. When we receive the interrupt, we - * read this register to find out what ADSP task the command is - * comming from. - * - * The ADSP should *always* be ready on the first call, but the - * irq handler calls us in a loop (to handle back-to-back command - * processing), so we give the DSP some time to return to the - * ready state. The DSP will not issue another IRQ for events - * pending between the first IRQ and the event queue being drained, - * unfortunately. - */ - - for (cnt = 0; cnt < 10; cnt++) { - ctrl_word = readl(info->read_ctrl); - - if ((ctrl_word & ADSP_RTOS_READ_CTRL_WORD_FLAG_M) == - ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V) - goto ready; - - udelay(10); - } - pr_warning("adsp: not ready after 100uS\n"); - rc = -EBUSY; - goto done; - -ready: - /* Here we check to see if there are pending messages. If there are - * none, we siply return -EAGAIN to indicate that there are no more - * messages pending. - */ - ready = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_READY_M; - if ((ready != ADSP_RTOS_READ_CTRL_WORD_READY_V) && - (ready != ADSP_RTOS_READ_CTRL_WORD_CONT_V)) { - rc = -EAGAIN; - goto done; - } - - /* DSP says that there are messages waiting for the host to read */ - - /* Get the Command Type */ - cmd_type = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M; - - /* Get the DSP buffer address */ - dsp_addr = (void *)((ctrl_word & - ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M) + - (uint32_t)MSM_AD5_BASE); - - /* We can only handle Task-to-Host messages */ - if (cmd_type != ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V) { - pr_err("adsp: unknown dsp cmd_type %d\n", cmd_type); - rc = -EIO; - goto done; - } - - adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(info, dsp_addr); - - ctrl_word = readl(info->read_ctrl); - ctrl_word &= ~ADSP_RTOS_READ_CTRL_WORD_READY_M; - - /* Write ctrl word to the DSP */ - writel(ctrl_word, info->read_ctrl); - - /* Generate an interrupt to the DSP */ - writel(1, info->send_irq); - -done: - spin_unlock_irqrestore(&adsp_cmd_lock, flags); - return rc; -} - -static irqreturn_t adsp_irq_handler(int irq, void *data) -{ - struct adsp_info *info = &adsp_info; - int cnt = 0; - for (cnt = 0; cnt < 10; cnt++) - if (adsp_get_event(info) < 0) - break; - if (cnt > info->event_backlog_max) - info->event_backlog_max = cnt; - info->events_received += cnt; - if (cnt == 10) - pr_err("adsp: too many (%d) events for single irq!\n", cnt); - return IRQ_HANDLED; -} - -int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate) -{ - if (module->clk && clk_rate) - return clk_set_rate(module->clk, clk_rate); - - return -EINVAL; -} - -int msm_adsp_enable(struct msm_adsp_module *module) -{ - int rc = 0; - - pr_info("msm_adsp_enable() '%s'state[%d] id[%d]\n", - module->name, module->state, module->id); - - mutex_lock(&module->lock); - switch (module->state) { - case ADSP_STATE_DISABLED: - rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_ENABLE, - module->id, module); - if (rc) - break; - module->state = ADSP_STATE_ENABLING; - mutex_unlock(&module->lock); - rc = wait_event_timeout(module->state_wait, - module->state != ADSP_STATE_ENABLING, - 1 * HZ); - mutex_lock(&module->lock); - if (module->state == ADSP_STATE_ENABLED) { - rc = 0; - } else { - pr_err("adsp: module '%s' enable timed out\n", - module->name); - rc = -ETIMEDOUT; - } - break; - case ADSP_STATE_ENABLING: - pr_warning("adsp: module '%s' enable in progress\n", - module->name); - break; - case ADSP_STATE_ENABLED: - pr_warning("adsp: module '%s' already enabled\n", - module->name); - break; - case ADSP_STATE_DISABLING: - pr_err("adsp: module '%s' disable in progress\n", - module->name); - rc = -EBUSY; - break; - } - mutex_unlock(&module->lock); - return rc; -} -EXPORT_SYMBOL(msm_adsp_enable); - -static int msm_adsp_disable_locked(struct msm_adsp_module *module) -{ - int rc = 0; - - switch (module->state) { - case ADSP_STATE_DISABLED: - pr_warning("adsp: module '%s' already disabled\n", - module->name); - break; - case ADSP_STATE_ENABLING: - case ADSP_STATE_ENABLED: - rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE, - module->id, module); - module->state = ADSP_STATE_DISABLED; - } - return rc; -} - -int msm_adsp_disable(struct msm_adsp_module *module) -{ - int rc; - pr_info("msm_adsp_disable() '%s'\n", module->name); - mutex_lock(&module->lock); - rc = msm_adsp_disable_locked(module); - mutex_unlock(&module->lock); - return rc; -} -EXPORT_SYMBOL(msm_adsp_disable); - -static int msm_adsp_probe(struct platform_device *pdev) -{ - unsigned count; - int rc, i; - int max_module_id; - - pr_info("adsp: probe\n"); - -#if CONFIG_MSM_AMSS_VERSION >= 6350 - adsp_info.init_info_ptr = kzalloc( - (sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL); - if (!adsp_info.init_info_ptr) - return -ENOMEM; -#endif - - rc = adsp_init_info(&adsp_info); - if (rc) - return rc; - adsp_info.send_irq += (uint32_t) MSM_AD5_BASE; - adsp_info.read_ctrl += (uint32_t) MSM_AD5_BASE; - adsp_info.write_ctrl += (uint32_t) MSM_AD5_BASE; - count = adsp_info.module_count; - -#if CONFIG_MSM_AMSS_VERSION >= 6350 - max_module_id = count; -#else - max_module_id = adsp_info.max_module_id + 1; -#endif - - adsp_modules = kzalloc( - sizeof(struct msm_adsp_module) * count + - sizeof(void *) * max_module_id, GFP_KERNEL); - if (!adsp_modules) - return -ENOMEM; - - adsp_info.id_to_module = (void *) (adsp_modules + count); - - spin_lock_init(&adsp_cmd_lock); - - rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING, - "adsp", 0); - if (rc < 0) - goto fail_request_irq; - disable_irq(INT_ADSP); - - rpc_cb_server_client = msm_rpc_open(); - if (IS_ERR(rpc_cb_server_client)) { - rpc_cb_server_client = NULL; - rc = PTR_ERR(rpc_cb_server_client); - pr_err("adsp: could not create rpc server (%d)\n", rc); - goto fail_rpc_open; - } - - rc = msm_rpc_register_server(rpc_cb_server_client, - RPC_ADSP_RTOS_MTOA_PROG, - RPC_ADSP_RTOS_MTOA_VERS); - if (rc) { - pr_err("adsp: could not register callback server (%d)\n", rc); - goto fail_rpc_register; - } - - /* start the kernel thread to process the callbacks */ - kthread_run(adsp_rpc_thread, NULL, "kadspd"); - - for (i = 0; i < count; i++) { - struct msm_adsp_module *mod = adsp_modules + i; - mutex_init(&mod->lock); - init_waitqueue_head(&mod->state_wait); - mod->info = &adsp_info; - mod->name = adsp_info.module[i].name; - mod->id = adsp_info.module[i].id; - if (adsp_info.module[i].clk_name) - mod->clk = clk_get(NULL, adsp_info.module[i].clk_name); - else - mod->clk = NULL; - if (mod->clk && adsp_info.module[i].clk_rate) - clk_set_rate(mod->clk, adsp_info.module[i].clk_rate); - mod->verify_cmd = adsp_info.module[i].verify_cmd; - mod->patch_event = adsp_info.module[i].patch_event; - INIT_HLIST_HEAD(&mod->pmem_regions); - mod->pdev.name = adsp_info.module[i].pdev_name; - mod->pdev.id = -1; -#if CONFIG_MSM_AMSS_VERSION >= 6350 - adsp_info.id_to_module[i] = mod; -#else - adsp_info.id_to_module[mod->id] = mod; -#endif - platform_device_register(&mod->pdev); - } - - msm_adsp_publish_cdevs(adsp_modules, count); - - return 0; - -fail_rpc_register: - msm_rpc_close(rpc_cb_server_client); - rpc_cb_server_client = NULL; -fail_rpc_open: - enable_irq(INT_ADSP); - free_irq(INT_ADSP, 0); -fail_request_irq: - kfree(adsp_modules); -#if CONFIG_MSM_AMSS_VERSION >= 6350 - kfree(adsp_info.init_info_ptr); -#endif - return rc; -} - -static struct platform_driver msm_adsp_driver = { - .probe = msm_adsp_probe, - .driver = { - .name = MSM_ADSP_DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init adsp_init(void) -{ - return platform_driver_register(&msm_adsp_driver); -} - -device_initcall(adsp_init); diff --git a/drivers/staging/dream/qdsp5/adsp.h b/drivers/staging/dream/qdsp5/adsp.h deleted file mode 100644 index 0e5c9abd3da5..000000000000 --- a/drivers/staging/dream/qdsp5/adsp.h +++ /dev/null @@ -1,369 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp.h - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * Author: Iliyan Malchev <ibm@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ARCH_ARM_MACH_MSM_ADSP_H -#define _ARCH_ARM_MACH_MSM_ADSP_H - -#include <linux/types.h> -#include <linux/msm_adsp.h> -#include <mach/msm_rpcrouter.h> -#include <mach/msm_adsp.h> - -int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr, - unsigned long len); -int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr, - unsigned long *kvaddr, unsigned long len); -int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr); - -int adsp_vfe_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size); -int adsp_jpeg_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size); -int adsp_lpm_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size); -int adsp_video_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size); -int adsp_videoenc_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size); - - -struct adsp_event; - -int adsp_vfe_patch_event(struct msm_adsp_module *module, - struct adsp_event *event); - -int adsp_jpeg_patch_event(struct msm_adsp_module *module, - struct adsp_event *event); - - -struct adsp_module_info { - const char *name; - const char *pdev_name; - uint32_t id; - const char *clk_name; - unsigned long clk_rate; - int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *, - size_t); - int (*patch_event) (struct msm_adsp_module*, struct adsp_event *); -}; - -#define ADSP_EVENT_MAX_SIZE 496 -#define EVENT_LEN 12 -#define EVENT_MSG_ID ((uint16_t)~0) - -struct adsp_event { - struct list_head list; - uint32_t size; /* always in bytes */ - uint16_t msg_id; - uint16_t type; /* 0 for msgs (from aDSP), -1 for events (from ARM9) */ - int is16; /* always 0 (msg is 32-bit) when the event type is 1(ARM9) */ - union { - uint16_t msg16[ADSP_EVENT_MAX_SIZE / 2]; - uint32_t msg32[ADSP_EVENT_MAX_SIZE / 4]; - } data; -}; - -struct adsp_info { - uint32_t send_irq; - uint32_t read_ctrl; - uint32_t write_ctrl; - - uint32_t max_msg16_size; - uint32_t max_msg32_size; - - uint32_t max_task_id; - uint32_t max_module_id; - uint32_t max_queue_id; - uint32_t max_image_id; - - /* for each image id, a map of queue id to offset */ - uint32_t **queue_offset; - - /* for each image id, a map of task id to module id */ - uint32_t **task_to_module; - - /* for each module id, map of module id to module */ - struct msm_adsp_module **id_to_module; - - uint32_t module_count; - struct adsp_module_info *module; - - /* stats */ - uint32_t events_received; - uint32_t event_backlog_max; - -#if CONFIG_MSM_AMSS_VERSION >= 6350 - /* rpc_client for init_info */ - struct msm_rpc_endpoint *init_info_rpc_client; - struct adsp_rtos_mp_mtoa_init_info_type *init_info_ptr; - wait_queue_head_t init_info_wait; - unsigned init_info_state; -#endif -}; - -#define RPC_ADSP_RTOS_ATOM_PROG 0x3000000a -#define RPC_ADSP_RTOS_MTOA_PROG 0x3000000b -#define RPC_ADSP_RTOS_ATOM_NULL_PROC 0 -#define RPC_ADSP_RTOS_MTOA_NULL_PROC 0 -#define RPC_ADSP_RTOS_APP_TO_MODEM_PROC 2 -#define RPC_ADSP_RTOS_MODEM_TO_APP_PROC 2 - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(1,0) -#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(2,1) /* must be actual vers */ -#define MSM_ADSP_DRIVER_NAME "rs3000000a:00010000" -#elif (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225) -#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(0x71d1094b, 0) -#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(0xee3a9966, 0) -#define MSM_ADSP_DRIVER_NAME "rs3000000a:71d1094b" -#elif CONFIG_MSM_AMSS_VERSION == 6210 -#define RPC_ADSP_RTOS_ATOM_VERS MSM_RPC_VERS(0x20f17fd3, 0) -#define RPC_ADSP_RTOS_MTOA_VERS MSM_RPC_VERS(0x75babbd6, 0) -#define MSM_ADSP_DRIVER_NAME "rs3000000a:20f17fd3" -#else -#error "Unknown AMSS version" -#endif - -enum rpc_adsp_rtos_proc_type { - RPC_ADSP_RTOS_PROC_NONE = 0, - RPC_ADSP_RTOS_PROC_MODEM = 1, - RPC_ADSP_RTOS_PROC_APPS = 2, -}; - -enum { - RPC_ADSP_RTOS_CMD_REGISTER_APP, - RPC_ADSP_RTOS_CMD_ENABLE, - RPC_ADSP_RTOS_CMD_DISABLE, - RPC_ADSP_RTOS_CMD_KERNEL_COMMAND, - RPC_ADSP_RTOS_CMD_16_COMMAND, - RPC_ADSP_RTOS_CMD_32_COMMAND, - RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP, - RPC_ADSP_RTOS_CMD_REMOTE_EVENT, - RPC_ADSP_RTOS_CMD_SET_STATE, -#if CONFIG_MSM_AMSS_VERSION >= 6350 - RPC_ADSP_RTOS_CMD_REMOTE_INIT_INFO_EVENT, - RPC_ADSP_RTOS_CMD_GET_INIT_INFO, -#endif -}; - -enum rpc_adsp_rtos_mod_status_type { - RPC_ADSP_RTOS_MOD_READY, - RPC_ADSP_RTOS_MOD_DISABLE, - RPC_ADSP_RTOS_SERVICE_RESET, - RPC_ADSP_RTOS_CMD_FAIL, - RPC_ADSP_RTOS_CMD_SUCCESS, -#if CONFIG_MSM_AMSS_VERSION >= 6350 - RPC_ADSP_RTOS_INIT_INFO, - RPC_ADSP_RTOS_DISABLE_FAIL, -#endif -}; - -struct rpc_adsp_rtos_app_to_modem_args_t { - struct rpc_request_hdr hdr; - uint32_t gotit; /* if 1, the next elements are present */ - uint32_t cmd; /* e.g., RPC_ADSP_RTOS_CMD_REGISTER_APP */ - uint32_t proc_id; /* e.g., RPC_ADSP_RTOS_PROC_APPS */ - uint32_t module; /* e.g., QDSP_MODULE_AUDPPTASK */ -}; - -#if CONFIG_MSM_AMSS_VERSION >= 6350 -enum qdsp_image_type { - QDSP_IMAGE_COMBO, - QDSP_IMAGE_GAUDIO, - QDSP_IMAGE_QTV_LP, - QDSP_IMAGE_MAX, - /* DO NOT USE: Force this enum to be a 32bit type to improve speed */ - QDSP_IMAGE_32BIT_DUMMY = 0x10000 -}; - -struct adsp_rtos_mp_mtoa_header_type { - enum rpc_adsp_rtos_mod_status_type event; - enum rpc_adsp_rtos_proc_type proc_id; -}; - -/* ADSP RTOS MP Communications - Modem to APP's Event Info*/ -struct adsp_rtos_mp_mtoa_type { - uint32_t module; - uint32_t image; - uint32_t apps_okts; -}; - -/* ADSP RTOS MP Communications - Modem to APP's Init Info */ -#define IMG_MAX 8 -#define ENTRIES_MAX 64 - -struct queue_to_offset_type { - uint32_t queue; - uint32_t offset; -}; - -struct adsp_rtos_mp_mtoa_init_info_type { - uint32_t image_count; - uint32_t num_queue_offsets; - struct queue_to_offset_type queue_offsets_tbl[IMG_MAX][ENTRIES_MAX]; - uint32_t num_task_module_entries; - uint32_t task_to_module_tbl[IMG_MAX][ENTRIES_MAX]; - - uint32_t module_table_size; - uint32_t module_entries[ENTRIES_MAX]; - /* - * queue_offsets[] is to store only queue_offsets - */ - uint32_t queue_offsets[IMG_MAX][ENTRIES_MAX]; -}; - -struct adsp_rtos_mp_mtoa_s_type { - struct adsp_rtos_mp_mtoa_header_type mp_mtoa_header; - - uint32_t desc_field; - union { - struct adsp_rtos_mp_mtoa_init_info_type mp_mtoa_init_packet; - struct adsp_rtos_mp_mtoa_type mp_mtoa_packet; - } adsp_rtos_mp_mtoa_data; -}; - -struct rpc_adsp_rtos_modem_to_app_args_t { - struct rpc_request_hdr hdr; - uint32_t gotit; /* if 1, the next elements are present */ - struct adsp_rtos_mp_mtoa_s_type mtoa_pkt; -}; -#else -struct rpc_adsp_rtos_modem_to_app_args_t { - struct rpc_request_hdr hdr; - uint32_t gotit; /* if 1, the next elements are present */ - uint32_t event; /* e.g., RPC_ADSP_RTOS_CMD_REGISTER_APP */ - uint32_t proc_id; /* e.g., RPC_ADSP_RTOS_PROC_APPS */ - uint32_t module; /* e.g., QDSP_MODULE_AUDPPTASK */ - uint32_t image; /* RPC_QDSP_IMAGE_GAUDIO */ -}; -#endif /* CONFIG_MSM_AMSS_VERSION >= 6350 */ - -#define ADSP_STATE_DISABLED 0 -#define ADSP_STATE_ENABLING 1 -#define ADSP_STATE_ENABLED 2 -#define ADSP_STATE_DISABLING 3 -#if CONFIG_MSM_AMSS_VERSION >= 6350 -#define ADSP_STATE_INIT_INFO 4 -#endif - -struct msm_adsp_module { - struct mutex lock; - const char *name; - unsigned id; - struct adsp_info *info; - - struct msm_rpc_endpoint *rpc_client; - struct msm_adsp_ops *ops; - void *driver_data; - - /* statistics */ - unsigned num_commands; - unsigned num_events; - - wait_queue_head_t state_wait; - unsigned state; - - struct platform_device pdev; - struct clk *clk; - int open_count; - - struct mutex pmem_regions_lock; - struct hlist_head pmem_regions; - int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *, - size_t); - int (*patch_event) (struct msm_adsp_module*, struct adsp_event *); -}; - -extern void msm_adsp_publish_cdevs(struct msm_adsp_module *, unsigned); -extern int adsp_init_info(struct adsp_info *info); - -/* Value to indicate that a queue is not defined for a particular image */ -#if CONFIG_MSM_AMSS_VERSION >= 6350 -#define QDSP_RTOS_NO_QUEUE 0xfffffffe -#else -#define QDSP_RTOS_NO_QUEUE 0xffffffff -#endif - -/* - * Constants used to communicate with the ADSP RTOS - */ -#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M 0x80000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V 0x80000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_AVAIL_V 0x00000000U - -#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_M 0x70000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_REQ_V 0x00000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V 0x10000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_NO_CMD_V 0x70000000U - -#define ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M 0x0E000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V 0x00000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_NO_FREE_BUF_V 0x02000000U - -#define ADSP_RTOS_WRITE_CTRL_WORD_KERNEL_FLG_M 0x01000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_MSG_WRITE_V 0x00000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_V 0x01000000U - -#define ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M 0x00FFFFFFU -#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_ID_M 0x00FFFFFFU - -/* Combination of MUTEX and CMD bits to check if the DSP is busy */ -#define ADSP_RTOS_WRITE_CTRL_WORD_READY_M 0xF0000000U -#define ADSP_RTOS_WRITE_CTRL_WORD_READY_V 0x70000000U - -/* RTOS to Host processor command mask values */ -#define ADSP_RTOS_READ_CTRL_WORD_FLAG_M 0x80000000U -#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_WAIT_V 0x00000000U -#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V 0x80000000U - -#define ADSP_RTOS_READ_CTRL_WORD_CMD_M 0x60000000U -#define ADSP_RTOS_READ_CTRL_WORD_READ_DONE_V 0x00000000U -#define ADSP_RTOS_READ_CTRL_WORD_READ_REQ_V 0x20000000U -#define ADSP_RTOS_READ_CTRL_WORD_NO_CMD_V 0x60000000U - -/* Combination of FLAG and COMMAND bits to check if MSG ready */ -#define ADSP_RTOS_READ_CTRL_WORD_READY_M 0xE0000000U -#define ADSP_RTOS_READ_CTRL_WORD_READY_V 0xA0000000U -#define ADSP_RTOS_READ_CTRL_WORD_CONT_V 0xC0000000U -#define ADSP_RTOS_READ_CTRL_WORD_DONE_V 0xE0000000U - -#define ADSP_RTOS_READ_CTRL_WORD_STATUS_M 0x18000000U -#define ADSP_RTOS_READ_CTRL_WORD_NO_ERR_V 0x00000000U - -#define ADSP_RTOS_READ_CTRL_WORD_IN_PROG_M 0x04000000U -#define ADSP_RTOS_READ_CTRL_WORD_NO_READ_IN_PROG_V 0x00000000U -#define ADSP_RTOS_READ_CTRL_WORD_READ_IN_PROG_V 0x04000000U - -#define ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M 0x03000000U -#define ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V 0x00000000U -#define ADSP_RTOS_READ_CTRL_WORD_CMD_KRNL_TO_H_V 0x01000000U -#define ADSP_RTOS_READ_CTRL_WORD_CMD_H_TO_KRNL_CFM_V 0x02000000U - -#define ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M 0x00FFFFFFU - -#define ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M 0x000000FFU -#define ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M 0x0000FF00U - -/* Base address of DSP and DSP hardware registers */ -#define QDSP_RAMC_OFFSET 0x400000 - -#endif /* _ARCH_ARM_MACH_MSM_ADSP_H */ diff --git a/drivers/staging/dream/qdsp5/adsp_6210.c b/drivers/staging/dream/qdsp5/adsp_6210.c deleted file mode 100644 index 3cf4e99ed862..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_6210.c +++ /dev/null @@ -1,283 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_6210.h - * - * Copyright (c) 2008 QUALCOMM Incorporated. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "adsp.h" - -/* Firmware modules */ -typedef enum { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEO_AAC_VOC, - QDSP_MODULE_PCM_DEC, - QDSP_MODULE_AUDIO_DEC_MP3, - QDSP_MODULE_AUDIO_DEC_AAC, - QDSP_MODULE_AUDIO_DEC_WMA, - QDSP_MODULE_HOSTPCM, - QDSP_MODULE_DTMF, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_SBC_ENC, - QDSP_MODULE_VOC, - QDSP_MODULE_VOC_PCM, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_WAV_ENC, - QDSP_MODULE_AACLC_ENC, - QDSP_MODULE_VIDEO_AMR, - QDSP_MODULE_VOC_AMR, - QDSP_MODULE_VOC_EVRC, - QDSP_MODULE_VOC_13K, - QDSP_MODULE_VOC_FGV, - QDSP_MODULE_DIAGTASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_QCAMTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MIDI, - QDSP_MODULE_GAUDIO, - QDSP_MODULE_VDEC_LP_MODE, - QDSP_MODULE_MAX, -} qdsp_module_type; - -#define QDSP_RTOS_MAX_TASK_ID 19U - -/* Table of modules indexed by task ID for the GAUDIO image */ -static qdsp_module_type qdsp_gaudio_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the GAUDIO image */ -static uint32_t qdsp_gaudio_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x3be, /* QDSP_mpuAfeQueue */ - 0x3ee, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x3c2, /* QDSP_uPAudPPCmd1Queue */ - 0x3c6, /* QDSP_uPAudPPCmd2Queue */ - 0x3ca, /* QDSP_uPAudPPCmd3Queue */ - 0x3da, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - 0x3de, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - 0x3e2, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - 0x3e6, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - 0x3ea, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x3ce, /* QDSP_uPAudPreProcCmdQueue */ - 0x3d6, /* QDSP_uPAudRecBitStreamQueue */ - 0x3d2, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE /* QDSP_vfeCommandTableQueue */ -}; - -/* Table of modules indexed by task ID for the COMBO image */ -static qdsp_module_type qdsp_combo_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the COMBO image */ -static uint32_t qdsp_combo_queue_offset_table[] = { - 0x585, /* QDSP_lpmCommandQueue */ - 0x52d, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - 0x541, /* QDSP_mpuModmathCmdQueue */ - 0x555, /* QDSP_mpuVDecCmdQueue */ - 0x559, /* QDSP_mpuVDecPktQueue */ - 0x551, /* QDSP_mpuVEncCmdQueue */ - 0x535, /* QDSP_rxMpuDecCmdQueue */ - 0x539, /* QDSP_rxMpuDecPktQueue */ - 0x53d, /* QDSP_txMpuEncQueue */ - 0x55d, /* QDSP_uPAudPPCmd1Queue */ - 0x561, /* QDSP_uPAudPPCmd2Queue */ - 0x565, /* QDSP_uPAudPPCmd3Queue */ - 0x575, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - 0x579, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x569, /* QDSP_uPAudPreProcCmdQueue */ - 0x571, /* QDSP_uPAudRecBitStreamQueue */ - 0x56d, /* QDSP_uPAudRecCmdQueue */ - 0x581, /* QDSP_uPJpegActionCmdQueue */ - 0x57d, /* QDSP_uPJpegCfgCmdQueue */ - 0x531, /* QDSP_uPVocProcQueue */ - 0x545, /* QDSP_vfeCommandQueue */ - 0x54d, /* QDSP_vfeCommandScaleQueue */ - 0x549 /* QDSP_vfeCommandTableQueue */ -}; - -/* Table of modules indexed by task ID for the QTV_LP image */ -static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the QTV_LP image */ -static uint32_t qdsp_qtv_lp_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x40c, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - 0x410, /* QDSP_mpuVDecCmdQueue */ - 0x414, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x41c, /* QDSP_uPAudPPCmd1Queue */ - 0x420, /* QDSP_uPAudPPCmd2Queue */ - 0x424, /* QDSP_uPAudPPCmd3Queue */ - 0x430, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x418, /* QDSP_uPAudPreProcCmdQueue */ - 0x42c, /* QDSP_uPAudRecBitStreamQueue */ - 0x428, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE /* QDSP_vfeCommandTableQueue */ -}; - -/* Tables to convert tasks to modules */ -static uint32_t *qdsp_task_to_module[] = { - qdsp_combo_task_to_module_table, - qdsp_gaudio_task_to_module_table, - qdsp_qtv_lp_task_to_module_table, -}; - -/* Tables to retrieve queue offsets */ -static uint32_t *qdsp_queue_offset_table[] = { - qdsp_combo_queue_offset_table, - qdsp_gaudio_queue_offset_table, - qdsp_qtv_lp_queue_offset_table, -}; - -#define QDSP_MODULE(n) \ - { .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n } - -static struct adsp_module_info module_info[] = { - QDSP_MODULE(AUDPPTASK), - QDSP_MODULE(AUDRECTASK), - QDSP_MODULE(AUDPREPROCTASK), - QDSP_MODULE(VFETASK), - QDSP_MODULE(QCAMTASK), - QDSP_MODULE(LPMTASK), - QDSP_MODULE(JPEGTASK), - QDSP_MODULE(VIDEOTASK), - QDSP_MODULE(VDEC_LP_MODE), -}; - -int adsp_init_info(struct adsp_info *info) -{ - info->send_irq = 0x00c00200; - info->read_ctrl = 0x00400038; - info->write_ctrl = 0x00400034; - - info->max_msg16_size = 193; - info->max_msg32_size = 8; - - info->max_task_id = 16; - info->max_module_id = QDSP_MODULE_MAX - 1; - info->max_queue_id = QDSP_QUEUE_MAX; - info->max_image_id = 2; - info->queue_offset = qdsp_queue_offset_table; - info->task_to_module = qdsp_task_to_module; - - info->module_count = ARRAY_SIZE(module_info); - info->module = module_info; - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_6220.c b/drivers/staging/dream/qdsp5/adsp_6220.c deleted file mode 100644 index 02225cd7ec8f..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_6220.c +++ /dev/null @@ -1,284 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_6220.h - * - * Copyright (c) 2008 QUALCOMM Incorporated. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "adsp.h" - -/* Firmware modules */ -typedef enum { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEO_AAC_VOC, - QDSP_MODULE_PCM_DEC, - QDSP_MODULE_AUDIO_DEC_MP3, - QDSP_MODULE_AUDIO_DEC_AAC, - QDSP_MODULE_AUDIO_DEC_WMA, - QDSP_MODULE_HOSTPCM, - QDSP_MODULE_DTMF, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_SBC_ENC, - QDSP_MODULE_VOC, - QDSP_MODULE_VOC_PCM, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_WAV_ENC, - QDSP_MODULE_AACLC_ENC, - QDSP_MODULE_VIDEO_AMR, - QDSP_MODULE_VOC_AMR, - QDSP_MODULE_VOC_EVRC, - QDSP_MODULE_VOC_13K, - QDSP_MODULE_VOC_FGV, - QDSP_MODULE_DIAGTASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_QCAMTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MIDI, - QDSP_MODULE_GAUDIO, - QDSP_MODULE_VDEC_LP_MODE, - QDSP_MODULE_MAX, -} qdsp_module_type; - -#define QDSP_RTOS_MAX_TASK_ID 19U - -/* Table of modules indexed by task ID for the GAUDIO image */ -static qdsp_module_type qdsp_gaudio_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the GAUDIO image */ -static uint32_t qdsp_gaudio_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x3f0, /* QDSP_mpuAfeQueue */ - 0x420, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x3f4, /* QDSP_uPAudPPCmd1Queue */ - 0x3f8, /* QDSP_uPAudPPCmd2Queue */ - 0x3fc, /* QDSP_uPAudPPCmd3Queue */ - 0x40c, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - 0x410, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - 0x414, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - 0x418, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - 0x41c, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x400, /* QDSP_uPAudPreProcCmdQueue */ - 0x408, /* QDSP_uPAudRecBitStreamQueue */ - 0x404, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE /* QDSP_vfeCommandTableQueue */ -}; - -/* Table of modules indexed by task ID for the COMBO image */ -static qdsp_module_type qdsp_combo_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the COMBO image */ -static uint32_t qdsp_combo_queue_offset_table[] = { - 0x6f2, /* QDSP_lpmCommandQueue */ - 0x69e, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - 0x6b2, /* QDSP_mpuModmathCmdQueue */ - 0x6c6, /* QDSP_mpuVDecCmdQueue */ - 0x6ca, /* QDSP_mpuVDecPktQueue */ - 0x6c2, /* QDSP_mpuVEncCmdQueue */ - 0x6a6, /* QDSP_rxMpuDecCmdQueue */ - 0x6aa, /* QDSP_rxMpuDecPktQueue */ - 0x6ae, /* QDSP_txMpuEncQueue */ - 0x6ce, /* QDSP_uPAudPPCmd1Queue */ - 0x6d2, /* QDSP_uPAudPPCmd2Queue */ - 0x6d6, /* QDSP_uPAudPPCmd3Queue */ - 0x6e6, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x6da, /* QDSP_uPAudPreProcCmdQueue */ - 0x6e2, /* QDSP_uPAudRecBitStreamQueue */ - 0x6de, /* QDSP_uPAudRecCmdQueue */ - 0x6ee, /* QDSP_uPJpegActionCmdQueue */ - 0x6ea, /* QDSP_uPJpegCfgCmdQueue */ - 0x6a2, /* QDSP_uPVocProcQueue */ - 0x6b6, /* QDSP_vfeCommandQueue */ - 0x6be, /* QDSP_vfeCommandScaleQueue */ - 0x6ba /* QDSP_vfeCommandTableQueue */ -}; - -/* Table of modules indexed by task ID for the QTV_LP image */ -static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX -}; - -/* Queue offset table indexed by queue ID for the QTV_LP image */ -static uint32_t qdsp_qtv_lp_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x430, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - 0x434, /* QDSP_mpuVDecCmdQueue */ - 0x438, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x440, /* QDSP_uPAudPPCmd1Queue */ - 0x444, /* QDSP_uPAudPPCmd2Queue */ - 0x448, /* QDSP_uPAudPPCmd3Queue */ - 0x454, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x43c, /* QDSP_uPAudPreProcCmdQueue */ - 0x450, /* QDSP_uPAudRecBitStreamQueue */ - 0x44c, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE /* QDSP_vfeCommandTableQueue */ -}; - -/* Tables to convert tasks to modules */ -static qdsp_module_type *qdsp_task_to_module[] = { - qdsp_combo_task_to_module_table, - qdsp_gaudio_task_to_module_table, - qdsp_qtv_lp_task_to_module_table, -}; - -/* Tables to retrieve queue offsets */ -static uint32_t *qdsp_queue_offset_table[] = { - qdsp_combo_queue_offset_table, - qdsp_gaudio_queue_offset_table, - qdsp_qtv_lp_queue_offset_table, -}; - -#define QDSP_MODULE(n) \ - { .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n } - -static struct adsp_module_info module_info[] = { - QDSP_MODULE(AUDPLAY0TASK), - QDSP_MODULE(AUDPPTASK), - QDSP_MODULE(AUDPREPROCTASK), - QDSP_MODULE(AUDRECTASK), - QDSP_MODULE(VFETASK), - QDSP_MODULE(QCAMTASK), - QDSP_MODULE(LPMTASK), - QDSP_MODULE(JPEGTASK), - QDSP_MODULE(VIDEOTASK), - QDSP_MODULE(VDEC_LP_MODE), -}; - -int adsp_init_info(struct adsp_info *info) -{ - info->send_irq = 0x00c00200; - info->read_ctrl = 0x00400038; - info->write_ctrl = 0x00400034; - - info->max_msg16_size = 193; - info->max_msg32_size = 8; - - info->max_task_id = 16; - info->max_module_id = QDSP_MODULE_MAX - 1; - info->max_queue_id = QDSP_QUEUE_MAX; - info->max_image_id = 2; - info->queue_offset = qdsp_queue_offset_table; - info->task_to_module = qdsp_task_to_module; - - info->module_count = ARRAY_SIZE(module_info); - info->module = module_info; - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_6225.c b/drivers/staging/dream/qdsp5/adsp_6225.c deleted file mode 100644 index 5078afbb1a8c..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_6225.c +++ /dev/null @@ -1,328 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_6225.h - * - * Copyright (c) 2008 QUALCOMM Incorporated. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "adsp.h" - -/* Firmware modules */ -typedef enum { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEO_AAC_VOC, - QDSP_MODULE_PCM_DEC, - QDSP_MODULE_AUDIO_DEC_MP3, - QDSP_MODULE_AUDIO_DEC_AAC, - QDSP_MODULE_AUDIO_DEC_WMA, - QDSP_MODULE_HOSTPCM, - QDSP_MODULE_DTMF, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_SBC_ENC, - QDSP_MODULE_VOC_UMTS, - QDSP_MODULE_VOC_CDMA, - QDSP_MODULE_VOC_PCM, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_WAV_ENC, - QDSP_MODULE_AACLC_ENC, - QDSP_MODULE_VIDEO_AMR, - QDSP_MODULE_VOC_AMR, - QDSP_MODULE_VOC_EVRC, - QDSP_MODULE_VOC_13K, - QDSP_MODULE_VOC_FGV, - QDSP_MODULE_DIAGTASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_QCAMTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MIDI, - QDSP_MODULE_GAUDIO, - QDSP_MODULE_VDEC_LP_MODE, - QDSP_MODULE_MAX, -} qdsp_module_type; - -#define QDSP_RTOS_MAX_TASK_ID 30U - -/* Table of modules indexed by task ID for the GAUDIO image */ -static qdsp_module_type qdsp_gaudio_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_AUDPLAY2TASK, - QDSP_MODULE_AUDPLAY3TASK, - QDSP_MODULE_AUDPLAY4TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_GRAPHICSTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, -}; - -/* Queue offset table indexed by queue ID for the GAUDIO image */ -static uint32_t qdsp_gaudio_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x3f0, /* QDSP_mpuAfeQueue */ - 0x420, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x3f4, /* QDSP_uPAudPPCmd1Queue */ - 0x3f8, /* QDSP_uPAudPPCmd2Queue */ - 0x3fc, /* QDSP_uPAudPPCmd3Queue */ - 0x40c, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - 0x410, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - 0x414, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - 0x418, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - 0x41c, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x400, /* QDSP_uPAudPreProcCmdQueue */ - 0x408, /* QDSP_uPAudRecBitStreamQueue */ - 0x404, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandTableQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPDiagQueue */ -}; - -/* Table of modules indexed by task ID for the COMBO image */ -static qdsp_module_type qdsp_combo_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_VOCDECTASK, - QDSP_MODULE_VOCENCTASK, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_VIDEOENCTASK, - QDSP_MODULE_VOICEPROCTASK, - QDSP_MODULE_VFETASK, - QDSP_MODULE_JPEGTASK, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_AUDPLAY1TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_LPMTASK, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MODMATHTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_DIAGTASK, - QDSP_MODULE_MAX, -}; - -/* Queue offset table indexed by queue ID for the COMBO image */ -static uint32_t qdsp_combo_queue_offset_table[] = { - 0x714, /* QDSP_lpmCommandQueue */ - 0x6bc, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - 0x6d0, /* QDSP_mpuModmathCmdQueue */ - 0x6e8, /* QDSP_mpuVDecCmdQueue */ - 0x6ec, /* QDSP_mpuVDecPktQueue */ - 0x6e4, /* QDSP_mpuVEncCmdQueue */ - 0x6c4, /* QDSP_rxMpuDecCmdQueue */ - 0x6c8, /* QDSP_rxMpuDecPktQueue */ - 0x6cc, /* QDSP_txMpuEncQueue */ - 0x6f0, /* QDSP_uPAudPPCmd1Queue */ - 0x6f4, /* QDSP_uPAudPPCmd2Queue */ - 0x6f8, /* QDSP_uPAudPPCmd3Queue */ - 0x708, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x6fc, /* QDSP_uPAudPreProcCmdQueue */ - 0x704, /* QDSP_uPAudRecBitStreamQueue */ - 0x700, /* QDSP_uPAudRecCmdQueue */ - 0x710, /* QDSP_uPJpegActionCmdQueue */ - 0x70c, /* QDSP_uPJpegCfgCmdQueue */ - 0x6c0, /* QDSP_uPVocProcQueue */ - 0x6d8, /* QDSP_vfeCommandQueue */ - 0x6e0, /* QDSP_vfeCommandScaleQueue */ - 0x6dc, /* QDSP_vfeCommandTableQueue */ - 0x6d4, /* QDSP_uPDiagQueue */ -}; - -/* Table of modules indexed by task ID for the QTV_LP image */ -static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = { - QDSP_MODULE_KERNEL, - QDSP_MODULE_AFETASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_VIDEOTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDPPTASK, - QDSP_MODULE_AUDPLAY0TASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_AUDRECTASK, - QDSP_MODULE_AUDPREPROCTASK, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, - QDSP_MODULE_MAX, -}; - -/* Queue offset table indexed by queue ID for the QTV_LP image */ -static uint32_t qdsp_qtv_lp_queue_offset_table[] = { - QDSP_RTOS_NO_QUEUE, /* QDSP_lpmCommandQueue */ - 0x3fe, /* QDSP_mpuAfeQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuGraphicsCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuModmathCmdQueue */ - 0x402, /* QDSP_mpuVDecCmdQueue */ - 0x406, /* QDSP_mpuVDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_mpuVEncCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_rxMpuDecPktQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_txMpuEncQueue */ - 0x40e, /* QDSP_uPAudPPCmd1Queue */ - 0x412, /* QDSP_uPAudPPCmd2Queue */ - 0x416, /* QDSP_uPAudPPCmd3Queue */ - 0x422, /* QDSP_uPAudPlay0BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay1BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay2BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay3BitStreamCtrlQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPAudPlay4BitStreamCtrlQueue */ - 0x40a, /* QDSP_uPAudPreProcCmdQueue */ - 0x41e, /* QDSP_uPAudRecBitStreamQueue */ - 0x41a, /* QDSP_uPAudRecCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegActionCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPJpegCfgCmdQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPVocProcQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandScaleQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_vfeCommandTableQueue */ - QDSP_RTOS_NO_QUEUE, /* QDSP_uPDiagQueue */ -}; - -/* Tables to convert tasks to modules */ -static qdsp_module_type *qdsp_task_to_module[] = { - qdsp_combo_task_to_module_table, - qdsp_gaudio_task_to_module_table, - qdsp_qtv_lp_task_to_module_table, -}; - -/* Tables to retrieve queue offsets */ -static uint32_t *qdsp_queue_offset_table[] = { - qdsp_combo_queue_offset_table, - qdsp_gaudio_queue_offset_table, - qdsp_qtv_lp_queue_offset_table, -}; - -#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \ - { .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \ - .clk_name = clkname, .clk_rate = clkrate, \ - .verify_cmd = verify_cmd_func, .patch_event = patch_event_func } - -static struct adsp_module_info module_info[] = { - QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd, - adsp_vfe_patch_event), - QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL), - QDSP_MODULE(JPEGTASK, "vdc_clk", 0, adsp_jpeg_verify_cmd, - adsp_jpeg_patch_event), - QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000, - adsp_video_verify_cmd, NULL), - QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL), - QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000, - adsp_videoenc_verify_cmd, NULL), -}; - -int adsp_init_info(struct adsp_info *info) -{ - info->send_irq = 0x00c00200; - info->read_ctrl = 0x00400038; - info->write_ctrl = 0x00400034; - - info->max_msg16_size = 193; - info->max_msg32_size = 8; - - info->max_task_id = 16; - info->max_module_id = QDSP_MODULE_MAX - 1; - info->max_queue_id = QDSP_QUEUE_MAX; - info->max_image_id = 2; - info->queue_offset = qdsp_queue_offset_table; - info->task_to_module = qdsp_task_to_module; - - info->module_count = ARRAY_SIZE(module_info); - info->module = module_info; - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_driver.c b/drivers/staging/dream/qdsp5/adsp_driver.c deleted file mode 100644 index 28a6f8da9477..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_driver.c +++ /dev/null @@ -1,643 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_driver.c - * - * Copyright (C) 2008 Google, Inc. - * Author: Iliyan Malchev <ibm@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/cdev.h> -#include <linux/fs.h> -#include <linux/list.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/uaccess.h> - -#include "adsp.h" - -#include <linux/msm_adsp.h> -#include <linux/android_pmem.h> - -struct adsp_pmem_region { - struct hlist_node list; - void *vaddr; - unsigned long paddr; - unsigned long kvaddr; - unsigned long len; - struct file *file; -}; - -struct adsp_device { - struct msm_adsp_module *module; - - spinlock_t event_queue_lock; - wait_queue_head_t event_wait; - struct list_head event_queue; - int abort; - - const char *name; - struct device *device; - struct cdev cdev; -}; - -static struct adsp_device *inode_to_device(struct inode *inode); - -#define __CONTAINS(r, v, l) ({ \ - typeof(r) __r = r; \ - typeof(v) __v = v; \ - typeof(v) __e = __v + l; \ - int res = __v >= __r->vaddr && \ - __e <= __r->vaddr + __r->len; \ - res; \ -}) - -#define CONTAINS(r1, r2) ({ \ - typeof(r2) __r2 = r2; \ - __CONTAINS(r1, __r2->vaddr, __r2->len); \ -}) - -#define IN_RANGE(r, v) ({ \ - typeof(r) __r = r; \ - typeof(v) __vv = v; \ - int res = ((__vv >= __r->vaddr) && \ - (__vv < (__r->vaddr + __r->len))); \ - res; \ -}) - -#define OVERLAPS(r1, r2) ({ \ - typeof(r1) __r1 = r1; \ - typeof(r2) __r2 = r2; \ - typeof(__r2->vaddr) __v = __r2->vaddr; \ - typeof(__v) __e = __v + __r2->len - 1; \ - int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \ - res; \ -}) - -static int adsp_pmem_check(struct msm_adsp_module *module, - void *vaddr, unsigned long len) -{ - struct adsp_pmem_region *region_elt; - struct hlist_node *node; - struct adsp_pmem_region t = { .vaddr = vaddr, .len = len }; - - hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) { - if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) || - OVERLAPS(region_elt, &t)) { - printk(KERN_ERR "adsp: module %s:" - " region (vaddr %p len %ld)" - " clashes with registered region" - " (vaddr %p paddr %p len %ld)\n", - module->name, - vaddr, len, - region_elt->vaddr, - (void *)region_elt->paddr, - region_elt->len); - return -EINVAL; - } - } - - return 0; -} - -static int adsp_pmem_add(struct msm_adsp_module *module, - struct adsp_pmem_info *info) -{ - unsigned long paddr, kvaddr, len; - struct file *file; - struct adsp_pmem_region *region; - int rc = -EINVAL; - - mutex_lock(&module->pmem_regions_lock); - region = kmalloc(sizeof(*region), GFP_KERNEL); - if (!region) { - rc = -ENOMEM; - goto end; - } - INIT_HLIST_NODE(®ion->list); - if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) { - kfree(region); - goto end; - } - - rc = adsp_pmem_check(module, info->vaddr, len); - if (rc < 0) { - put_pmem_file(file); - kfree(region); - goto end; - } - - region->vaddr = info->vaddr; - region->paddr = paddr; - region->kvaddr = kvaddr; - region->len = len; - region->file = file; - - hlist_add_head(®ion->list, &module->pmem_regions); -end: - mutex_unlock(&module->pmem_regions_lock); - return rc; -} - -static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr, - unsigned long len, struct adsp_pmem_region **region) -{ - struct hlist_node *node; - void *vaddr = *addr; - struct adsp_pmem_region *region_elt; - - int match_count = 0; - - *region = NULL; - - /* returns physical address or zero */ - hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) { - if (vaddr >= region_elt->vaddr && - vaddr < region_elt->vaddr + region_elt->len && - vaddr + len <= region_elt->vaddr + region_elt->len) { - /* offset since we could pass vaddr inside a registerd - * pmem buffer - */ - - match_count++; - if (!*region) - *region = region_elt; - } - } - - if (match_count > 1) { - printk(KERN_ERR "adsp: module %s: " - "multiple hits for vaddr %p, len %ld\n", - module->name, vaddr, len); - hlist_for_each_entry(region_elt, node, - &module->pmem_regions, list) { - if (vaddr >= region_elt->vaddr && - vaddr < region_elt->vaddr + region_elt->len && - vaddr + len <= region_elt->vaddr + region_elt->len) - printk(KERN_ERR "\t%p, %ld --> %p\n", - region_elt->vaddr, - region_elt->len, - (void *)region_elt->paddr); - } - } - - return *region ? 0 : -1; -} - -int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr, - unsigned long *kvaddr, unsigned long len) -{ - struct adsp_pmem_region *region; - void *vaddr = *addr; - unsigned long *paddr = (unsigned long *)addr; - int ret; - - ret = adsp_pmem_lookup_vaddr(module, addr, len, ®ion); - if (ret) { - printk(KERN_ERR "adsp: not patching %s (paddr & kvaddr)," - " lookup (%p, %ld) failed\n", - module->name, vaddr, len); - return ret; - } - *paddr = region->paddr + (vaddr - region->vaddr); - *kvaddr = region->kvaddr + (vaddr - region->vaddr); - return 0; -} - -int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr, - unsigned long len) -{ - struct adsp_pmem_region *region; - void *vaddr = *addr; - unsigned long *paddr = (unsigned long *)addr; - int ret; - - ret = adsp_pmem_lookup_vaddr(module, addr, len, ®ion); - if (ret) { - printk(KERN_ERR "adsp: not patching %s, lookup (%p, %ld) failed\n", - module->name, vaddr, len); - return ret; - } - - *paddr = region->paddr + (vaddr - region->vaddr); - return 0; -} - -static int adsp_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - /* call the per module verifier */ - if (module->verify_cmd) - return module->verify_cmd(module, queue_id, cmd_data, - cmd_size); - else - printk(KERN_INFO "adsp: no packet verifying function " - "for task %s\n", module->name); - return 0; -} - -static long adsp_write_cmd(struct adsp_device *adev, void __user *arg) -{ - struct adsp_command_t cmd; - unsigned char buf[256]; - void *cmd_data; - long rc; - - if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd))) - return -EFAULT; - - if (cmd.len > 256) { - cmd_data = kmalloc(cmd.len, GFP_USER); - if (!cmd_data) - return -ENOMEM; - } else { - cmd_data = buf; - } - - if (copy_from_user(cmd_data, (void __user *)(cmd.data), cmd.len)) { - rc = -EFAULT; - goto end; - } - - mutex_lock(&adev->module->pmem_regions_lock); - if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) { - printk(KERN_ERR "module %s: verify failed.\n", - adev->module->name); - rc = -EINVAL; - goto end; - } - rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len); -end: - mutex_unlock(&adev->module->pmem_regions_lock); - - if (cmd.len > 256) - kfree(cmd_data); - - return rc; -} - -static int adsp_events_pending(struct adsp_device *adev) -{ - unsigned long flags; - int yes; - spin_lock_irqsave(&adev->event_queue_lock, flags); - yes = !list_empty(&adev->event_queue); - spin_unlock_irqrestore(&adev->event_queue_lock, flags); - return yes || adev->abort; -} - -static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr, - struct adsp_pmem_region **region) -{ - struct hlist_node *node; - unsigned long paddr = (unsigned long)(*addr); - struct adsp_pmem_region *region_elt; - - hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) { - if (paddr >= region_elt->paddr && - paddr < region_elt->paddr + region_elt->len) { - *region = region_elt; - return 0; - } - } - return -1; -} - -int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr) -{ - struct adsp_pmem_region *region; - unsigned long paddr = (unsigned long)(*addr); - unsigned long *vaddr = (unsigned long *)addr; - int ret; - - ret = adsp_pmem_lookup_paddr(module, addr, ®ion); - if (ret) { - printk(KERN_ERR "adsp: not patching %s, paddr %p lookup failed\n", - module->name, vaddr); - return ret; - } - - *vaddr = (unsigned long)region->vaddr + (paddr - region->paddr); - return 0; -} - -static int adsp_patch_event(struct msm_adsp_module *module, - struct adsp_event *event) -{ - /* call the per-module msg verifier */ - if (module->patch_event) - return module->patch_event(module, event); - return 0; -} - -static long adsp_get_event(struct adsp_device *adev, void __user *arg) -{ - unsigned long flags; - struct adsp_event *data = NULL; - struct adsp_event_t evt; - int timeout; - long rc = 0; - - if (copy_from_user(&evt, arg, sizeof(struct adsp_event_t))) - return -EFAULT; - - timeout = (int)evt.timeout_ms; - - if (timeout > 0) { - rc = wait_event_interruptible_timeout( - adev->event_wait, adsp_events_pending(adev), - msecs_to_jiffies(timeout)); - if (rc == 0) - return -ETIMEDOUT; - } else { - rc = wait_event_interruptible( - adev->event_wait, adsp_events_pending(adev)); - } - if (rc < 0) - return rc; - - if (adev->abort) - return -ENODEV; - - spin_lock_irqsave(&adev->event_queue_lock, flags); - if (!list_empty(&adev->event_queue)) { - data = list_first_entry(&adev->event_queue, - struct adsp_event, list); - list_del(&data->list); - } - spin_unlock_irqrestore(&adev->event_queue_lock, flags); - - if (!data) - return -EAGAIN; - - /* DSP messages are type 0; they may contain physical addresses */ - if (data->type == 0) - adsp_patch_event(adev->module, data); - - /* map adsp_event --> adsp_event_t */ - if (evt.len < data->size) { - rc = -ETOOSMALL; - goto end; - } - if (data->msg_id != EVENT_MSG_ID) { - if (copy_to_user((void *)(evt.data), data->data.msg16, - data->size)) { - rc = -EFAULT; - goto end; - } - } else { - if (copy_to_user((void *)(evt.data), data->data.msg32, - data->size)) { - rc = -EFAULT; - goto end; - } - } - - evt.type = data->type; /* 0 --> from aDSP, 1 --> from ARM9 */ - evt.msg_id = data->msg_id; - evt.flags = data->is16; - evt.len = data->size; - if (copy_to_user(arg, &evt, sizeof(evt))) - rc = -EFAULT; -end: - kfree(data); - return rc; -} - -static long adsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct adsp_device *adev = filp->private_data; - - switch (cmd) { - case ADSP_IOCTL_ENABLE: - return msm_adsp_enable(adev->module); - - case ADSP_IOCTL_DISABLE: - return msm_adsp_disable(adev->module); - - case ADSP_IOCTL_DISABLE_EVENT_RSP: - return 0; - - case ADSP_IOCTL_DISABLE_ACK: - pr_err("adsp: ADSP_IOCTL_DISABLE_ACK is not implemented.\n"); - break; - - case ADSP_IOCTL_WRITE_COMMAND: - return adsp_write_cmd(adev, (void __user *) arg); - - case ADSP_IOCTL_GET_EVENT: - return adsp_get_event(adev, (void __user *) arg); - - case ADSP_IOCTL_SET_CLKRATE: { -#if CONFIG_MSM_AMSS_VERSION==6350 - unsigned long clk_rate; - if (copy_from_user(&clk_rate, (void *) arg, sizeof(clk_rate))) - return -EFAULT; - return adsp_set_clkrate(adev->module, clk_rate); -#endif - } - - case ADSP_IOCTL_REGISTER_PMEM: { - struct adsp_pmem_info info; - if (copy_from_user(&info, (void *) arg, sizeof(info))) - return -EFAULT; - return adsp_pmem_add(adev->module, &info); - } - - case ADSP_IOCTL_ABORT_EVENT_READ: - adev->abort = 1; - wake_up(&adev->event_wait); - break; - - default: - break; - } - return -EINVAL; -} - -static int adsp_release(struct inode *inode, struct file *filp) -{ - struct adsp_device *adev = filp->private_data; - struct msm_adsp_module *module = adev->module; - struct hlist_node *node, *tmp; - struct adsp_pmem_region *region; - - pr_info("adsp_release() '%s'\n", adev->name); - - /* clear module before putting it to avoid race with open() */ - adev->module = NULL; - - mutex_lock(&module->pmem_regions_lock); - hlist_for_each_safe(node, tmp, &module->pmem_regions) { - region = hlist_entry(node, struct adsp_pmem_region, list); - hlist_del(node); - put_pmem_file(region->file); - kfree(region); - } - mutex_unlock(&module->pmem_regions_lock); - BUG_ON(!hlist_empty(&module->pmem_regions)); - - msm_adsp_put(module); - return 0; -} - -static void adsp_event(void *driver_data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)) -{ - struct adsp_device *adev = driver_data; - struct adsp_event *event; - unsigned long flags; - - if (len > ADSP_EVENT_MAX_SIZE) { - pr_err("adsp_event: event too large (%d bytes)\n", len); - return; - } - - event = kmalloc(sizeof(*event), GFP_ATOMIC); - if (!event) { - pr_err("adsp_event: cannot allocate buffer\n"); - return; - } - - if (id != EVENT_MSG_ID) { - event->type = 0; - event->is16 = 0; - event->msg_id = id; - event->size = len; - - getevent(event->data.msg16, len); - } else { - event->type = 1; - event->is16 = 1; - event->msg_id = id; - event->size = len; - getevent(event->data.msg32, len); - } - - spin_lock_irqsave(&adev->event_queue_lock, flags); - list_add_tail(&event->list, &adev->event_queue); - spin_unlock_irqrestore(&adev->event_queue_lock, flags); - wake_up(&adev->event_wait); -} - -static struct msm_adsp_ops adsp_ops = { - .event = adsp_event, -}; - -static int adsp_open(struct inode *inode, struct file *filp) -{ - struct adsp_device *adev; - int rc; - - rc = nonseekable_open(inode, filp); - if (rc < 0) - return rc; - - adev = inode_to_device(inode); - if (!adev) - return -ENODEV; - - pr_info("adsp_open() name = '%s'\n", adev->name); - - rc = msm_adsp_get(adev->name, &adev->module, &adsp_ops, adev); - if (rc) - return rc; - - pr_info("adsp_open() module '%s' adev %p\n", adev->name, adev); - filp->private_data = adev; - adev->abort = 0; - INIT_HLIST_HEAD(&adev->module->pmem_regions); - mutex_init(&adev->module->pmem_regions_lock); - - return 0; -} - -static unsigned adsp_device_count; -static struct adsp_device *adsp_devices; - -static struct adsp_device *inode_to_device(struct inode *inode) -{ - unsigned n = MINOR(inode->i_rdev); - if (n < adsp_device_count) { - if (adsp_devices[n].device) - return adsp_devices + n; - } - return NULL; -} - -static dev_t adsp_devno; -static struct class *adsp_class; - -static struct file_operations adsp_fops = { - .owner = THIS_MODULE, - .open = adsp_open, - .unlocked_ioctl = adsp_ioctl, - .release = adsp_release, - .llseek = no_llseek, -}; - -static void adsp_create(struct adsp_device *adev, const char *name, - struct device *parent, dev_t devt) -{ - struct device *dev; - int rc; - - dev = device_create(adsp_class, parent, devt, "%s", name); - if (IS_ERR(dev)) - return; - - init_waitqueue_head(&adev->event_wait); - INIT_LIST_HEAD(&adev->event_queue); - spin_lock_init(&adev->event_queue_lock); - - cdev_init(&adev->cdev, &adsp_fops); - adev->cdev.owner = THIS_MODULE; - - rc = cdev_add(&adev->cdev, devt, 1); - if (rc < 0) { - device_destroy(adsp_class, devt); - } else { - adev->device = dev; - adev->name = name; - } -} - -void msm_adsp_publish_cdevs(struct msm_adsp_module *modules, unsigned n) -{ - int rc; - - adsp_devices = kzalloc(sizeof(struct adsp_device) * n, GFP_KERNEL); - if (!adsp_devices) - return; - - adsp_class = class_create(THIS_MODULE, "adsp"); - if (IS_ERR(adsp_class)) - goto fail_create_class; - - rc = alloc_chrdev_region(&adsp_devno, 0, n, "adsp"); - if (rc < 0) - goto fail_alloc_region; - - adsp_device_count = n; - for (n = 0; n < adsp_device_count; n++) { - adsp_create(adsp_devices + n, - modules[n].name, &modules[n].pdev.dev, - MKDEV(MAJOR(adsp_devno), n)); - } - - return; - -fail_alloc_region: - class_unregister(adsp_class); -fail_create_class: - kfree(adsp_devices); -} diff --git a/drivers/staging/dream/qdsp5/adsp_info.c b/drivers/staging/dream/qdsp5/adsp_info.c deleted file mode 100644 index b9c77d20b5c4..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_info.c +++ /dev/null @@ -1,121 +0,0 @@ -/* arch/arm/mach-msm/adsp_info.c - * - * Copyright (c) 2008 QUALCOMM Incorporated. - * Copyright (c) 2008 QUALCOMM USA, INC. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "adsp.h" - -/* Firmware modules */ -#define QDSP_MODULE_KERNEL 0x0106dd4e -#define QDSP_MODULE_AFETASK 0x0106dd6f -#define QDSP_MODULE_AUDPLAY0TASK 0x0106dd70 -#define QDSP_MODULE_AUDPLAY1TASK 0x0106dd71 -#define QDSP_MODULE_AUDPPTASK 0x0106dd72 -#define QDSP_MODULE_VIDEOTASK 0x0106dd73 -#define QDSP_MODULE_VIDEO_AAC_VOC 0x0106dd74 -#define QDSP_MODULE_PCM_DEC 0x0106dd75 -#define QDSP_MODULE_AUDIO_DEC_MP3 0x0106dd76 -#define QDSP_MODULE_AUDIO_DEC_AAC 0x0106dd77 -#define QDSP_MODULE_AUDIO_DEC_WMA 0x0106dd78 -#define QDSP_MODULE_HOSTPCM 0x0106dd79 -#define QDSP_MODULE_DTMF 0x0106dd7a -#define QDSP_MODULE_AUDRECTASK 0x0106dd7b -#define QDSP_MODULE_AUDPREPROCTASK 0x0106dd7c -#define QDSP_MODULE_SBC_ENC 0x0106dd7d -#define QDSP_MODULE_VOC_UMTS 0x0106dd9a -#define QDSP_MODULE_VOC_CDMA 0x0106dd98 -#define QDSP_MODULE_VOC_PCM 0x0106dd7f -#define QDSP_MODULE_VOCENCTASK 0x0106dd80 -#define QDSP_MODULE_VOCDECTASK 0x0106dd81 -#define QDSP_MODULE_VOICEPROCTASK 0x0106dd82 -#define QDSP_MODULE_VIDEOENCTASK 0x0106dd83 -#define QDSP_MODULE_VFETASK 0x0106dd84 -#define QDSP_MODULE_WAV_ENC 0x0106dd85 -#define QDSP_MODULE_AACLC_ENC 0x0106dd86 -#define QDSP_MODULE_VIDEO_AMR 0x0106dd87 -#define QDSP_MODULE_VOC_AMR 0x0106dd88 -#define QDSP_MODULE_VOC_EVRC 0x0106dd89 -#define QDSP_MODULE_VOC_13K 0x0106dd8a -#define QDSP_MODULE_VOC_FGV 0x0106dd8b -#define QDSP_MODULE_DIAGTASK 0x0106dd8c -#define QDSP_MODULE_JPEGTASK 0x0106dd8d -#define QDSP_MODULE_LPMTASK 0x0106dd8e -#define QDSP_MODULE_QCAMTASK 0x0106dd8f -#define QDSP_MODULE_MODMATHTASK 0x0106dd90 -#define QDSP_MODULE_AUDPLAY2TASK 0x0106dd91 -#define QDSP_MODULE_AUDPLAY3TASK 0x0106dd92 -#define QDSP_MODULE_AUDPLAY4TASK 0x0106dd93 -#define QDSP_MODULE_GRAPHICSTASK 0x0106dd94 -#define QDSP_MODULE_MIDI 0x0106dd95 -#define QDSP_MODULE_GAUDIO 0x0106dd96 -#define QDSP_MODULE_VDEC_LP_MODE 0x0106dd97 -#define QDSP_MODULE_MAX 0x7fffffff - - /* DO NOT USE: Force this enum to be a 32bit type to improve speed */ -#define QDSP_MODULE_32BIT_DUMMY 0x10000 - -static uint32_t *qdsp_task_to_module[IMG_MAX]; -static uint32_t *qdsp_queue_offset_table[IMG_MAX]; - -#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \ - { .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \ - .clk_name = clkname, .clk_rate = clkrate, \ - .verify_cmd = verify_cmd_func, .patch_event = patch_event_func } - -static struct adsp_module_info module_info[] = { - QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd, - adsp_vfe_patch_event), - QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL), - QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL), - QDSP_MODULE(JPEGTASK, "vdc_clk", 96000000, adsp_jpeg_verify_cmd, - adsp_jpeg_patch_event), - QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000, - adsp_video_verify_cmd, NULL), - QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL), - QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000, - adsp_videoenc_verify_cmd, NULL), -}; - -int adsp_init_info(struct adsp_info *info) -{ - uint32_t img_num; - - info->send_irq = 0x00c00200; - info->read_ctrl = 0x00400038; - info->write_ctrl = 0x00400034; - - info->max_msg16_size = 193; - info->max_msg32_size = 8; - for (img_num = 0; img_num < IMG_MAX; img_num++) - qdsp_queue_offset_table[img_num] = - &info->init_info_ptr->queue_offsets[img_num][0]; - - for (img_num = 0; img_num < IMG_MAX; img_num++) - qdsp_task_to_module[img_num] = - &info->init_info_ptr->task_to_module_tbl[img_num][0]; - info->max_task_id = 30; - info->max_module_id = QDSP_MODULE_MAX - 1; - info->max_queue_id = QDSP_MAX_NUM_QUEUES; - info->max_image_id = 2; - info->queue_offset = qdsp_queue_offset_table; - info->task_to_module = qdsp_task_to_module; - - info->module_count = ARRAY_SIZE(module_info); - info->module = module_info; - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_jpeg_patch_event.c b/drivers/staging/dream/qdsp5/adsp_jpeg_patch_event.c deleted file mode 100644 index 4f493edb6c94..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_jpeg_patch_event.c +++ /dev/null @@ -1,31 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c - * - * Verification code for aDSP JPEG events. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <mach/qdsp5/qdsp5jpegmsg.h> -#include "adsp.h" - -int adsp_jpeg_patch_event(struct msm_adsp_module *module, - struct adsp_event *event) -{ - if (event->msg_id == JPEG_MSG_ENC_OP_PRODUCED) { - jpeg_msg_enc_op_produced *op = (jpeg_msg_enc_op_produced *)event->data.msg16; - return adsp_pmem_paddr_fixup(module, (void **)&op->op_buf_addr); - } - - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_jpeg_verify_cmd.c b/drivers/staging/dream/qdsp5/adsp_jpeg_verify_cmd.c deleted file mode 100644 index b33eba25569c..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_jpeg_verify_cmd.c +++ /dev/null @@ -1,182 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c - * - * Verification code for aDSP JPEG packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <mach/qdsp5/qdsp5jpegcmdi.h> -#include "adsp.h" - -static uint32_t dec_fmt; - -static inline void get_sizes(jpeg_cmd_enc_cfg *cmd, uint32_t *luma_size, - uint32_t *chroma_size) -{ - uint32_t fmt, luma_width, luma_height; - - fmt = cmd->process_cfg & JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M; - luma_width = (cmd->ip_size_cfg & JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M) - >> 16; - luma_height = cmd->frag_cfg & JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M; - *luma_size = luma_width * luma_height; - if (fmt == JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2) - *chroma_size = *luma_size/2; - else - *chroma_size = *luma_size; -} - -static inline int verify_jpeg_cmd_enc_cfg(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - jpeg_cmd_enc_cfg *cmd = (jpeg_cmd_enc_cfg *)cmd_data; - uint32_t luma_size, chroma_size; - int i, num_frags; - - if (cmd_size != sizeof(jpeg_cmd_enc_cfg)) { - printk(KERN_ERR "adsp: module %s: JPEG ENC CFG invalid cmd_size %d\n", - module->name, cmd_size); - return -1; - } - - get_sizes(cmd, &luma_size, &chroma_size); - num_frags = (cmd->process_cfg >> 10) & 0xf; - num_frags = ((num_frags == 1) ? num_frags : num_frags * 2); - for (i = 0; i < num_frags; i += 2) { - if (adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i]), luma_size) || - adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i+1]), chroma_size)) - return -1; - } - - if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_0_cfg_part1, - cmd->op_buf_0_cfg_part2) || - adsp_pmem_fixup(module, (void **)&cmd->op_buf_1_cfg_part1, - cmd->op_buf_1_cfg_part2)) - return -1; - return 0; -} - -static inline int verify_jpeg_cmd_dec_cfg(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - jpeg_cmd_dec_cfg *cmd = (jpeg_cmd_dec_cfg *)cmd_data; - uint32_t div; - - if (cmd_size != sizeof(jpeg_cmd_dec_cfg)) { - printk(KERN_ERR "adsp: module %s: JPEG DEC CFG invalid cmd_size %d\n", - module->name, cmd_size); - return -1; - } - - if (adsp_pmem_fixup(module, (void **)&cmd->ip_stream_buf_cfg_part1, - cmd->ip_stream_buf_cfg_part2) || - adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part1, - cmd->op_stream_buf_0_cfg_part2) || - adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part1, - cmd->op_stream_buf_1_cfg_part2)) - return -1; - dec_fmt = cmd->op_data_format & - JPEG_CMD_DEC_OP_DATA_FORMAT_M; - div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ? 2 : 1; - if (adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part3, - cmd->op_stream_buf_0_cfg_part2 / div) || - adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part3, - cmd->op_stream_buf_1_cfg_part2 / div)) - return -1; - return 0; -} - -static int verify_jpeg_cfg_cmd(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - uint32_t cmd_id = ((uint32_t *)cmd_data)[0]; - switch(cmd_id) { - case JPEG_CMD_ENC_CFG: - return verify_jpeg_cmd_enc_cfg(module, cmd_data, cmd_size); - case JPEG_CMD_DEC_CFG: - return verify_jpeg_cmd_dec_cfg(module, cmd_data, cmd_size); - default: - if (cmd_id > 1) { - printk(KERN_ERR "adsp: module %s: invalid JPEG CFG cmd_id %d\n", module->name, cmd_id); - return -1; - } - } - return 0; -} - -static int verify_jpeg_action_cmd(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - uint32_t cmd_id = ((uint32_t *)cmd_data)[0]; - switch (cmd_id) { - case JPEG_CMD_ENC_OP_CONSUMED: - { - jpeg_cmd_enc_op_consumed *cmd = - (jpeg_cmd_enc_op_consumed *)cmd_data; - - if (cmd_size != sizeof(jpeg_cmd_enc_op_consumed)) { - printk(KERN_ERR "adsp: module %s: JPEG_CMD_ENC_OP_CONSUMED invalid size %d\n", - module->name, cmd_size); - return -1; - } - - if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_addr, - cmd->op_buf_size)) - return -1; - } - break; - case JPEG_CMD_DEC_OP_CONSUMED: - { - uint32_t div; - jpeg_cmd_dec_op_consumed *cmd = - (jpeg_cmd_dec_op_consumed *)cmd_data; - - if (cmd_size != sizeof(jpeg_cmd_enc_op_consumed)) { - printk(KERN_ERR "adsp: module %s: JPEG_CMD_DEC_OP_CONSUMED invalid size %d\n", - module->name, cmd_size); - return -1; - } - - div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ? 2 : 1; - if (adsp_pmem_fixup(module, (void **)&cmd->luma_op_buf_addr, - cmd->luma_op_buf_size) || - adsp_pmem_fixup(module, (void **)&cmd->chroma_op_buf_addr, - cmd->luma_op_buf_size / div)) - return -1; - } - break; - default: - if (cmd_id > 7) { - printk(KERN_ERR "adsp: module %s: invalid cmd_id %d\n", - module->name, cmd_id); - return -1; - } - } - return 0; -} - -int adsp_jpeg_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - switch(queue_id) { - case QDSP_uPJpegCfgCmdQueue: - return verify_jpeg_cfg_cmd(module, cmd_data, cmd_size); - case QDSP_uPJpegActionCmdQueue: - return verify_jpeg_action_cmd(module, cmd_data, cmd_size); - default: - return -1; - } -} - diff --git a/drivers/staging/dream/qdsp5/adsp_lpm_verify_cmd.c b/drivers/staging/dream/qdsp5/adsp_lpm_verify_cmd.c deleted file mode 100644 index 1e23ef392700..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_lpm_verify_cmd.c +++ /dev/null @@ -1,65 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c - * - * Verificion code for aDSP LPM packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <mach/qdsp5/qdsp5lpmcmdi.h> -#include "adsp.h" - -int adsp_lpm_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - uint32_t cmd_id, col_height, input_row_incr, output_row_incr, - input_size, output_size; - uint32_t size_mask = 0x0fff; - lpm_cmd_start *cmd; - - if (queue_id != QDSP_lpmCommandQueue) { - printk(KERN_ERR "adsp: module %s: wrong queue id %d\n", - module->name, queue_id); - return -1; - } - - cmd = (lpm_cmd_start *)cmd_data; - cmd_id = cmd->cmd_id; - - if (cmd_id == LPM_CMD_START) { - if (cmd_size != sizeof(lpm_cmd_start)) { - printk(KERN_ERR "adsp: module %s: wrong size %d, expect %d\n", - module->name, cmd_size, sizeof(lpm_cmd_start)); - return -1; - } - col_height = cmd->ip_data_cfg_part1 & size_mask; - input_row_incr = cmd->ip_data_cfg_part2 & size_mask; - output_row_incr = cmd->op_data_cfg_part1 & size_mask; - input_size = col_height * input_row_incr; - output_size = col_height * output_row_incr; - if ((cmd->ip_data_cfg_part4 && adsp_pmem_fixup(module, - (void **)(&cmd->ip_data_cfg_part4), - input_size)) || - (cmd->op_data_cfg_part3 && adsp_pmem_fixup(module, - (void **)(&cmd->op_data_cfg_part3), - output_size))) - return -1; - } else if (cmd_id > 1) { - printk(KERN_ERR "adsp: module %s: invalid cmd_id %d\n", - module->name, cmd_id); - return -1; - } - return 0; -} - diff --git a/drivers/staging/dream/qdsp5/adsp_vfe_patch_event.c b/drivers/staging/dream/qdsp5/adsp_vfe_patch_event.c deleted file mode 100644 index a56392b3521c..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_vfe_patch_event.c +++ /dev/null @@ -1,54 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c - * - * Verification code for aDSP VFE packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <mach/qdsp5/qdsp5vfemsg.h> -#include "adsp.h" - -static int patch_op_event(struct msm_adsp_module *module, - struct adsp_event *event) -{ - vfe_msg_op1 *op = (vfe_msg_op1 *)event->data.msg16; - if (adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_y_addr) || - adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_cbcr_addr)) - return -1; - return 0; -} - -static int patch_af_wb_event(struct msm_adsp_module *module, - struct adsp_event *event) -{ - vfe_msg_stats_wb_exp *af = (vfe_msg_stats_wb_exp *)event->data.msg16; - return adsp_pmem_paddr_fixup(module, (void **)&af->wb_exp_stats_op_buf); -} - -int adsp_vfe_patch_event(struct msm_adsp_module *module, - struct adsp_event *event) -{ - switch(event->msg_id) { - case VFE_MSG_OP1: - case VFE_MSG_OP2: - return patch_op_event(module, event); - case VFE_MSG_STATS_AF: - case VFE_MSG_STATS_WB_EXP: - return patch_af_wb_event(module, event); - default: - break; - } - - return 0; -} diff --git a/drivers/staging/dream/qdsp5/adsp_vfe_verify_cmd.c b/drivers/staging/dream/qdsp5/adsp_vfe_verify_cmd.c deleted file mode 100644 index 927d50a730ff..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_vfe_verify_cmd.c +++ /dev/null @@ -1,239 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c - * - * Verification code for aDSP VFE packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <mach/qdsp5/qdsp5vfecmdi.h> -#include "adsp.h" - -static uint32_t size1_y, size2_y, size1_cbcr, size2_cbcr; -static uint32_t af_size = 4228; -static uint32_t awb_size = 8196; - -static inline int verify_cmd_op_ack(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - vfe_cmd_op1_ack *cmd = (vfe_cmd_op1_ack *)cmd_data; - void **addr_y = (void **)&cmd->op1_buf_y_addr; - void **addr_cbcr = (void **)(&cmd->op1_buf_cbcr_addr); - - if (cmd_size != sizeof(vfe_cmd_op1_ack)) - return -1; - if ((*addr_y && adsp_pmem_fixup(module, addr_y, size1_y)) || - (*addr_cbcr && adsp_pmem_fixup(module, addr_cbcr, size1_cbcr))) - return -1; - return 0; -} - -static inline int verify_cmd_stats_autofocus_cfg(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - int i; - vfe_cmd_stats_autofocus_cfg *cmd = - (vfe_cmd_stats_autofocus_cfg *)cmd_data; - - if (cmd_size != sizeof(vfe_cmd_stats_autofocus_cfg)) - return -1; - - for (i = 0; i < 3; i++) { - void **addr = (void **)(&cmd->af_stats_op_buf[i]); - if (*addr && adsp_pmem_fixup(module, addr, af_size)) - return -1; - } - return 0; -} - -static inline int verify_cmd_stats_wb_exp_cfg(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - vfe_cmd_stats_wb_exp_cfg *cmd = - (vfe_cmd_stats_wb_exp_cfg *)cmd_data; - int i; - - if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_cfg)) - return -1; - - for (i = 0; i < 3; i++) { - void **addr = (void **)(&cmd->wb_exp_stats_op_buf[i]); - if (*addr && adsp_pmem_fixup(module, addr, awb_size)) - return -1; - } - return 0; -} - -static inline int verify_cmd_stats_af_ack(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - vfe_cmd_stats_af_ack *cmd = (vfe_cmd_stats_af_ack *)cmd_data; - void **addr = (void **)&cmd->af_stats_op_buf; - - if (cmd_size != sizeof(vfe_cmd_stats_af_ack)) - return -1; - - if (*addr && adsp_pmem_fixup(module, addr, af_size)) - return -1; - return 0; -} - -static inline int verify_cmd_stats_wb_exp_ack(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - vfe_cmd_stats_wb_exp_ack *cmd = - (vfe_cmd_stats_wb_exp_ack *)cmd_data; - void **addr = (void **)&cmd->wb_exp_stats_op_buf; - - if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_ack)) - return -1; - - if (*addr && adsp_pmem_fixup(module, addr, awb_size)) - return -1; - return 0; -} - -static int verify_vfe_command(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - uint32_t cmd_id = ((uint32_t *)cmd_data)[0]; - switch (cmd_id) { - case VFE_CMD_OP1_ACK: - return verify_cmd_op_ack(module, cmd_data, cmd_size); - case VFE_CMD_OP2_ACK: - return verify_cmd_op_ack(module, cmd_data, cmd_size); - case VFE_CMD_STATS_AUTOFOCUS_CFG: - return verify_cmd_stats_autofocus_cfg(module, cmd_data, - cmd_size); - case VFE_CMD_STATS_WB_EXP_CFG: - return verify_cmd_stats_wb_exp_cfg(module, cmd_data, cmd_size); - case VFE_CMD_STATS_AF_ACK: - return verify_cmd_stats_af_ack(module, cmd_data, cmd_size); - case VFE_CMD_STATS_WB_EXP_ACK: - return verify_cmd_stats_wb_exp_ack(module, cmd_data, cmd_size); - default: - if (cmd_id > 29) { - printk(KERN_ERR "adsp: module %s: invalid VFE command id %d\n", module->name, cmd_id); - return -1; - } - } - return 0; -} - -static int verify_vfe_command_scale(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - uint32_t cmd_id = ((uint32_t *)cmd_data)[0]; - // FIXME: check the size - if (cmd_id > 1) { - printk(KERN_ERR "adsp: module %s: invalid VFE SCALE command id %d\n", module->name, cmd_id); - return -1; - } - return 0; -} - - -static uint32_t get_size(uint32_t hw) -{ - uint32_t height, width; - uint32_t height_mask = 0x3ffc; - uint32_t width_mask = 0x3ffc000; - - height = (hw & height_mask) >> 2; - width = (hw & width_mask) >> 14 ; - return height * width; -} - -static int verify_vfe_command_table(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - uint32_t cmd_id = ((uint32_t *)cmd_data)[0]; - int i; - - switch (cmd_id) { - case VFE_CMD_AXI_IP_CFG: - { - vfe_cmd_axi_ip_cfg *cmd = (vfe_cmd_axi_ip_cfg *)cmd_data; - uint32_t size; - if (cmd_size != sizeof(vfe_cmd_axi_ip_cfg)) { - printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_IP_CFG) command size %d\n", - module->name, cmd_size); - return -1; - } - size = get_size(cmd->ip_cfg_part2); - - for (i = 0; i < 8; i++) { - void **addr = (void **) - &cmd->ip_buf_addr[i]; - if (*addr && adsp_pmem_fixup(module, addr, size)) - return -1; - } - } - case VFE_CMD_AXI_OP_CFG: - { - vfe_cmd_axi_op_cfg *cmd = (vfe_cmd_axi_op_cfg *)cmd_data; - void **addr1_y, **addr2_y, **addr1_cbcr, **addr2_cbcr; - - if (cmd_size != sizeof(vfe_cmd_axi_op_cfg)) { - printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_OP_CFG) command size %d\n", - module->name, cmd_size); - return -1; - } - size1_y = get_size(cmd->op1_y_cfg_part2); - size1_cbcr = get_size(cmd->op1_cbcr_cfg_part2); - size2_y = get_size(cmd->op2_y_cfg_part2); - size2_cbcr = get_size(cmd->op2_cbcr_cfg_part2); - for (i = 0; i < 8; i++) { - addr1_y = (void **)(&cmd->op1_buf1_addr[2*i]); - addr1_cbcr = (void **)(&cmd->op1_buf1_addr[2*i+1]); - addr2_y = (void **)(&cmd->op2_buf1_addr[2*i]); - addr2_cbcr = (void **)(&cmd->op2_buf1_addr[2*i+1]); -/* - printk("module %s: [%d] %p %p %p %p\n", - module->name, i, - *addr1_y, *addr1_cbcr, *addr2_y, *addr2_cbcr); -*/ - if ((*addr1_y && adsp_pmem_fixup(module, addr1_y, size1_y)) || - (*addr1_cbcr && adsp_pmem_fixup(module, addr1_cbcr, size1_cbcr)) || - (*addr2_y && adsp_pmem_fixup(module, addr2_y, size2_y)) || - (*addr2_cbcr && adsp_pmem_fixup(module, addr2_cbcr, size2_cbcr))) - return -1; - } - } - default: - if (cmd_id > 4) { - printk(KERN_ERR "adsp: module %s: invalid VFE TABLE command id %d\n", - module->name, cmd_id); - return -1; - } - } - return 0; -} - -int adsp_vfe_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - switch (queue_id) { - case QDSP_vfeCommandQueue: - return verify_vfe_command(module, cmd_data, cmd_size); - case QDSP_vfeCommandScaleQueue: - return verify_vfe_command_scale(module, cmd_data, cmd_size); - case QDSP_vfeCommandTableQueue: - return verify_vfe_command_table(module, cmd_data, cmd_size); - default: - printk(KERN_ERR "adsp: module %s: unknown queue id %d\n", - module->name, queue_id); - return -1; - } -} diff --git a/drivers/staging/dream/qdsp5/adsp_video_verify_cmd.c b/drivers/staging/dream/qdsp5/adsp_video_verify_cmd.c deleted file mode 100644 index 53aff77cfd92..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_video_verify_cmd.c +++ /dev/null @@ -1,163 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c - * - * Verificion code for aDSP VDEC packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <linux/io.h> - -#define ADSP_DEBUG_MSGS 0 -#if ADSP_DEBUG_MSGS -#define DLOG(fmt,args...) \ - do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ - ##args); } \ - while (0) -#else -#define DLOG(x...) do {} while (0) -#endif - - -#include <mach/qdsp5/qdsp5vdeccmdi.h> -#include "adsp.h" - -static inline void *high_low_short_to_ptr(unsigned short high, - unsigned short low) -{ - return (void *)((((unsigned long)high) << 16) | ((unsigned long)low)); -} - -static inline void ptr_to_high_low_short(void *ptr, unsigned short *high, - unsigned short *low) -{ - *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff); - *low = (unsigned short)((unsigned long)ptr & 0xffff); -} - -static int pmem_fixup_high_low(unsigned short *high, - unsigned short *low, - unsigned short size_high, - unsigned short size_low, - struct msm_adsp_module *module, - unsigned long *addr, unsigned long *size) -{ - void *phys_addr; - unsigned long phys_size; - unsigned long kvaddr; - - phys_addr = high_low_short_to_ptr(*high, *low); - phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low); - DLOG("virt %x %x\n", phys_addr, phys_size); - if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) { - DLOG("ah%x al%x sh%x sl%x addr %x size %x\n", - *high, *low, size_high, size_low, phys_addr, phys_size); - return -1; - } - ptr_to_high_low_short(phys_addr, high, low); - DLOG("phys %x %x\n", phys_addr, phys_size); - if (addr) - *addr = kvaddr; - if (size) - *size = phys_size; - return 0; -} - -static int verify_vdec_pkt_cmd(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - unsigned short cmd_id = ((unsigned short *)cmd_data)[0]; - viddec_cmd_subframe_pkt *pkt; - unsigned long subframe_pkt_addr; - unsigned long subframe_pkt_size; - viddec_cmd_frame_header_packet *frame_header_pkt; - int i, num_addr, skip; - unsigned short *frame_buffer_high, *frame_buffer_low; - unsigned long frame_buffer_size; - unsigned short frame_buffer_size_high, frame_buffer_size_low; - - DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data); - if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) { - printk(KERN_INFO "adsp_video: unknown video packet %u\n", - cmd_id); - return 0; - } - if (cmd_size < sizeof(viddec_cmd_subframe_pkt)) - return -1; - - pkt = (viddec_cmd_subframe_pkt *)cmd_data; - - if (pmem_fixup_high_low(&(pkt->subframe_packet_high), - &(pkt->subframe_packet_low), - pkt->subframe_packet_size_high, - pkt->subframe_packet_size_low, - module, - &subframe_pkt_addr, - &subframe_pkt_size)) - return -1; - - /* deref those ptrs and check if they are a frame header packet */ - frame_header_pkt = (viddec_cmd_frame_header_packet *)subframe_pkt_addr; - - switch (frame_header_pkt->packet_id) { - case 0xB201: /* h.264 */ - num_addr = skip = 8; - break; - case 0x4D01: /* mpeg-4 and h.263 */ - num_addr = 3; - skip = 0; - break; - default: - return 0; - } - - frame_buffer_high = &frame_header_pkt->frame_buffer_0_high; - frame_buffer_low = &frame_header_pkt->frame_buffer_0_low; - frame_buffer_size = (frame_header_pkt->x_dimension * - frame_header_pkt->y_dimension * 3) / 2; - ptr_to_high_low_short((void *)frame_buffer_size, - &frame_buffer_size_high, - &frame_buffer_size_low); - for (i = 0; i < num_addr; i++) { - if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low, - frame_buffer_size_high, - frame_buffer_size_low, - module, - NULL, NULL)) - return -1; - frame_buffer_high += 2; - frame_buffer_low += 2; - } - /* Patch the output buffer. */ - frame_buffer_high += 2*skip; - frame_buffer_low += 2*skip; - if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low, - frame_buffer_size_high, - frame_buffer_size_low, module, NULL, NULL)) - return -1; - return 0; -} - -int adsp_video_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - switch (queue_id) { - case QDSP_mpuVDecPktQueue: - DLOG("\n"); - return verify_vdec_pkt_cmd(module, cmd_data, cmd_size); - default: - printk(KERN_INFO "unknown video queue %u\n", queue_id); - return 0; - } -} - diff --git a/drivers/staging/dream/qdsp5/adsp_videoenc_verify_cmd.c b/drivers/staging/dream/qdsp5/adsp_videoenc_verify_cmd.c deleted file mode 100644 index ee3744950523..000000000000 --- a/drivers/staging/dream/qdsp5/adsp_videoenc_verify_cmd.c +++ /dev/null @@ -1,235 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c - * - * Verificion code for aDSP VENC packets from userspace. - * - * Copyright (c) 2008 QUALCOMM Incorporated - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <linux/io.h> - -#define ADSP_DEBUG_MSGS 0 -#if ADSP_DEBUG_MSGS -#define DLOG(fmt,args...) \ - do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ - ##args); } \ - while (0) -#else -#define DLOG(x...) do {} while (0) -#endif - -#include <mach/qdsp5/qdsp5venccmdi.h> -#include "adsp.h" - - -static unsigned short x_dimension, y_dimension; - -static inline void *high_low_short_to_ptr(unsigned short high, - unsigned short low) -{ - return (void *)((((unsigned long)high) << 16) | ((unsigned long)low)); -} - -static inline void ptr_to_high_low_short(void *ptr, unsigned short *high, - unsigned short *low) -{ - *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff); - *low = (unsigned short)((unsigned long)ptr & 0xffff); -} - -static int pmem_fixup_high_low(unsigned short *high, - unsigned short *low, - unsigned short size_high, - unsigned short size_low, - struct msm_adsp_module *module, - unsigned long *addr, unsigned long *size) -{ - void *phys_addr; - unsigned long phys_size; - unsigned long kvaddr; - - phys_addr = high_low_short_to_ptr(*high, *low); - phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low); - DLOG("virt %x %x\n", phys_addr, phys_size); - if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) { - DLOG("ah%x al%x sh%x sl%x addr %x size %x\n", - *high, *low, size_high, size_low, phys_addr, phys_size); - return -1; - } - ptr_to_high_low_short(phys_addr, high, low); - DLOG("phys %x %x\n", phys_addr, phys_size); - if (addr) - *addr = kvaddr; - if (size) - *size = phys_size; - return 0; -} - -static int verify_venc_cmd(struct msm_adsp_module *module, - void *cmd_data, size_t cmd_size) -{ - unsigned short cmd_id = ((unsigned short *)cmd_data)[0]; - unsigned long frame_buf_size, luma_buf_size, chroma_buf_size; - unsigned short frame_buf_size_high, frame_buf_size_low; - unsigned short luma_buf_size_high, luma_buf_size_low; - unsigned short chroma_buf_size_high, chroma_buf_size_low; - videnc_cmd_cfg *config_cmd; - videnc_cmd_frame_start *frame_cmd; - videnc_cmd_dis *dis_cmd; - - DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data); - switch (cmd_id) { - case VIDENC_CMD_ACTIVE: - if (cmd_size < sizeof(videnc_cmd_active)) - return -1; - break; - case VIDENC_CMD_IDLE: - if (cmd_size < sizeof(videnc_cmd_idle)) - return -1; - x_dimension = y_dimension = 0; - break; - case VIDENC_CMD_STATUS_QUERY: - if (cmd_size < sizeof(videnc_cmd_status_query)) - return -1; - break; - case VIDENC_CMD_RC_CFG: - if (cmd_size < sizeof(videnc_cmd_rc_cfg)) - return -1; - break; - case VIDENC_CMD_INTRA_REFRESH: - if (cmd_size < sizeof(videnc_cmd_intra_refresh)) - return -1; - break; - case VIDENC_CMD_DIGITAL_ZOOM: - if (cmd_size < sizeof(videnc_cmd_digital_zoom)) - return -1; - break; - case VIDENC_CMD_DIS_CFG: - if (cmd_size < sizeof(videnc_cmd_dis_cfg)) - return -1; - break; - case VIDENC_CMD_CFG: - if (cmd_size < sizeof(videnc_cmd_cfg)) - return -1; - config_cmd = (videnc_cmd_cfg *)cmd_data; - x_dimension = ((config_cmd->venc_frame_dim) & 0xFF00)>>8; - x_dimension = x_dimension*16; - y_dimension = (config_cmd->venc_frame_dim) & 0xFF; - y_dimension = y_dimension * 16; - break; - case VIDENC_CMD_FRAME_START: - if (cmd_size < sizeof(videnc_cmd_frame_start)) - return -1; - frame_cmd = (videnc_cmd_frame_start *)cmd_data; - luma_buf_size = x_dimension * y_dimension; - chroma_buf_size = luma_buf_size>>1; - frame_buf_size = luma_buf_size + chroma_buf_size; - ptr_to_high_low_short((void *)luma_buf_size, - &luma_buf_size_high, - &luma_buf_size_low); - ptr_to_high_low_short((void *)chroma_buf_size, - &chroma_buf_size_high, - &chroma_buf_size_low); - ptr_to_high_low_short((void *)frame_buf_size, - &frame_buf_size_high, - &frame_buf_size_low); - /* Address of raw Y data. */ - if (pmem_fixup_high_low(&frame_cmd->input_luma_addr_high, - &frame_cmd->input_luma_addr_low, - luma_buf_size_high, - luma_buf_size_low, - module, - NULL, NULL)) - return -1; - /* Address of raw CbCr data */ - if (pmem_fixup_high_low(&frame_cmd->input_chroma_addr_high, - &frame_cmd->input_chroma_addr_low, - chroma_buf_size_high, - chroma_buf_size_low, - module, - NULL, NULL)) - return -1; - /* Reference VOP */ - if (pmem_fixup_high_low(&frame_cmd->ref_vop_buf_ptr_high, - &frame_cmd->ref_vop_buf_ptr_low, - frame_buf_size_high, - frame_buf_size_low, - module, - NULL, NULL)) - return -1; - /* Encoded Packet Address */ - if (pmem_fixup_high_low(&frame_cmd->enc_pkt_buf_ptr_high, - &frame_cmd->enc_pkt_buf_ptr_low, - frame_cmd->enc_pkt_buf_size_high, - frame_cmd->enc_pkt_buf_size_low, - module, - NULL, NULL)) - return -1; - /* Unfiltered VOP Buffer Address */ - if (pmem_fixup_high_low( - &frame_cmd->unfilt_recon_vop_buf_ptr_high, - &frame_cmd->unfilt_recon_vop_buf_ptr_low, - frame_buf_size_high, - frame_buf_size_low, - module, - NULL, NULL)) - return -1; - /* Filtered VOP Buffer Address */ - if (pmem_fixup_high_low(&frame_cmd->filt_recon_vop_buf_ptr_high, - &frame_cmd->filt_recon_vop_buf_ptr_low, - frame_buf_size_high, - frame_buf_size_low, - module, - NULL, NULL)) - return -1; - break; - case VIDENC_CMD_DIS: - if (cmd_size < sizeof(videnc_cmd_dis)) - return -1; - dis_cmd = (videnc_cmd_dis *)cmd_data; - luma_buf_size = x_dimension * y_dimension; - ptr_to_high_low_short((void *)luma_buf_size, - &luma_buf_size_high, - &luma_buf_size_low); - /* Prev VFE Luma Output Address */ - if (pmem_fixup_high_low(&dis_cmd->vfe_out_prev_luma_addr_high, - &dis_cmd->vfe_out_prev_luma_addr_low, - luma_buf_size_high, - luma_buf_size_low, - module, - NULL, NULL)) - return -1; - break; - default: - printk(KERN_INFO "adsp_video:unknown encoder video command %u\n", - cmd_id); - return 0; - } - - return 0; -} - - -int adsp_videoenc_verify_cmd(struct msm_adsp_module *module, - unsigned int queue_id, void *cmd_data, - size_t cmd_size) -{ - switch (queue_id) { - case QDSP_mpuVEncCmdQueue: - DLOG("\n"); - return verify_venc_cmd(module, cmd_data, cmd_size); - default: - printk(KERN_INFO "unknown video queue %u\n", queue_id); - return 0; - } -} - diff --git a/drivers/staging/dream/qdsp5/audio_aac.c b/drivers/staging/dream/qdsp5/audio_aac.c deleted file mode 100644 index 45f4c78ab6e7..000000000000 --- a/drivers/staging/dream/qdsp5/audio_aac.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audio_aac.c - * - * aac audio decoder device - * - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2008-2009 QUALCOMM USA, INC. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include "audmgr.h" - -#include <mach/msm_adsp.h> -#include <mach/msm_audio_aac.h> -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> -#include <mach/qdsp5/qdsp5audplaycmdi.h> -#include <mach/qdsp5/qdsp5audplaymsg.h> - -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -#ifdef DEBUG -#define dprintk(format, arg...) \ -printk(KERN_DEBUG format, ## arg) -#else -#define dprintk(format, arg...) do {} while (0) -#endif - -#define BUFSZ 32768 -#define DMASZ (BUFSZ * 2) - -#define AUDPLAY_INVALID_READ_PTR_OFFSET 0xFFFF -#define AUDDEC_DEC_AAC 5 - -#define PCM_BUFSZ_MIN 9600 /* Hold one stereo AAC frame */ -#define PCM_BUF_MAX_COUNT 5 /* DSP only accepts 5 buffers at most - but support 2 buffers currently */ -#define ROUTING_MODE_FTRT 1 -#define ROUTING_MODE_RT 2 -/* Decoder status received from AUDPPTASK */ -#define AUDPP_DEC_STATUS_SLEEP 0 -#define AUDPP_DEC_STATUS_INIT 1 -#define AUDPP_DEC_STATUS_CFG 2 -#define AUDPP_DEC_STATUS_PLAY 3 - -struct buffer { - void *data; - unsigned size; - unsigned used; /* Input usage actual DSP produced PCM size */ - unsigned addr; -}; - -struct audio { - struct buffer out[2]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - - atomic_t out_bytes; - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t write_wait; - - /* Host PCM section */ - struct buffer in[PCM_BUF_MAX_COUNT]; - struct mutex read_lock; - wait_queue_head_t read_wait; /* Wait queue for read */ - char *read_data; /* pointer to reader buffer */ - dma_addr_t read_phys; /* physical address of reader buffer */ - uint8_t read_next; /* index to input buffers to be read next */ - uint8_t fill_next; /* index to buffer that DSP should be filling */ - uint8_t pcm_buf_count; /* number of pcm buffer allocated */ - /* ---- End of Host PCM section */ - - struct msm_adsp_module *audplay; - - /* configuration to use on next enable */ - uint32_t out_sample_rate; - uint32_t out_channel_mode; - struct msm_audio_aac_config aac_config; - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - int rflush; /* Read flush */ - int wflush; /* Write flush */ - int opened; - int enabled; - int running; - int stopped; /* set when stopped, cleared on flush */ - int pcm_feedback; - int buf_refresh; - - int reserved; /* A byte is being reserved */ - char rsv_byte; /* Handle odd length user data */ - - unsigned volume; - - uint16_t dec_id; - uint32_t read_ptr_offset; -}; - -static int auddec_dsp_config(struct audio *audio, int enable); -static void audpp_cmd_cfg_adec_params(struct audio *audio); -static void audpp_cmd_cfg_routing_mode(struct audio *audio); -static void audplay_send_data(struct audio *audio, unsigned needed); -static void audplay_config_hostpcm(struct audio *audio); -static void audplay_buffer_refresh(struct audio *audio); -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg); - -/* must be called with audio->lock held */ -static int audio_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - dprintk("audio_enable()\n"); - - if (audio->enabled) - return 0; - - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK; - cfg.codec = RPC_AUD_DEF_CODEC_AAC; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audplay)) { - pr_err("audio: msm_adsp_enable(audplay) failed\n"); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - msm_adsp_disable(audio->audplay); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audio_disable(struct audio *audio) -{ - dprintk("audio_disable()\n"); - if (audio->enabled) { - audio->enabled = 0; - auddec_dsp_config(audio, 0); - wake_up(&audio->write_wait); - wake_up(&audio->read_wait); - msm_adsp_disable(audio->audplay); - audpp_disable(audio->dec_id, audio); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload) -{ - uint8_t index; - unsigned long flags; - - if (audio->rflush) - return; - - spin_lock_irqsave(&audio->dsp_lock, flags); - for (index = 0; index < payload[1]; index++) { - if (audio->in[audio->fill_next].addr == - payload[2 + index * 2]) { - dprintk("audio_update_pcm_buf_entry: in[%d] ready\n", - audio->fill_next); - audio->in[audio->fill_next].used = - payload[3 + index * 2]; - if ((++audio->fill_next) == audio->pcm_buf_count) - audio->fill_next = 0; - - } else { - pr_err - ("audio_update_pcm_buf_entry: expected=%x ret=%x\n" - , audio->in[audio->fill_next].addr, - payload[1 + index * 2]); - break; - } - } - if (audio->in[audio->fill_next].used == 0) { - audplay_buffer_refresh(audio); - } else { - dprintk("audio_update_pcm_buf_entry: read cannot keep up\n"); - audio->buf_refresh = 1; - } - wake_up(&audio->read_wait); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - -} - -static void audplay_dsp_event(void *data, unsigned id, size_t len, - void (*getevent) (void *ptr, size_t len)) -{ - struct audio *audio = data; - uint32_t msg[28]; - getevent(msg, sizeof(msg)); - - dprintk("audplay_dsp_event: msg_id=%x\n", id); - - switch (id) { - case AUDPLAY_MSG_DEC_NEEDS_DATA: - audplay_send_data(audio, 1); - break; - - case AUDPLAY_MSG_BUFFER_UPDATE: - audio_update_pcm_buf_entry(audio, msg); - break; - - default: - pr_err("unexpected message from decoder \n"); - } -} - -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned status = msg[1]; - - switch (status) { - case AUDPP_DEC_STATUS_SLEEP: - dprintk("decoder status: sleep \n"); - break; - - case AUDPP_DEC_STATUS_INIT: - dprintk("decoder status: init \n"); - audpp_cmd_cfg_routing_mode(audio); - break; - - case AUDPP_DEC_STATUS_CFG: - dprintk("decoder status: cfg \n"); - break; - case AUDPP_DEC_STATUS_PLAY: - dprintk("decoder status: play \n"); - if (audio->pcm_feedback) { - audplay_config_hostpcm(audio); - audplay_buffer_refresh(audio); - } - break; - default: - pr_err("unknown decoder status \n"); - } - break; - } - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - dprintk("audio_dsp_event: CFG_MSG ENABLE\n"); - auddec_dsp_config(audio, 1); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(audio->dec_id, audio->volume, - 0); - audpp_avsync(audio->dec_id, 22050); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - dprintk("audio_dsp_event: CFG_MSG DISABLE\n"); - audpp_avsync(audio->dec_id, 0); - audio->running = 0; - } else { - pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - dprintk("audio_dsp_event: ROUTING_ACK mode=%d\n", msg[1]); - audpp_cmd_cfg_adec_params(audio); - break; - - case AUDPP_MSG_FLUSH_ACK: - dprintk("%s: FLUSH_ACK\n", __func__); - audio->wflush = 0; - audio->rflush = 0; - if (audio->pcm_feedback) - audplay_buffer_refresh(audio); - break; - - default: - pr_err("audio_dsp_event: UNKNOWN (%d)\n", id); - } - -} - -struct msm_adsp_ops audplay_adsp_ops_aac = { - .event = audplay_dsp_event, -}; - -#define audplay_send_queue0(audio, cmd, len) \ - msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \ - cmd, len) - -static int auddec_dsp_config(struct audio *audio, int enable) -{ - audpp_cmd_cfg_dec_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE; - if (enable) - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AAC; - else - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_adec_params(struct audio *audio) -{ - audpp_cmd_cfg_adec_params_aac cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS; - cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN; - cmd.common.dec_id = audio->dec_id; - cmd.common.input_sampling_frequency = audio->out_sample_rate; - cmd.format = audio->aac_config.format; - cmd.audio_object = audio->aac_config.audio_object; - cmd.ep_config = audio->aac_config.ep_config; - cmd.aac_section_data_resilience_flag = - audio->aac_config.aac_section_data_resilience_flag; - cmd.aac_scalefactor_data_resilience_flag = - audio->aac_config.aac_scalefactor_data_resilience_flag; - cmd.aac_spectral_data_resilience_flag = - audio->aac_config.aac_spectral_data_resilience_flag; - cmd.sbr_on_flag = audio->aac_config.sbr_on_flag; - cmd.sbr_ps_on_flag = audio->aac_config.sbr_ps_on_flag; - cmd.channel_configuration = audio->aac_config.channel_configuration; - - audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_routing_mode(struct audio *audio) -{ - struct audpp_cmd_routing_mode cmd; - dprintk("audpp_cmd_cfg_routing_mode()\n"); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_ROUTING_MODE; - cmd.object_number = audio->dec_id; - if (audio->pcm_feedback) - cmd.routing_mode = ROUTING_MODE_FTRT; - else - cmd.routing_mode = ROUTING_MODE_RT; - - audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static int audplay_dsp_send_data_avail(struct audio *audio, - unsigned idx, unsigned len) -{ - audplay_cmd_bitstream_data_avail cmd; - - cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL; - cmd.decoder_id = audio->dec_id; - cmd.buf_ptr = audio->out[idx].addr; - cmd.buf_size = len / 2; - cmd.partition_number = 0; - return audplay_send_queue0(audio, &cmd, sizeof(cmd)); -} - -static void audplay_buffer_refresh(struct audio *audio) -{ - struct audplay_cmd_buffer_refresh refresh_cmd; - - refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH; - refresh_cmd.num_buffers = 1; - refresh_cmd.buf0_address = audio->in[audio->fill_next].addr; - refresh_cmd.buf0_length = audio->in[audio->fill_next].size - - (audio->in[audio->fill_next].size % 1024); /* AAC frame size */ - refresh_cmd.buf_read_count = 0; - dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n", - refresh_cmd.buf0_address, refresh_cmd.buf0_length); - (void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd)); -} - -static void audplay_config_hostpcm(struct audio *audio) -{ - struct audplay_cmd_hpcm_buf_cfg cfg_cmd; - - dprintk("audplay_config_hostpcm()\n"); - cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG; - cfg_cmd.max_buffers = audio->pcm_buf_count; - cfg_cmd.byte_swap = 0; - cfg_cmd.hostpcm_config = (0x8000) | (0x4000); - cfg_cmd.feedback_frequency = 1; - cfg_cmd.partition_number = 0; - (void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd)); - -} - -static void audplay_send_data(struct audio *audio, unsigned needed) -{ - struct buffer *frame; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (!audio->running) - goto done; - - if (needed && !audio->wflush) { - /* We were called from the callback because the DSP - * requested more data. Note that the DSP does want - * more data, and if a buffer was in-flight, mark it - * as available (since the DSP must now be done with - * it). - */ - audio->out_needed = 1; - frame = audio->out + audio->out_tail; - if (frame->used == 0xffffffff) { - dprintk("frame %d free\n", audio->out_tail); - frame->used = 0; - audio->out_tail ^= 1; - wake_up(&audio->write_wait); - } - } - - if (audio->out_needed) { - /* If the DSP currently wants data and we have a - * buffer available, we will send it and reset - * the needed flag. We'll mark the buffer as in-flight - * so that it won't be recycled until the next buffer - * is requested - */ - - frame = audio->out + audio->out_tail; - if (frame->used) { - BUG_ON(frame->used == 0xffffffff); -/* printk("frame %d busy\n", audio->out_tail); */ - audplay_dsp_send_data_avail(audio, audio->out_tail, - frame->used); - frame->used = 0xffffffff; - audio->out_needed = 0; - } - } - done: - spin_unlock_irqrestore(&audio->dsp_lock, flags); -} - -/* ------------------- device --------------------- */ - -static void audio_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->reserved = 0; - audio->out_needed = 0; - atomic_set(&audio->out_bytes, 0); -} - -static void audio_flush_pcm_buf(struct audio *audio) -{ - uint8_t index; - - for (index = 0; index < PCM_BUF_MAX_COUNT; index++) - audio->in[index].used = 0; - audio->buf_refresh = 0; - audio->read_next = 0; - audio->fill_next = 0; -} - -static int audaac_validate_usr_config(struct msm_audio_aac_config *config) -{ - int ret_val = -1; - - if (config->format != AUDIO_AAC_FORMAT_ADTS && - config->format != AUDIO_AAC_FORMAT_RAW && - config->format != AUDIO_AAC_FORMAT_PSUEDO_RAW && - config->format != AUDIO_AAC_FORMAT_LOAS) - goto done; - - if (config->audio_object != AUDIO_AAC_OBJECT_LC && - config->audio_object != AUDIO_AAC_OBJECT_LTP && - config->audio_object != AUDIO_AAC_OBJECT_ERLC) - goto done; - - if (config->audio_object == AUDIO_AAC_OBJECT_ERLC) { - if (config->ep_config > 3) - goto done; - if (config->aac_scalefactor_data_resilience_flag != - AUDIO_AAC_SCA_DATA_RES_OFF && - config->aac_scalefactor_data_resilience_flag != - AUDIO_AAC_SCA_DATA_RES_ON) - goto done; - if (config->aac_section_data_resilience_flag != - AUDIO_AAC_SEC_DATA_RES_OFF && - config->aac_section_data_resilience_flag != - AUDIO_AAC_SEC_DATA_RES_ON) - goto done; - if (config->aac_spectral_data_resilience_flag != - AUDIO_AAC_SPEC_DATA_RES_OFF && - config->aac_spectral_data_resilience_flag != - AUDIO_AAC_SPEC_DATA_RES_ON) - goto done; - } else { - config->aac_section_data_resilience_flag = - AUDIO_AAC_SEC_DATA_RES_OFF; - config->aac_scalefactor_data_resilience_flag = - AUDIO_AAC_SCA_DATA_RES_OFF; - config->aac_spectral_data_resilience_flag = - AUDIO_AAC_SPEC_DATA_RES_OFF; - } - - if (config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_OFF && - config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_ON) - goto done; - - if (config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_OFF && - config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_ON) - goto done; - - if (config->dual_mono_mode > AUDIO_AAC_DUAL_MONO_PL_SR) - goto done; - - if (config->channel_configuration > 2) - goto done; - - ret_val = 0; - done: - return ret_val; -} - -static void audio_ioport_reset(struct audio *audio) -{ - /* Make sure read/write thread are free from - * sleep and knowing that system is not able - * to process io request at the moment - */ - wake_up(&audio->write_wait); - mutex_lock(&audio->write_lock); - audio_flush(audio); - mutex_unlock(&audio->write_lock); - wake_up(&audio->read_wait); - mutex_lock(&audio->read_lock); - audio_flush_pcm_buf(audio); - mutex_unlock(&audio->read_lock); -} - -static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0; - - dprintk("audio_ioctl() cmd = %d\n", cmd); - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = audpp_avsync_byte_count(audio->dec_id); - stats.sample_count = audpp_avsync_sample_count(audio->dec_id); - if (copy_to_user((void *)arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(audio->dec_id, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - return 0; - } - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audio_enable(audio); - break; - case AUDIO_STOP: - rc = audio_disable(audio); - audio->stopped = 1; - audio_ioport_reset(audio); - audio->stopped = 0; - break; - case AUDIO_FLUSH: - dprintk("%s: AUDIO_FLUSH\n", __func__); - audio->rflush = 1; - audio->wflush = 1; - audio_ioport_reset(audio); - if (audio->running) - audpp_flush(audio->dec_id); - else { - audio->rflush = 0; - audio->wflush = 0; - } - break; - - case AUDIO_SET_CONFIG:{ - struct msm_audio_config config; - - if (copy_from_user - (&config, (void *)arg, sizeof(config))) { - rc = -EFAULT; - break; - } - - if (config.channel_count == 1) { - config.channel_count = - AUDPP_CMD_PCM_INTF_MONO_V; - } else if (config.channel_count == 2) { - config.channel_count = - AUDPP_CMD_PCM_INTF_STEREO_V; - } else { - rc = -EINVAL; - break; - } - - audio->out_sample_rate = config.sample_rate; - audio->out_channel_mode = config.channel_count; - rc = 0; - break; - } - case AUDIO_GET_CONFIG:{ - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = audio->out_sample_rate; - if (audio->out_channel_mode == - AUDPP_CMD_PCM_INTF_MONO_V) { - config.channel_count = 1; - } else { - config.channel_count = 2; - } - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - - break; - } - case AUDIO_GET_AAC_CONFIG:{ - if (copy_to_user((void *)arg, &audio->aac_config, - sizeof(audio->aac_config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_AAC_CONFIG:{ - struct msm_audio_aac_config usr_config; - - if (copy_from_user - (&usr_config, (void *)arg, - sizeof(usr_config))) { - rc = -EFAULT; - break; - } - - if (audaac_validate_usr_config(&usr_config) == 0) { - audio->aac_config = usr_config; - rc = 0; - } else - rc = -EINVAL; - - break; - } - case AUDIO_GET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - config.pcm_feedback = 0; - config.buffer_count = PCM_BUF_MAX_COUNT; - config.buffer_size = PCM_BUFSZ_MIN; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - if (copy_from_user - (&config, (void *)arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if ((config.buffer_count > PCM_BUF_MAX_COUNT) || - (config.buffer_count == 1)) - config.buffer_count = PCM_BUF_MAX_COUNT; - - if (config.buffer_size < PCM_BUFSZ_MIN) - config.buffer_size = PCM_BUFSZ_MIN; - - /* Check if pcm feedback is required */ - if ((config.pcm_feedback) && (!audio->read_data)) { - dprintk("ioctl: allocate PCM buffer %d\n", - config.buffer_count * - config.buffer_size); - audio->read_data = - dma_alloc_coherent(NULL, - config.buffer_size * - config.buffer_count, - &audio->read_phys, - GFP_KERNEL); - if (!audio->read_data) { - pr_err("audio_aac: buf alloc fail\n"); - rc = -1; - } else { - uint8_t index; - uint32_t offset = 0; - audio->pcm_feedback = 1; - audio->buf_refresh = 0; - audio->pcm_buf_count = - config.buffer_count; - audio->read_next = 0; - audio->fill_next = 0; - - for (index = 0; - index < config.buffer_count; - index++) { - audio->in[index].data = - audio->read_data + offset; - audio->in[index].addr = - audio->read_phys + offset; - audio->in[index].size = - config.buffer_size; - audio->in[index].used = 0; - offset += config.buffer_size; - } - rc = 0; - } - } else { - rc = 0; - } - break; - } - case AUDIO_PAUSE: - dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg); - rc = audpp_pause(audio->dec_id, (int) arg); - break; - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audio_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - int rc = 0; - - if (!audio->pcm_feedback) - return 0; /* PCM feedback is not enabled. Nothing to read */ - - mutex_lock(&audio->read_lock); - dprintk("audio_read() %d \n", count); - while (count > 0) { - rc = wait_event_interruptible(audio->read_wait, - (audio->in[audio->read_next]. - used > 0) || (audio->stopped) - || (audio->rflush)); - - if (rc < 0) - break; - - if (audio->stopped || audio->rflush) { - rc = -EBUSY; - break; - } - - if (count < audio->in[audio->read_next].used) { - /* Read must happen in frame boundary. Since driver - does not know frame size, read count must be greater - or equal to size of PCM samples */ - dprintk("audio_read: no partial frame done reading\n"); - break; - } else { - dprintk("audio_read: read from in[%d]\n", - audio->read_next); - if (copy_to_user - (buf, audio->in[audio->read_next].data, - audio->in[audio->read_next].used)) { - pr_err("audio_read: invalid addr %x \n", - (unsigned int)buf); - rc = -EFAULT; - break; - } - count -= audio->in[audio->read_next].used; - buf += audio->in[audio->read_next].used; - audio->in[audio->read_next].used = 0; - if ((++audio->read_next) == audio->pcm_buf_count) - audio->read_next = 0; - if (audio->in[audio->read_next].used == 0) - break; /* No data ready at this moment - * Exit while loop to prevent - * output thread sleep too long - */ - } - } - - /* don't feed output buffer to HW decoder during flushing - * buffer refresh command will be sent once flush completes - * send buf refresh command here can confuse HW decoder - */ - if (audio->buf_refresh && !audio->rflush) { - audio->buf_refresh = 0; - dprintk("audio_read: kick start pcm feedback again\n"); - audplay_buffer_refresh(audio); - } - - mutex_unlock(&audio->read_lock); - - if (buf > start) - rc = buf - start; - - dprintk("audio_read: read %d bytes\n", rc); - return rc; -} - -static ssize_t audio_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - char *cpy_ptr; - int rc = 0; - unsigned dsize; - - mutex_lock(&audio->write_lock); - while (count > 0) { - frame = audio->out + audio->out_head; - cpy_ptr = frame->data; - dsize = 0; - rc = wait_event_interruptible(audio->write_wait, - (frame->used == 0) - || (audio->stopped) - || (audio->wflush)); - if (rc < 0) - break; - if (audio->stopped || audio->wflush) { - rc = -EBUSY; - break; - } - - if (audio->reserved) { - dprintk("%s: append reserved byte %x\n", - __func__, audio->rsv_byte); - *cpy_ptr = audio->rsv_byte; - xfer = (count > (frame->size - 1)) ? - frame->size - 1 : count; - cpy_ptr++; - dsize = 1; - audio->reserved = 0; - } else - xfer = (count > frame->size) ? frame->size : count; - - if (copy_from_user(cpy_ptr, buf, xfer)) { - rc = -EFAULT; - break; - } - - dsize += xfer; - if (dsize & 1) { - audio->rsv_byte = ((char *) frame->data)[dsize - 1]; - dprintk("%s: odd length buf reserve last byte %x\n", - __func__, audio->rsv_byte); - audio->reserved = 1; - dsize--; - } - count -= xfer; - buf += xfer; - - if (dsize > 0) { - audio->out_head ^= 1; - frame->used = dsize; - audplay_send_data(audio, 0); - } - } - mutex_unlock(&audio->write_lock); - if (buf > start) - return buf - start; - return rc; -} - -static int audio_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - dprintk("audio_release()\n"); - - mutex_lock(&audio->lock); - audio_disable(audio); - audio_flush(audio); - audio_flush_pcm_buf(audio); - msm_adsp_put(audio->audplay); - audio->audplay = NULL; - audio->opened = 0; - audio->reserved = 0; - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - audio->data = NULL; - if (audio->read_data != NULL) { - dma_free_coherent(NULL, - audio->in[0].size * audio->pcm_buf_count, - audio->read_data, audio->read_phys); - audio->read_data = NULL; - } - audio->pcm_feedback = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio the_aac_audio; - -static int audio_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_aac_audio; - int rc; - - mutex_lock(&audio->lock); - - if (audio->opened) { - pr_err("audio: busy\n"); - rc = -EBUSY; - goto done; - } - - if (!audio->data) { - audio->data = dma_alloc_coherent(NULL, DMASZ, - &audio->phys, GFP_KERNEL); - if (!audio->data) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto done; - } - } - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto done; - - rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, - &audplay_adsp_ops_aac, audio); - if (rc) { - pr_err("audio: failed to get audplay0 dsp module\n"); - goto done; - } - audio->out_sample_rate = 44100; - audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V; - audio->aac_config.format = AUDIO_AAC_FORMAT_ADTS; - audio->aac_config.audio_object = AUDIO_AAC_OBJECT_LC; - audio->aac_config.ep_config = 0; - audio->aac_config.aac_section_data_resilience_flag = - AUDIO_AAC_SEC_DATA_RES_OFF; - audio->aac_config.aac_scalefactor_data_resilience_flag = - AUDIO_AAC_SCA_DATA_RES_OFF; - audio->aac_config.aac_spectral_data_resilience_flag = - AUDIO_AAC_SPEC_DATA_RES_OFF; - audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_ON; - audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_ON; - audio->aac_config.dual_mono_mode = AUDIO_AAC_DUAL_MONO_PL_SR; - audio->aac_config.channel_configuration = 2; - audio->dec_id = 0; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = BUFSZ; - - audio->out[1].data = audio->data + BUFSZ; - audio->out[1].addr = audio->phys + BUFSZ; - audio->out[1].size = BUFSZ; - - audio->volume = 0x2000; /* Q13 1.0 */ - - audio_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; -done: - mutex_unlock(&audio->lock); - return rc; -} - -static struct file_operations audio_aac_fops = { - .owner = THIS_MODULE, - .open = audio_open, - .release = audio_release, - .read = audio_read, - .write = audio_write, - .unlocked_ioctl = audio_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_aac_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_aac", - .fops = &audio_aac_fops, -}; - -static int __init audio_init(void) -{ - mutex_init(&the_aac_audio.lock); - mutex_init(&the_aac_audio.write_lock); - mutex_init(&the_aac_audio.read_lock); - spin_lock_init(&the_aac_audio.dsp_lock); - init_waitqueue_head(&the_aac_audio.write_wait); - init_waitqueue_head(&the_aac_audio.read_wait); - the_aac_audio.read_data = NULL; - return misc_register(&audio_aac_misc); -} - -device_initcall(audio_init); diff --git a/drivers/staging/dream/qdsp5/audio_amrnb.c b/drivers/staging/dream/qdsp5/audio_amrnb.c deleted file mode 100644 index 402bbc13281a..000000000000 --- a/drivers/staging/dream/qdsp5/audio_amrnb.c +++ /dev/null @@ -1,875 +0,0 @@ -/* linux/arch/arm/mach-msm/qdsp5/audio_amrnb.c - * - * amrnb audio decoder device - * - * Copyright (c) 2008 QUALCOMM USA, INC. - * - * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c - * - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * All source code in this file is licensed under the following license except - * where indicated. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can find it at http://www.fsf.org - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> -#include <linux/msm_audio.h> -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> -#include <mach/qdsp5/qdsp5audplaycmdi.h> -#include <mach/qdsp5/qdsp5audplaymsg.h> - -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -#define DEBUG -#ifdef DEBUG -#define dprintk(format, arg...) \ -printk(KERN_DEBUG format, ## arg) -#else -#define dprintk(format, arg...) do {} while (0) -#endif - -#define BUFSZ 1024 /* Hold minimum 700ms voice data */ -#define DMASZ (BUFSZ * 2) - -#define AUDPLAY_INVALID_READ_PTR_OFFSET 0xFFFF -#define AUDDEC_DEC_AMRNB 10 - -#define PCM_BUFSZ_MIN 1600 /* 100ms worth of data */ -#define AMRNB_DECODED_FRSZ 320 /* AMR-NB 20ms 8KHz mono PCM size */ -#define PCM_BUF_MAX_COUNT 5 /* DSP only accepts 5 buffers at most - but support 2 buffers currently */ -#define ROUTING_MODE_FTRT 1 -#define ROUTING_MODE_RT 2 -/* Decoder status received from AUDPPTASK */ -#define AUDPP_DEC_STATUS_SLEEP 0 -#define AUDPP_DEC_STATUS_INIT 1 -#define AUDPP_DEC_STATUS_CFG 2 -#define AUDPP_DEC_STATUS_PLAY 3 - -struct buffer { - void *data; - unsigned size; - unsigned used; /* Input usage actual DSP produced PCM size */ - unsigned addr; -}; - -struct audio { - struct buffer out[2]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - - atomic_t out_bytes; - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t write_wait; - - /* Host PCM section */ - struct buffer in[PCM_BUF_MAX_COUNT]; - struct mutex read_lock; - wait_queue_head_t read_wait; /* Wait queue for read */ - char *read_data; /* pointer to reader buffer */ - dma_addr_t read_phys; /* physical address of reader buffer */ - uint8_t read_next; /* index to input buffers to be read next */ - uint8_t fill_next; /* index to buffer that DSP should be filling */ - uint8_t pcm_buf_count; /* number of pcm buffer allocated */ - /* ---- End of Host PCM section */ - - struct msm_adsp_module *audplay; - - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - uint8_t opened:1; - uint8_t enabled:1; - uint8_t running:1; - uint8_t stopped:1; /* set when stopped, cleared on flush */ - uint8_t pcm_feedback:1; - uint8_t buf_refresh:1; - - unsigned volume; - - uint16_t dec_id; - uint32_t read_ptr_offset; -}; - -struct audpp_cmd_cfg_adec_params_amrnb { - audpp_cmd_cfg_adec_params_common common; - unsigned short stereo_cfg; -} __attribute__((packed)) ; - -static int auddec_dsp_config(struct audio *audio, int enable); -static void audpp_cmd_cfg_adec_params(struct audio *audio); -static void audpp_cmd_cfg_routing_mode(struct audio *audio); -static void audamrnb_send_data(struct audio *audio, unsigned needed); -static void audamrnb_config_hostpcm(struct audio *audio); -static void audamrnb_buffer_refresh(struct audio *audio); -static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg); - -/* must be called with audio->lock held */ -static int audamrnb_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - dprintk("audamrnb_enable()\n"); - - if (audio->enabled) - return 0; - - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK; - cfg.codec = RPC_AUD_DEF_CODEC_AMR_NB; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audplay)) { - pr_err("audio: msm_adsp_enable(audplay) failed\n"); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - if (audpp_enable(audio->dec_id, audamrnb_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - msm_adsp_disable(audio->audplay); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audamrnb_disable(struct audio *audio) -{ - dprintk("audamrnb_disable()\n"); - if (audio->enabled) { - audio->enabled = 0; - auddec_dsp_config(audio, 0); - wake_up(&audio->write_wait); - wake_up(&audio->read_wait); - msm_adsp_disable(audio->audplay); - audpp_disable(audio->dec_id, audio); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audamrnb_update_pcm_buf_entry(struct audio *audio, - uint32_t *payload) -{ - uint8_t index; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - for (index = 0; index < payload[1]; index++) { - if (audio->in[audio->fill_next].addr == - payload[2 + index * 2]) { - dprintk("audamrnb_update_pcm_buf_entry: in[%d] ready\n", - audio->fill_next); - audio->in[audio->fill_next].used = - payload[3 + index * 2]; - if ((++audio->fill_next) == audio->pcm_buf_count) - audio->fill_next = 0; - - } else { - pr_err - ("audamrnb_update_pcm_buf_entry: expected=%x ret=%x\n" - , audio->in[audio->fill_next].addr, - payload[1 + index * 2]); - break; - } - } - if (audio->in[audio->fill_next].used == 0) { - audamrnb_buffer_refresh(audio); - } else { - dprintk("audamrnb_update_pcm_buf_entry: read cannot keep up\n"); - audio->buf_refresh = 1; - } - - spin_unlock_irqrestore(&audio->dsp_lock, flags); - wake_up(&audio->read_wait); -} - -static void audplay_dsp_event(void *data, unsigned id, size_t len, - void (*getevent) (void *ptr, size_t len)) -{ - struct audio *audio = data; - uint32_t msg[28]; - getevent(msg, sizeof(msg)); - - dprintk("audplay_dsp_event: msg_id=%x\n", id); - - switch (id) { - case AUDPLAY_MSG_DEC_NEEDS_DATA: - audamrnb_send_data(audio, 1); - break; - - case AUDPLAY_MSG_BUFFER_UPDATE: - audamrnb_update_pcm_buf_entry(audio, msg); - break; - - default: - pr_err("unexpected message from decoder \n"); - } -} - -static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned status = msg[1]; - - switch (status) { - case AUDPP_DEC_STATUS_SLEEP: - dprintk("decoder status: sleep \n"); - break; - - case AUDPP_DEC_STATUS_INIT: - dprintk("decoder status: init \n"); - audpp_cmd_cfg_routing_mode(audio); - break; - - case AUDPP_DEC_STATUS_CFG: - dprintk("decoder status: cfg \n"); - break; - case AUDPP_DEC_STATUS_PLAY: - dprintk("decoder status: play \n"); - if (audio->pcm_feedback) { - audamrnb_config_hostpcm(audio); - audamrnb_buffer_refresh(audio); - } - break; - default: - pr_err("unknown decoder status \n"); - break; - } - break; - } - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - dprintk("audamrnb_dsp_event: CFG_MSG ENABLE\n"); - auddec_dsp_config(audio, 1); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(audio->dec_id, audio->volume, - 0); - audpp_avsync(audio->dec_id, 22050); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - dprintk("audamrnb_dsp_event: CFG_MSG DISABLE\n"); - audpp_avsync(audio->dec_id, 0); - audio->running = 0; - } else { - pr_err("audamrnb_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - dprintk("audamrnb_dsp_event: ROUTING_ACK mode=%d\n", msg[1]); - audpp_cmd_cfg_adec_params(audio); - break; - - default: - pr_err("audamrnb_dsp_event: UNKNOWN (%d)\n", id); - } - -} - -struct msm_adsp_ops audplay_adsp_ops_amrnb = { - .event = audplay_dsp_event, -}; - -#define audplay_send_queue0(audio, cmd, len) \ - msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \ - cmd, len) - -static int auddec_dsp_config(struct audio *audio, int enable) -{ - audpp_cmd_cfg_dec_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE; - if (enable) - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRNB; - else - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_adec_params(struct audio *audio) -{ - struct audpp_cmd_cfg_adec_params_amrnb cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS; - cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN; - cmd.common.dec_id = audio->dec_id; - cmd.common.input_sampling_frequency = 8000; - cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V; - - audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_routing_mode(struct audio *audio) -{ - struct audpp_cmd_routing_mode cmd; - dprintk("audpp_cmd_cfg_routing_mode()\n"); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_ROUTING_MODE; - cmd.object_number = audio->dec_id; - if (audio->pcm_feedback) - cmd.routing_mode = ROUTING_MODE_FTRT; - else - cmd.routing_mode = ROUTING_MODE_RT; - - audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static int audplay_dsp_send_data_avail(struct audio *audio, - unsigned idx, unsigned len) -{ - audplay_cmd_bitstream_data_avail cmd; - - cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL; - cmd.decoder_id = audio->dec_id; - cmd.buf_ptr = audio->out[idx].addr; - cmd.buf_size = len / 2; - cmd.partition_number = 0; - return audplay_send_queue0(audio, &cmd, sizeof(cmd)); -} - -static void audamrnb_buffer_refresh(struct audio *audio) -{ - struct audplay_cmd_buffer_refresh refresh_cmd; - - refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH; - refresh_cmd.num_buffers = 1; - refresh_cmd.buf0_address = audio->in[audio->fill_next].addr; - refresh_cmd.buf0_length = audio->in[audio->fill_next].size - - (audio->in[audio->fill_next].size % AMRNB_DECODED_FRSZ); - refresh_cmd.buf_read_count = 0; - dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n", - refresh_cmd.buf0_address, refresh_cmd.buf0_length); - (void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd)); -} - -static void audamrnb_config_hostpcm(struct audio *audio) -{ - struct audplay_cmd_hpcm_buf_cfg cfg_cmd; - - dprintk("audamrnb_config_hostpcm()\n"); - cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG; - cfg_cmd.max_buffers = audio->pcm_buf_count; - cfg_cmd.byte_swap = 0; - cfg_cmd.hostpcm_config = (0x8000) | (0x4000); - cfg_cmd.feedback_frequency = 1; - cfg_cmd.partition_number = 0; - (void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd)); - -} - -static void audamrnb_send_data(struct audio *audio, unsigned needed) -{ - struct buffer *frame; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (!audio->running) - goto done; - - if (needed) { - /* We were called from the callback because the DSP - * requested more data. Note that the DSP does want - * more data, and if a buffer was in-flight, mark it - * as available (since the DSP must now be done with - * it). - */ - audio->out_needed = 1; - frame = audio->out + audio->out_tail; - if (frame->used == 0xffffffff) { - frame->used = 0; - audio->out_tail ^= 1; - wake_up(&audio->write_wait); - } - } - - if (audio->out_needed) { - /* If the DSP currently wants data and we have a - * buffer available, we will send it and reset - * the needed flag. We'll mark the buffer as in-flight - * so that it won't be recycled until the next buffer - * is requested - */ - - frame = audio->out + audio->out_tail; - if (frame->used) { - BUG_ON(frame->used == 0xffffffff); -/* printk("frame %d busy\n", audio->out_tail); */ - audplay_dsp_send_data_avail(audio, audio->out_tail, - frame->used); - frame->used = 0xffffffff; - audio->out_needed = 0; - } - } - done: - spin_unlock_irqrestore(&audio->dsp_lock, flags); -} - -/* ------------------- device --------------------- */ - -static void audamrnb_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->stopped = 0; - atomic_set(&audio->out_bytes, 0); -} - -static void audamrnb_flush_pcm_buf(struct audio *audio) -{ - uint8_t index; - - for (index = 0; index < PCM_BUF_MAX_COUNT; index++) - audio->in[index].used = 0; - - audio->read_next = 0; - audio->fill_next = 0; -} - -static long audamrnb_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0; - - dprintk("audamrnb_ioctl() cmd = %d\n", cmd); - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = audpp_avsync_byte_count(audio->dec_id); - stats.sample_count = audpp_avsync_sample_count(audio->dec_id); - if (copy_to_user((void *)arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(audio->dec_id, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - return 0; - } - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audamrnb_enable(audio); - break; - case AUDIO_STOP: - rc = audamrnb_disable(audio); - audio->stopped = 1; - break; - case AUDIO_FLUSH: - if (audio->stopped) { - /* Make sure we're stopped and we wake any threads - * that might be blocked holding the write_lock. - * While audio->stopped write threads will always - * exit immediately. - */ - wake_up(&audio->write_wait); - mutex_lock(&audio->write_lock); - audamrnb_flush(audio); - mutex_unlock(&audio->write_lock); - wake_up(&audio->read_wait); - mutex_lock(&audio->read_lock); - audamrnb_flush_pcm_buf(audio); - mutex_unlock(&audio->read_lock); - break; - } - - case AUDIO_SET_CONFIG:{ - dprintk("AUDIO_SET_CONFIG not applicable \n"); - break; - } - case AUDIO_GET_CONFIG:{ - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = 8000; - config.channel_count = 1; - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - - break; - } - case AUDIO_GET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - config.pcm_feedback = 0; - config.buffer_count = PCM_BUF_MAX_COUNT; - config.buffer_size = PCM_BUFSZ_MIN; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - if (copy_from_user - (&config, (void *)arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if ((config.buffer_count > PCM_BUF_MAX_COUNT) || - (config.buffer_count == 1)) - config.buffer_count = PCM_BUF_MAX_COUNT; - - if (config.buffer_size < PCM_BUFSZ_MIN) - config.buffer_size = PCM_BUFSZ_MIN; - - /* Check if pcm feedback is required */ - if ((config.pcm_feedback) && (!audio->read_data)) { - dprintk("audamrnb_ioctl: allocate PCM buf %d\n", - config.buffer_count * - config.buffer_size); - audio->read_data = - dma_alloc_coherent(NULL, - config.buffer_size * - config.buffer_count, - &audio->read_phys, - GFP_KERNEL); - if (!audio->read_data) { - pr_err("audamrnb_ioctl: no mem for pcm buf\n"); - rc = -1; - } else { - uint8_t index; - uint32_t offset = 0; - audio->pcm_feedback = 1; - audio->buf_refresh = 0; - audio->pcm_buf_count = - config.buffer_count; - audio->read_next = 0; - audio->fill_next = 0; - - for (index = 0; - index < config.buffer_count; index++) { - audio->in[index].data = - audio->read_data + offset; - audio->in[index].addr = - audio->read_phys + offset; - audio->in[index].size = - config.buffer_size; - audio->in[index].used = 0; - offset += config.buffer_size; - } - rc = 0; - } - } else { - rc = 0; - } - break; - } - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audamrnb_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - int rc = 0; - - if (!audio->pcm_feedback) - return 0; /* PCM feedback is not enabled. Nothing to read */ - - mutex_lock(&audio->read_lock); - dprintk("audamrnb_read() %d \n", count); - while (count > 0) { - rc = wait_event_interruptible(audio->read_wait, - (audio->in[audio->read_next]. - used > 0) || (audio->stopped)); - - if (rc < 0) - break; - - if (audio->stopped) { - rc = -EBUSY; - break; - } - - if (count < audio->in[audio->read_next].used) { - /* Read must happen in frame boundary. Since driver does - * not know frame size, read count must be greater or - * equal to size of PCM samples - */ - dprintk("audamrnb_read:read stop - partial frame\n"); - break; - } else { - dprintk("audamrnb_read: read from in[%d]\n", - audio->read_next); - if (copy_to_user - (buf, audio->in[audio->read_next].data, - audio->in[audio->read_next].used)) { - pr_err("audamrnb_read: invalid addr %x \n", - (unsigned int)buf); - rc = -EFAULT; - break; - } - count -= audio->in[audio->read_next].used; - buf += audio->in[audio->read_next].used; - audio->in[audio->read_next].used = 0; - if ((++audio->read_next) == audio->pcm_buf_count) - audio->read_next = 0; - } - } - - if (audio->buf_refresh) { - audio->buf_refresh = 0; - dprintk("audamrnb_read: kick start pcm feedback again\n"); - audamrnb_buffer_refresh(audio); - } - - mutex_unlock(&audio->read_lock); - - if (buf > start) - rc = buf - start; - - dprintk("audamrnb_read: read %d bytes\n", rc); - return rc; -} - -static ssize_t audamrnb_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - int rc = 0; - - if (count & 1) - return -EINVAL; - dprintk("audamrnb_write() \n"); - mutex_lock(&audio->write_lock); - while (count > 0) { - frame = audio->out + audio->out_head; - rc = wait_event_interruptible(audio->write_wait, - (frame->used == 0) - || (audio->stopped)); - dprintk("audamrnb_write() buffer available\n"); - if (rc < 0) - break; - if (audio->stopped) { - rc = -EBUSY; - break; - } - xfer = (count > frame->size) ? frame->size : count; - if (copy_from_user(frame->data, buf, xfer)) { - rc = -EFAULT; - break; - } - - frame->used = xfer; - audio->out_head ^= 1; - count -= xfer; - buf += xfer; - - audamrnb_send_data(audio, 0); - - } - mutex_unlock(&audio->write_lock); - if (buf > start) - return buf - start; - return rc; -} - -static int audamrnb_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - dprintk("audamrnb_release()\n"); - - mutex_lock(&audio->lock); - audamrnb_disable(audio); - audamrnb_flush(audio); - audamrnb_flush_pcm_buf(audio); - msm_adsp_put(audio->audplay); - audio->audplay = NULL; - audio->opened = 0; - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - audio->data = NULL; - if (audio->read_data != NULL) { - dma_free_coherent(NULL, - audio->in[0].size * audio->pcm_buf_count, - audio->read_data, audio->read_phys); - audio->read_data = NULL; - } - audio->pcm_feedback = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio the_amrnb_audio; - -static int audamrnb_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_amrnb_audio; - int rc; - - mutex_lock(&audio->lock); - - if (audio->opened) { - pr_err("audio: busy\n"); - rc = -EBUSY; - goto done; - } - - if (!audio->data) { - audio->data = dma_alloc_coherent(NULL, DMASZ, - &audio->phys, GFP_KERNEL); - if (!audio->data) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto done; - } - } - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto done; - - rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, - &audplay_adsp_ops_amrnb, audio); - if (rc) { - pr_err("audio: failed to get audplay0 dsp module\n"); - audmgr_disable(&audio->audmgr); - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - audio->data = NULL; - goto done; - } - - audio->dec_id = 0; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = BUFSZ; - - audio->out[1].data = audio->data + BUFSZ; - audio->out[1].addr = audio->phys + BUFSZ; - audio->out[1].size = BUFSZ; - - audio->volume = 0x2000; /* Q13 1.0 */ - - audamrnb_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; -done: - mutex_unlock(&audio->lock); - return rc; -} - -static struct file_operations audio_amrnb_fops = { - .owner = THIS_MODULE, - .open = audamrnb_open, - .release = audamrnb_release, - .read = audamrnb_read, - .write = audamrnb_write, - .unlocked_ioctl = audamrnb_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_amrnb_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_amrnb", - .fops = &audio_amrnb_fops, -}; - -static int __init audamrnb_init(void) -{ - mutex_init(&the_amrnb_audio.lock); - mutex_init(&the_amrnb_audio.write_lock); - mutex_init(&the_amrnb_audio.read_lock); - spin_lock_init(&the_amrnb_audio.dsp_lock); - init_waitqueue_head(&the_amrnb_audio.write_wait); - init_waitqueue_head(&the_amrnb_audio.read_wait); - the_amrnb_audio.read_data = NULL; - return misc_register(&audio_amrnb_misc); -} - -static void __exit audamrnb_exit(void) -{ - misc_deregister(&audio_amrnb_misc); -} - -module_init(audamrnb_init); -module_exit(audamrnb_exit); - -MODULE_DESCRIPTION("MSM AMR-NB driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("QUALCOMM Inc"); diff --git a/drivers/staging/dream/qdsp5/audio_evrc.c b/drivers/staging/dream/qdsp5/audio_evrc.c deleted file mode 100644 index 24a892647370..000000000000 --- a/drivers/staging/dream/qdsp5/audio_evrc.c +++ /dev/null @@ -1,847 +0,0 @@ -/* arch/arm/mach-msm/audio_evrc.c - * - * Copyright (c) 2008 QUALCOMM USA, INC. - * - * This code also borrows from audio_aac.c, which is - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can find it at http://www.fsf.org. - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/gfp.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> -#include <linux/msm_audio.h> -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> -#include <mach/qdsp5/qdsp5audplaycmdi.h> -#include <mach/qdsp5/qdsp5audplaymsg.h> - -#include "adsp.h" - -#ifdef DEBUG -#define dprintk(format, arg...) \ - printk(KERN_DEBUG format, ## arg) -#else -#define dprintk(format, arg...) do {} while (0) -#endif - -/* Hold 30 packets of 24 bytes each*/ -#define BUFSZ 720 -#define DMASZ (BUFSZ * 2) - -#define AUDDEC_DEC_EVRC 12 - -#define PCM_BUFSZ_MIN 1600 /* 100ms worth of data */ -#define PCM_BUF_MAX_COUNT 5 -/* DSP only accepts 5 buffers at most - * but support 2 buffers currently - */ -#define EVRC_DECODED_FRSZ 320 /* EVRC 20ms 8KHz mono PCM size */ - -#define ROUTING_MODE_FTRT 1 -#define ROUTING_MODE_RT 2 -/* Decoder status received from AUDPPTASK */ -#define AUDPP_DEC_STATUS_SLEEP 0 -#define AUDPP_DEC_STATUS_INIT 1 -#define AUDPP_DEC_STATUS_CFG 2 -#define AUDPP_DEC_STATUS_PLAY 3 - -struct buffer { - void *data; - unsigned size; - unsigned used; /* Input usage actual DSP produced PCM size */ - unsigned addr; -}; - -struct audio { - struct buffer out[2]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - - atomic_t out_bytes; - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t write_wait; - - /* Host PCM section */ - struct buffer in[PCM_BUF_MAX_COUNT]; - struct mutex read_lock; - wait_queue_head_t read_wait; /* Wait queue for read */ - char *read_data; /* pointer to reader buffer */ - dma_addr_t read_phys; /* physical address of reader buffer */ - uint8_t read_next; /* index to input buffers to be read next */ - uint8_t fill_next; /* index to buffer that DSP should be filling */ - uint8_t pcm_buf_count; /* number of pcm buffer allocated */ - /* ---- End of Host PCM section */ - - struct msm_adsp_module *audplay; - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - uint8_t opened:1; - uint8_t enabled:1; - uint8_t running:1; - uint8_t stopped:1; /* set when stopped, cleared on flush */ - uint8_t pcm_feedback:1; - uint8_t buf_refresh:1; - - unsigned volume; - uint16_t dec_id; - uint32_t read_ptr_offset; -}; -static struct audio the_evrc_audio; - -static int auddec_dsp_config(struct audio *audio, int enable); -static void audpp_cmd_cfg_adec_params(struct audio *audio); -static void audpp_cmd_cfg_routing_mode(struct audio *audio); -static void audevrc_send_data(struct audio *audio, unsigned needed); -static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg); -static void audevrc_config_hostpcm(struct audio *audio); -static void audevrc_buffer_refresh(struct audio *audio); - -/* must be called with audio->lock held */ -static int audevrc_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - if (audio->enabled) - return 0; - - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK; - cfg.codec = RPC_AUD_DEF_CODEC_EVRC; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audplay)) { - pr_err("audio: msm_adsp_enable(audplay) failed\n"); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - if (audpp_enable(audio->dec_id, audevrc_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - msm_adsp_disable(audio->audplay); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audevrc_disable(struct audio *audio) -{ - if (audio->enabled) { - audio->enabled = 0; - auddec_dsp_config(audio, 0); - wake_up(&audio->write_wait); - wake_up(&audio->read_wait); - msm_adsp_disable(audio->audplay); - audpp_disable(audio->dec_id, audio); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - } - return 0; -} - -/* ------------------- dsp --------------------- */ - -static void audevrc_update_pcm_buf_entry(struct audio *audio, - uint32_t *payload) -{ - uint8_t index; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - for (index = 0; index < payload[1]; index++) { - if (audio->in[audio->fill_next].addr - == payload[2 + index * 2]) { - dprintk("audevrc_update_pcm_buf_entry: in[%d] ready\n", - audio->fill_next); - audio->in[audio->fill_next].used = - payload[3 + index * 2]; - if ((++audio->fill_next) == audio->pcm_buf_count) - audio->fill_next = 0; - - } else { - pr_err - ("audevrc_update_pcm_buf_entry: expected=%x ret=%x\n", - audio->in[audio->fill_next].addr, - payload[1 + index * 2]); - break; - } - } - if (audio->in[audio->fill_next].used == 0) { - audevrc_buffer_refresh(audio); - } else { - dprintk("audevrc_update_pcm_buf_entry: read cannot keep up\n"); - audio->buf_refresh = 1; - } - - spin_unlock_irqrestore(&audio->dsp_lock, flags); - wake_up(&audio->read_wait); -} - -static void audplay_dsp_event(void *data, unsigned id, size_t len, - void (*getevent) (void *ptr, size_t len)) -{ - struct audio *audio = data; - uint32_t msg[28]; - getevent(msg, sizeof(msg)); - - dprintk("audplay_dsp_event: msg_id=%x\n", id); - switch (id) { - case AUDPLAY_MSG_DEC_NEEDS_DATA: - audevrc_send_data(audio, 1); - break; - case AUDPLAY_MSG_BUFFER_UPDATE: - dprintk("audevrc_update_pcm_buf_entry:======> \n"); - audevrc_update_pcm_buf_entry(audio, msg); - break; - default: - pr_err("unexpected message from decoder \n"); - } -} - -static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned status = msg[1]; - - switch (status) { - case AUDPP_DEC_STATUS_SLEEP: - dprintk("decoder status: sleep \n"); - break; - - case AUDPP_DEC_STATUS_INIT: - dprintk("decoder status: init \n"); - audpp_cmd_cfg_routing_mode(audio); - break; - - case AUDPP_DEC_STATUS_CFG: - dprintk("decoder status: cfg \n"); - break; - case AUDPP_DEC_STATUS_PLAY: - dprintk("decoder status: play \n"); - if (audio->pcm_feedback) { - audevrc_config_hostpcm(audio); - audevrc_buffer_refresh(audio); - } - break; - default: - pr_err("unknown decoder status \n"); - } - break; - } - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - dprintk("audevrc_dsp_event: CFG_MSG ENABLE\n"); - auddec_dsp_config(audio, 1); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(audio->dec_id, audio->volume, - 0); - audpp_avsync(audio->dec_id, 22050); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - dprintk("audevrc_dsp_event: CFG_MSG DISABLE\n"); - audpp_avsync(audio->dec_id, 0); - audio->running = 0; - } else { - pr_err("audevrc_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - dprintk("audevrc_dsp_event: ROUTING_ACK\n"); - audpp_cmd_cfg_adec_params(audio); - break; - - default: - pr_err("audevrc_dsp_event: UNKNOWN (%d)\n", id); - } - -} - -struct msm_adsp_ops audplay_adsp_ops_evrc = { - .event = audplay_dsp_event, -}; - -#define audplay_send_queue0(audio, cmd, len) \ - msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \ - cmd, len) - -static int auddec_dsp_config(struct audio *audio, int enable) -{ - audpp_cmd_cfg_dec_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE; - if (enable) - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_EVRC; - else - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_adec_params(struct audio *audio) -{ - struct audpp_cmd_cfg_adec_params_evrc cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS; - cmd.common.length = sizeof(cmd); - cmd.common.dec_id = audio->dec_id; - cmd.common.input_sampling_frequency = 8000; - cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V; - - audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_routing_mode(struct audio *audio) -{ - struct audpp_cmd_routing_mode cmd; - dprintk("audpp_cmd_cfg_routing_mode()\n"); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_ROUTING_MODE; - cmd.object_number = audio->dec_id; - if (audio->pcm_feedback) - cmd.routing_mode = ROUTING_MODE_FTRT; - else - cmd.routing_mode = ROUTING_MODE_RT; - - audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static int audplay_dsp_send_data_avail(struct audio *audio, - unsigned idx, unsigned len) -{ - audplay_cmd_bitstream_data_avail cmd; - - cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL; - cmd.decoder_id = audio->dec_id; - cmd.buf_ptr = audio->out[idx].addr; - cmd.buf_size = len / 2; - cmd.partition_number = 0; - return audplay_send_queue0(audio, &cmd, sizeof(cmd)); -} - -static void audevrc_buffer_refresh(struct audio *audio) -{ - struct audplay_cmd_buffer_refresh refresh_cmd; - - refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH; - refresh_cmd.num_buffers = 1; - refresh_cmd.buf0_address = audio->in[audio->fill_next].addr; - refresh_cmd.buf0_length = audio->in[audio->fill_next].size; - - refresh_cmd.buf_read_count = 0; - dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n", - refresh_cmd.buf0_address, refresh_cmd.buf0_length); - audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd)); -} - -static void audevrc_config_hostpcm(struct audio *audio) -{ - struct audplay_cmd_hpcm_buf_cfg cfg_cmd; - - dprintk("audevrc_config_hostpcm()\n"); - cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG; - cfg_cmd.max_buffers = 1; - cfg_cmd.byte_swap = 0; - cfg_cmd.hostpcm_config = (0x8000) | (0x4000); - cfg_cmd.feedback_frequency = 1; - cfg_cmd.partition_number = 0; - audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd)); - -} - -static void audevrc_send_data(struct audio *audio, unsigned needed) -{ - struct buffer *frame; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (!audio->running) - goto done; - - if (needed) { - /* We were called from the callback because the DSP - * requested more data. Note that the DSP does want - * more data, and if a buffer was in-flight, mark it - * as available (since the DSP must now be done with - * it). - */ - audio->out_needed = 1; - frame = audio->out + audio->out_tail; - if (frame->used == 0xffffffff) { - dprintk("frame %d free\n", audio->out_tail); - frame->used = 0; - audio->out_tail ^= 1; - wake_up(&audio->write_wait); - } - } - - if (audio->out_needed) { - /* If the DSP currently wants data and we have a - * buffer available, we will send it and reset - * the needed flag. We'll mark the buffer as in-flight - * so that it won't be recycled until the next buffer - * is requested - */ - - frame = audio->out + audio->out_tail; - if (frame->used) { - BUG_ON(frame->used == 0xffffffff); - dprintk("frame %d busy\n", audio->out_tail); - audplay_dsp_send_data_avail(audio, audio->out_tail, - frame->used); - frame->used = 0xffffffff; - audio->out_needed = 0; - } - } -done: - spin_unlock_irqrestore(&audio->dsp_lock, flags); -} - -/* ------------------- device --------------------- */ - -static void audevrc_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->stopped = 0; - atomic_set(&audio->out_bytes, 0); -} - -static void audevrc_flush_pcm_buf(struct audio *audio) -{ - uint8_t index; - - for (index = 0; index < PCM_BUF_MAX_COUNT; index++) - audio->in[index].used = 0; - - audio->read_next = 0; - audio->fill_next = 0; -} - -static long audevrc_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0; - - dprintk("audevrc_ioctl() cmd = %d\n", cmd); - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = audpp_avsync_byte_count(audio->dec_id); - stats.sample_count = audpp_avsync_sample_count(audio->dec_id); - if (copy_to_user((void *)arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(audio->dec_id, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - return 0; - } - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audevrc_enable(audio); - break; - case AUDIO_STOP: - rc = audevrc_disable(audio); - audio->stopped = 1; - break; - case AUDIO_SET_CONFIG:{ - dprintk("AUDIO_SET_CONFIG not applicable \n"); - break; - } - case AUDIO_GET_CONFIG:{ - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = 8000; - config.channel_count = 1; - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void *)arg, &config, sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_GET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - config.pcm_feedback = 0; - config.buffer_count = PCM_BUF_MAX_COUNT; - config.buffer_size = PCM_BUFSZ_MIN; - if (copy_to_user((void *)arg, &config, sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - if (copy_from_user - (&config, (void *)arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if ((config.buffer_count > PCM_BUF_MAX_COUNT) || - (config.buffer_count == 1)) - config.buffer_count = PCM_BUF_MAX_COUNT; - - if (config.buffer_size < PCM_BUFSZ_MIN) - config.buffer_size = PCM_BUFSZ_MIN; - - /* Check if pcm feedback is required */ - if ((config.pcm_feedback) && (!audio->read_data)) { - dprintk("audevrc_ioctl: allocate PCM buf %d\n", - config.buffer_count * - config.buffer_size); - audio->read_data = - dma_alloc_coherent(NULL, - config.buffer_size * - config.buffer_count, - &audio->read_phys, - GFP_KERNEL); - if (!audio->read_data) { - pr_err - ("audevrc_ioctl: no mem for pcm buf\n"); - rc = -1; - } else { - uint8_t index; - uint32_t offset = 0; - audio->pcm_feedback = 1; - audio->buf_refresh = 0; - audio->pcm_buf_count = - config.buffer_count; - audio->read_next = 0; - audio->fill_next = 0; - - for (index = 0; - index < config.buffer_count; - index++) { - audio->in[index].data = - audio->read_data + offset; - audio->in[index].addr = - audio->read_phys + offset; - audio->in[index].size = - config.buffer_size; - audio->in[index].used = 0; - offset += config.buffer_size; - } - rc = 0; - } - } else { - rc = 0; - } - break; - } - case AUDIO_PAUSE: - dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg); - rc = audpp_pause(audio->dec_id, (int) arg); - break; - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audevrc_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - int rc = 0; - if (!audio->pcm_feedback) { - return 0; - /* PCM feedback is not enabled. Nothing to read */ - } - mutex_lock(&audio->read_lock); - dprintk("audevrc_read() \n"); - while (count > 0) { - rc = wait_event_interruptible(audio->read_wait, - (audio->in[audio->read_next]. - used > 0) || (audio->stopped)); - dprintk("audevrc_read() wait terminated \n"); - if (rc < 0) - break; - if (audio->stopped) { - rc = -EBUSY; - break; - } - if (count < audio->in[audio->read_next].used) { - /* Read must happen in frame boundary. Since driver does - * not know frame size, read count must be greater or - * equal to size of PCM samples - */ - dprintk("audevrc_read:read stop - partial frame\n"); - break; - } else { - dprintk("audevrc_read: read from in[%d]\n", - audio->read_next); - if (copy_to_user - (buf, audio->in[audio->read_next].data, - audio->in[audio->read_next].used)) { - pr_err("audevrc_read: invalid addr %x \n", - (unsigned int)buf); - rc = -EFAULT; - break; - } - count -= audio->in[audio->read_next].used; - buf += audio->in[audio->read_next].used; - audio->in[audio->read_next].used = 0; - if ((++audio->read_next) == audio->pcm_buf_count) - audio->read_next = 0; - if (audio->in[audio->read_next].used == 0) - break; /* No data ready at this moment - * Exit while loop to prevent - * output thread sleep too long - */ - - } - } - if (audio->buf_refresh) { - audio->buf_refresh = 0; - dprintk("audevrc_read: kick start pcm feedback again\n"); - audevrc_buffer_refresh(audio); - } - mutex_unlock(&audio->read_lock); - if (buf > start) - rc = buf - start; - dprintk("audevrc_read: read %d bytes\n", rc); - return rc; -} - -static ssize_t audevrc_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - int rc = 0; - - if (count & 1) - return -EINVAL; - mutex_lock(&audio->write_lock); - dprintk("audevrc_write() \n"); - while (count > 0) { - frame = audio->out + audio->out_head; - rc = wait_event_interruptible(audio->write_wait, - (frame->used == 0) - || (audio->stopped)); - if (rc < 0) - break; - if (audio->stopped) { - rc = -EBUSY; - break; - } - xfer = (count > frame->size) ? frame->size : count; - if (copy_from_user(frame->data, buf, xfer)) { - rc = -EFAULT; - break; - } - - frame->used = xfer; - audio->out_head ^= 1; - count -= xfer; - buf += xfer; - - audevrc_send_data(audio, 0); - - } - mutex_unlock(&audio->write_lock); - if (buf > start) - return buf - start; - return rc; -} - -static int audevrc_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - dprintk("audevrc_release()\n"); - - mutex_lock(&audio->lock); - audevrc_disable(audio); - audevrc_flush(audio); - audevrc_flush_pcm_buf(audio); - msm_adsp_put(audio->audplay); - audio->audplay = NULL; - audio->opened = 0; - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - audio->data = NULL; - if (audio->read_data != NULL) { - dma_free_coherent(NULL, - audio->in[0].size * audio->pcm_buf_count, - audio->read_data, audio->read_phys); - audio->read_data = NULL; - } - audio->pcm_feedback = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio the_evrc_audio; - -static int audevrc_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_evrc_audio; - int rc; - - if (audio->opened) { - pr_err("audio: busy\n"); - return -EBUSY; - } - - /* Acquire Lock */ - mutex_lock(&audio->lock); - - if (!audio->data) { - audio->data = dma_alloc_coherent(NULL, DMASZ, - &audio->phys, GFP_KERNEL); - if (!audio->data) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto dma_fail; - } - } - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto audmgr_fail; - - rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, - &audplay_adsp_ops_evrc, audio); - if (rc) { - pr_err("audio: failed to get audplay0 dsp module\n"); - goto adsp_fail; - } - - audio->dec_id = 0; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = BUFSZ; - - audio->out[1].data = audio->data + BUFSZ; - audio->out[1].addr = audio->phys + BUFSZ; - audio->out[1].size = BUFSZ; - - audio->volume = 0x3FFF; - - audevrc_flush(audio); - - audio->opened = 1; - file->private_data = audio; - - mutex_unlock(&audio->lock); - return rc; - -adsp_fail: - audmgr_close(&audio->audmgr); -audmgr_fail: - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); -dma_fail: - mutex_unlock(&audio->lock); - return rc; -} - -static struct file_operations audio_evrc_fops = { - .owner = THIS_MODULE, - .open = audevrc_open, - .release = audevrc_release, - .read = audevrc_read, - .write = audevrc_write, - .unlocked_ioctl = audevrc_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_evrc_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_evrc", - .fops = &audio_evrc_fops, -}; - -static int __init audevrc_init(void) -{ - mutex_init(&the_evrc_audio.lock); - mutex_init(&the_evrc_audio.write_lock); - mutex_init(&the_evrc_audio.read_lock); - spin_lock_init(&the_evrc_audio.dsp_lock); - init_waitqueue_head(&the_evrc_audio.write_wait); - init_waitqueue_head(&the_evrc_audio.read_wait); - the_evrc_audio.read_data = NULL; - return misc_register(&audio_evrc_misc); -} - -static void __exit audevrc_exit(void) -{ - misc_deregister(&audio_evrc_misc); -} - -module_init(audevrc_init); -module_exit(audevrc_exit); - -MODULE_DESCRIPTION("MSM EVRC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("QUALCOMM Inc"); diff --git a/drivers/staging/dream/qdsp5/audio_in.c b/drivers/staging/dream/qdsp5/audio_in.c deleted file mode 100644 index b51fa096074e..000000000000 --- a/drivers/staging/dream/qdsp5/audio_in.c +++ /dev/null @@ -1,970 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audio_in.c - * - * pcm audio input device - * - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <linux/delay.h> - -#include <linux/msm_audio.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> -#include <mach/msm_rpcrouter.h> - -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audpreproccmdi.h> -#include <mach/qdsp5/qdsp5audpreprocmsg.h> -#include <mach/qdsp5/qdsp5audreccmdi.h> -#include <mach/qdsp5/qdsp5audrecmsg.h> - -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -/* FRAME_NUM must be a power of two */ -#define FRAME_NUM (8) -#define FRAME_SIZE (2052 * 2) -#define MONO_DATA_SIZE (2048) -#define STEREO_DATA_SIZE (MONO_DATA_SIZE * 2) -#define DMASZ (FRAME_SIZE * FRAME_NUM) - -#define AGC_PARAM_SIZE (20) -#define NS_PARAM_SIZE (6) -#define IIR_PARAM_SIZE (48) -#define DEBUG (0) - -#define AGC_ENABLE 0x0001 -#define NS_ENABLE 0x0002 -#define IIR_ENABLE 0x0004 - -struct tx_agc_config { - uint16_t agc_params[AGC_PARAM_SIZE]; -}; - -struct ns_config { - uint16_t ns_params[NS_PARAM_SIZE]; -}; - -struct tx_iir_filter { - uint16_t num_bands; - uint16_t iir_params[IIR_PARAM_SIZE]; -}; - -struct audpre_cmd_iir_config_type { - uint16_t cmd_id; - uint16_t active_flag; - uint16_t num_bands; - uint16_t iir_params[IIR_PARAM_SIZE]; -}; - -struct buffer { - void *data; - uint32_t size; - uint32_t read; - uint32_t addr; -}; - -struct audio_in { - struct buffer in[FRAME_NUM]; - - spinlock_t dsp_lock; - - atomic_t in_bytes; - - struct mutex lock; - struct mutex read_lock; - wait_queue_head_t wait; - - struct msm_adsp_module *audpre; - struct msm_adsp_module *audrec; - - /* configuration to use on next enable */ - uint32_t samp_rate; - uint32_t channel_mode; - uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */ - uint32_t type; /* 0 for PCM ,1 for AAC */ - uint32_t dsp_cnt; - uint32_t in_head; /* next buffer dsp will write */ - uint32_t in_tail; /* next buffer read() will read */ - uint32_t in_count; /* number of buffers available to read() */ - - unsigned short samp_rate_index; - - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - int opened; - int enabled; - int running; - int stopped; /* set when stopped, cleared on flush */ - - /* audpre settings */ - int agc_enable; - struct tx_agc_config agc; - - int ns_enable; - struct ns_config ns; - - int iir_enable; - struct tx_iir_filter iir; -}; - -static int audio_in_dsp_enable(struct audio_in *audio, int enable); -static int audio_in_encoder_config(struct audio_in *audio); -static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt); -static void audio_flush(struct audio_in *audio); -static int audio_dsp_set_agc(struct audio_in *audio); -static int audio_dsp_set_ns(struct audio_in *audio); -static int audio_dsp_set_tx_iir(struct audio_in *audio); - -static unsigned convert_dsp_samp_index(unsigned index) -{ - switch (index) { - case 48000: return AUDREC_CMD_SAMP_RATE_INDX_48000; - case 44100: return AUDREC_CMD_SAMP_RATE_INDX_44100; - case 32000: return AUDREC_CMD_SAMP_RATE_INDX_32000; - case 24000: return AUDREC_CMD_SAMP_RATE_INDX_24000; - case 22050: return AUDREC_CMD_SAMP_RATE_INDX_22050; - case 16000: return AUDREC_CMD_SAMP_RATE_INDX_16000; - case 12000: return AUDREC_CMD_SAMP_RATE_INDX_12000; - case 11025: return AUDREC_CMD_SAMP_RATE_INDX_11025; - case 8000: return AUDREC_CMD_SAMP_RATE_INDX_8000; - default: return AUDREC_CMD_SAMP_RATE_INDX_11025; - } -} - -static unsigned convert_samp_rate(unsigned hz) -{ - switch (hz) { - case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000; - case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100; - case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000; - case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000; - case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050; - case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000; - case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000; - case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025; - case 8000: return RPC_AUD_DEF_SAMPLE_RATE_8000; - default: return RPC_AUD_DEF_SAMPLE_RATE_11025; - } -} - -static unsigned convert_samp_index(unsigned index) -{ - switch (index) { - case RPC_AUD_DEF_SAMPLE_RATE_48000: return 48000; - case RPC_AUD_DEF_SAMPLE_RATE_44100: return 44100; - case RPC_AUD_DEF_SAMPLE_RATE_32000: return 32000; - case RPC_AUD_DEF_SAMPLE_RATE_24000: return 24000; - case RPC_AUD_DEF_SAMPLE_RATE_22050: return 22050; - case RPC_AUD_DEF_SAMPLE_RATE_16000: return 16000; - case RPC_AUD_DEF_SAMPLE_RATE_12000: return 12000; - case RPC_AUD_DEF_SAMPLE_RATE_11025: return 11025; - case RPC_AUD_DEF_SAMPLE_RATE_8000: return 8000; - default: return 11025; - } -} - -/* must be called with audio->lock held */ -static int audio_in_enable(struct audio_in *audio) -{ - struct audmgr_config cfg; - int rc; - - if (audio->enabled) - return 0; - - cfg.tx_rate = audio->samp_rate; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.def_method = RPC_AUD_DEF_METHOD_RECORD; - if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) - cfg.codec = RPC_AUD_DEF_CODEC_PCM; - else - cfg.codec = RPC_AUD_DEF_CODEC_AAC; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audpre)) { - pr_err("audrec: msm_adsp_enable(audpre) failed\n"); - return -ENODEV; - } - if (msm_adsp_enable(audio->audrec)) { - pr_err("audrec: msm_adsp_enable(audrec) failed\n"); - return -ENODEV; - } - - audio->enabled = 1; - audio_in_dsp_enable(audio, 1); - - return 0; -} - -/* must be called with audio->lock held */ -static int audio_in_disable(struct audio_in *audio) -{ - if (audio->enabled) { - audio->enabled = 0; - - audio_in_dsp_enable(audio, 0); - - wake_up(&audio->wait); - - msm_adsp_disable(audio->audrec); - msm_adsp_disable(audio->audpre); - audmgr_disable(&audio->audmgr); - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audpre_dsp_event(void *data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)) -{ - uint16_t msg[2]; - getevent(msg, sizeof(msg)); - - switch (id) { - case AUDPREPROC_MSG_CMD_CFG_DONE_MSG: - pr_info("audpre: type %d, status_flag %d\n", msg[0], msg[1]); - break; - case AUDPREPROC_MSG_ERROR_MSG_ID: - pr_info("audpre: err_index %d\n", msg[0]); - break; - default: - pr_err("audpre: unknown event %d\n", id); - } -} - -struct audio_frame { - uint16_t count_low; - uint16_t count_high; - uint16_t bytes; - uint16_t unknown; - unsigned char samples[]; -} __attribute__((packed)); - -static void audio_in_get_dsp_frames(struct audio_in *audio) -{ - struct audio_frame *frame; - uint32_t index; - unsigned long flags; - - index = audio->in_head; - - /* XXX check for bogus frame size? */ - - frame = (void *) (((char *)audio->in[index].data) - sizeof(*frame)); - - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->in[index].size = frame->bytes; - - audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1); - - /* If overflow, move the tail index foward. */ - if (audio->in_head == audio->in_tail) - audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1); - else - audio->in_count++; - - audio_dsp_read_buffer(audio, audio->dsp_cnt++); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - - wake_up(&audio->wait); -} - -static void audrec_dsp_event(void *data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)) -{ - struct audio_in *audio = data; - uint16_t msg[3]; - getevent(msg, sizeof(msg)); - - switch (id) { - case AUDREC_MSG_CMD_CFG_DONE_MSG: - if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) { - if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA) { - pr_info("audpre: CFG ENABLED\n"); - audio_dsp_set_agc(audio); - audio_dsp_set_ns(audio); - audio_dsp_set_tx_iir(audio); - audio_in_encoder_config(audio); - } else { - pr_info("audrec: CFG SLEEP\n"); - audio->running = 0; - } - } else { - pr_info("audrec: CMD_CFG_DONE %x\n", msg[0]); - } - break; - case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: { - pr_info("audrec: PARAM CFG DONE\n"); - audio->running = 1; - break; - } - case AUDREC_MSG_FATAL_ERR_MSG: - pr_err("audrec: ERROR %x\n", msg[0]); - break; - case AUDREC_MSG_PACKET_READY_MSG: -/* REC_DBG("type %x, count %d", msg[0], (msg[1] | (msg[2] << 16))); */ - audio_in_get_dsp_frames(audio); - break; - default: - pr_err("audrec: unknown event %d\n", id); - } -} - -struct msm_adsp_ops audpre_adsp_ops = { - .event = audpre_dsp_event, -}; - -struct msm_adsp_ops audrec_adsp_ops = { - .event = audrec_dsp_event, -}; - - -#define audio_send_queue_pre(audio, cmd, len) \ - msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len) -#define audio_send_queue_recbs(audio, cmd, len) \ - msm_adsp_write(audio->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len) -#define audio_send_queue_rec(audio, cmd, len) \ - msm_adsp_write(audio->audrec, \ - QDSP_uPAudRecCmdQueue, cmd, len) - -static int audio_dsp_set_agc(struct audio_in *audio) -{ - audpreproc_cmd_cfg_agc_params cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS; - - if (audio->agc_enable) { - /* cmd.tx_agc_param_mask = 0xFE00 from sample code */ - cmd.tx_agc_param_mask = - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN) | - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG); - cmd.tx_agc_enable_flag = - AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA; - memcpy(&cmd.static_gain, &audio->agc.agc_params[0], - sizeof(uint16_t) * 6); - /* cmd.param_mask = 0xFFF0 from sample code */ - cmd.param_mask = - (1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) | - (1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) | - (1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) | - (1 << AUDPREPROC_CMD_PARAM_MASK_ATTACKK) | - (1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW) | - (1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST) | - (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK) | - (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MIN) | - (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MAX) | - (1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_UP) | - (1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN) | - (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK); - memcpy(&cmd.aig_attackk, &audio->agc.agc_params[6], - sizeof(uint16_t) * 14); - - } else { - cmd.tx_agc_param_mask = - (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG); - cmd.tx_agc_enable_flag = - AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS; - } -#if DEBUG - pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); - pr_info("tx_agc_param_mask = 0x%04x\n", cmd.tx_agc_param_mask); - pr_info("tx_agc_enable_flag = 0x%04x\n", cmd.tx_agc_enable_flag); - pr_info("static_gain = 0x%04x\n", cmd.static_gain); - pr_info("adaptive_gain_flag = 0x%04x\n", cmd.adaptive_gain_flag); - pr_info("expander_th = 0x%04x\n", cmd.expander_th); - pr_info("expander_slope = 0x%04x\n", cmd.expander_slope); - pr_info("compressor_th = 0x%04x\n", cmd.compressor_th); - pr_info("compressor_slope = 0x%04x\n", cmd.compressor_slope); - pr_info("param_mask = 0x%04x\n", cmd.param_mask); - pr_info("aig_attackk = 0x%04x\n", cmd.aig_attackk); - pr_info("aig_leak_down = 0x%04x\n", cmd.aig_leak_down); - pr_info("aig_leak_up = 0x%04x\n", cmd.aig_leak_up); - pr_info("aig_max = 0x%04x\n", cmd.aig_max); - pr_info("aig_min = 0x%04x\n", cmd.aig_min); - pr_info("aig_releasek = 0x%04x\n", cmd.aig_releasek); - pr_info("aig_leakrate_fast = 0x%04x\n", cmd.aig_leakrate_fast); - pr_info("aig_leakrate_slow = 0x%04x\n", cmd.aig_leakrate_slow); - pr_info("attackk_msw = 0x%04x\n", cmd.attackk_msw); - pr_info("attackk_lsw = 0x%04x\n", cmd.attackk_lsw); - pr_info("delay = 0x%04x\n", cmd.delay); - pr_info("releasek_msw = 0x%04x\n", cmd.releasek_msw); - pr_info("releasek_lsw = 0x%04x\n", cmd.releasek_lsw); - pr_info("rms_tav = 0x%04x\n", cmd.rms_tav); -#endif - return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); -} - -static int audio_dsp_set_ns(struct audio_in *audio) -{ - audpreproc_cmd_cfg_ns_params cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS; - - if (audio->ns_enable) { - /* cmd.ec_mode_new is fixed as 0x0064 when enable from sample code */ - cmd.ec_mode_new = - AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA | - AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA | - AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA; - memcpy(&cmd.dens_gamma_n, &audio->ns.ns_params, - sizeof(audio->ns.ns_params)); - } else { - cmd.ec_mode_new = - AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS | - AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS; - } -#if DEBUG - pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); - pr_info("ec_mode_new = 0x%04x\n", cmd.ec_mode_new); - pr_info("dens_gamma_n = 0x%04x\n", cmd.dens_gamma_n); - pr_info("dens_nfe_block_size = 0x%04x\n", cmd.dens_nfe_block_size); - pr_info("dens_limit_ns = 0x%04x\n", cmd.dens_limit_ns); - pr_info("dens_limit_ns_d = 0x%04x\n", cmd.dens_limit_ns_d); - pr_info("wb_gamma_e = 0x%04x\n", cmd.wb_gamma_e); - pr_info("wb_gamma_n = 0x%04x\n", cmd.wb_gamma_n); -#endif - return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); -} - -static int audio_dsp_set_tx_iir(struct audio_in *audio) -{ - struct audpre_cmd_iir_config_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS; - - if (audio->iir_enable) { - cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA; - cmd.num_bands = audio->iir.num_bands; - memcpy(&cmd.iir_params, &audio->iir.iir_params, - sizeof(audio->iir.iir_params)); - } else { - cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS; - } -#if DEBUG - pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); - pr_info("active_flag = 0x%04x\n", cmd.active_flag); -#endif - return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); -} - -static int audio_in_dsp_enable(struct audio_in *audio, int enable) -{ - audrec_cmd_cfg cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDREC_CMD_CFG; - cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS; - cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | audio->type); - cmd.type_1 = 0; - - return audio_send_queue_rec(audio, &cmd, sizeof(cmd)); -} - -static int audio_in_encoder_config(struct audio_in *audio) -{ - audrec_cmd_arec0param_cfg cmd; - uint16_t *data = (void *) audio->data; - unsigned n; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG; - cmd.ptr_to_extpkt_buffer_msw = audio->phys >> 16; - cmd.ptr_to_extpkt_buffer_lsw = audio->phys; - cmd.buf_len = FRAME_NUM; /* Both WAV and AAC use 8 frames */ - cmd.samp_rate_index = audio->samp_rate_index; - cmd.stereo_mode = audio->channel_mode; /* 0 for mono, 1 for stereo */ - - /* FIXME have no idea why cmd.rec_quality is fixed - * as 0x1C00 from sample code - */ - cmd.rec_quality = 0x1C00; - - /* prepare buffer pointers: - * Mono: 1024 samples + 4 halfword header - * Stereo: 2048 samples + 4 halfword header - * AAC - * Mono/Stere: 768 + 4 halfword header - */ - for (n = 0; n < FRAME_NUM; n++) { - audio->in[n].data = data + 4; - if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) - data += (4 + (audio->channel_mode ? 2048 : 1024)); - else if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) - data += (4 + 768); - } - - return audio_send_queue_rec(audio, &cmd, sizeof(cmd)); -} - -static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt) -{ - audrec_cmd_packet_ext_ptr cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR; - /* Both WAV and AAC use AUDREC_CMD_TYPE_0 */ - cmd.type = AUDREC_CMD_TYPE_0; - cmd.curr_rec_count_msw = read_cnt >> 16; - cmd.curr_rec_count_lsw = read_cnt; - - return audio_send_queue_recbs(audio, &cmd, sizeof(cmd)); -} - -/* ------------------- device --------------------- */ - -static void audio_enable_agc(struct audio_in *audio, int enable) -{ - if (audio->agc_enable != enable) { - audio->agc_enable = enable; - if (audio->running) - audio_dsp_set_agc(audio); - } -} - -static void audio_enable_ns(struct audio_in *audio, int enable) -{ - if (audio->ns_enable != enable) { - audio->ns_enable = enable; - if (audio->running) - audio_dsp_set_ns(audio); - } -} - -static void audio_enable_tx_iir(struct audio_in *audio, int enable) -{ - if (audio->iir_enable != enable) { - audio->iir_enable = enable; - if (audio->running) - audio_dsp_set_tx_iir(audio); - } -} - -static void audio_flush(struct audio_in *audio) -{ - int i; - - audio->dsp_cnt = 0; - audio->in_head = 0; - audio->in_tail = 0; - audio->in_count = 0; - for (i = 0; i < FRAME_NUM; i++) { - audio->in[i].size = 0; - audio->in[i].read = 0; - } -} - -static long audio_in_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct audio_in *audio = file->private_data; - int rc; - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = atomic_read(&audio->in_bytes); - if (copy_to_user((void *) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audio_in_enable(audio); - break; - case AUDIO_STOP: - rc = audio_in_disable(audio); - audio->stopped = 1; - break; - case AUDIO_FLUSH: - if (audio->stopped) { - /* Make sure we're stopped and we wake any threads - * that might be blocked holding the read_lock. - * While audio->stopped read threads will always - * exit immediately. - */ - wake_up(&audio->wait); - mutex_lock(&audio->read_lock); - audio_flush(audio); - mutex_unlock(&audio->read_lock); - } - case AUDIO_SET_CONFIG: { - struct msm_audio_config cfg; - if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) { - rc = -EFAULT; - break; - } - if (cfg.channel_count == 1) { - cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO; - } else if (cfg.channel_count == 2) { - cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO; - } else { - rc = -EINVAL; - break; - } - - if (cfg.type == 0) { - cfg.type = AUDREC_CMD_TYPE_0_INDEX_WAV; - } else if (cfg.type == 1) { - cfg.type = AUDREC_CMD_TYPE_0_INDEX_AAC; - } else { - rc = -EINVAL; - break; - } - audio->samp_rate = convert_samp_rate(cfg.sample_rate); - audio->samp_rate_index = - convert_dsp_samp_index(cfg.sample_rate); - audio->channel_mode = cfg.channel_count; - audio->buffer_size = - audio->channel_mode ? STEREO_DATA_SIZE - : MONO_DATA_SIZE; - audio->type = cfg.type; - rc = 0; - break; - } - case AUDIO_GET_CONFIG: { - struct msm_audio_config cfg; - cfg.buffer_size = audio->buffer_size; - cfg.buffer_count = FRAME_NUM; - cfg.sample_rate = convert_samp_index(audio->samp_rate); - if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO) - cfg.channel_count = 1; - else - cfg.channel_count = 2; - if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) - cfg.type = 0; - else - cfg.type = 1; - cfg.unused[0] = 0; - cfg.unused[1] = 0; - cfg.unused[2] = 0; - if (copy_to_user((void *) arg, &cfg, sizeof(cfg))) - rc = -EFAULT; - else - rc = 0; - break; - } - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audio_in_read(struct file *file, - char __user *buf, - size_t count, loff_t *pos) -{ - struct audio_in *audio = file->private_data; - unsigned long flags; - const char __user *start = buf; - void *data; - uint32_t index; - uint32_t size; - int rc = 0; - - mutex_lock(&audio->read_lock); - while (count > 0) { - rc = wait_event_interruptible( - audio->wait, (audio->in_count > 0) || audio->stopped); - if (rc < 0) - break; - - if (audio->stopped) { - rc = -EBUSY; - break; - } - - index = audio->in_tail; - data = (uint8_t *) audio->in[index].data; - size = audio->in[index].size; - if (count >= size) { - if (copy_to_user(buf, data, size)) { - rc = -EFAULT; - break; - } - spin_lock_irqsave(&audio->dsp_lock, flags); - if (index != audio->in_tail) { - /* overrun -- data is invalid and we need to retry */ - spin_unlock_irqrestore(&audio->dsp_lock, flags); - continue; - } - audio->in[index].size = 0; - audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1); - audio->in_count--; - spin_unlock_irqrestore(&audio->dsp_lock, flags); - count -= size; - buf += size; - if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) - break; - } else { - pr_err("audio_in: short read\n"); - break; - } - if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) - break; /* AAC only read one frame */ - } - mutex_unlock(&audio->read_lock); - - if (buf > start) - return buf - start; - - return rc; -} - -static ssize_t audio_in_write(struct file *file, - const char __user *buf, - size_t count, loff_t *pos) -{ - return -EINVAL; -} - -static int audio_in_release(struct inode *inode, struct file *file) -{ - struct audio_in *audio = file->private_data; - - mutex_lock(&audio->lock); - audio_in_disable(audio); - audio_flush(audio); - msm_adsp_put(audio->audrec); - msm_adsp_put(audio->audpre); - audio->audrec = NULL; - audio->audpre = NULL; - audio->opened = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio_in the_audio_in; - -static int audio_in_open(struct inode *inode, struct file *file) -{ - struct audio_in *audio = &the_audio_in; - int rc; - - mutex_lock(&audio->lock); - if (audio->opened) { - rc = -EBUSY; - goto done; - } - - /* Settings will be re-config at AUDIO_SET_CONFIG, - * but at least we need to have initial config - */ - audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025; - audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025; - audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO; - audio->buffer_size = MONO_DATA_SIZE; - audio->type = AUDREC_CMD_TYPE_0_INDEX_WAV; - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto done; - rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre, - &audpre_adsp_ops, audio); - if (rc) - goto done; - rc = msm_adsp_get("AUDRECTASK", &audio->audrec, - &audrec_adsp_ops, audio); - if (rc) - goto done; - - audio->dsp_cnt = 0; - audio->stopped = 0; - - audio_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; -done: - mutex_unlock(&audio->lock); - return rc; -} - -static long audpre_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct audio_in *audio = file->private_data; - int rc = 0, enable; - uint16_t enable_mask; -#if DEBUG - int i; -#endif - - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_ENABLE_AUDPRE: { - if (copy_from_user(&enable_mask, (void *) arg, - sizeof(enable_mask))) - goto out_fault; - - enable = (enable_mask & AGC_ENABLE) ? 1 : 0; - audio_enable_agc(audio, enable); - enable = (enable_mask & NS_ENABLE) ? 1 : 0; - audio_enable_ns(audio, enable); - enable = (enable_mask & IIR_ENABLE) ? 1 : 0; - audio_enable_tx_iir(audio, enable); - break; - } - case AUDIO_SET_AGC: { - if (copy_from_user(&audio->agc, (void *) arg, - sizeof(audio->agc))) - goto out_fault; -#if DEBUG - pr_info("set agc\n"); - for (i = 0; i < AGC_PARAM_SIZE; i++) \ - pr_info("agc_params[%d] = 0x%04x\n", i, - audio->agc.agc_params[i]); -#endif - break; - } - case AUDIO_SET_NS: { - if (copy_from_user(&audio->ns, (void *) arg, - sizeof(audio->ns))) - goto out_fault; -#if DEBUG - pr_info("set ns\n"); - for (i = 0; i < NS_PARAM_SIZE; i++) \ - pr_info("ns_params[%d] = 0x%04x\n", - i, audio->ns.ns_params[i]); -#endif - break; - } - case AUDIO_SET_TX_IIR: { - if (copy_from_user(&audio->iir, (void *) arg, - sizeof(audio->iir))) - goto out_fault; -#if DEBUG - pr_info("set iir\n"); - pr_info("iir.num_bands = 0x%04x\n", audio->iir.num_bands); - for (i = 0; i < IIR_PARAM_SIZE; i++) \ - pr_info("iir_params[%d] = 0x%04x\n", - i, audio->iir.iir_params[i]); -#endif - break; - } - default: - rc = -EINVAL; - } - - goto out; - -out_fault: - rc = -EFAULT; -out: - mutex_unlock(&audio->lock); - return rc; -} - -static int audpre_open(struct inode *inode, struct file *file) -{ - struct audio_in *audio = &the_audio_in; - file->private_data = audio; - return 0; -} - -static struct file_operations audio_fops = { - .owner = THIS_MODULE, - .open = audio_in_open, - .release = audio_in_release, - .read = audio_in_read, - .write = audio_in_write, - .unlocked_ioctl = audio_in_ioctl, - .llseek = noop_llseek, -}; - -static struct file_operations audpre_fops = { - .owner = THIS_MODULE, - .open = audpre_open, - .unlocked_ioctl = audpre_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_in_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_pcm_in", - .fops = &audio_fops, -}; - -struct miscdevice audpre_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_audpre", - .fops = &audpre_fops, -}; - -static int __init audio_in_init(void) -{ - int rc; - the_audio_in.data = dma_alloc_coherent(NULL, DMASZ, - &the_audio_in.phys, GFP_KERNEL); - if (!the_audio_in.data) { - printk(KERN_ERR "%s: Unable to allocate DMA buffer\n", - __func__); - return -ENOMEM; - } - - mutex_init(&the_audio_in.lock); - mutex_init(&the_audio_in.read_lock); - spin_lock_init(&the_audio_in.dsp_lock); - init_waitqueue_head(&the_audio_in.wait); - rc = misc_register(&audio_in_misc); - if (!rc) { - rc = misc_register(&audpre_misc); - if (rc < 0) - misc_deregister(&audio_in_misc); - } - return rc; -} - -device_initcall(audio_in_init); diff --git a/drivers/staging/dream/qdsp5/audio_mp3.c b/drivers/staging/dream/qdsp5/audio_mp3.c deleted file mode 100644 index 409a19ce6039..000000000000 --- a/drivers/staging/dream/qdsp5/audio_mp3.c +++ /dev/null @@ -1,972 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audio_mp3.c - * - * mp3 audio output device - * - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> - -#include <linux/msm_audio.h> - -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> -#include <mach/qdsp5/qdsp5audplaycmdi.h> -#include <mach/qdsp5/qdsp5audplaymsg.h> - -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -#ifdef DEBUG -#define dprintk(format, arg...) \ -printk(KERN_DEBUG format, ## arg) -#else -#define dprintk(format, arg...) do {} while (0) -#endif - -/* Size must be power of 2 */ -#define BUFSZ_MAX 32768 -#define BUFSZ_MIN 4096 -#define DMASZ_MAX (BUFSZ_MAX * 2) -#define DMASZ_MIN (BUFSZ_MIN * 2) - -#define AUDPLAY_INVALID_READ_PTR_OFFSET 0xFFFF -#define AUDDEC_DEC_MP3 2 - -#define PCM_BUFSZ_MIN 4800 /* Hold one stereo MP3 frame */ -#define PCM_BUF_MAX_COUNT 5 /* DSP only accepts 5 buffers at most - but support 2 buffers currently */ -#define ROUTING_MODE_FTRT 1 -#define ROUTING_MODE_RT 2 -/* Decoder status received from AUDPPTASK */ -#define AUDPP_DEC_STATUS_SLEEP 0 -#define AUDPP_DEC_STATUS_INIT 1 -#define AUDPP_DEC_STATUS_CFG 2 -#define AUDPP_DEC_STATUS_PLAY 3 - -struct buffer { - void *data; - unsigned size; - unsigned used; /* Input usage actual DSP produced PCM size */ - unsigned addr; -}; - -struct audio { - struct buffer out[2]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - unsigned out_dma_sz; - - atomic_t out_bytes; - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t write_wait; - - /* Host PCM section */ - struct buffer in[PCM_BUF_MAX_COUNT]; - struct mutex read_lock; - wait_queue_head_t read_wait; /* Wait queue for read */ - char *read_data; /* pointer to reader buffer */ - dma_addr_t read_phys; /* physical address of reader buffer */ - uint8_t read_next; /* index to input buffers to be read next */ - uint8_t fill_next; /* index to buffer that DSP should be filling */ - uint8_t pcm_buf_count; /* number of pcm buffer allocated */ - /* ---- End of Host PCM section */ - - struct msm_adsp_module *audplay; - - /* configuration to use on next enable */ - uint32_t out_sample_rate; - uint32_t out_channel_mode; - - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - int rflush; /* Read flush */ - int wflush; /* Write flush */ - int opened; - int enabled; - int running; - int stopped; /* set when stopped, cleared on flush */ - int pcm_feedback; - int buf_refresh; - - int reserved; /* A byte is being reserved */ - char rsv_byte; /* Handle odd length user data */ - - unsigned volume; - - uint16_t dec_id; - uint32_t read_ptr_offset; -}; - -static int auddec_dsp_config(struct audio *audio, int enable); -static void audpp_cmd_cfg_adec_params(struct audio *audio); -static void audpp_cmd_cfg_routing_mode(struct audio *audio); -static void audplay_send_data(struct audio *audio, unsigned needed); -static void audplay_config_hostpcm(struct audio *audio); -static void audplay_buffer_refresh(struct audio *audio); -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg); - -/* must be called with audio->lock held */ -static int audio_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - pr_info("audio_enable()\n"); - - if (audio->enabled) - return 0; - - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK; - cfg.codec = RPC_AUD_DEF_CODEC_MP3; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audplay)) { - pr_err("audio: msm_adsp_enable(audplay) failed\n"); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - msm_adsp_disable(audio->audplay); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audio_disable(struct audio *audio) -{ - pr_info("audio_disable()\n"); - if (audio->enabled) { - audio->enabled = 0; - auddec_dsp_config(audio, 0); - wake_up(&audio->write_wait); - wake_up(&audio->read_wait); - msm_adsp_disable(audio->audplay); - audpp_disable(audio->dec_id, audio); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload) -{ - uint8_t index; - unsigned long flags; - - if (audio->rflush) { - audio->buf_refresh = 1; - return; - } - spin_lock_irqsave(&audio->dsp_lock, flags); - for (index = 0; index < payload[1]; index++) { - if (audio->in[audio->fill_next].addr == - payload[2 + index * 2]) { - pr_info("audio_update_pcm_buf_entry: in[%d] ready\n", - audio->fill_next); - audio->in[audio->fill_next].used = - payload[3 + index * 2]; - if ((++audio->fill_next) == audio->pcm_buf_count) - audio->fill_next = 0; - - } else { - pr_err - ("audio_update_pcm_buf_entry: expected=%x ret=%x\n" - , audio->in[audio->fill_next].addr, - payload[1 + index * 2]); - break; - } - } - if (audio->in[audio->fill_next].used == 0) { - audplay_buffer_refresh(audio); - } else { - pr_info("audio_update_pcm_buf_entry: read cannot keep up\n"); - audio->buf_refresh = 1; - } - wake_up(&audio->read_wait); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - -} - -static void audplay_dsp_event(void *data, unsigned id, size_t len, - void (*getevent) (void *ptr, size_t len)) -{ - struct audio *audio = data; - uint32_t msg[28]; - getevent(msg, sizeof(msg)); - - dprintk("audplay_dsp_event: msg_id=%x\n", id); - - switch (id) { - case AUDPLAY_MSG_DEC_NEEDS_DATA: - audplay_send_data(audio, 1); - break; - - case AUDPLAY_MSG_BUFFER_UPDATE: - audio_update_pcm_buf_entry(audio, msg); - break; - - default: - pr_err("unexpected message from decoder \n"); - break; - } -} - -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned status = msg[1]; - - switch (status) { - case AUDPP_DEC_STATUS_SLEEP: - pr_info("decoder status: sleep \n"); - break; - - case AUDPP_DEC_STATUS_INIT: - pr_info("decoder status: init \n"); - audpp_cmd_cfg_routing_mode(audio); - break; - - case AUDPP_DEC_STATUS_CFG: - pr_info("decoder status: cfg \n"); - break; - case AUDPP_DEC_STATUS_PLAY: - pr_info("decoder status: play \n"); - if (audio->pcm_feedback) { - audplay_config_hostpcm(audio); - audplay_buffer_refresh(audio); - } - break; - default: - pr_err("unknown decoder status \n"); - break; - } - break; - } - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - pr_info("audio_dsp_event: CFG_MSG ENABLE\n"); - auddec_dsp_config(audio, 1); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(audio->dec_id, audio->volume, - 0); - audpp_avsync(audio->dec_id, 22050); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - pr_info("audio_dsp_event: CFG_MSG DISABLE\n"); - audpp_avsync(audio->dec_id, 0); - audio->running = 0; - } else { - pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - pr_info("audio_dsp_event: ROUTING_ACK mode=%d\n", msg[1]); - audpp_cmd_cfg_adec_params(audio); - break; - - case AUDPP_MSG_FLUSH_ACK: - dprintk("%s: FLUSH_ACK\n", __func__); - audio->wflush = 0; - audio->rflush = 0; - if (audio->pcm_feedback) - audplay_buffer_refresh(audio); - break; - - default: - pr_err("audio_dsp_event: UNKNOWN (%d)\n", id); - } - -} - - -struct msm_adsp_ops audplay_adsp_ops = { - .event = audplay_dsp_event, -}; - - -#define audplay_send_queue0(audio, cmd, len) \ - msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \ - cmd, len) - -static int auddec_dsp_config(struct audio *audio, int enable) -{ - audpp_cmd_cfg_dec_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE; - if (enable) - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_ENA_DEC_V | - AUDDEC_DEC_MP3; - else - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_DIS_DEC_V; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_adec_params(struct audio *audio) -{ - audpp_cmd_cfg_adec_params_mp3 cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS; - cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN; - cmd.common.dec_id = audio->dec_id; - cmd.common.input_sampling_frequency = audio->out_sample_rate; - - audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_routing_mode(struct audio *audio) -{ - struct audpp_cmd_routing_mode cmd; - pr_info("audpp_cmd_cfg_routing_mode()\n"); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_ROUTING_MODE; - cmd.object_number = audio->dec_id; - if (audio->pcm_feedback) - cmd.routing_mode = ROUTING_MODE_FTRT; - else - cmd.routing_mode = ROUTING_MODE_RT; - - audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static int audplay_dsp_send_data_avail(struct audio *audio, - unsigned idx, unsigned len) -{ - audplay_cmd_bitstream_data_avail cmd; - - cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL; - cmd.decoder_id = audio->dec_id; - cmd.buf_ptr = audio->out[idx].addr; - cmd.buf_size = len/2; - cmd.partition_number = 0; - return audplay_send_queue0(audio, &cmd, sizeof(cmd)); -} - -static void audplay_buffer_refresh(struct audio *audio) -{ - struct audplay_cmd_buffer_refresh refresh_cmd; - - refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH; - refresh_cmd.num_buffers = 1; - refresh_cmd.buf0_address = audio->in[audio->fill_next].addr; - refresh_cmd.buf0_length = audio->in[audio->fill_next].size - - (audio->in[audio->fill_next].size % 576); /* Mp3 frame size */ - refresh_cmd.buf_read_count = 0; - pr_info("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n", - refresh_cmd.buf0_address, refresh_cmd.buf0_length); - (void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd)); -} - -static void audplay_config_hostpcm(struct audio *audio) -{ - struct audplay_cmd_hpcm_buf_cfg cfg_cmd; - - pr_info("audplay_config_hostpcm()\n"); - cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG; - cfg_cmd.max_buffers = 1; - cfg_cmd.byte_swap = 0; - cfg_cmd.hostpcm_config = (0x8000) | (0x4000); - cfg_cmd.feedback_frequency = 1; - cfg_cmd.partition_number = 0; - (void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd)); - -} - -static void audplay_send_data(struct audio *audio, unsigned needed) -{ - struct buffer *frame; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (!audio->running) - goto done; - - if (audio->wflush) { - audio->out_needed = 1; - goto done; - } - - if (needed && !audio->wflush) { - /* We were called from the callback because the DSP - * requested more data. Note that the DSP does want - * more data, and if a buffer was in-flight, mark it - * as available (since the DSP must now be done with - * it). - */ - audio->out_needed = 1; - frame = audio->out + audio->out_tail; - if (frame->used == 0xffffffff) { - dprintk("frame %d free\n", audio->out_tail); - frame->used = 0; - audio->out_tail ^= 1; - wake_up(&audio->write_wait); - } - } - - if (audio->out_needed) { - /* If the DSP currently wants data and we have a - * buffer available, we will send it and reset - * the needed flag. We'll mark the buffer as in-flight - * so that it won't be recycled until the next buffer - * is requested - */ - - frame = audio->out + audio->out_tail; - if (frame->used) { - BUG_ON(frame->used == 0xffffffff); - dprintk("frame %d busy\n", audio->out_tail); - audplay_dsp_send_data_avail(audio, audio->out_tail, - frame->used); - frame->used = 0xffffffff; - audio->out_needed = 0; - } - } -done: - spin_unlock_irqrestore(&audio->dsp_lock, flags); -} - -/* ------------------- device --------------------- */ - -static void audio_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->reserved = 0; - atomic_set(&audio->out_bytes, 0); -} - -static void audio_flush_pcm_buf(struct audio *audio) -{ - uint8_t index; - - for (index = 0; index < PCM_BUF_MAX_COUNT; index++) - audio->in[index].used = 0; - - audio->read_next = 0; - audio->fill_next = 0; -} - -static void audio_ioport_reset(struct audio *audio) -{ - /* Make sure read/write thread are free from - * sleep and knowing that system is not able - * to process io request at the moment - */ - wake_up(&audio->write_wait); - mutex_lock(&audio->write_lock); - audio_flush(audio); - mutex_unlock(&audio->write_lock); - wake_up(&audio->read_wait); - mutex_lock(&audio->read_lock); - audio_flush_pcm_buf(audio); - mutex_unlock(&audio->read_lock); -} - -static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0; - - pr_info("audio_ioctl() cmd = %d\n", cmd); - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = audpp_avsync_byte_count(audio->dec_id); - stats.sample_count = audpp_avsync_sample_count(audio->dec_id); - if (copy_to_user((void *) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(audio->dec_id, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - return 0; - } - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audio_enable(audio); - break; - case AUDIO_STOP: - rc = audio_disable(audio); - audio->stopped = 1; - audio_ioport_reset(audio); - audio->stopped = 0; - break; - case AUDIO_FLUSH: - dprintk("%s: AUDIO_FLUSH\n", __func__); - audio->rflush = 1; - audio->wflush = 1; - audio_ioport_reset(audio); - audio->rflush = 0; - audio->wflush = 0; - - if (audio->buf_refresh) { - audio->buf_refresh = 0; - audplay_buffer_refresh(audio); - } - break; - - case AUDIO_SET_CONFIG: { - struct msm_audio_config config; - if (copy_from_user(&config, (void *) arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if (config.channel_count == 1) { - config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V; - } else if (config.channel_count == 2) { - config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V; - } else { - rc = -EINVAL; - break; - } - audio->out_sample_rate = config.sample_rate; - audio->out_channel_mode = config.channel_count; - rc = 0; - break; - } - case AUDIO_GET_CONFIG: { - struct msm_audio_config config; - config.buffer_size = (audio->out_dma_sz >> 1); - config.buffer_count = 2; - config.sample_rate = audio->out_sample_rate; - if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) { - config.channel_count = 1; - } else { - config.channel_count = 2; - } - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void *) arg, &config, sizeof(config))) { - rc = -EFAULT; - } else { - rc = 0; - } - break; - } - case AUDIO_GET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - config.pcm_feedback = 0; - config.buffer_count = PCM_BUF_MAX_COUNT; - config.buffer_size = PCM_BUFSZ_MIN; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - if (copy_from_user - (&config, (void *)arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if ((config.buffer_count > PCM_BUF_MAX_COUNT) || - (config.buffer_count == 1)) - config.buffer_count = PCM_BUF_MAX_COUNT; - - if (config.buffer_size < PCM_BUFSZ_MIN) - config.buffer_size = PCM_BUFSZ_MIN; - - /* Check if pcm feedback is required */ - if ((config.pcm_feedback) && (!audio->read_data)) { - pr_info("ioctl: allocate PCM buffer %d\n", - config.buffer_count * - config.buffer_size); - audio->read_data = - dma_alloc_coherent(NULL, - config.buffer_size * - config.buffer_count, - &audio->read_phys, - GFP_KERNEL); - if (!audio->read_data) { - pr_err("audio_mp3: malloc pcm buf failed\n"); - rc = -1; - } else { - uint8_t index; - uint32_t offset = 0; - audio->pcm_feedback = 1; - audio->buf_refresh = 0; - audio->pcm_buf_count = - config.buffer_count; - audio->read_next = 0; - audio->fill_next = 0; - - for (index = 0; - index < config.buffer_count; - index++) { - audio->in[index].data = - audio->read_data + offset; - audio->in[index].addr = - audio->read_phys + offset; - audio->in[index].size = - config.buffer_size; - audio->in[index].used = 0; - offset += config.buffer_size; - } - rc = 0; - } - } else { - rc = 0; - } - break; - } - case AUDIO_PAUSE: - dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg); - rc = audpp_pause(audio->dec_id, (int) arg); - break; - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audio_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - int rc = 0; - - if (!audio->pcm_feedback) - return 0; /* PCM feedback disabled. Nothing to read */ - - mutex_lock(&audio->read_lock); - pr_info("audio_read() %d \n", count); - while (count > 0) { - rc = wait_event_interruptible(audio->read_wait, - (audio->in[audio->read_next]. - used > 0) || (audio->stopped) - || (audio->rflush)); - - if (rc < 0) - break; - - if (audio->stopped || audio->rflush) { - rc = -EBUSY; - break; - } - - if (count < audio->in[audio->read_next].used) { - /* Read must happen in frame boundary. Since - * driver does not know frame size, read count - * must be greater or equal - * to size of PCM samples - */ - pr_info("audio_read: no partial frame done reading\n"); - break; - } else { - pr_info("audio_read: read from in[%d]\n", - audio->read_next); - if (copy_to_user - (buf, audio->in[audio->read_next].data, - audio->in[audio->read_next].used)) { - pr_err("audio_read: invalid addr %x \n", - (unsigned int)buf); - rc = -EFAULT; - break; - } - count -= audio->in[audio->read_next].used; - buf += audio->in[audio->read_next].used; - audio->in[audio->read_next].used = 0; - if ((++audio->read_next) == audio->pcm_buf_count) - audio->read_next = 0; - if (audio->in[audio->read_next].used == 0) - break; /* No data ready at this moment - * Exit while loop to prevent - * output thread sleep too long - */ - } - } - - /* don't feed output buffer to HW decoder during flushing - * buffer refresh command will be sent once flush completes - * send buf refresh command here can confuse HW decoder - */ - if (audio->buf_refresh && !audio->rflush) { - audio->buf_refresh = 0; - pr_info("audio_read: kick start pcm feedback again\n"); - audplay_buffer_refresh(audio); - } - - mutex_unlock(&audio->read_lock); - - if (buf > start) - rc = buf - start; - - pr_info("audio_read: read %d bytes\n", rc); - return rc; -} - -static ssize_t audio_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - char *cpy_ptr; - int rc = 0; - unsigned dsize; - - mutex_lock(&audio->write_lock); - while (count > 0) { - frame = audio->out + audio->out_head; - cpy_ptr = frame->data; - dsize = 0; - rc = wait_event_interruptible(audio->write_wait, - (frame->used == 0) - || (audio->stopped) - || (audio->wflush)); - if (rc < 0) - break; - if (audio->stopped || audio->wflush) { - rc = -EBUSY; - break; - } - - if (audio->reserved) { - dprintk("%s: append reserved byte %x\n", - __func__, audio->rsv_byte); - *cpy_ptr = audio->rsv_byte; - xfer = (count > (frame->size - 1)) ? - frame->size - 1 : count; - cpy_ptr++; - dsize = 1; - audio->reserved = 0; - } else - xfer = (count > frame->size) ? frame->size : count; - - if (copy_from_user(cpy_ptr, buf, xfer)) { - rc = -EFAULT; - break; - } - - dsize += xfer; - if (dsize & 1) { - audio->rsv_byte = ((char *) frame->data)[dsize - 1]; - dprintk("%s: odd length buf reserve last byte %x\n", - __func__, audio->rsv_byte); - audio->reserved = 1; - dsize--; - } - count -= xfer; - buf += xfer; - - if (dsize > 0) { - audio->out_head ^= 1; - frame->used = dsize; - audplay_send_data(audio, 0); - } - } - mutex_unlock(&audio->write_lock); - if (buf > start) - return buf - start; - return rc; -} - -static int audio_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - dprintk("audio_release()\n"); - - mutex_lock(&audio->lock); - audio_disable(audio); - audio_flush(audio); - audio_flush_pcm_buf(audio); - msm_adsp_put(audio->audplay); - audio->audplay = NULL; - audio->opened = 0; - audio->reserved = 0; - dma_free_coherent(NULL, audio->out_dma_sz, audio->data, audio->phys); - audio->data = NULL; - if (audio->read_data != NULL) { - dma_free_coherent(NULL, - audio->in[0].size * audio->pcm_buf_count, - audio->read_data, audio->read_phys); - audio->read_data = NULL; - } - audio->pcm_feedback = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio the_mp3_audio; - -static int audio_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_mp3_audio; - int rc; - unsigned pmem_sz; - - mutex_lock(&audio->lock); - - if (audio->opened) { - pr_err("audio: busy\n"); - rc = -EBUSY; - goto done; - } - - pmem_sz = DMASZ_MAX; - - while (pmem_sz >= DMASZ_MIN) { - audio->data = dma_alloc_coherent(NULL, pmem_sz, - &audio->phys, GFP_KERNEL); - if (audio->data) - break; - else if (pmem_sz == DMASZ_MIN) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto done; - } else - pmem_sz >>= 1; - } - - dprintk("%s: allocated %d bytes DMA buffer\n", __func__, pmem_sz); - - rc = audmgr_open(&audio->audmgr); - if (rc) { - dma_free_coherent(NULL, pmem_sz, - audio->data, audio->phys); - goto done; - } - - rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, &audplay_adsp_ops, - audio); - if (rc) { - pr_err("audio: failed to get audplay0 dsp module\n"); - dma_free_coherent(NULL, pmem_sz, - audio->data, audio->phys); - audmgr_close(&audio->audmgr); - goto done; - } - - audio->out_dma_sz = pmem_sz; - pmem_sz >>= 1; /* Shift by 1 to get size of ping pong buffer */ - - audio->out_sample_rate = 44100; - audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V; - audio->dec_id = 0; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = pmem_sz; - - audio->out[1].data = audio->data + pmem_sz; - audio->out[1].addr = audio->phys + pmem_sz; - audio->out[1].size = pmem_sz; - - audio->volume = 0x2000; /* equal to Q13 number 1.0 Unit Gain */ - - audio_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; -done: - mutex_unlock(&audio->lock); - return rc; -} - -static struct file_operations audio_mp3_fops = { - .owner = THIS_MODULE, - .open = audio_open, - .release = audio_release, - .read = audio_read, - .write = audio_write, - .unlocked_ioctl = audio_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_mp3_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_mp3", - .fops = &audio_mp3_fops, -}; - -static int __init audio_init(void) -{ - mutex_init(&the_mp3_audio.lock); - mutex_init(&the_mp3_audio.write_lock); - mutex_init(&the_mp3_audio.read_lock); - spin_lock_init(&the_mp3_audio.dsp_lock); - init_waitqueue_head(&the_mp3_audio.write_wait); - init_waitqueue_head(&the_mp3_audio.read_wait); - the_mp3_audio.read_data = NULL; - return misc_register(&audio_mp3_misc); -} - -device_initcall(audio_init); diff --git a/drivers/staging/dream/qdsp5/audio_out.c b/drivers/staging/dream/qdsp5/audio_out.c deleted file mode 100644 index d20e89541567..000000000000 --- a/drivers/staging/dream/qdsp5/audio_out.c +++ /dev/null @@ -1,841 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audio_out.c - * - * pcm audio output device - * - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/delay.h> -#include <linux/wakelock.h> -#include <linux/gfp.h> - -#include <linux/msm_audio.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> - -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> - -#include "evlog.h" - -#define LOG_AUDIO_EVENTS 1 -#define LOG_AUDIO_FAULTS 0 - -enum { - EV_NULL, - EV_OPEN, - EV_WRITE, - EV_RETURN, - EV_IOCTL, - EV_WRITE_WAIT, - EV_WAIT_EVENT, - EV_FILL_BUFFER, - EV_SEND_BUFFER, - EV_DSP_EVENT, - EV_ENABLE, -}; - -#if (LOG_AUDIO_EVENTS != 1) -static inline void LOG(unsigned id, unsigned arg) {} -#else -static const char *pcm_log_strings[] = { - "NULL", - "OPEN", - "WRITE", - "RETURN", - "IOCTL", - "WRITE_WAIT", - "WAIT_EVENT", - "FILL_BUFFER", - "SEND_BUFFER", - "DSP_EVENT", - "ENABLE", -}; - -DECLARE_LOG(pcm_log, 64, pcm_log_strings); - -static int __init _pcm_log_init(void) -{ - return ev_log_init(&pcm_log); -} -module_init(_pcm_log_init); - -#define LOG(id,arg) ev_log_write(&pcm_log, id, arg) -#endif - - - - - -#define BUFSZ (960 * 5) -#define DMASZ (BUFSZ * 2) - -#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000 -#define AUDPP_CMD_EQ_FLAG_DIS 0x0000 -#define AUDPP_CMD_EQ_FLAG_ENA -1 -#define AUDPP_CMD_IIR_FLAG_DIS 0x0000 -#define AUDPP_CMD_IIR_FLAG_ENA -1 - -#define AUDPP_CMD_IIR_TUNING_FILTER 1 -#define AUDPP_CMD_EQUALIZER 2 -#define AUDPP_CMD_ADRC 3 - -#define ADRC_ENABLE 0x0001 -#define EQ_ENABLE 0x0002 -#define IIR_ENABLE 0x0004 - -struct adrc_filter { - uint16_t compression_th; - uint16_t compression_slope; - uint16_t rms_time; - uint16_t attack_const_lsw; - uint16_t attack_const_msw; - uint16_t release_const_lsw; - uint16_t release_const_msw; - uint16_t adrc_system_delay; -}; - -struct eqalizer { - uint16_t num_bands; - uint16_t eq_params[132]; -}; - -struct rx_iir_filter { - uint16_t num_bands; - uint16_t iir_params[48]; -}; - -typedef struct { - audpp_cmd_cfg_object_params_common common; - uint16_t eq_flag; - uint16_t num_bands; - uint16_t eq_params[132]; -} audpp_cmd_cfg_object_params_eq; - -typedef struct { - audpp_cmd_cfg_object_params_common common; - uint16_t active_flag; - uint16_t num_bands; - uint16_t iir_params[48]; -} audpp_cmd_cfg_object_params_rx_iir; - -struct buffer { - void *data; - unsigned size; - unsigned used; - unsigned addr; -}; - -struct audio { - struct buffer out[2]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - - atomic_t out_bytes; - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t wait; - - /* configuration to use on next enable */ - uint32_t out_sample_rate; - uint32_t out_channel_mode; - uint32_t out_weight; - uint32_t out_buffer_size; - - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - int opened; - int enabled; - int running; - int stopped; /* set when stopped, cleared on flush */ - unsigned volume; - - int adrc_enable; - struct adrc_filter adrc; - - int eq_enable; - struct eqalizer eq; - - int rx_iir_enable; - struct rx_iir_filter iir; -}; - -static void audio_prevent_sleep(struct audio *audio) -{ - printk(KERN_INFO "++++++++++++++++++++++++++++++\n"); -} - -static void audio_allow_sleep(struct audio *audio) -{ - printk(KERN_INFO "------------------------------\n"); -} - -static int audio_dsp_out_enable(struct audio *audio, int yes); -static int audio_dsp_send_buffer(struct audio *audio, unsigned id, unsigned len); -static int audio_dsp_set_adrc(struct audio *audio); -static int audio_dsp_set_eq(struct audio *audio); -static int audio_dsp_set_rx_iir(struct audio *audio); - -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg); - -/* must be called with audio->lock held */ -static int audio_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - pr_info("audio_enable()\n"); - - if (audio->enabled) - return 0; - - /* refuse to start if we're not ready */ - if (!audio->out[0].used || !audio->out[1].used) - return -EIO; - - /* we start buffers 0 and 1, so buffer 0 will be the - * next one the dsp will want - */ - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM; - cfg.codec = RPC_AUD_DEF_CODEC_PCM; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - audio_prevent_sleep(audio); - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) { - audio_allow_sleep(audio); - return rc; - } - - if (audpp_enable(-1, audio_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - audmgr_disable(&audio->audmgr); - audio_allow_sleep(audio); - return -ENODEV; - } - - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audio_disable(struct audio *audio) -{ - pr_info("audio_disable()\n"); - if (audio->enabled) { - audio->enabled = 0; - audio_dsp_out_enable(audio, 0); - - audpp_disable(-1, audio); - - wake_up(&audio->wait); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - audio_allow_sleep(audio); - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audio_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - struct buffer *frame; - unsigned long flags; - - LOG(EV_DSP_EVENT, id); - switch (id) { - case AUDPP_MSG_HOST_PCM_INTF_MSG: { - unsigned id = msg[2]; - unsigned idx = msg[3] - 1; - - /* pr_info("audio_dsp_event: HOST_PCM id %d idx %d\n", id, idx); */ - if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) { - pr_err("bogus id\n"); - break; - } - if (idx > 1) { - pr_err("bogus buffer idx\n"); - break; - } - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (audio->running) { - atomic_add(audio->out[idx].used, &audio->out_bytes); - audio->out[idx].used = 0; - - frame = audio->out + audio->out_tail; - if (frame->used) { - audio_dsp_send_buffer( - audio, audio->out_tail, frame->used); - audio->out_tail ^= 1; - } else { - audio->out_needed++; - } - wake_up(&audio->wait); - } - spin_unlock_irqrestore(&audio->dsp_lock, flags); - break; - } - case AUDPP_MSG_PCMDMAMISSED: - pr_info("audio_dsp_event: PCMDMAMISSED %d\n", msg[0]); - break; - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - LOG(EV_ENABLE, 1); - pr_info("audio_dsp_event: CFG_MSG ENABLE\n"); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(5, audio->volume, 0); - audio_dsp_set_adrc(audio); - audio_dsp_set_eq(audio); - audio_dsp_set_rx_iir(audio); - audio_dsp_out_enable(audio, 1); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - LOG(EV_ENABLE, 0); - pr_info("audio_dsp_event: CFG_MSG DISABLE\n"); - audio->running = 0; - } else { - pr_err("audio_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - default: - pr_err("audio_dsp_event: UNKNOWN (%d)\n", id); - } -} - -static int audio_dsp_out_enable(struct audio *audio, int yes) -{ - audpp_cmd_pcm_intf cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_PCM_INTF_2; - cmd.object_num = AUDPP_CMD_PCM_INTF_OBJECT_NUM; - cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V; - cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V; - - if (yes) { - cmd.write_buf1LSW = audio->out[0].addr; - cmd.write_buf1MSW = audio->out[0].addr >> 16; - cmd.write_buf1_len = audio->out[0].size; - cmd.write_buf2LSW = audio->out[1].addr; - cmd.write_buf2MSW = audio->out[1].addr >> 16; - cmd.write_buf2_len = audio->out[1].size; - cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V; - cmd.weight_decoder_to_rx = audio->out_weight; - cmd.weight_arm_to_rx = 1; - cmd.partition_number_arm_to_dsp = 0; - cmd.sample_rate = audio->out_sample_rate; - cmd.channel_mode = audio->out_channel_mode; - } - - return audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static int audio_dsp_send_buffer(struct audio *audio, unsigned idx, unsigned len) -{ - audpp_cmd_pcm_intf_send_buffer cmd; - - cmd.cmd_id = AUDPP_CMD_PCM_INTF_2; - cmd.host_pcm_object = AUDPP_CMD_PCM_INTF_OBJECT_NUM; - cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V; - cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V; - cmd.dsp_to_arm_buf_id = 0; - cmd.arm_to_dsp_buf_id = idx + 1; - cmd.arm_to_dsp_buf_len = len; - - LOG(EV_SEND_BUFFER, idx); - return audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static int audio_dsp_set_adrc(struct audio *audio) -{ - audpp_cmd_cfg_object_params_adrc cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE; - cmd.common.command_type = AUDPP_CMD_ADRC; - - if (audio->adrc_enable) { - cmd.adrc_flag = AUDPP_CMD_ADRC_FLAG_ENA; - cmd.compression_th = audio->adrc.compression_th; - cmd.compression_slope = audio->adrc.compression_slope; - cmd.rms_time = audio->adrc.rms_time; - cmd.attack_const_lsw = audio->adrc.attack_const_lsw; - cmd.attack_const_msw = audio->adrc.attack_const_msw; - cmd.release_const_lsw = audio->adrc.release_const_lsw; - cmd.release_const_msw = audio->adrc.release_const_msw; - cmd.adrc_system_delay = audio->adrc.adrc_system_delay; - } else { - cmd.adrc_flag = AUDPP_CMD_ADRC_FLAG_DIS; - } - return audpp_send_queue3(&cmd, sizeof(cmd)); -} - -static int audio_dsp_set_eq(struct audio *audio) -{ - audpp_cmd_cfg_object_params_eq cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE; - cmd.common.command_type = AUDPP_CMD_EQUALIZER; - - if (audio->eq_enable) { - cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA; - cmd.num_bands = audio->eq.num_bands; - memcpy(&cmd.eq_params, audio->eq.eq_params, - sizeof(audio->eq.eq_params)); - } else { - cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS; - } - return audpp_send_queue3(&cmd, sizeof(cmd)); -} - -static int audio_dsp_set_rx_iir(struct audio *audio) -{ - audpp_cmd_cfg_object_params_rx_iir cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE; - cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER; - - if (audio->rx_iir_enable) { - cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA; - cmd.num_bands = audio->iir.num_bands; - memcpy(&cmd.iir_params, audio->iir.iir_params, - sizeof(audio->iir.iir_params)); - } else { - cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS; - } - - return audpp_send_queue3(&cmd, sizeof(cmd)); -} - -/* ------------------- device --------------------- */ - -static int audio_enable_adrc(struct audio *audio, int enable) -{ - if (audio->adrc_enable != enable) { - audio->adrc_enable = enable; - if (audio->running) - audio_dsp_set_adrc(audio); - } - return 0; -} - -static int audio_enable_eq(struct audio *audio, int enable) -{ - if (audio->eq_enable != enable) { - audio->eq_enable = enable; - if (audio->running) - audio_dsp_set_eq(audio); - } - return 0; -} - -static int audio_enable_rx_iir(struct audio *audio, int enable) -{ - if (audio->rx_iir_enable != enable) { - audio->rx_iir_enable = enable; - if (audio->running) - audio_dsp_set_rx_iir(audio); - } - return 0; -} - -static void audio_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->stopped = 0; -} - -static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc; - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = atomic_read(&audio->out_bytes); - if (copy_to_user((void*) arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(6, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - } - - LOG(EV_IOCTL, cmd); - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audio_enable(audio); - break; - case AUDIO_STOP: - rc = audio_disable(audio); - audio->stopped = 1; - break; - case AUDIO_FLUSH: - if (audio->stopped) { - /* Make sure we're stopped and we wake any threads - * that might be blocked holding the write_lock. - * While audio->stopped write threads will always - * exit immediately. - */ - wake_up(&audio->wait); - mutex_lock(&audio->write_lock); - audio_flush(audio); - mutex_unlock(&audio->write_lock); - } - case AUDIO_SET_CONFIG: { - struct msm_audio_config config; - if (copy_from_user(&config, (void*) arg, sizeof(config))) { - rc = -EFAULT; - break; - } - if (config.channel_count == 1) { - config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V; - } else if (config.channel_count == 2) { - config.channel_count= AUDPP_CMD_PCM_INTF_STEREO_V; - } else { - rc = -EINVAL; - break; - } - audio->out_sample_rate = config.sample_rate; - audio->out_channel_mode = config.channel_count; - rc = 0; - break; - } - case AUDIO_GET_CONFIG: { - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = 2; - config.sample_rate = audio->out_sample_rate; - if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) { - config.channel_count = 1; - } else { - config.channel_count = 2; - } - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void*) arg, &config, sizeof(config))) { - rc = -EFAULT; - } else { - rc = 0; - } - break; - } - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audio_read(struct file *file, char __user *buf, size_t count, loff_t *pos) -{ - return -EINVAL; -} - -static inline int rt_policy(int policy) -{ - if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR)) - return 1; - return 0; -} - -static inline int task_has_rt_policy(struct task_struct *p) -{ - return rt_policy(p->policy); -} - -static ssize_t audio_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct sched_param s = { .sched_priority = 1 }; - struct audio *audio = file->private_data; - unsigned long flags; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - int old_prio = current->rt_priority; - int old_policy = current->policy; - int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE); - int rc = 0; - - LOG(EV_WRITE, count | (audio->running << 28) | (audio->stopped << 24)); - - /* just for this write, set us real-time */ - if (!task_has_rt_policy(current)) { - struct cred *new = prepare_creds(); - cap_raise(new->cap_effective, CAP_SYS_NICE); - commit_creds(new); - sched_setscheduler(current, SCHED_RR, &s); - } - - mutex_lock(&audio->write_lock); - while (count > 0) { - frame = audio->out + audio->out_head; - - LOG(EV_WAIT_EVENT, 0); - rc = wait_event_interruptible(audio->wait, - (frame->used == 0) || (audio->stopped)); - LOG(EV_WAIT_EVENT, 1); - - if (rc < 0) - break; - if (audio->stopped) { - rc = -EBUSY; - break; - } - xfer = count > frame->size ? frame->size : count; - if (copy_from_user(frame->data, buf, xfer)) { - rc = -EFAULT; - break; - } - frame->used = xfer; - audio->out_head ^= 1; - count -= xfer; - buf += xfer; - - spin_lock_irqsave(&audio->dsp_lock, flags); - LOG(EV_FILL_BUFFER, audio->out_head ^ 1); - frame = audio->out + audio->out_tail; - if (frame->used && audio->out_needed) { - audio_dsp_send_buffer(audio, audio->out_tail, frame->used); - audio->out_tail ^= 1; - audio->out_needed--; - } - spin_unlock_irqrestore(&audio->dsp_lock, flags); - } - - mutex_unlock(&audio->write_lock); - - /* restore scheduling policy and priority */ - if (!rt_policy(old_policy)) { - struct sched_param v = { .sched_priority = old_prio }; - sched_setscheduler(current, old_policy, &v); - if (likely(!cap_nice)) { - struct cred *new = prepare_creds(); - cap_lower(new->cap_effective, CAP_SYS_NICE); - commit_creds(new); - sched_setscheduler(current, SCHED_RR, &s); - } - } - - LOG(EV_RETURN,(buf > start) ? (buf - start) : rc); - if (buf > start) - return buf - start; - return rc; -} - -static int audio_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - LOG(EV_OPEN, 0); - mutex_lock(&audio->lock); - audio_disable(audio); - audio_flush(audio); - audio->opened = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static struct audio the_audio; - -static int audio_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_audio; - int rc; - - mutex_lock(&audio->lock); - - if (audio->opened) { - pr_err("audio: busy\n"); - rc = -EBUSY; - goto done; - } - - if (!audio->data) { - audio->data = dma_alloc_coherent(NULL, DMASZ, - &audio->phys, GFP_KERNEL); - if (!audio->data) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto done; - } - } - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto done; - - audio->out_buffer_size = BUFSZ; - audio->out_sample_rate = 44100; - audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V; - audio->out_weight = 100; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = BUFSZ; - - audio->out[1].data = audio->data + BUFSZ; - audio->out[1].addr = audio->phys + BUFSZ; - audio->out[1].size = BUFSZ; - - audio->volume = 0x2000; - - audio_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; - LOG(EV_OPEN, 1); -done: - mutex_unlock(&audio->lock); - return rc; -} - -static long audpp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0, enable; - uint16_t enable_mask; - - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_ENABLE_AUDPP: - if (copy_from_user(&enable_mask, (void *) arg, sizeof(enable_mask))) - goto out_fault; - - enable = (enable_mask & ADRC_ENABLE)? 1 : 0; - audio_enable_adrc(audio, enable); - enable = (enable_mask & EQ_ENABLE)? 1 : 0; - audio_enable_eq(audio, enable); - enable = (enable_mask & IIR_ENABLE)? 1 : 0; - audio_enable_rx_iir(audio, enable); - break; - - case AUDIO_SET_ADRC: - if (copy_from_user(&audio->adrc, (void*) arg, sizeof(audio->adrc))) - goto out_fault; - break; - - case AUDIO_SET_EQ: - if (copy_from_user(&audio->eq, (void*) arg, sizeof(audio->eq))) - goto out_fault; - break; - - case AUDIO_SET_RX_IIR: - if (copy_from_user(&audio->iir, (void*) arg, sizeof(audio->iir))) - goto out_fault; - break; - - default: - rc = -EINVAL; - } - - goto out; - - out_fault: - rc = -EFAULT; - out: - mutex_unlock(&audio->lock); - return rc; -} - -static int audpp_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_audio; - - file->private_data = audio; - return 0; -} - -static struct file_operations audio_fops = { - .owner = THIS_MODULE, - .open = audio_open, - .release = audio_release, - .read = audio_read, - .write = audio_write, - .unlocked_ioctl = audio_ioctl, - .llseek = noop_llseek, -}; - -static struct file_operations audpp_fops = { - .owner = THIS_MODULE, - .open = audpp_open, - .unlocked_ioctl = audpp_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_pcm_out", - .fops = &audio_fops, -}; - -struct miscdevice audpp_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_pcm_ctl", - .fops = &audpp_fops, -}; - -static int __init audio_init(void) -{ - mutex_init(&the_audio.lock); - mutex_init(&the_audio.write_lock); - spin_lock_init(&the_audio.dsp_lock); - init_waitqueue_head(&the_audio.wait); - return (misc_register(&audio_misc) || misc_register(&audpp_misc)); -} - -device_initcall(audio_init); diff --git a/drivers/staging/dream/qdsp5/audio_qcelp.c b/drivers/staging/dream/qdsp5/audio_qcelp.c deleted file mode 100644 index 911bab416b85..000000000000 --- a/drivers/staging/dream/qdsp5/audio_qcelp.c +++ /dev/null @@ -1,858 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audio_qcelp.c - * - * qcelp 13k audio decoder device - * - * Copyright (c) 2008 QUALCOMM USA, INC. - * - * This code is based in part on audio_mp3.c, which is - * Copyright (C) 2008 Google, Inc. - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can find it at http://www.fsf.org. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> -#include <linux/msm_audio.h> -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> -#include <mach/qdsp5/qdsp5audplaycmdi.h> -#include <mach/qdsp5/qdsp5audplaymsg.h> - -#include "audmgr.h" -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -#ifdef DEBUG -#define dprintk(format, arg...) \ -printk(KERN_DEBUG format, ## arg) -#else -#define dprintk(format, arg...) do {} while (0) -#endif - -#define BUFSZ 1080 /* QCELP 13K Hold 600ms packet data = 36 * 30 */ -#define BUF_COUNT 2 -#define DMASZ (BUFSZ * BUF_COUNT) - -#define PCM_BUFSZ_MIN 1600 /* 100ms worth of data */ -#define PCM_BUF_MAX_COUNT 5 - -#define AUDDEC_DEC_QCELP 9 - -#define ROUTING_MODE_FTRT 1 -#define ROUTING_MODE_RT 2 -/* Decoder status received from AUDPPTASK */ -#define AUDPP_DEC_STATUS_SLEEP 0 -#define AUDPP_DEC_STATUS_INIT 1 -#define AUDPP_DEC_STATUS_CFG 2 -#define AUDPP_DEC_STATUS_PLAY 3 - -struct buffer { - void *data; - unsigned size; - unsigned used; /* Input usage actual DSP produced PCM size */ - unsigned addr; -}; - -struct audio { - struct buffer out[BUF_COUNT]; - - spinlock_t dsp_lock; - - uint8_t out_head; - uint8_t out_tail; - uint8_t out_needed; /* number of buffers the dsp is waiting for */ - - struct mutex lock; - struct mutex write_lock; - wait_queue_head_t write_wait; - - /* Host PCM section - START */ - struct buffer in[PCM_BUF_MAX_COUNT]; - struct mutex read_lock; - wait_queue_head_t read_wait; /* Wait queue for read */ - char *read_data; /* pointer to reader buffer */ - dma_addr_t read_phys; /* physical address of reader buffer */ - uint8_t read_next; /* index to input buffers to be read next */ - uint8_t fill_next; /* index to buffer that DSP should be filling */ - uint8_t pcm_buf_count; /* number of pcm buffer allocated */ - /* Host PCM section - END */ - - struct msm_adsp_module *audplay; - - struct audmgr audmgr; - - /* data allocated for various buffers */ - char *data; - dma_addr_t phys; - - uint8_t opened:1; - uint8_t enabled:1; - uint8_t running:1; - uint8_t stopped:1; /* set when stopped, cleared on flush */ - uint8_t pcm_feedback:1; /* set when non-tunnel mode */ - uint8_t buf_refresh:1; - - unsigned volume; - - uint16_t dec_id; -}; - -static struct audio the_qcelp_audio; - -static int auddec_dsp_config(struct audio *audio, int enable); -static void audpp_cmd_cfg_adec_params(struct audio *audio); -static void audpp_cmd_cfg_routing_mode(struct audio *audio); -static void audqcelp_send_data(struct audio *audio, unsigned needed); -static void audqcelp_config_hostpcm(struct audio *audio); -static void audqcelp_buffer_refresh(struct audio *audio); -static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg); - -/* must be called with audio->lock held */ -static int audqcelp_enable(struct audio *audio) -{ - struct audmgr_config cfg; - int rc; - - dprintk("audqcelp_enable()\n"); - - if (audio->enabled) - return 0; - - audio->out_tail = 0; - audio->out_needed = 0; - - cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; - cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000; - cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK; - cfg.codec = RPC_AUD_DEF_CODEC_13K; - cfg.snd_method = RPC_SND_METHOD_MIDI; - - rc = audmgr_enable(&audio->audmgr, &cfg); - if (rc < 0) - return rc; - - if (msm_adsp_enable(audio->audplay)) { - pr_err("audio: msm_adsp_enable(audplay) failed\n"); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - - if (audpp_enable(audio->dec_id, audqcelp_dsp_event, audio)) { - pr_err("audio: audpp_enable() failed\n"); - msm_adsp_disable(audio->audplay); - audmgr_disable(&audio->audmgr); - return -ENODEV; - } - audio->enabled = 1; - return 0; -} - -/* must be called with audio->lock held */ -static int audqcelp_disable(struct audio *audio) -{ - dprintk("audqcelp_disable()\n"); - if (audio->enabled) { - audio->enabled = 0; - auddec_dsp_config(audio, 0); - wake_up(&audio->write_wait); - wake_up(&audio->read_wait); - msm_adsp_disable(audio->audplay); - audpp_disable(audio->dec_id, audio); - audmgr_disable(&audio->audmgr); - audio->out_needed = 0; - } - return 0; -} - -/* ------------------- dsp --------------------- */ -static void audqcelp_update_pcm_buf_entry(struct audio *audio, - uint32_t *payload) -{ - uint8_t index; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - for (index = 0; index < payload[1]; index++) { - if (audio->in[audio->fill_next].addr == - payload[2 + index * 2]) { - dprintk("audqcelp_update_pcm_buf_entry: in[%d] ready\n", - audio->fill_next); - audio->in[audio->fill_next].used = - payload[3 + index * 2]; - if ((++audio->fill_next) == audio->pcm_buf_count) - audio->fill_next = 0; - } else { - pr_err( - "audqcelp_update_pcm_buf_entry: expected=%x ret=%x\n", - audio->in[audio->fill_next].addr, - payload[1 + index * 2]); - break; - } - } - if (audio->in[audio->fill_next].used == 0) { - audqcelp_buffer_refresh(audio); - } else { - dprintk("audqcelp_update_pcm_buf_entry: read cannot keep up\n"); - audio->buf_refresh = 1; - } - - spin_unlock_irqrestore(&audio->dsp_lock, flags); - wake_up(&audio->read_wait); -} - -static void audplay_dsp_event(void *data, unsigned id, size_t len, - void (*getevent) (void *ptr, size_t len)) -{ - struct audio *audio = data; - uint32_t msg[28]; - getevent(msg, sizeof(msg)); - - dprintk("audplay_dsp_event: msg_id=%x\n", id); - - switch (id) { - case AUDPLAY_MSG_DEC_NEEDS_DATA: - audqcelp_send_data(audio, 1); - break; - - case AUDPLAY_MSG_BUFFER_UPDATE: - audqcelp_update_pcm_buf_entry(audio, msg); - break; - - default: - pr_err("unexpected message from decoder \n"); - } -} - -static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg) -{ - struct audio *audio = private; - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned status = msg[1]; - - switch (status) { - case AUDPP_DEC_STATUS_SLEEP: - dprintk("decoder status: sleep \n"); - break; - - case AUDPP_DEC_STATUS_INIT: - dprintk("decoder status: init \n"); - audpp_cmd_cfg_routing_mode(audio); - break; - - case AUDPP_DEC_STATUS_CFG: - dprintk("decoder status: cfg \n"); - break; - case AUDPP_DEC_STATUS_PLAY: - dprintk("decoder status: play \n"); - if (audio->pcm_feedback) { - audqcelp_config_hostpcm(audio); - audqcelp_buffer_refresh(audio); - } - break; - default: - pr_err("unknown decoder status \n"); - } - break; - } - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - dprintk("audqcelp_dsp_event: CFG_MSG ENABLE\n"); - auddec_dsp_config(audio, 1); - audio->out_needed = 0; - audio->running = 1; - audpp_set_volume_and_pan(audio->dec_id, audio->volume, - 0); - audpp_avsync(audio->dec_id, 22050); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - dprintk("audqcelp_dsp_event: CFG_MSG DISABLE\n"); - audpp_avsync(audio->dec_id, 0); - audio->running = 0; - } else { - pr_err("audqcelp_dsp_event: CFG_MSG %d?\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - dprintk("audqcelp_dsp_event: ROUTING_ACK mode=%d\n", msg[1]); - audpp_cmd_cfg_adec_params(audio); - break; - default: - pr_err("audqcelp_dsp_event: UNKNOWN (%d)\n", id); - } - -} - -struct msm_adsp_ops audplay_adsp_ops_qcelp = { - .event = audplay_dsp_event, -}; - -#define audplay_send_queue0(audio, cmd, len) \ - msm_adsp_write(audio->audplay, QDSP_uPAudPlay0BitStreamCtrlQueue, \ - cmd, len) - -static int auddec_dsp_config(struct audio *audio, int enable) -{ - audpp_cmd_cfg_dec_type cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE; - if (enable) - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | - AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_QCELP; - else - cmd.dec0_cfg = AUDPP_CMD_UPDATDE_CFG_DEC | AUDPP_CMD_DIS_DEC_V; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_adec_params(struct audio *audio) -{ - struct audpp_cmd_cfg_adec_params_v13k cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS; - cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN; - cmd.common.dec_id = audio->dec_id; - cmd.common.input_sampling_frequency = 8000; - cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V; - - audpp_send_queue2(&cmd, sizeof(cmd)); -} - -static void audpp_cmd_cfg_routing_mode(struct audio *audio) -{ - struct audpp_cmd_routing_mode cmd; - dprintk("audpp_cmd_cfg_routing_mode()\n"); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd_id = AUDPP_CMD_ROUTING_MODE; - cmd.object_number = audio->dec_id; - if (audio->pcm_feedback) - cmd.routing_mode = ROUTING_MODE_FTRT; - else - cmd.routing_mode = ROUTING_MODE_RT; - audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static int audplay_dsp_send_data_avail(struct audio *audio, - unsigned idx, unsigned len) -{ - audplay_cmd_bitstream_data_avail cmd; - - cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL; - cmd.decoder_id = audio->dec_id; - cmd.buf_ptr = audio->out[idx].addr; - cmd.buf_size = len / 2; - cmd.partition_number = 0; - return audplay_send_queue0(audio, &cmd, sizeof(cmd)); -} - -static void audqcelp_buffer_refresh(struct audio *audio) -{ - struct audplay_cmd_buffer_refresh refresh_cmd; - - refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH; - refresh_cmd.num_buffers = 1; - refresh_cmd.buf0_address = audio->in[audio->fill_next].addr; - refresh_cmd.buf0_length = audio->in[audio->fill_next].size; - refresh_cmd.buf_read_count = 0; - dprintk("audplay_buffer_fresh: buf0_addr=%x buf0_len=%d\n", - refresh_cmd.buf0_address, refresh_cmd.buf0_length); - - (void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd)); -} - -static void audqcelp_config_hostpcm(struct audio *audio) -{ - struct audplay_cmd_hpcm_buf_cfg cfg_cmd; - - dprintk("audqcelp_config_hostpcm()\n"); - cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG; - cfg_cmd.max_buffers = audio->pcm_buf_count; - cfg_cmd.byte_swap = 0; - cfg_cmd.hostpcm_config = (0x8000) | (0x4000); - cfg_cmd.feedback_frequency = 1; - cfg_cmd.partition_number = 0; - - (void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd)); -} - -static void audqcelp_send_data(struct audio *audio, unsigned needed) -{ - struct buffer *frame; - unsigned long flags; - - spin_lock_irqsave(&audio->dsp_lock, flags); - if (!audio->running) - goto done; - - if (needed) { - /* We were called from the callback because the DSP - * requested more data. Note that the DSP does want - * more data, and if a buffer was in-flight, mark it - * as available (since the DSP must now be done with - * it). - */ - audio->out_needed = 1; - frame = audio->out + audio->out_tail; - if (frame->used == 0xffffffff) { - dprintk("frame %d free\n", audio->out_tail); - frame->used = 0; - audio->out_tail ^= 1; - wake_up(&audio->write_wait); - } - } - - if (audio->out_needed) { - /* If the DSP currently wants data and we have a - * buffer available, we will send it and reset - * the needed flag. We'll mark the buffer as in-flight - * so that it won't be recycled until the next buffer - * is requested - */ - - frame = audio->out + audio->out_tail; - if (frame->used) { - BUG_ON(frame->used == 0xffffffff); - dprintk("frame %d busy\n", audio->out_tail); - audplay_dsp_send_data_avail(audio, audio->out_tail, - frame->used); - frame->used = 0xffffffff; - audio->out_needed = 0; - } - } - done: - spin_unlock_irqrestore(&audio->dsp_lock, flags); -} - -/* ------------------- device --------------------- */ - -static void audqcelp_flush(struct audio *audio) -{ - audio->out[0].used = 0; - audio->out[1].used = 0; - audio->out_head = 0; - audio->out_tail = 0; - audio->stopped = 0; -} - -static void audqcelp_flush_pcm_buf(struct audio *audio) -{ - uint8_t index; - - for (index = 0; index < PCM_BUF_MAX_COUNT; index++) - audio->in[index].used = 0; - - audio->read_next = 0; - audio->fill_next = 0; -} - -static long audqcelp_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct audio *audio = file->private_data; - int rc = 0; - - dprintk("audqcelp_ioctl() cmd = %d\n", cmd); - - if (cmd == AUDIO_GET_STATS) { - struct msm_audio_stats stats; - stats.byte_count = audpp_avsync_byte_count(audio->dec_id); - stats.sample_count = audpp_avsync_sample_count(audio->dec_id); - if (copy_to_user((void *)arg, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - if (cmd == AUDIO_SET_VOLUME) { - unsigned long flags; - spin_lock_irqsave(&audio->dsp_lock, flags); - audio->volume = arg; - if (audio->running) - audpp_set_volume_and_pan(audio->dec_id, arg, 0); - spin_unlock_irqrestore(&audio->dsp_lock, flags); - return 0; - } - mutex_lock(&audio->lock); - switch (cmd) { - case AUDIO_START: - rc = audqcelp_enable(audio); - break; - case AUDIO_STOP: - rc = audqcelp_disable(audio); - audio->stopped = 1; - break; - case AUDIO_FLUSH: - if (audio->stopped) { - /* Make sure we're stopped and we wake any threads - * that might be blocked holding the write_lock. - * While audio->stopped write threads will always - * exit immediately. - */ - wake_up(&audio->write_wait); - mutex_lock(&audio->write_lock); - audqcelp_flush(audio); - mutex_unlock(&audio->write_lock); - wake_up(&audio->read_wait); - mutex_lock(&audio->read_lock); - audqcelp_flush_pcm_buf(audio); - mutex_unlock(&audio->read_lock); - break; - } - break; - case AUDIO_SET_CONFIG: - dprintk("AUDIO_SET_CONFIG not applicable \n"); - break; - case AUDIO_GET_CONFIG:{ - struct msm_audio_config config; - config.buffer_size = BUFSZ; - config.buffer_count = BUF_COUNT; - config.sample_rate = 8000; - config.channel_count = 1; - config.unused[0] = 0; - config.unused[1] = 0; - config.unused[2] = 0; - config.unused[3] = 0; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - - break; - } - case AUDIO_GET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - - config.pcm_feedback = 0; - config.buffer_count = PCM_BUF_MAX_COUNT; - config.buffer_size = PCM_BUFSZ_MIN; - if (copy_to_user((void *)arg, &config, - sizeof(config))) - rc = -EFAULT; - else - rc = 0; - break; - } - case AUDIO_SET_PCM_CONFIG:{ - struct msm_audio_pcm_config config; - - if (copy_from_user(&config, (void *)arg, - sizeof(config))) { - rc = -EFAULT; - break; - } - if ((config.buffer_count > PCM_BUF_MAX_COUNT) || - (config.buffer_count == 1)) - config.buffer_count = PCM_BUF_MAX_COUNT; - - if (config.buffer_size < PCM_BUFSZ_MIN) - config.buffer_size = PCM_BUFSZ_MIN; - - /* Check if pcm feedback is required */ - if ((config.pcm_feedback) && (!audio->read_data)) { - dprintk( - "audqcelp_ioctl: allocate PCM buf %d\n", - config.buffer_count * config.buffer_size); - audio->read_data = dma_alloc_coherent(NULL, - config.buffer_size * config.buffer_count, - &audio->read_phys, GFP_KERNEL); - if (!audio->read_data) { - pr_err( - "audqcelp_ioctl: no mem for pcm buf\n" - ); - rc = -ENOMEM; - } else { - uint8_t index; - uint32_t offset = 0; - - audio->pcm_feedback = 1; - audio->buf_refresh = 0; - audio->pcm_buf_count = - config.buffer_count; - audio->read_next = 0; - audio->fill_next = 0; - - for (index = 0; - index < config.buffer_count; index++) { - audio->in[index].data = - audio->read_data + offset; - audio->in[index].addr = - audio->read_phys + offset; - audio->in[index].size = - config.buffer_size; - audio->in[index].used = 0; - offset += config.buffer_size; - } - rc = 0; - } - } else { - rc = 0; - } - break; - } - case AUDIO_PAUSE: - dprintk("%s: AUDIO_PAUSE %ld\n", __func__, arg); - rc = audpp_pause(audio->dec_id, (int) arg); - break; - default: - rc = -EINVAL; - } - mutex_unlock(&audio->lock); - return rc; -} - -static ssize_t audqcelp_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - int rc = 0; - - if (!audio->pcm_feedback) - return 0; /* PCM feedback is not enabled. Nothing to read */ - - mutex_lock(&audio->read_lock); - dprintk("audqcelp_read() %d \n", count); - while (count > 0) { - rc = wait_event_interruptible(audio->read_wait, - (audio->in[audio->read_next].used > 0) || - (audio->stopped)); - if (rc < 0) - break; - - if (audio->stopped) { - rc = -EBUSY; - break; - } - - if (count < audio->in[audio->read_next].used) { - /* Read must happen in frame boundary. Since driver does - not know frame size, read count must be greater or equal - to size of PCM samples */ - dprintk("audqcelp_read:read stop - partial frame\n"); - break; - } else { - dprintk("audqcelp_read: read from in[%d]\n", - audio->read_next); - if (copy_to_user(buf, - audio->in[audio->read_next].data, - audio->in[audio->read_next].used)) { - pr_err("audqcelp_read: invalid addr %x \n", - (unsigned int)buf); - rc = -EFAULT; - break; - } - count -= audio->in[audio->read_next].used; - buf += audio->in[audio->read_next].used; - audio->in[audio->read_next].used = 0; - if ((++audio->read_next) == audio->pcm_buf_count) - audio->read_next = 0; - } - } - - if (audio->buf_refresh) { - audio->buf_refresh = 0; - dprintk("audqcelp_read: kick start pcm feedback again\n"); - audqcelp_buffer_refresh(audio); - } - - mutex_unlock(&audio->read_lock); - - if (buf > start) - rc = buf - start; - - dprintk("audqcelp_read: read %d bytes\n", rc); - return rc; -} - -static ssize_t audqcelp_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct audio *audio = file->private_data; - const char __user *start = buf; - struct buffer *frame; - size_t xfer; - int rc = 0; - - if (count & 1) - return -EINVAL; - dprintk("audqcelp_write() \n"); - mutex_lock(&audio->write_lock); - while (count > 0) { - frame = audio->out + audio->out_head; - rc = wait_event_interruptible(audio->write_wait, - (frame->used == 0) - || (audio->stopped)); - dprintk("audqcelp_write() buffer available\n"); - if (rc < 0) - break; - if (audio->stopped) { - rc = -EBUSY; - break; - } - xfer = (count > frame->size) ? frame->size : count; - if (copy_from_user(frame->data, buf, xfer)) { - rc = -EFAULT; - break; - } - - frame->used = xfer; - audio->out_head ^= 1; - count -= xfer; - buf += xfer; - - audqcelp_send_data(audio, 0); - - } - mutex_unlock(&audio->write_lock); - if (buf > start) - return buf - start; - return rc; -} - -static int audqcelp_release(struct inode *inode, struct file *file) -{ - struct audio *audio = file->private_data; - - dprintk("audqcelp_release()\n"); - - mutex_lock(&audio->lock); - audqcelp_disable(audio); - audqcelp_flush(audio); - audqcelp_flush_pcm_buf(audio); - msm_adsp_put(audio->audplay); - audio->audplay = NULL; - audio->opened = 0; - if (audio->data) - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - audio->data = NULL; - if (audio->read_data) { - dma_free_coherent(NULL, - audio->in[0].size * audio->pcm_buf_count, - audio->read_data, audio->read_phys); - audio->read_data = NULL; - } - audio->pcm_feedback = 0; - mutex_unlock(&audio->lock); - return 0; -} - -static int audqcelp_open(struct inode *inode, struct file *file) -{ - struct audio *audio = &the_qcelp_audio; - int rc; - - mutex_lock(&audio->lock); - - if (audio->opened) { - pr_err("audio: busy\n"); - rc = -EBUSY; - goto done; - } - - audio->data = dma_alloc_coherent(NULL, DMASZ, - &audio->phys, GFP_KERNEL); - if (!audio->data) { - pr_err("audio: could not allocate DMA buffers\n"); - rc = -ENOMEM; - goto done; - } - - rc = audmgr_open(&audio->audmgr); - if (rc) - goto err; - - rc = msm_adsp_get("AUDPLAY0TASK", &audio->audplay, - &audplay_adsp_ops_qcelp, audio); - if (rc) { - pr_err("audio: failed to get audplay0 dsp module\n"); - audmgr_close(&audio->audmgr); - goto err; - } - - audio->dec_id = 0; - - audio->out[0].data = audio->data + 0; - audio->out[0].addr = audio->phys + 0; - audio->out[0].size = BUFSZ; - - audio->out[1].data = audio->data + BUFSZ; - audio->out[1].addr = audio->phys + BUFSZ; - audio->out[1].size = BUFSZ; - - audio->volume = 0x2000; /* Q13 1.0 */ - - audqcelp_flush(audio); - - file->private_data = audio; - audio->opened = 1; - rc = 0; -done: - mutex_unlock(&audio->lock); - return rc; -err: - dma_free_coherent(NULL, DMASZ, audio->data, audio->phys); - mutex_unlock(&audio->lock); - return rc; -} - -static struct file_operations audio_qcelp_fops = { - .owner = THIS_MODULE, - .open = audqcelp_open, - .release = audqcelp_release, - .read = audqcelp_read, - .write = audqcelp_write, - .unlocked_ioctl = audqcelp_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice audio_qcelp_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_qcelp", - .fops = &audio_qcelp_fops, -}; - -static int __init audqcelp_init(void) -{ - mutex_init(&the_qcelp_audio.lock); - mutex_init(&the_qcelp_audio.write_lock); - mutex_init(&the_qcelp_audio.read_lock); - spin_lock_init(&the_qcelp_audio.dsp_lock); - init_waitqueue_head(&the_qcelp_audio.write_wait); - init_waitqueue_head(&the_qcelp_audio.read_wait); - the_qcelp_audio.read_data = NULL; - return misc_register(&audio_qcelp_misc); -} - -static void __exit audqcelp_exit(void) -{ - misc_deregister(&audio_qcelp_misc); -} - -module_init(audqcelp_init); -module_exit(audqcelp_exit); - -MODULE_DESCRIPTION("MSM QCELP 13K driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("QUALCOMM"); diff --git a/drivers/staging/dream/qdsp5/audmgr.c b/drivers/staging/dream/qdsp5/audmgr.c deleted file mode 100644 index 427ae6c0bea8..000000000000 --- a/drivers/staging/dream/qdsp5/audmgr.c +++ /dev/null @@ -1,314 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audmgr.c - * - * interface to "audmgr" service on the baseband cpu - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/slab.h> -#include <linux/kthread.h> -#include <linux/wait.h> - -#include <asm/atomic.h> -#include <mach/msm_rpcrouter.h> - -#include "audmgr.h" - -#define STATE_CLOSED 0 -#define STATE_DISABLED 1 -#define STATE_ENABLING 2 -#define STATE_ENABLED 3 -#define STATE_DISABLING 4 -#define STATE_ERROR 5 - -static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid) -{ - uint32_t rep[6]; - - rep[0] = cpu_to_be32(xid); - rep[1] = cpu_to_be32(1); - rep[2] = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED); - rep[3] = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS); - rep[4] = 0; - rep[5] = 0; - - msm_rpc_write(ept, rep, sizeof(rep)); -} - -static void process_audmgr_callback(struct audmgr *am, - struct rpc_audmgr_cb_func_ptr *args, - int len) -{ - if (len < (sizeof(uint32_t) * 3)) - return; - if (be32_to_cpu(args->set_to_one) != 1) - return; - - switch (be32_to_cpu(args->status)) { - case RPC_AUDMGR_STATUS_READY: - if (len < sizeof(uint32_t) * 4) - break; - am->handle = be32_to_cpu(args->u.handle); - pr_info("audmgr: rpc READY handle=0x%08x\n", am->handle); - break; - case RPC_AUDMGR_STATUS_CODEC_CONFIG: { - uint32_t volume; - if (len < sizeof(uint32_t) * 4) - break; - volume = be32_to_cpu(args->u.volume); - pr_info("audmgr: rpc CODEC_CONFIG volume=0x%08x\n", volume); - am->state = STATE_ENABLED; - wake_up(&am->wait); - break; - } - case RPC_AUDMGR_STATUS_PENDING: - pr_err("audmgr: PENDING?\n"); - break; - case RPC_AUDMGR_STATUS_SUSPEND: - pr_err("audmgr: SUSPEND?\n"); - break; - case RPC_AUDMGR_STATUS_FAILURE: - pr_err("audmgr: FAILURE\n"); - break; - case RPC_AUDMGR_STATUS_VOLUME_CHANGE: - pr_err("audmgr: VOLUME_CHANGE?\n"); - break; - case RPC_AUDMGR_STATUS_DISABLED: - pr_err("audmgr: DISABLED\n"); - am->state = STATE_DISABLED; - wake_up(&am->wait); - break; - case RPC_AUDMGR_STATUS_ERROR: - pr_err("audmgr: ERROR?\n"); - am->state = STATE_ERROR; - wake_up(&am->wait); - break; - default: - break; - } -} - -static void process_rpc_request(uint32_t proc, uint32_t xid, - void *data, int len, void *private) -{ - struct audmgr *am = private; - uint32_t *x = data; - - if (0) { - int n = len / 4; - pr_info("rpc_call proc %d:", proc); - while (n--) - printk(" %08x", be32_to_cpu(*x++)); - printk("\n"); - } - - if (proc == AUDMGR_CB_FUNC_PTR) - process_audmgr_callback(am, data, len); - else - pr_err("audmgr: unknown rpc proc %d\n", proc); - rpc_ack(am->ept, xid); -} - -#define RPC_TYPE_REQUEST 0 -#define RPC_TYPE_REPLY 1 - -#define RPC_VERSION 2 - -#define RPC_COMMON_HDR_SZ (sizeof(uint32_t) * 2) -#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr)) -#define RPC_REPLY_HDR_SZ (sizeof(uint32_t) * 3) -#define RPC_REPLY_SZ (sizeof(uint32_t) * 6) - -static int audmgr_rpc_thread(void *data) -{ - struct audmgr *am = data; - struct rpc_request_hdr *hdr = NULL; - uint32_t type; - int len; - - pr_info("audmgr_rpc_thread() start\n"); - - while (!kthread_should_stop()) { - if (hdr) { - kfree(hdr); - hdr = NULL; - } - len = msm_rpc_read(am->ept, (void **) &hdr, -1, -1); - if (len < 0) { - pr_err("audmgr: rpc read failed (%d)\n", len); - break; - } - if (len < RPC_COMMON_HDR_SZ) - continue; - - type = be32_to_cpu(hdr->type); - if (type == RPC_TYPE_REPLY) { - struct rpc_reply_hdr *rep = (void *) hdr; - uint32_t status; - if (len < RPC_REPLY_HDR_SZ) - continue; - status = be32_to_cpu(rep->reply_stat); - if (status == RPCMSG_REPLYSTAT_ACCEPTED) { - status = be32_to_cpu(rep->data.acc_hdr.accept_stat); - pr_info("audmgr: rpc_reply status %d\n", status); - } else { - pr_info("audmgr: rpc_reply denied!\n"); - } - /* process reply */ - continue; - } - - if (len < RPC_REQUEST_HDR_SZ) - continue; - - process_rpc_request(be32_to_cpu(hdr->procedure), - be32_to_cpu(hdr->xid), - (void *) (hdr + 1), - len - sizeof(*hdr), - data); - } - pr_info("audmgr_rpc_thread() exit\n"); - if (hdr) { - kfree(hdr); - hdr = NULL; - } - am->task = NULL; - wake_up(&am->wait); - return 0; -} - -struct audmgr_enable_msg { - struct rpc_request_hdr hdr; - struct rpc_audmgr_enable_client_args args; -}; - -struct audmgr_disable_msg { - struct rpc_request_hdr hdr; - uint32_t handle; -}; - -int audmgr_open(struct audmgr *am) -{ - int rc; - - if (am->state != STATE_CLOSED) - return 0; - - am->ept = msm_rpc_connect(AUDMGR_PROG, - AUDMGR_VERS, - MSM_RPC_UNINTERRUPTIBLE); - - init_waitqueue_head(&am->wait); - - if (IS_ERR(am->ept)) { - rc = PTR_ERR(am->ept); - am->ept = NULL; - pr_err("audmgr: failed to connect to audmgr svc\n"); - return rc; - } - - am->task = kthread_run(audmgr_rpc_thread, am, "audmgr_rpc"); - if (IS_ERR(am->task)) { - rc = PTR_ERR(am->task); - am->task = NULL; - msm_rpc_close(am->ept); - am->ept = NULL; - return rc; - } - - am->state = STATE_DISABLED; - return 0; -} -EXPORT_SYMBOL(audmgr_open); - -int audmgr_close(struct audmgr *am) -{ - return -EBUSY; -} -EXPORT_SYMBOL(audmgr_close); - -int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg) -{ - struct audmgr_enable_msg msg; - int rc; - - if (am->state == STATE_ENABLED) - return 0; - - if (am->state == STATE_DISABLING) - pr_err("audmgr: state is DISABLING in enable?\n"); - am->state = STATE_ENABLING; - - msg.args.set_to_one = cpu_to_be32(1); - msg.args.tx_sample_rate = cpu_to_be32(cfg->tx_rate); - msg.args.rx_sample_rate = cpu_to_be32(cfg->rx_rate); - msg.args.def_method = cpu_to_be32(cfg->def_method); - msg.args.codec_type = cpu_to_be32(cfg->codec); - msg.args.snd_method = cpu_to_be32(cfg->snd_method); - msg.args.cb_func = cpu_to_be32(0x11111111); - msg.args.client_data = cpu_to_be32(0x11223344); - - msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept), - AUDMGR_ENABLE_CLIENT); - - rc = msm_rpc_write(am->ept, &msg, sizeof(msg)); - if (rc < 0) - return rc; - - rc = wait_event_timeout(am->wait, am->state != STATE_ENABLING, 15 * HZ); - if (rc == 0) { - pr_err("audmgr_enable: ARM9 did not reply to RPC am->state = %d\n", am->state); - BUG(); - } - if (am->state == STATE_ENABLED) - return 0; - - pr_err("audmgr: unexpected state %d while enabling?!\n", am->state); - return -ENODEV; -} -EXPORT_SYMBOL(audmgr_enable); - -int audmgr_disable(struct audmgr *am) -{ - struct audmgr_disable_msg msg; - int rc; - - if (am->state == STATE_DISABLED) - return 0; - - msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept), - AUDMGR_DISABLE_CLIENT); - msg.handle = cpu_to_be32(am->handle); - - am->state = STATE_DISABLING; - - rc = msm_rpc_write(am->ept, &msg, sizeof(msg)); - if (rc < 0) - return rc; - - rc = wait_event_timeout(am->wait, am->state != STATE_DISABLING, 15 * HZ); - if (rc == 0) { - pr_err("audmgr_disable: ARM9 did not reply to RPC am->state = %d\n", am->state); - BUG(); - } - - if (am->state == STATE_DISABLED) - return 0; - - pr_err("audmgr: unexpected state %d while disabling?!\n", am->state); - return -ENODEV; -} -EXPORT_SYMBOL(audmgr_disable); diff --git a/drivers/staging/dream/qdsp5/audmgr.h b/drivers/staging/dream/qdsp5/audmgr.h deleted file mode 100644 index c07c36b3a0a3..000000000000 --- a/drivers/staging/dream/qdsp5/audmgr.h +++ /dev/null @@ -1,215 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audmgr.h - * - * Copyright 2008 (c) QUALCOMM Incorporated. - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ARCH_ARM_MACH_MSM_AUDMGR_H -#define _ARCH_ARM_MACH_MSM_AUDMGR_H - -#if CONFIG_MSM_AMSS_VERSION==6350 -#include "audmgr_new.h" -#else - -enum rpc_aud_def_sample_rate_type { - RPC_AUD_DEF_SAMPLE_RATE_NONE, - RPC_AUD_DEF_SAMPLE_RATE_8000, - RPC_AUD_DEF_SAMPLE_RATE_11025, - RPC_AUD_DEF_SAMPLE_RATE_12000, - RPC_AUD_DEF_SAMPLE_RATE_16000, - RPC_AUD_DEF_SAMPLE_RATE_22050, - RPC_AUD_DEF_SAMPLE_RATE_24000, - RPC_AUD_DEF_SAMPLE_RATE_32000, - RPC_AUD_DEF_SAMPLE_RATE_44100, - RPC_AUD_DEF_SAMPLE_RATE_48000, - RPC_AUD_DEF_SAMPLE_RATE_MAX, -}; - -enum rpc_aud_def_method_type { - RPC_AUD_DEF_METHOD_NONE, - RPC_AUD_DEF_METHOD_KEY_BEEP, - RPC_AUD_DEF_METHOD_PLAYBACK, - RPC_AUD_DEF_METHOD_VOICE, - RPC_AUD_DEF_METHOD_RECORD, - RPC_AUD_DEF_METHOD_HOST_PCM, - RPC_AUD_DEF_METHOD_MIDI_OUT, - RPC_AUD_DEF_METHOD_RECORD_SBC, - RPC_AUD_DEF_METHOD_DTMF_RINGER, - RPC_AUD_DEF_METHOD_MAX, -}; - -enum rpc_aud_def_codec_type { - RPC_AUD_DEF_CODEC_NONE, - RPC_AUD_DEF_CODEC_DTMF, - RPC_AUD_DEF_CODEC_MIDI, - RPC_AUD_DEF_CODEC_MP3, - RPC_AUD_DEF_CODEC_PCM, - RPC_AUD_DEF_CODEC_AAC, - RPC_AUD_DEF_CODEC_WMA, - RPC_AUD_DEF_CODEC_RA, - RPC_AUD_DEF_CODEC_ADPCM, - RPC_AUD_DEF_CODEC_GAUDIO, - RPC_AUD_DEF_CODEC_VOC_EVRC, - RPC_AUD_DEF_CODEC_VOC_13K, - RPC_AUD_DEF_CODEC_VOC_4GV_NB, - RPC_AUD_DEF_CODEC_VOC_AMR, - RPC_AUD_DEF_CODEC_VOC_EFR, - RPC_AUD_DEF_CODEC_VOC_FR, - RPC_AUD_DEF_CODEC_VOC_HR, - RPC_AUD_DEF_CODEC_VOC, - RPC_AUD_DEF_CODEC_SBC, - RPC_AUD_DEF_CODEC_VOC_PCM, - RPC_AUD_DEF_CODEC_AMR_WB, - RPC_AUD_DEF_CODEC_AMR_WB_PLUS, - RPC_AUD_DEF_CODEC_MAX, -}; - -enum rpc_snd_method_type { - RPC_SND_METHOD_VOICE = 0, - RPC_SND_METHOD_KEY_BEEP, - RPC_SND_METHOD_MESSAGE, - RPC_SND_METHOD_RING, - RPC_SND_METHOD_MIDI, - RPC_SND_METHOD_AUX, - RPC_SND_METHOD_MAX, -}; - -enum rpc_voc_codec_type { - RPC_VOC_CODEC_DEFAULT, - RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT, - RPC_VOC_CODEC_ON_CHIP_1, - RPC_VOC_CODEC_STEREO_HEADSET, - RPC_VOC_CODEC_ON_CHIP_AUX, - RPC_VOC_CODEC_BT_OFF_BOARD, - RPC_VOC_CODEC_BT_A2DP, - RPC_VOC_CODEC_OFF_BOARD, - RPC_VOC_CODEC_SDAC, - RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL, - RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET, - RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET, - RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM, - RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET, - RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET, - RPC_VOC_CODEC_TTY_ON_CHIP_1, - RPC_VOC_CODEC_TTY_OFF_BOARD, - RPC_VOC_CODEC_TTY_VCO, - RPC_VOC_CODEC_TTY_HCO, - RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC, - RPC_VOC_CODEC_MAX, - RPC_VOC_CODEC_NONE, -}; - -enum rpc_audmgr_status_type { - RPC_AUDMGR_STATUS_READY, - RPC_AUDMGR_STATUS_CODEC_CONFIG, - RPC_AUDMGR_STATUS_PENDING, - RPC_AUDMGR_STATUS_SUSPEND, - RPC_AUDMGR_STATUS_FAILURE, - RPC_AUDMGR_STATUS_VOLUME_CHANGE, - RPC_AUDMGR_STATUS_DISABLED, - RPC_AUDMGR_STATUS_ERROR, -}; - -struct rpc_audmgr_enable_client_args { - uint32_t set_to_one; - uint32_t tx_sample_rate; - uint32_t rx_sample_rate; - uint32_t def_method; - uint32_t codec_type; - uint32_t snd_method; - - uint32_t cb_func; - uint32_t client_data; -}; - -#define AUDMGR_ENABLE_CLIENT 2 -#define AUDMGR_DISABLE_CLIENT 3 -#define AUDMGR_SUSPEND_EVENT_RSP 4 -#define AUDMGR_REGISTER_OPERATION_LISTENER 5 -#define AUDMGR_UNREGISTER_OPERATION_LISTENER 6 -#define AUDMGR_REGISTER_CODEC_LISTENER 7 -#define AUDMGR_GET_RX_SAMPLE_RATE 8 -#define AUDMGR_GET_TX_SAMPLE_RATE 9 -#define AUDMGR_SET_DEVICE_MODE 10 - -#if CONFIG_MSM_AMSS_VERSION < 6220 -#define AUDMGR_PROG_VERS "rs30000013:46255756" -#define AUDMGR_PROG 0x30000013 -#define AUDMGR_VERS 0x46255756 -#else -#define AUDMGR_PROG_VERS "rs30000013:e94e8f0c" -#define AUDMGR_PROG 0x30000013 -#define AUDMGR_VERS 0xe94e8f0c -#endif - -struct rpc_audmgr_cb_func_ptr { - uint32_t cb_id; - uint32_t set_to_one; - uint32_t status; - union { - uint32_t handle; - uint32_t volume; - - } u; -}; - -#define AUDMGR_CB_FUNC_PTR 1 -#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR 2 -#define AUDMGR_CODEC_LSTR_FUNC_PTR 3 - -#if CONFIG_MSM_AMSS_VERSION < 6220 -#define AUDMGR_CB_PROG 0x31000013 -#define AUDMGR_CB_VERS 0x5fa922a9 -#else -#define AUDMGR_CB_PROG 0x31000013 -#define AUDMGR_CB_VERS 0x21570ba7 -#endif - -struct audmgr { - wait_queue_head_t wait; - uint32_t handle; - struct msm_rpc_endpoint *ept; - struct task_struct *task; - int state; -}; - -struct audmgr_config { - uint32_t tx_rate; - uint32_t rx_rate; - uint32_t def_method; - uint32_t codec; - uint32_t snd_method; -}; - -int audmgr_open(struct audmgr *am); -int audmgr_close(struct audmgr *am); -int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg); -int audmgr_disable(struct audmgr *am); - -typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg); - -int audpp_enable(int id, audpp_event_func func, void *private); -void audpp_disable(int id, void *private); - -int audpp_send_queue1(void *cmd, unsigned len); -int audpp_send_queue2(void *cmd, unsigned len); -int audpp_send_queue3(void *cmd, unsigned len); - -int audpp_pause(unsigned id, int pause); -int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan); -void audpp_avsync(int id, unsigned rate); -unsigned audpp_avsync_sample_count(int id); -unsigned audpp_avsync_byte_count(int id); - -#endif -#endif diff --git a/drivers/staging/dream/qdsp5/audmgr_new.h b/drivers/staging/dream/qdsp5/audmgr_new.h deleted file mode 100644 index 49670fe48b9e..000000000000 --- a/drivers/staging/dream/qdsp5/audmgr_new.h +++ /dev/null @@ -1,213 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/audmgr.h - * - * Copyright 2008 (c) QUALCOMM Incorporated. - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H -#define _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H - -enum rpc_aud_def_sample_rate_type { - RPC_AUD_DEF_SAMPLE_RATE_NONE, - RPC_AUD_DEF_SAMPLE_RATE_8000, - RPC_AUD_DEF_SAMPLE_RATE_11025, - RPC_AUD_DEF_SAMPLE_RATE_12000, - RPC_AUD_DEF_SAMPLE_RATE_16000, - RPC_AUD_DEF_SAMPLE_RATE_22050, - RPC_AUD_DEF_SAMPLE_RATE_24000, - RPC_AUD_DEF_SAMPLE_RATE_32000, - RPC_AUD_DEF_SAMPLE_RATE_44100, - RPC_AUD_DEF_SAMPLE_RATE_48000, - RPC_AUD_DEF_SAMPLE_RATE_MAX, -}; - -enum rpc_aud_def_method_type { - RPC_AUD_DEF_METHOD_NONE, - RPC_AUD_DEF_METHOD_KEY_BEEP, - RPC_AUD_DEF_METHOD_PLAYBACK, - RPC_AUD_DEF_METHOD_VOICE, - RPC_AUD_DEF_METHOD_RECORD, - RPC_AUD_DEF_METHOD_HOST_PCM, - RPC_AUD_DEF_METHOD_MIDI_OUT, - RPC_AUD_DEF_METHOD_RECORD_SBC, - RPC_AUD_DEF_METHOD_DTMF_RINGER, - RPC_AUD_DEF_METHOD_MAX, -}; - -enum rpc_aud_def_codec_type { - RPC_AUD_DEF_CODEC_NONE, - RPC_AUD_DEF_CODEC_DTMF, - RPC_AUD_DEF_CODEC_MIDI, - RPC_AUD_DEF_CODEC_MP3, - RPC_AUD_DEF_CODEC_PCM, - RPC_AUD_DEF_CODEC_AAC, - RPC_AUD_DEF_CODEC_WMA, - RPC_AUD_DEF_CODEC_RA, - RPC_AUD_DEF_CODEC_ADPCM, - RPC_AUD_DEF_CODEC_GAUDIO, - RPC_AUD_DEF_CODEC_VOC_EVRC, - RPC_AUD_DEF_CODEC_VOC_13K, - RPC_AUD_DEF_CODEC_VOC_4GV_NB, - RPC_AUD_DEF_CODEC_VOC_AMR, - RPC_AUD_DEF_CODEC_VOC_EFR, - RPC_AUD_DEF_CODEC_VOC_FR, - RPC_AUD_DEF_CODEC_VOC_HR, - RPC_AUD_DEF_CODEC_VOC_CDMA, - RPC_AUD_DEF_CODEC_VOC_CDMA_WB, - RPC_AUD_DEF_CODEC_VOC_UMTS, - RPC_AUD_DEF_CODEC_VOC_UMTS_WB, - RPC_AUD_DEF_CODEC_SBC, - RPC_AUD_DEF_CODEC_VOC_PCM, - RPC_AUD_DEF_CODEC_AMR_WB, - RPC_AUD_DEF_CODEC_AMR_WB_PLUS, - RPC_AUD_DEF_CODEC_AAC_BSAC, - RPC_AUD_DEF_CODEC_MAX, - RPC_AUD_DEF_CODEC_AMR_NB, - RPC_AUD_DEF_CODEC_13K, - RPC_AUD_DEF_CODEC_EVRC, - RPC_AUD_DEF_CODEC_MAX_002, -}; - -enum rpc_snd_method_type { - RPC_SND_METHOD_VOICE = 0, - RPC_SND_METHOD_KEY_BEEP, - RPC_SND_METHOD_MESSAGE, - RPC_SND_METHOD_RING, - RPC_SND_METHOD_MIDI, - RPC_SND_METHOD_AUX, - RPC_SND_METHOD_MAX, -}; - -enum rpc_voc_codec_type { - RPC_VOC_CODEC_DEFAULT, - RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT, - RPC_VOC_CODEC_ON_CHIP_1, - RPC_VOC_CODEC_STEREO_HEADSET, - RPC_VOC_CODEC_ON_CHIP_AUX, - RPC_VOC_CODEC_BT_OFF_BOARD, - RPC_VOC_CODEC_BT_A2DP, - RPC_VOC_CODEC_OFF_BOARD, - RPC_VOC_CODEC_SDAC, - RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL, - RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET, - RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET, - RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM, - RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET, - RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET, - RPC_VOC_CODEC_TTY_ON_CHIP_1, - RPC_VOC_CODEC_TTY_OFF_BOARD, - RPC_VOC_CODEC_TTY_VCO, - RPC_VOC_CODEC_TTY_HCO, - RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC, - RPC_VOC_CODEC_MAX, - RPC_VOC_CODEC_NONE, -}; - -enum rpc_audmgr_status_type { - RPC_AUDMGR_STATUS_READY, - RPC_AUDMGR_STATUS_CODEC_CONFIG, - RPC_AUDMGR_STATUS_PENDING, - RPC_AUDMGR_STATUS_SUSPEND, - RPC_AUDMGR_STATUS_FAILURE, - RPC_AUDMGR_STATUS_VOLUME_CHANGE, - RPC_AUDMGR_STATUS_DISABLED, - RPC_AUDMGR_STATUS_ERROR, -}; - -struct rpc_audmgr_enable_client_args { - uint32_t set_to_one; - uint32_t tx_sample_rate; - uint32_t rx_sample_rate; - uint32_t def_method; - uint32_t codec_type; - uint32_t snd_method; - - uint32_t cb_func; - uint32_t client_data; -}; - -#define AUDMGR_ENABLE_CLIENT 2 -#define AUDMGR_DISABLE_CLIENT 3 -#define AUDMGR_SUSPEND_EVENT_RSP 4 -#define AUDMGR_REGISTER_OPERATION_LISTENER 5 -#define AUDMGR_UNREGISTER_OPERATION_LISTENER 6 -#define AUDMGR_REGISTER_CODEC_LISTENER 7 -#define AUDMGR_GET_RX_SAMPLE_RATE 8 -#define AUDMGR_GET_TX_SAMPLE_RATE 9 -#define AUDMGR_SET_DEVICE_MODE 10 - -#define AUDMGR_PROG 0x30000013 -#define AUDMGR_VERS MSM_RPC_VERS(1,0) - -struct rpc_audmgr_cb_func_ptr { - uint32_t cb_id; - uint32_t status; /* Audmgr status */ - uint32_t set_to_one; /* Pointer status (1 = valid, 0 = invalid) */ - uint32_t disc; - /* disc = AUDMGR_STATUS_READY => data=handle - disc = AUDMGR_STATUS_CODEC_CONFIG => data = handle - disc = AUDMGR_STATUS_DISABLED => data =status_disabled - disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume-change */ - union { - uint32_t handle; - uint32_t volume; - uint32_t status_disabled; - uint32_t volume_change; - } u; -}; - -#define AUDMGR_CB_FUNC_PTR 1 -#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR 2 -#define AUDMGR_CODEC_LSTR_FUNC_PTR 3 - -#define AUDMGR_CB_PROG 0x31000013 -#define AUDMGR_CB_VERS 0xf8e3e2d9 - -struct audmgr { - wait_queue_head_t wait; - uint32_t handle; - struct msm_rpc_endpoint *ept; - struct task_struct *task; - int state; -}; - -struct audmgr_config { - uint32_t tx_rate; - uint32_t rx_rate; - uint32_t def_method; - uint32_t codec; - uint32_t snd_method; -}; - -int audmgr_open(struct audmgr *am); -int audmgr_close(struct audmgr *am); -int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg); -int audmgr_disable(struct audmgr *am); - -typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg); - -int audpp_enable(int id, audpp_event_func func, void *private); -void audpp_disable(int id, void *private); - -int audpp_send_queue1(void *cmd, unsigned len); -int audpp_send_queue2(void *cmd, unsigned len); -int audpp_send_queue3(void *cmd, unsigned len); - -int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan); -int audpp_pause(unsigned id, int pause); -int audpp_flush(unsigned id); -void audpp_avsync(int id, unsigned rate); -unsigned audpp_avsync_sample_count(int id); -unsigned audpp_avsync_byte_count(int id); - -#endif diff --git a/drivers/staging/dream/qdsp5/audpp.c b/drivers/staging/dream/qdsp5/audpp.c deleted file mode 100644 index d06556eda316..000000000000 --- a/drivers/staging/dream/qdsp5/audpp.c +++ /dev/null @@ -1,429 +0,0 @@ - -/* arch/arm/mach-msm/qdsp5/audpp.c - * - * common code to deal with the AUDPP dsp task (audio postproc) - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/wait.h> -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/msm_adsp.h> - -#include "audmgr.h" - -#include <mach/qdsp5/qdsp5audppcmdi.h> -#include <mach/qdsp5/qdsp5audppmsg.h> - -/* for queue ids - should be relative to module number*/ -#include "adsp.h" - -#include "evlog.h" - - -enum { - EV_NULL, - EV_ENABLE, - EV_DISABLE, - EV_EVENT, - EV_DATA, -}; - -static const char *dsp_log_strings[] = { - "NULL", - "ENABLE", - "DISABLE", - "EVENT", - "DATA", -}; - -DECLARE_LOG(dsp_log, 64, dsp_log_strings); - -static int __init _dsp_log_init(void) -{ - return ev_log_init(&dsp_log); -} -module_init(_dsp_log_init); -#define LOG(id,arg) ev_log_write(&dsp_log, id, arg) - -static DEFINE_MUTEX(audpp_lock); - -#define CH_COUNT 5 -#define AUDPP_CLNT_MAX_COUNT 6 -#define AUDPP_AVSYNC_INFO_SIZE 7 - -struct audpp_state { - struct msm_adsp_module *mod; - audpp_event_func func[AUDPP_CLNT_MAX_COUNT]; - void *private[AUDPP_CLNT_MAX_COUNT]; - struct mutex *lock; - unsigned open_count; - unsigned enabled; - - /* which channels are actually enabled */ - unsigned avsync_mask; - - /* flags, 48 bits sample/bytes counter per channel */ - uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1]; -}; - -struct audpp_state the_audpp_state = { - .lock = &audpp_lock, -}; - -int audpp_send_queue1(void *cmd, unsigned len) -{ - return msm_adsp_write(the_audpp_state.mod, - QDSP_uPAudPPCmd1Queue, cmd, len); -} -EXPORT_SYMBOL(audpp_send_queue1); - -int audpp_send_queue2(void *cmd, unsigned len) -{ - return msm_adsp_write(the_audpp_state.mod, - QDSP_uPAudPPCmd2Queue, cmd, len); -} -EXPORT_SYMBOL(audpp_send_queue2); - -int audpp_send_queue3(void *cmd, unsigned len) -{ - return msm_adsp_write(the_audpp_state.mod, - QDSP_uPAudPPCmd3Queue, cmd, len); -} -EXPORT_SYMBOL(audpp_send_queue3); - -static int audpp_dsp_config(int enable) -{ - audpp_cmd_cfg cmd; - - cmd.cmd_id = AUDPP_CMD_CFG; - cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP; - - return audpp_send_queue1(&cmd, sizeof(cmd)); -} - -static void audpp_broadcast(struct audpp_state *audpp, unsigned id, - uint16_t *msg) -{ - unsigned n; - for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) { - if (audpp->func[n]) - audpp->func[n] (audpp->private[n], id, msg); - } -} - -static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id, - unsigned id, uint16_t *msg) -{ - if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id]) - audpp->func[clnt_id] (audpp->private[clnt_id], id, msg); -} - -static void audpp_dsp_event(void *data, unsigned id, size_t len, - void (*getevent)(void *ptr, size_t len)) -{ - struct audpp_state *audpp = data; - uint16_t msg[8]; - - if (id == AUDPP_MSG_AVSYNC_MSG) { - getevent(audpp->avsync, sizeof(audpp->avsync)); - - /* mask off any channels we're not watching to avoid - * cases where we might get one last update after - * disabling avsync and end up in an odd state when - * we next read... - */ - audpp->avsync[0] &= audpp->avsync_mask; - return; - } - - getevent(msg, sizeof(msg)); - - LOG(EV_EVENT, (id << 16) | msg[0]); - LOG(EV_DATA, (msg[1] << 16) | msg[2]); - - switch (id) { - case AUDPP_MSG_STATUS_MSG:{ - unsigned cid = msg[0]; - pr_info("audpp: status %d %d %d\n", cid, msg[1], - msg[2]); - if ((cid < 5) && audpp->func[cid]) - audpp->func[cid] (audpp->private[cid], id, msg); - break; - } - case AUDPP_MSG_HOST_PCM_INTF_MSG: - if (audpp->func[5]) - audpp->func[5] (audpp->private[5], id, msg); - break; - case AUDPP_MSG_PCMDMAMISSED: - pr_err("audpp: DMA missed obj=%x\n", msg[0]); - break; - case AUDPP_MSG_CFG_MSG: - if (msg[0] == AUDPP_MSG_ENA_ENA) { - pr_info("audpp: ENABLE\n"); - audpp->enabled = 1; - audpp_broadcast(audpp, id, msg); - } else if (msg[0] == AUDPP_MSG_ENA_DIS) { - pr_info("audpp: DISABLE\n"); - audpp->enabled = 0; - audpp_broadcast(audpp, id, msg); - } else { - pr_err("audpp: invalid config msg %d\n", msg[0]); - } - break; - case AUDPP_MSG_ROUTING_ACK: - audpp_broadcast(audpp, id, msg); - break; - case AUDPP_MSG_FLUSH_ACK: - audpp_notify_clnt(audpp, msg[0], id, msg); - break; - default: - pr_info("audpp: unhandled msg id %x\n", id); - } -} - -static struct msm_adsp_ops adsp_ops = { - .event = audpp_dsp_event, -}; - -static void audpp_fake_event(struct audpp_state *audpp, int id, - unsigned event, unsigned arg) -{ - uint16_t msg[1]; - msg[0] = arg; - audpp->func[id] (audpp->private[id], event, msg); -} - -int audpp_enable(int id, audpp_event_func func, void *private) -{ - struct audpp_state *audpp = &the_audpp_state; - int res = 0; - - if (id < -1 || id > 4) - return -EINVAL; - - if (id == -1) - id = 5; - - mutex_lock(audpp->lock); - if (audpp->func[id]) { - res = -EBUSY; - goto out; - } - - audpp->func[id] = func; - audpp->private[id] = private; - - LOG(EV_ENABLE, 1); - if (audpp->open_count++ == 0) { - pr_info("audpp: enable\n"); - res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp); - if (res < 0) { - pr_err("audpp: cannot open AUDPPTASK\n"); - audpp->open_count = 0; - audpp->func[id] = NULL; - audpp->private[id] = NULL; - goto out; - } - LOG(EV_ENABLE, 2); - msm_adsp_enable(audpp->mod); - audpp_dsp_config(1); - } else { - unsigned long flags; - local_irq_save(flags); - if (audpp->enabled) - audpp_fake_event(audpp, id, - AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA); - local_irq_restore(flags); - } - - res = 0; -out: - mutex_unlock(audpp->lock); - return res; -} -EXPORT_SYMBOL(audpp_enable); - -void audpp_disable(int id, void *private) -{ - struct audpp_state *audpp = &the_audpp_state; - unsigned long flags; - - if (id < -1 || id > 4) - return; - - if (id == -1) - id = 5; - - mutex_lock(audpp->lock); - LOG(EV_DISABLE, 1); - if (!audpp->func[id]) - goto out; - if (audpp->private[id] != private) - goto out; - - local_irq_save(flags); - audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS); - audpp->func[id] = NULL; - audpp->private[id] = NULL; - local_irq_restore(flags); - - if (--audpp->open_count == 0) { - pr_info("audpp: disable\n"); - LOG(EV_DISABLE, 2); - audpp_dsp_config(0); - msm_adsp_disable(audpp->mod); - msm_adsp_put(audpp->mod); - audpp->mod = NULL; - } -out: - mutex_unlock(audpp->lock); -} -EXPORT_SYMBOL(audpp_disable); - -#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT)) - -void audpp_avsync(int id, unsigned rate) -{ - unsigned long flags; - audpp_cmd_avsync cmd; - - if (BAD_ID(id)) - return; - - local_irq_save(flags); - if (rate) - the_audpp_state.avsync_mask |= (1 << id); - else - the_audpp_state.avsync_mask &= (~(1 << id)); - the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask; - local_irq_restore(flags); - - cmd.cmd_id = AUDPP_CMD_AVSYNC; - cmd.object_number = id; - cmd.interrupt_interval_lsw = rate; - cmd.interrupt_interval_msw = rate >> 16; - audpp_send_queue1(&cmd, sizeof(cmd)); -} -EXPORT_SYMBOL(audpp_avsync); - -unsigned audpp_avsync_sample_count(int id) -{ - uint16_t *avsync = the_audpp_state.avsync; - unsigned val; - unsigned long flags; - unsigned mask; - - if (BAD_ID(id)) - return 0; - - mask = 1 << id; - id = id * AUDPP_AVSYNC_INFO_SIZE + 2; - local_irq_save(flags); - if (avsync[0] & mask) - val = (avsync[id] << 16) | avsync[id + 1]; - else - val = 0; - local_irq_restore(flags); - - return val; -} -EXPORT_SYMBOL(audpp_avsync_sample_count); - -unsigned audpp_avsync_byte_count(int id) -{ - uint16_t *avsync = the_audpp_state.avsync; - unsigned val; - unsigned long flags; - unsigned mask; - - if (BAD_ID(id)) - return 0; - - mask = 1 << id; - id = id * AUDPP_AVSYNC_INFO_SIZE + 5; - local_irq_save(flags); - if (avsync[0] & mask) - val = (avsync[id] << 16) | avsync[id + 1]; - else - val = 0; - local_irq_restore(flags); - - return val; -} -EXPORT_SYMBOL(audpp_avsync_byte_count); - -#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000 -#define AUDPP_CMD_VOLUME_PAN 0 - -int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan) -{ - /* cmd, obj_cfg[7], cmd_type, volume, pan */ - uint16_t cmd[11]; - - if (id > 6) - return -EINVAL; - - memset(cmd, 0, sizeof(cmd)); - cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS; - cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE; - cmd[8] = AUDPP_CMD_VOLUME_PAN; - cmd[9] = volume; - cmd[10] = pan; - - return audpp_send_queue3(cmd, sizeof(cmd)); -} -EXPORT_SYMBOL(audpp_set_volume_and_pan); - -int audpp_pause(unsigned id, int pause) -{ - /* pause 1 = pause 0 = resume */ - u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)]; - - if (id >= CH_COUNT) - return -EINVAL; - - memset(pause_cmd, 0, sizeof(pause_cmd)); - - pause_cmd[0] = AUDPP_CMD_DEC_CTRL; - if (pause == 1) - pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V; - else if (pause == 0) - pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V; - else - return -EINVAL; - - return audpp_send_queue1(pause_cmd, sizeof(pause_cmd)); -} -EXPORT_SYMBOL(audpp_pause); - -int audpp_flush(unsigned id) -{ - u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)]; - - if (id >= CH_COUNT) - return -EINVAL; - - memset(flush_cmd, 0, sizeof(flush_cmd)); - - flush_cmd[0] = AUDPP_CMD_DEC_CTRL; - flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V; - - return audpp_send_queue1(flush_cmd, sizeof(flush_cmd)); -} -EXPORT_SYMBOL(audpp_flush); diff --git a/drivers/staging/dream/qdsp5/evlog.h b/drivers/staging/dream/qdsp5/evlog.h deleted file mode 100644 index e5ab86b9dd7c..000000000000 --- a/drivers/staging/dream/qdsp5/evlog.h +++ /dev/null @@ -1,134 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/evlog.h - * - * simple event log debugging facility - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/fs.h> -#include <linux/hrtimer.h> -#include <linux/debugfs.h> - -#define EV_LOG_ENTRY_NAME(n) n##_entry - -#define DECLARE_LOG(_name, _size, _str) \ -static struct ev_entry EV_LOG_ENTRY_NAME(_name)[_size]; \ -static struct ev_log _name = { \ - .name = #_name, \ - .strings = _str, \ - .num_strings = ARRAY_SIZE(_str), \ - .entry = EV_LOG_ENTRY_NAME(_name), \ - .max = ARRAY_SIZE(EV_LOG_ENTRY_NAME(_name)), \ -} - -struct ev_entry { - ktime_t when; - uint32_t id; - uint32_t arg; -}; - -struct ev_log { - struct ev_entry *entry; - unsigned max; - unsigned next; - unsigned fault; - const char **strings; - unsigned num_strings; - const char *name; -}; - -static char ev_buf[4096]; - -static ssize_t ev_log_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct ev_log *log = file->private_data; - struct ev_entry *entry; - unsigned long flags; - int size = 0; - unsigned n, id, max; - ktime_t now, t; - - max = log->max; - now = ktime_get(); - local_irq_save(flags); - n = (log->next - 1) & (max - 1); - entry = log->entry; - while (n != log->next) { - t = ktime_sub(now, entry[n].when); - id = entry[n].id; - if (id) { - const char *str; - if (id < log->num_strings) - str = log->strings[id]; - else - str = "UNKNOWN"; - size += scnprintf(ev_buf + size, 4096 - size, - "%8d.%03d %08x %s\n", - t.tv.sec, t.tv.nsec / 1000000, - entry[n].arg, str); - } - n = (n - 1) & (max - 1); - } - log->fault = 0; - local_irq_restore(flags); - return simple_read_from_buffer(buf, count, ppos, ev_buf, size); -} - -static void ev_log_write(struct ev_log *log, unsigned id, unsigned arg) -{ - struct ev_entry *entry; - unsigned long flags; - local_irq_save(flags); - - if (log->fault) { - if (log->fault == 1) - goto done; - log->fault--; - } - - entry = log->entry + log->next; - entry->when = ktime_get(); - entry->id = id; - entry->arg = arg; - log->next = (log->next + 1) & (log->max - 1); -done: - local_irq_restore(flags); -} - -static void ev_log_freeze(struct ev_log *log, unsigned count) -{ - unsigned long flags; - local_irq_save(flags); - log->fault = count; - local_irq_restore(flags); -} - -static int ev_log_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static const struct file_operations ev_log_ops = { - .read = ev_log_read, - .open = ev_log_open, - .llseek = default_llseek, -}; - -static int ev_log_init(struct ev_log *log) -{ - debugfs_create_file(log->name, 0444, 0, log, &ev_log_ops); - return 0; -} - diff --git a/drivers/staging/dream/qdsp5/snd.c b/drivers/staging/dream/qdsp5/snd.c deleted file mode 100644 index e0f2f7bca29e..000000000000 --- a/drivers/staging/dream/qdsp5/snd.c +++ /dev/null @@ -1,280 +0,0 @@ -/* arch/arm/mach-msm/qdsp5/snd.c - * - * interface to "snd" service on the baseband cpu - * - * Copyright (C) 2008 HTC Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/delay.h> -#include <linux/msm_audio.h> - -#include <asm/atomic.h> -#include <asm/ioctls.h> -#include <mach/board.h> -#include <mach/msm_rpcrouter.h> - -struct snd_ctxt { - struct mutex lock; - int opened; - struct msm_rpc_endpoint *ept; - struct msm_snd_endpoints *snd_epts; -}; - -static struct snd_ctxt the_snd; - -#define RPC_SND_PROG 0x30000002 -#define RPC_SND_CB_PROG 0x31000002 -#if CONFIG_MSM_AMSS_VERSION == 6210 -#define RPC_SND_VERS 0x94756085 /* 2490720389 */ -#elif (CONFIG_MSM_AMSS_VERSION == 6220) || \ - (CONFIG_MSM_AMSS_VERSION == 6225) -#define RPC_SND_VERS 0xaa2b1a44 /* 2854951492 */ -#elif CONFIG_MSM_AMSS_VERSION == 6350 -#define RPC_SND_VERS MSM_RPC_VERS(1,0) -#endif - -#define SND_SET_DEVICE_PROC 2 -#define SND_SET_VOLUME_PROC 3 - -struct rpc_snd_set_device_args { - uint32_t device; - uint32_t ear_mute; - uint32_t mic_mute; - - uint32_t cb_func; - uint32_t client_data; -}; - -struct rpc_snd_set_volume_args { - uint32_t device; - uint32_t method; - uint32_t volume; - - uint32_t cb_func; - uint32_t client_data; -}; - -struct snd_set_device_msg { - struct rpc_request_hdr hdr; - struct rpc_snd_set_device_args args; -}; - -struct snd_set_volume_msg { - struct rpc_request_hdr hdr; - struct rpc_snd_set_volume_args args; -}; - -struct snd_endpoint *get_snd_endpoints(int *size); - -static inline int check_mute(int mute) -{ - return (mute == SND_MUTE_MUTED || - mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL; -} - -static int get_endpoint(struct snd_ctxt *snd, unsigned long arg) -{ - int rc = 0, index; - struct msm_snd_endpoint ept; - - if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) { - pr_err("snd_ioctl get endpoint: invalid read pointer.\n"); - return -EFAULT; - } - - index = ept.id; - if (index < 0 || index >= snd->snd_epts->num) { - pr_err("snd_ioctl get endpoint: invalid index!\n"); - return -EINVAL; - } - - ept.id = snd->snd_epts->endpoints[index].id; - strncpy(ept.name, - snd->snd_epts->endpoints[index].name, - sizeof(ept.name)); - - if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) { - pr_err("snd_ioctl get endpoint: invalid write pointer.\n"); - rc = -EFAULT; - } - - return rc; -} - -static long snd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct snd_set_device_msg dmsg; - struct snd_set_volume_msg vmsg; - struct msm_snd_device_config dev; - struct msm_snd_volume_config vol; - struct snd_ctxt *snd = file->private_data; - int rc = 0; - - mutex_lock(&snd->lock); - switch (cmd) { - case SND_SET_DEVICE: - if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) { - pr_err("snd_ioctl set device: invalid pointer.\n"); - rc = -EFAULT; - break; - } - - dmsg.args.device = cpu_to_be32(dev.device); - dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute); - dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute); - if (check_mute(dev.ear_mute) < 0 || - check_mute(dev.mic_mute) < 0) { - pr_err("snd_ioctl set device: invalid mute status.\n"); - rc = -EINVAL; - break; - } - dmsg.args.cb_func = -1; - dmsg.args.client_data = 0; - - pr_info("snd_set_device %d %d %d\n", dev.device, - dev.ear_mute, dev.mic_mute); - - rc = msm_rpc_call(snd->ept, - SND_SET_DEVICE_PROC, - &dmsg, sizeof(dmsg), 5 * HZ); - break; - - case SND_SET_VOLUME: - if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) { - pr_err("snd_ioctl set volume: invalid pointer.\n"); - rc = -EFAULT; - break; - } - - vmsg.args.device = cpu_to_be32(vol.device); - vmsg.args.method = cpu_to_be32(vol.method); - if (vol.method != SND_METHOD_VOICE) { - pr_err("snd_ioctl set volume: invalid method.\n"); - rc = -EINVAL; - break; - } - - vmsg.args.volume = cpu_to_be32(vol.volume); - vmsg.args.cb_func = -1; - vmsg.args.client_data = 0; - - pr_info("snd_set_volume %d %d %d\n", vol.device, - vol.method, vol.volume); - - rc = msm_rpc_call(snd->ept, - SND_SET_VOLUME_PROC, - &vmsg, sizeof(vmsg), 5 * HZ); - break; - - case SND_GET_NUM_ENDPOINTS: - if (copy_to_user((void __user *)arg, - &snd->snd_epts->num, sizeof(unsigned))) { - pr_err("snd_ioctl get endpoint: invalid pointer.\n"); - rc = -EFAULT; - } - break; - - case SND_GET_ENDPOINT: - rc = get_endpoint(snd, arg); - break; - - default: - pr_err("snd_ioctl unknown command.\n"); - rc = -EINVAL; - break; - } - mutex_unlock(&snd->lock); - - return rc; -} - -static int snd_release(struct inode *inode, struct file *file) -{ - struct snd_ctxt *snd = file->private_data; - - mutex_lock(&snd->lock); - snd->opened = 0; - mutex_unlock(&snd->lock); - return 0; -} - -static int snd_open(struct inode *inode, struct file *file) -{ - struct snd_ctxt *snd = &the_snd; - int rc = 0; - - mutex_lock(&snd->lock); - if (snd->opened == 0) { - if (snd->ept == NULL) { - snd->ept = msm_rpc_connect(RPC_SND_PROG, RPC_SND_VERS, - MSM_RPC_UNINTERRUPTIBLE); - if (IS_ERR(snd->ept)) { - rc = PTR_ERR(snd->ept); - snd->ept = NULL; - pr_err("snd: failed to connect snd svc\n"); - goto err; - } - } - file->private_data = snd; - snd->opened = 1; - } else { - pr_err("snd already opened.\n"); - rc = -EBUSY; - } - -err: - mutex_unlock(&snd->lock); - return rc; -} - -static struct file_operations snd_fops = { - .owner = THIS_MODULE, - .open = snd_open, - .release = snd_release, - .unlocked_ioctl = snd_ioctl, - .llseek = noop_llseek, -}; - -struct miscdevice snd_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "msm_snd", - .fops = &snd_fops, -}; - -static int snd_probe(struct platform_device *pdev) -{ - struct snd_ctxt *snd = &the_snd; - mutex_init(&snd->lock); - snd->snd_epts = (struct msm_snd_endpoints *)pdev->dev.platform_data; - return misc_register(&snd_misc); -} - -static struct platform_driver snd_plat_driver = { - .probe = snd_probe, - .driver = { - .name = "msm_snd", - .owner = THIS_MODULE, - }, -}; - -static int __init snd_init(void) -{ - return platform_driver_register(&snd_plat_driver); -} - -module_init(snd_init); diff --git a/drivers/staging/dream/synaptics_i2c_rmi.c b/drivers/staging/dream/synaptics_i2c_rmi.c deleted file mode 100644 index 3320359408a9..000000000000 --- a/drivers/staging/dream/synaptics_i2c_rmi.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Support for synaptics touchscreen. - * - * Copyright (C) 2007 Google, Inc. - * Author: Arve Hjønnevåg <arve@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * http://www.synaptics.com/sites/default/files/511_000099_01F.pdf - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/slab.h> -#ifdef CONFIG_HAS_EARLYSUSPEND -#include <linux/earlysuspend.h> -#endif -#include <linux/hrtimer.h> -#include <linux/i2c.h> -#include <linux/input.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include "synaptics_i2c_rmi.h" - -static struct workqueue_struct *synaptics_wq; - -struct synaptics_ts_data { - u16 addr; - struct i2c_client *client; - struct input_dev *input_dev; - int use_irq; - struct hrtimer timer; - struct work_struct work; - u16 max[2]; - int snap_state[2][2]; - int snap_down_on[2]; - int snap_down_off[2]; - int snap_up_on[2]; - int snap_up_off[2]; - int snap_down[2]; - int snap_up[2]; - u32 flags; - int (*power)(int on); -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif -}; - -static int i2c_set(struct synaptics_ts_data *ts, u8 reg, u8 val, char *msg) -{ - int ret = i2c_smbus_write_byte_data(ts->client, reg, val); - if (ret < 0) - pr_err("i2c_smbus_write_byte_data failed (%s)\n", msg); - return ret; -} - -static int i2c_read(struct synaptics_ts_data *ts, u8 reg, char *msg) -{ - int ret = i2c_smbus_read_byte_data(ts->client, reg); - if (ret < 0) - pr_err("i2c_smbus_read_byte_data failed (%s)\n", msg); - return ret; -} -#ifdef CONFIG_HAS_EARLYSUSPEND -static void synaptics_ts_early_suspend(struct early_suspend *h); -static void synaptics_ts_late_resume(struct early_suspend *h); -#endif - -static int synaptics_init_panel(struct synaptics_ts_data *ts) -{ - int ret; - - ret = i2c_set(ts, 0xff, 0x10, "set page select"); - if (ret == 0) - ret = i2c_set(ts, 0x41, 0x04, "set No Clip Z"); - - ret = i2c_set(ts, 0xff, 0x04, "fallback page select"); - ret = i2c_set(ts, 0xf0, 0x81, "select 80 reports per second"); - return ret; -} - -static void decode_report(struct synaptics_ts_data *ts, u8 *buf) -{ -/* - * This sensor sends two 6-byte absolute finger reports, an optional - * 2-byte relative report followed by a status byte. This function - * reads the two finger reports and transforms the coordinates - * according the platform data so they can be aligned with the lcd - * behind the touchscreen. Typically we flip the y-axis since the - * sensor uses the bottom left corner as the origin, but if the sensor - * is mounted upside down the platform data will request that the - * x-axis should be flipped instead. The snap to inactive edge border - * are used to allow tapping the edges of the screen on the G1. The - * active area of the touchscreen is smaller than the lcd. When the - * finger gets close the edge of the screen we snap it to the - * edge. This allows ui elements at the edge of the screen to be hit, - * and it prevents hitting ui elements that are not at the edge of the - * screen when the finger is touching the edge. - */ - int pos[2][2]; - int f, a; - int base = 2; - int z = buf[1]; - int finger = buf[0] & 7; - - for (f = 0; f < 2; f++) { - u32 flip_flag = SYNAPTICS_FLIP_X; - for (a = 0; a < 2; a++) { - int p = buf[base + 1]; - p |= (u16)(buf[base] & 0x1f) << 8; - if (ts->flags & flip_flag) - p = ts->max[a] - p; - if (ts->flags & SYNAPTICS_SNAP_TO_INACTIVE_EDGE) { - if (ts->snap_state[f][a]) { - if (p <= ts->snap_down_off[a]) - p = ts->snap_down[a]; - else if (p >= ts->snap_up_off[a]) - p = ts->snap_up[a]; - else - ts->snap_state[f][a] = 0; - } else { - if (p <= ts->snap_down_on[a]) { - p = ts->snap_down[a]; - ts->snap_state[f][a] = 1; - } else if (p >= ts->snap_up_on[a]) { - p = ts->snap_up[a]; - ts->snap_state[f][a] = 1; - } - } - } - pos[f][a] = p; - base += 2; - flip_flag <<= 1; - } - base += 2; - if (ts->flags & SYNAPTICS_SWAP_XY) - swap(pos[f][0], pos[f][1]); - } - if (z) { - input_report_abs(ts->input_dev, ABS_X, pos[0][0]); - input_report_abs(ts->input_dev, ABS_Y, pos[0][1]); - } - input_report_abs(ts->input_dev, ABS_PRESSURE, z); - input_report_key(ts->input_dev, BTN_TOUCH, finger); - input_sync(ts->input_dev); -} - -static void synaptics_ts_work_func(struct work_struct *work) -{ - int i; - int ret; - int bad_data = 0; - struct i2c_msg msg[2]; - u8 start_reg = 0; - u8 buf[15]; - struct synaptics_ts_data *ts = - container_of(work, struct synaptics_ts_data, work); - - msg[0].addr = ts->client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &start_reg; - msg[1].addr = ts->client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(buf); - msg[1].buf = buf; - - for (i = 0; i < ((ts->use_irq && !bad_data) ? 1 : 10); i++) { - ret = i2c_transfer(ts->client->adapter, msg, 2); - if (ret < 0) { - pr_err("ts_work: i2c_transfer failed\n"); - bad_data = 1; - continue; - } - if ((buf[14] & 0xc0) != 0x40) { - pr_warning("synaptics_ts_work_func:" - " bad read %x %x %x %x %x %x %x %x %x" - " %x %x %x %x %x %x, ret %d\n", - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], - buf[12], buf[13], buf[14], ret); - if (bad_data) - synaptics_init_panel(ts); - bad_data = 1; - continue; - } - bad_data = 0; - if ((buf[14] & 1) == 0) - break; - - decode_report(ts, buf); - } -} - -static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer) -{ - struct synaptics_ts_data *ts = - container_of(timer, struct synaptics_ts_data, timer); - - queue_work(synaptics_wq, &ts->work); - - hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); - return HRTIMER_NORESTART; -} - -static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id) -{ - struct synaptics_ts_data *ts = dev_id; - - synaptics_ts_work_func(&ts->work); - return IRQ_HANDLED; -} - -static int detect(struct synaptics_ts_data *ts, u32 *panel_version) -{ - int ret; - int retry = 10; - - ret = i2c_set(ts, 0xf4, 0x01, "reset device"); - - while (retry-- > 0) { - ret = i2c_smbus_read_byte_data(ts->client, 0xe4); - if (ret >= 0) - break; - msleep(100); - } - if (ret < 0) { - pr_err("i2c_smbus_read_byte_data failed\n"); - return ret; - } - - *panel_version = ret << 8; - ret = i2c_read(ts, 0xe5, "product minor"); - if (ret < 0) - return ret; - *panel_version |= ret; - - ret = i2c_read(ts, 0xe3, "property"); - if (ret < 0) - return ret; - - pr_info("synaptics: version %x, product property %x\n", - *panel_version, ret); - return 0; -} - -static void compute_areas(struct synaptics_ts_data *ts, - struct synaptics_i2c_rmi_platform_data *pdata, - u16 max_x, u16 max_y) -{ - int inactive_area_left; - int inactive_area_right; - int inactive_area_top; - int inactive_area_bottom; - int snap_left_on; - int snap_left_off; - int snap_right_on; - int snap_right_off; - int snap_top_on; - int snap_top_off; - int snap_bottom_on; - int snap_bottom_off; - int fuzz_x; - int fuzz_y; - int fuzz_p; - int fuzz_w; - int swapped = !!(ts->flags & SYNAPTICS_SWAP_XY); - - inactive_area_left = pdata->inactive_left; - inactive_area_right = pdata->inactive_right; - inactive_area_top = pdata->inactive_top; - inactive_area_bottom = pdata->inactive_bottom; - snap_left_on = pdata->snap_left_on; - snap_left_off = pdata->snap_left_off; - snap_right_on = pdata->snap_right_on; - snap_right_off = pdata->snap_right_off; - snap_top_on = pdata->snap_top_on; - snap_top_off = pdata->snap_top_off; - snap_bottom_on = pdata->snap_bottom_on; - snap_bottom_off = pdata->snap_bottom_off; - fuzz_x = pdata->fuzz_x; - fuzz_y = pdata->fuzz_y; - fuzz_p = pdata->fuzz_p; - fuzz_w = pdata->fuzz_w; - - inactive_area_left = inactive_area_left * max_x / 0x10000; - inactive_area_right = inactive_area_right * max_x / 0x10000; - inactive_area_top = inactive_area_top * max_y / 0x10000; - inactive_area_bottom = inactive_area_bottom * max_y / 0x10000; - snap_left_on = snap_left_on * max_x / 0x10000; - snap_left_off = snap_left_off * max_x / 0x10000; - snap_right_on = snap_right_on * max_x / 0x10000; - snap_right_off = snap_right_off * max_x / 0x10000; - snap_top_on = snap_top_on * max_y / 0x10000; - snap_top_off = snap_top_off * max_y / 0x10000; - snap_bottom_on = snap_bottom_on * max_y / 0x10000; - snap_bottom_off = snap_bottom_off * max_y / 0x10000; - fuzz_x = fuzz_x * max_x / 0x10000; - fuzz_y = fuzz_y * max_y / 0x10000; - - - ts->snap_down[swapped] = -inactive_area_left; - ts->snap_up[swapped] = max_x + inactive_area_right; - ts->snap_down[!swapped] = -inactive_area_top; - ts->snap_up[!swapped] = max_y + inactive_area_bottom; - ts->snap_down_on[swapped] = snap_left_on; - ts->snap_down_off[swapped] = snap_left_off; - ts->snap_up_on[swapped] = max_x - snap_right_on; - ts->snap_up_off[swapped] = max_x - snap_right_off; - ts->snap_down_on[!swapped] = snap_top_on; - ts->snap_down_off[!swapped] = snap_top_off; - ts->snap_up_on[!swapped] = max_y - snap_bottom_on; - ts->snap_up_off[!swapped] = max_y - snap_bottom_off; - pr_info("synaptics_ts_probe: max_x %d, max_y %d\n", max_x, max_y); - pr_info("synaptics_ts_probe: inactive_x %d %d, inactive_y %d %d\n", - inactive_area_left, inactive_area_right, - inactive_area_top, inactive_area_bottom); - pr_info("synaptics_ts_probe: snap_x %d-%d %d-%d, snap_y %d-%d %d-%d\n", - snap_left_on, snap_left_off, snap_right_on, snap_right_off, - snap_top_on, snap_top_off, snap_bottom_on, snap_bottom_off); - - input_set_abs_params(ts->input_dev, ABS_X, - -inactive_area_left, max_x + inactive_area_right, - fuzz_x, 0); - input_set_abs_params(ts->input_dev, ABS_Y, - -inactive_area_top, max_y + inactive_area_bottom, - fuzz_y, 0); - input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, fuzz_p, 0); -} - -static struct synaptics_i2c_rmi_platform_data fake_pdata; - -static int __devinit synaptics_ts_probe( - struct i2c_client *client, const struct i2c_device_id *id) -{ - struct synaptics_ts_data *ts; - u8 buf0[4]; - u8 buf1[8]; - struct i2c_msg msg[2]; - int ret = 0; - struct synaptics_i2c_rmi_platform_data *pdata; - u32 panel_version = 0; - u16 max_x, max_y; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("synaptics_ts_probe: need I2C_FUNC_I2C\n"); - ret = -ENODEV; - goto err_check_functionality_failed; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - pr_err("synaptics_ts_probe: need I2C_FUNC_SMBUS_WORD_DATA\n"); - ret = -ENODEV; - goto err_check_functionality_failed; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - pr_err("synaptics_ts_probe: need I2C_FUNC_SMBUS_WORD_DATA\n"); - ret = -ENODEV; - goto err_check_functionality_failed; - } - - ts = kzalloc(sizeof(*ts), GFP_KERNEL); - if (ts == NULL) { - ret = -ENOMEM; - goto err_alloc_data_failed; - } - INIT_WORK(&ts->work, synaptics_ts_work_func); - ts->client = client; - i2c_set_clientdata(client, ts); - pdata = client->dev.platform_data; - if (pdata) - ts->power = pdata->power; - else - pdata = &fake_pdata; - - if (ts->power) { - ret = ts->power(1); - if (ret < 0) { - pr_err("synaptics_ts_probe power on failed\n"); - goto err_power_failed; - } - } - - ret = detect(ts, &panel_version); - if (ret) - goto err_detect_failed; - - while (pdata->version > panel_version) - pdata++; - ts->flags = pdata->flags; - - ret = i2c_read(ts, 0xf0, "device control"); - if (ret < 0) - goto err_detect_failed; - pr_info("synaptics: device control %x\n", ret); - - ret = i2c_read(ts, 0xf1, "interrupt enable"); - if (ret < 0) - goto err_detect_failed; - pr_info("synaptics_ts_probe: interrupt enable %x\n", ret); - - ret = i2c_set(ts, 0xf1, 0, "disable interrupt"); - if (ret < 0) - goto err_detect_failed; - - msg[0].addr = ts->client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = buf0; - buf0[0] = 0xe0; - msg[1].addr = ts->client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 8; - msg[1].buf = buf1; - ret = i2c_transfer(ts->client->adapter, msg, 2); - if (ret < 0) { - pr_err("i2c_transfer failed\n"); - goto err_detect_failed; - } - pr_info("synaptics_ts_probe: 0xe0: %x %x %x %x %x %x %x %x\n", - buf1[0], buf1[1], buf1[2], buf1[3], - buf1[4], buf1[5], buf1[6], buf1[7]); - - ret = i2c_set(ts, 0xff, 0x10, "page select = 0x10"); - if (ret < 0) - goto err_detect_failed; - - ret = i2c_smbus_read_word_data(ts->client, 0x04); - if (ret < 0) { - pr_err("i2c_smbus_read_word_data failed\n"); - goto err_detect_failed; - } - ts->max[0] = max_x = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); - ret = i2c_smbus_read_word_data(ts->client, 0x06); - if (ret < 0) { - pr_err("i2c_smbus_read_word_data failed\n"); - goto err_detect_failed; - } - ts->max[1] = max_y = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); - if (ts->flags & SYNAPTICS_SWAP_XY) - swap(max_x, max_y); - - /* will also switch back to page 0x04 */ - ret = synaptics_init_panel(ts); - if (ret < 0) { - pr_err("synaptics_init_panel failed\n"); - goto err_detect_failed; - } - - ts->input_dev = input_allocate_device(); - if (ts->input_dev == NULL) { - ret = -ENOMEM; - pr_err("synaptics: Failed to allocate input device\n"); - goto err_input_dev_alloc_failed; - } - ts->input_dev->name = "synaptics-rmi-touchscreen"; - ts->input_dev->phys = "msm/input0"; - ts->input_dev->id.bustype = BUS_I2C; - - __set_bit(EV_SYN, ts->input_dev->evbit); - __set_bit(EV_KEY, ts->input_dev->evbit); - __set_bit(BTN_TOUCH, ts->input_dev->keybit); - __set_bit(EV_ABS, ts->input_dev->evbit); - - compute_areas(ts, pdata, max_x, max_y); - - - ret = input_register_device(ts->input_dev); - if (ret) { - pr_err("synaptics: Unable to register %s input device\n", - ts->input_dev->name); - goto err_input_register_device_failed; - } - if (client->irq) { - ret = request_threaded_irq(client->irq, NULL, - synaptics_ts_irq_handler, - IRQF_TRIGGER_LOW|IRQF_ONESHOT, - client->name, ts); - if (ret == 0) { - ret = i2c_set(ts, 0xf1, 0x01, "enable abs int"); - if (ret) - free_irq(client->irq, ts); - } - if (ret == 0) - ts->use_irq = 1; - else - dev_err(&client->dev, "request_irq failed\n"); - } - if (!ts->use_irq) { - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = synaptics_ts_timer_func; - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - } -#ifdef CONFIG_HAS_EARLYSUSPEND - ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - ts->early_suspend.suspend = synaptics_ts_early_suspend; - ts->early_suspend.resume = synaptics_ts_late_resume; - register_early_suspend(&ts->early_suspend); -#endif - - pr_info("synaptics: Start touchscreen %s in %s mode\n", - ts->input_dev->name, ts->use_irq ? "interrupt" : "polling"); - - return 0; - -err_input_register_device_failed: - input_free_device(ts->input_dev); - -err_input_dev_alloc_failed: -err_detect_failed: -err_power_failed: - kfree(ts); -err_alloc_data_failed: -err_check_functionality_failed: - return ret; -} - -static int synaptics_ts_remove(struct i2c_client *client) -{ - struct synaptics_ts_data *ts = i2c_get_clientdata(client); -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&ts->early_suspend); -#endif - if (ts->use_irq) - free_irq(client->irq, ts); - else - hrtimer_cancel(&ts->timer); - input_unregister_device(ts->input_dev); - kfree(ts); - return 0; -} - -#ifdef CONFIG_PM -static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg) -{ - int ret; - struct synaptics_ts_data *ts = i2c_get_clientdata(client); - - if (ts->use_irq) - disable_irq(client->irq); - else - hrtimer_cancel(&ts->timer); - ret = cancel_work_sync(&ts->work); - if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */ - enable_irq(client->irq); - i2c_set(ts, 0xf1, 0, "disable interrupt"); - i2c_set(ts, 0xf0, 0x86, "deep sleep"); - - if (ts->power) { - ret = ts->power(0); - if (ret < 0) - pr_err("synaptics_ts_suspend power off failed\n"); - } - return 0; -} - -static int synaptics_ts_resume(struct i2c_client *client) -{ - int ret; - struct synaptics_ts_data *ts = i2c_get_clientdata(client); - - if (ts->power) { - ret = ts->power(1); - if (ret < 0) - pr_err("synaptics_ts_resume power on failed\n"); - } - - synaptics_init_panel(ts); - - if (ts->use_irq) { - enable_irq(client->irq); - i2c_set(ts, 0xf1, 0x01, "enable abs int"); - } else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - - return 0; -} - -#ifdef CONFIG_HAS_EARLYSUSPEND -static void synaptics_ts_early_suspend(struct early_suspend *h) -{ - struct synaptics_ts_data *ts; - ts = container_of(h, struct synaptics_ts_data, early_suspend); - synaptics_ts_suspend(ts->client, PMSG_SUSPEND); -} - -static void synaptics_ts_late_resume(struct early_suspend *h) -{ - struct synaptics_ts_data *ts; - ts = container_of(h, struct synaptics_ts_data, early_suspend); - synaptics_ts_resume(ts->client); -} -#endif -#else -#define synaptics_ts_suspend NULL -#define synaptics_ts_resume NULL -#endif - - - -static const struct i2c_device_id synaptics_ts_id[] = { - { SYNAPTICS_I2C_RMI_NAME, 0 }, - { } -}; - -static struct i2c_driver synaptics_ts_driver = { - .probe = synaptics_ts_probe, - .remove = synaptics_ts_remove, -#ifndef CONFIG_HAS_EARLYSUSPEND - .suspend = synaptics_ts_suspend, - .resume = synaptics_ts_resume, -#endif - .id_table = synaptics_ts_id, - .driver = { - .name = SYNAPTICS_I2C_RMI_NAME, - }, -}; - -static int __devinit synaptics_ts_init(void) -{ - synaptics_wq = create_singlethread_workqueue("synaptics_wq"); - if (!synaptics_wq) - return -ENOMEM; - return i2c_add_driver(&synaptics_ts_driver); -} - -static void __exit synaptics_ts_exit(void) -{ - i2c_del_driver(&synaptics_ts_driver); - if (synaptics_wq) - destroy_workqueue(synaptics_wq); -} - -module_init(synaptics_ts_init); -module_exit(synaptics_ts_exit); - -MODULE_DESCRIPTION("Synaptics Touchscreen Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Arve Hjønnevåg <arve@android.com>"); diff --git a/drivers/staging/dream/synaptics_i2c_rmi.h b/drivers/staging/dream/synaptics_i2c_rmi.h deleted file mode 100644 index ca51b2fc564d..000000000000 --- a/drivers/staging/dream/synaptics_i2c_rmi.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * include/linux/synaptics_i2c_rmi.h - platform data structure for f75375s sensor - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_SYNAPTICS_I2C_RMI_H -#define _LINUX_SYNAPTICS_I2C_RMI_H - -#define SYNAPTICS_I2C_RMI_NAME "synaptics-rmi-ts" - -enum { - SYNAPTICS_FLIP_X = 1UL << 0, - SYNAPTICS_FLIP_Y = 1UL << 1, - SYNAPTICS_SWAP_XY = 1UL << 2, - SYNAPTICS_SNAP_TO_INACTIVE_EDGE = 1UL << 3, -}; - -struct synaptics_i2c_rmi_platform_data { - uint32_t version; /* Use this entry for panels with */ - /* (major << 8 | minor) version or above. */ - /* If non-zero another array entry follows */ - int (*power)(int on); /* Only valid in first array entry */ - uint32_t flags; - uint32_t inactive_left; /* 0x10000 = screen width */ - uint32_t inactive_right; /* 0x10000 = screen width */ - uint32_t inactive_top; /* 0x10000 = screen height */ - uint32_t inactive_bottom; /* 0x10000 = screen height */ - uint32_t snap_left_on; /* 0x10000 = screen width */ - uint32_t snap_left_off; /* 0x10000 = screen width */ - uint32_t snap_right_on; /* 0x10000 = screen width */ - uint32_t snap_right_off; /* 0x10000 = screen width */ - uint32_t snap_top_on; /* 0x10000 = screen height */ - uint32_t snap_top_off; /* 0x10000 = screen height */ - uint32_t snap_bottom_on; /* 0x10000 = screen height */ - uint32_t snap_bottom_off; /* 0x10000 = screen height */ - uint32_t fuzz_x; /* 0x10000 = screen width */ - uint32_t fuzz_y; /* 0x10000 = screen height */ - int fuzz_p; - int fuzz_w; -}; - -#endif /* _LINUX_SYNAPTICS_I2C_RMI_H */ diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index c62d30017c07..61685ccceda8 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1937,11 +1937,10 @@ err_out_exit: /* * Some VFS magic here... */ -static int pohmelfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *pohmelfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, pohmelfs_fill_super, - mnt); + return mount_nodev(fs_type, flags, data, pohmelfs_fill_super); } /* @@ -1958,7 +1957,7 @@ static void pohmelfs_kill_super(struct super_block *sb) static struct file_system_type pohmel_fs_type = { .owner = THIS_MODULE, .name = "pohmel", - .get_sb = pohmelfs_get_sb, + .mount = pohmelfs_mount, .kill_sb = pohmelfs_kill_super, }; diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 552951aa7498..f9c493591ce7 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -793,16 +793,16 @@ out: return error; } -static int smb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *smb_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, smb_fill_super, mnt); + return mount_nodev(fs_type, flags, data, smb_fill_super); } static struct file_system_type smb_fs_type = { .owner = THIS_MODULE, .name = "smbfs", - .get_sb = smb_get_sb, + .mount = smb_mount, .kill_sb = kill_anon_super, .fs_flags = FS_BINARY_MOUNTDATA, }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index e2f63c0ea09d..9819a4cc3b26 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -574,16 +574,16 @@ static void fs_remove_file (struct dentry *dentry) /* --------------------------------------------------------------------- */ -static int usb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *usb_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt); + return mount_single(fs_type, flags, data, usbfs_fill_super); } static struct file_system_type usb_fs_type = { .owner = THIS_MODULE, .name = "usbfs", - .get_sb = usb_get_sb, + .mount = usb_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index f276e9594f00..4a830df4fc31 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1176,9 +1176,9 @@ invalid: /* "mount -t functionfs dev_name /dev/function" ends up here */ -static int -ffs_fs_get_sb(struct file_system_type *t, int flags, - const char *dev_name, void *opts, struct vfsmount *mnt) +static struct dentry * +ffs_fs_mount(struct file_system_type *t, int flags, + const char *dev_name, void *opts) { struct ffs_sb_fill_data data = { .perms = { @@ -1194,14 +1194,14 @@ ffs_fs_get_sb(struct file_system_type *t, int flags, ret = functionfs_check_dev_callback(dev_name); if (unlikely(ret < 0)) - return ret; + return ERR_PTR(ret); ret = ffs_fs_parse_opts(&data, opts); if (unlikely(ret < 0)) - return ret; + return ERR_PTR(ret); data.dev_name = dev_name; - return get_sb_single(t, flags, &data, ffs_sb_fill, mnt); + return mount_single(t, flags, &data, ffs_sb_fill); } static void @@ -1220,7 +1220,7 @@ ffs_fs_kill_sb(struct super_block *sb) static struct file_system_type ffs_fs_type = { .owner = THIS_MODULE, .name = "functionfs", - .get_sb = ffs_fs_get_sb, + .mount = ffs_fs_mount, .kill_sb = ffs_fs_kill_sb, }; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ba145e7fbe03..3ed73f49cf18 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2097,11 +2097,11 @@ enomem0: } /* "mount -t gadgetfs path /dev/gadget" ends up here */ -static int -gadgetfs_get_sb (struct file_system_type *t, int flags, - const char *path, void *opts, struct vfsmount *mnt) +static struct dentry * +gadgetfs_mount (struct file_system_type *t, int flags, + const char *path, void *opts) { - return get_sb_single (t, flags, opts, gadgetfs_fill_super, mnt); + return mount_single (t, flags, opts, gadgetfs_fill_super); } static void @@ -2119,7 +2119,7 @@ gadgetfs_kill_sb (struct super_block *sb) static struct file_system_type gadgetfs_type = { .owner = THIS_MODULE, .name = shortname, - .get_sb = gadgetfs_get_sb, + .mount = gadgetfs_mount, .kill_sb = gadgetfs_kill_sb, }; diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 6bb876d65252..cb23355f52d3 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -797,7 +797,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ - netif_stop_queue(net); netif_carrier_off(net); dev->gadget = g; @@ -812,6 +811,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) INFO(dev, "MAC %pM\n", net->dev_addr); INFO(dev, "HOST MAC %pM\n", dev->host_mac); + netif_stop_queue(net); the_dev = dev; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index bf2e7d234533..2391c396ca32 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -93,8 +93,9 @@ config USB_EHCI_TT_NEWSCHED config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \ - XPS_USB_HCD_XILINX || PPC_MPC512x) + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \ + ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ + PPC_MPC512x || CPU_CAVIUM_OCTEON) default y config USB_EHCI_BIG_ENDIAN_DESC @@ -434,3 +435,28 @@ config USB_IMX21_HCD To compile this driver as a module, choose M here: the module will be called "imx21-hcd". +config USB_OCTEON_EHCI + bool "Octeon on-chip EHCI support" + depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON + default n + select USB_EHCI_BIG_ENDIAN_MMIO + help + Enable support for the Octeon II SOC's on-chip EHCI + controller. It is needed for high-speed (480Mbit/sec) + USB 2.0 device support. All CN6XXX based chips with USB are + supported. + +config USB_OCTEON_OHCI + bool "Octeon on-chip OHCI support" + depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON + default USB_OCTEON_EHCI + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_OHCI_LITTLE_ENDIAN + help + Enable support for the Octeon II SOC's on-chip OHCI + controller. It is needed for low-speed USB 1.0 device + support. All CN6XXX based chips with USB are supported. + +config USB_OCTEON2_COMMON + bool + default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 91c5a1bd1026..624a362f2fee 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o +obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2adae8e39bba..502a7e6fef42 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1211,6 +1211,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_atmel_driver #endif +#ifdef CONFIG_USB_OCTEON_EHCI +#include "ehci-octeon.c" +#define PLATFORM_DRIVER ehci_octeon_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ !defined(XILINX_OF_PLATFORM_DRIVER) diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c new file mode 100644 index 000000000000..a31a031178a8 --- /dev/null +++ b/drivers/usb/host/ehci-octeon.c @@ -0,0 +1,207 @@ +/* + * EHCI HCD glue for Cavium Octeon II SOCs. + * + * Loosely based on ehci-au1xxx.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + * + */ + +#include <linux/platform_device.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +#define OCTEON_EHCI_HCD_NAME "octeon-ehci" + +/* Common clock init code. */ +void octeon2_usb_clocks_start(void); +void octeon2_usb_clocks_stop(void); + +static void ehci_octeon_start(void) +{ + union cvmx_uctlx_ehci_ctl ehci_ctl; + + octeon2_usb_clocks_start(); + + ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); + /* Use 64-bit addressing. */ + ehci_ctl.s.ehci_64b_addr_en = 1; + ehci_ctl.s.l2c_addr_msb = 0; + ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); +} + +static void ehci_octeon_stop(void) +{ + octeon2_usb_clocks_stop(); +} + +static const struct hc_driver ehci_octeon_hc_driver = { + .description = hcd_name, + .product_desc = "Octeon EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_init, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64); + +static int ehci_octeon_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource *res_mem; + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No irq assigned\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(&pdev->dev, "No register space assigned\n"); + return -ENODEV; + } + + /* + * We can DMA from anywhere. But the descriptors must be in + * the lower 4GB. + */ + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &ehci_octeon_dma_mask; + + hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = res_mem->end - res_mem->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + OCTEON_EHCI_HCD_NAME)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ehci_octeon_start(); + + ehci = hcd_to_ehci(hcd); + + /* Octeon EHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + ehci->big_endian_mmio = 1; +#endif + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) { + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); + goto err3; + } + + platform_set_drvdata(pdev, hcd); + + /* root ports should always stay powered */ + ehci_port_power(ehci, 1); + + return 0; +err3: + ehci_octeon_stop(); + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ehci_octeon_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + + ehci_octeon_stop(); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ehci_octeon_driver = { + .probe = ehci_octeon_drv_probe, + .remove = ehci_octeon_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = OCTEON_EHCI_HCD_NAME, + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME); diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c new file mode 100644 index 000000000000..72d672cfcf39 --- /dev/null +++ b/drivers/usb/host/octeon2-common.c @@ -0,0 +1,185 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + */ + +#include <linux/module.h> +#include <linux/delay.h> + +#include <asm/atomic.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0); + +void octeon2_usb_clocks_start(void) +{ + u64 div; + union cvmx_uctlx_if_ena if_ena; + union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; + union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; + union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; + int i; + unsigned long io_clk_64_to_ns; + + if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1) + return; + + io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); + + /* + * Step 1: Wait for voltages stable. That surely happened + * before starting the kernel. + * + * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 + */ + if_ena.u64 = 0; + if_ena.s.en = 1; + cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); + + /* Step 3: Configure the reference clock, PHY, and HCLK */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + /* 3a */ + clk_rst_ctl.s.p_por = 1; + clk_rst_ctl.s.hrst = 0; + clk_rst_ctl.s.p_prst = 0; + clk_rst_ctl.s.h_clkdiv_rst = 0; + clk_rst_ctl.s.o_clkdiv_rst = 0; + clk_rst_ctl.s.h_clkdiv_en = 0; + clk_rst_ctl.s.o_clkdiv_en = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3b */ + /* 12MHz crystal. */ + clk_rst_ctl.s.p_refclk_sel = 0; + clk_rst_ctl.s.p_refclk_div = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3c */ + div = octeon_get_io_clock_rate() / 130000000ull; + + switch (div) { + case 0: + div = 1; + break; + case 1: + case 2: + case 3: + case 4: + break; + case 5: + div = 4; + break; + case 6: + case 7: + div = 6; + break; + case 8: + case 9: + case 10: + case 11: + div = 8; + break; + default: + div = 12; + break; + } + clk_rst_ctl.s.h_div = div; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* Read it back, */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + clk_rst_ctl.s.h_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* 3d */ + clk_rst_ctl.s.h_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3e: delay 64 io clocks */ + ndelay(io_clk_64_to_ns); + + /* + * Step 4: Program the power-on reset field in the UCTL + * clock-reset-control register. + */ + clk_rst_ctl.s.p_por = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 5: Wait 1 ms for the PHY clock to start. */ + mdelay(1); + + /* + * Step 6: Program the reset input from automatic test + * equipment field in the UPHY CSR + */ + uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); + uphy_ctl_status.s.ate_reset = 1; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* Step 7: Wait for at least 10ns. */ + ndelay(10); + + /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ + uphy_ctl_status.s.ate_reset = 0; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* + * Step 9: Wait for at least 20ns for UPHY to output PHY clock + * signals and OHCI_CLK48 + */ + ndelay(20); + + /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ + /* 10a */ + clk_rst_ctl.s.o_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10b */ + clk_rst_ctl.s.o_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10c */ + ndelay(io_clk_64_to_ns); + + /* + * Step 11: Program the PHY reset field: + * UCTL0_CLK_RST_CTL[P_PRST] = 1 + */ + clk_rst_ctl.s.p_prst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 12: Wait 1 uS. */ + udelay(1); + + /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ + clk_rst_ctl.s.hrst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Now we can set some other registers. */ + + for (i = 0; i <= 1; i++) { + port_ctl_status.u64 = + cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); + /* Set txvreftune to 15 to obtain complient 'eye' diagram. */ + port_ctl_status.s.txvreftune = 15; + cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), + port_ctl_status.u64); + } +} +EXPORT_SYMBOL(octeon2_usb_clocks_start); + +void octeon2_usb_clocks_stop(void) +{ + union cvmx_uctlx_if_ena if_ena; + + if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0) + return; + + if_ena.u64 = 0; + if_ena.s.en = 0; + cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); +} +EXPORT_SYMBOL(octeon2_usb_clocks_stop); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f3713f43f3fe..5179acb7aa2f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1106,6 +1106,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_jz4740_driver #endif +#ifdef CONFIG_USB_OCTEON_OHCI +#include "ohci-octeon.c" +#define PLATFORM_DRIVER ohci_octeon_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OMAP1_PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c new file mode 100644 index 000000000000..e4ddfaf8870f --- /dev/null +++ b/drivers/usb/host/ohci-octeon.c @@ -0,0 +1,214 @@ +/* + * EHCI HCD glue for Cavium Octeon II SOCs. + * + * Loosely based on ehci-au1xxx.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + * + */ + +#include <linux/platform_device.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +#define OCTEON_OHCI_HCD_NAME "octeon-ohci" + +/* Common clock init code. */ +void octeon2_usb_clocks_start(void); +void octeon2_usb_clocks_stop(void); + +static void ohci_octeon_hw_start(void) +{ + union cvmx_uctlx_ohci_ctl ohci_ctl; + + octeon2_usb_clocks_start(); + + ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); + ohci_ctl.s.l2c_addr_msb = 0; + ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); + +} + +static void ohci_octeon_hw_stop(void) +{ + /* Undo ohci_octeon_start() */ + octeon2_usb_clocks_stop(); +} + +static int __devinit ohci_octeon_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_init(ohci); + + if (ret < 0) + return ret; + + ret = ohci_run(ohci); + + if (ret < 0) { + ohci_err(ohci, "can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_octeon_hc_driver = { + .description = hcd_name, + .product_desc = "Octeon OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_octeon_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + + .start_port_reset = ohci_start_port_reset, +}; + +static int ohci_octeon_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + void *reg_base; + struct resource *res_mem; + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No irq assigned\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(&pdev->dev, "No register space assigned\n"); + return -ENODEV; + } + + /* Ohci is a 32-bit device. */ + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = res_mem->end - res_mem->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + OCTEON_OHCI_HCD_NAME)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto err1; + } + + reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!reg_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ohci_octeon_hw_start(); + + hcd->regs = reg_base; + + ohci = hcd_to_ohci(hcd); + + /* Octeon OHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + ohci->flags |= OHCI_QUIRK_BE_MMIO; +#endif + + ohci_hcd_init(ohci); + + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) { + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); + goto err3; + } + + platform_set_drvdata(pdev, hcd); + + return 0; + +err3: + ohci_octeon_hw_stop(); + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ohci_octeon_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + + ohci_octeon_hw_stop(); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ohci_octeon_driver = { + .probe = ohci_octeon_drv_probe, + .remove = ohci_octeon_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = OCTEON_OHCI_HCD_NAME, + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME); diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 0bc97698af15..d335f484fcd8 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -124,7 +124,6 @@ #define PHY_DPLL_CLK (1 << 0) /* In module TWL4030_MODULE_PM_MASTER */ -#define PROTECT_KEY 0x0E #define STS_HW_CONDITIONS 0x0F /* In module TWL4030_MODULE_PM_RECEIVER */ @@ -418,8 +417,13 @@ static void twl4030_phy_resume(struct twl4030_usb *twl) static int twl4030_usb_ldo_init(struct twl4030_usb *twl) { /* Enable writing to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); + twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG1, + TWL4030_PM_MASTER_PROTECT_KEY); + + twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, + TWL4030_PM_MASTER_KEY_CFG2, + TWL4030_PM_MASTER_PROTECT_KEY); /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/ /*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ @@ -455,7 +459,8 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl) twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); /* disable access to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); + twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, + TWL4030_PM_MASTER_PROTECT_KEY); return 0; diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index 7c316c34dfca..b66d86ac7cea 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -318,7 +318,7 @@ static long mddi_wait_interrupt_timeout(struct mddi_info *mddi, static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask) { if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0) - printk(KERN_INFO KERN_ERR "mddi_wait_interrupt %d, timeout " + printk(KERN_INFO "mddi_wait_interrupt %d, timeout " "waiting for %x, INT = %x, STAT = %x gotint = %x\n", current->pid, intmask, mddi_readl(INT), mddi_readl(STAT), mddi->got_int); @@ -465,8 +465,7 @@ static int __init mddi_get_client_caps(struct mddi_info *mddi) if (mddi->flags & FLAG_HAVE_CAPS) break; - printk(KERN_INFO KERN_ERR "mddi_init, timeout waiting for " - "caps\n"); + printk(KERN_INFO "mddi_init, timeout waiting for caps\n"); } return mddi->flags & FLAG_HAVE_CAPS; } diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 3c28db03ad39..c3636d55a3c5 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -90,7 +90,7 @@ static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) mdp_irq_mask &= ~(mask); /* if no one is waiting on the interrupt, disable it */ if (!mdp_irq_mask) { - disable_irq(mdp->irq); + disable_irq_nosync(mdp->irq); if (clk) clk_disable(clk); } @@ -482,6 +482,7 @@ int mdp_probe(struct platform_device *pdev) /* register mdp device */ mdp->mdp_dev.dev.parent = &pdev->dev; mdp->mdp_dev.dev.class = mdp_class; + dev_set_name(&mdp->mdp_dev.dev, "mdp%d", pdev->id); /* if you can remove the platform device you'd have to implement * this: diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 5699ce0c1780..3f3d431033ca 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -123,83 +123,87 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, u32 linelength; bool yuv; - /* Select data format */ + /* + * Select data format. MIPI DSI is not hot-pluggable, so, we just use + * the default videomode. If this ever becomes a problem, We'll have to + * move this to mipi_display_on() above and use info->var.xres + */ switch (pdata->data_format) { case MIPI_RGB888: pctype = 0; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB565: pctype = 1; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_RGB666_LP: pctype = 2; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB666: pctype = 3; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_BGR888: pctype = 8; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR565: pctype = 9; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_BGR666_LP: pctype = 0xa; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR666: pctype = 0xb; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_YUYV: pctype = 4; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_UYVY: pctype = 5; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_YUV420_L: pctype = 6; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; - linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; yuv = true; break; case MIPI_YUV420: @@ -207,7 +211,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; /* Length of U/V line */ - linelength = (ch->lcd_cfg.xres + 1) / 2; + linelength = (ch->lcd_cfg[0].xres + 1) / 2; yuv = true; break; default: @@ -281,7 +285,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ /* * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see - * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default + * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default * (unused, since VMCTR2[HSABM] = 0) */ iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index ef989d94511c..55b3077ff6ff 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -28,6 +28,8 @@ #include <video/sh_mobile_hdmi.h> #include <video/sh_mobile_lcdc.h> +#include "sh_mobile_lcdcfb.h" + #define HDMI_SYSTEM_CTRL 0x00 /* System control */ #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ @@ -206,12 +208,15 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; - enum hotplug_state hp_state; + enum hotplug_state hp_state; /* hot-plug status */ + bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; + struct mutex mutex; /* Protect the info pointer */ struct delayed_work edid_work; struct fb_var_screeninfo var; + struct fb_monspecs monspec; }; static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) @@ -277,7 +282,7 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { */ /* External video parameter settings */ -static void hdmi_external_video_param(struct sh_hdmi *hdmi) +static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) { struct fb_var_screeninfo *var = &hdmi->var; u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; @@ -309,9 +314,9 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) if (var->sync & FB_SYNC_VERT_HIGH_ACT) sync |= 8; - pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", - htotal, hblank, hdelay, var->hsync_len, - vtotal, vblank, vdelay, var->vsync_len, sync); + dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", + htotal, hblank, hdelay, var->hsync_len, + vtotal, vblank, vdelay, var->vsync_len, sync); hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); @@ -336,7 +341,10 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); - /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for manual mode */ + /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ + if (!hdmi->preprogrammed_mode) + hdmi_write(hdmi, sync | 1 | (voffset << 4), + HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } /** @@ -454,21 +462,61 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) } /** - * sh_hdmi_phy_config() + * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ - hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ - hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); - hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); - hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); - hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + if (hdmi->var.yres > 480) { + /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ + /* + * [1:0] Speed_A + * [3:2] Speed_B + * [4] PLLA_Bypass + * [6] DRV_TEST_EN + * [7] DRV_TEST_IN + */ + hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + /* + * [2:0] BGR_I_OFFSET + * [6:4] BGR_V_OFFSET + */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ + hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + /* + * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ + hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + /* + * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + /* DRV_CONFIG, PE_CONFIG */ + hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + /* + * [2:0] AMON_SEL (4 == LPF voltage) + * [4] PLLA_CONFIG[16] + * [5] PLLB_CONFIG[16] + */ + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } else { + /* for 480p8bit 27MHz */ + hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } } /** @@ -476,6 +524,8 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) { + u8 vic; + /* AVI InfoFrame */ hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); @@ -500,9 +550,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); /* - * C = No Data - * M = 16:9 Picture Aspect Ratio - * R = Same as picture aspect ratio + * [7:6] C = Colorimetry: no data + * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio + * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio */ hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); @@ -516,9 +566,15 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) /* * VIC = 1280 x 720p: ignored if external config is used - * Send 2 for 720 x 480p, 16 for 1080p + * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode */ - hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); + if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) + vic = 16; + else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) + vic = 2; + else + vic = 4; + hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); /* PR = No Repetition */ hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); @@ -592,100 +648,6 @@ static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) } /** - * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET - */ -static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Gamut Metadata Packet */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x0A */ - hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) - */ -static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Audio Content Protection Packet (ACP) */ - hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x04 */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ACP_Type */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc1_setup() - ISRC1 Packet - */ -static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC1 Packet */ - hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x05 */ - hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_0-15 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc2_setup() - ISRC2 Packet - */ -static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC2 Packet */ - hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); - - /* HB0 Packet Type = 0x06 */ - hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_16-31 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** * sh_hdmi_configure() - Initialise HDMI for output */ static void sh_hdmi_configure(struct sh_hdmi *hdmi) @@ -705,18 +667,6 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) /* Audio InfoFrame */ sh_hdmi_audio_infoframe_setup(hdmi); - /* Gamut Metadata packet */ - sh_hdmi_gamut_metadata_setup(hdmi); - - /* Audio Content Protection (ACP) Packet */ - sh_hdmi_acp_setup(hdmi); - - /* ISRC1 Packet */ - sh_hdmi_isrc1_setup(hdmi); - - /* ISRC2 Packet */ - sh_hdmi_isrc2_setup(hdmi); - /* * Control packet auto send with VSYNC control: auto send * General control, Gamut metadata, ISRC, and ACP packets @@ -734,17 +684,42 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); } -static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) +static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, + const struct fb_videomode *mode) { - struct fb_var_screeninfo *var = &hdmi->var; - struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; - unsigned long height = var->height, width = var->width; - int i; + long target = PICOS2KHZ(mode->pixclock) * 1000, + rate = clk_round_rate(hdmi->hdmi_clk, target); + unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; + + dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", + mode->left_margin, mode->xres, + mode->right_margin, mode->hsync_len, + mode->upper_margin, mode->yres, + mode->lower_margin, mode->vsync_len); + + dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, + rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, + mode->refresh); + + return rate_error; +} + +static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) +{ + struct fb_var_screeninfo tmpvar; + struct fb_var_screeninfo *var = &tmpvar; + const struct fb_videomode *mode, *found = NULL; + struct fb_info *info = hdmi->info; + struct fb_modelist *modelist = NULL; + unsigned int f_width = 0, f_height = 0, f_refresh = 0; + unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ + bool exact_match = false; u8 edid[128]; + char *forced; + int i; /* Read EDID */ - pr_debug("Read back EDID code:"); + dev_dbg(hdmi->dev, "Read back EDID code:"); for (i = 0; i < 128; i++) { edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); #ifdef DEBUG @@ -759,29 +734,97 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) #ifdef DEBUG printk(KERN_CONT "\n"); #endif - fb_parse_edid(edid, var); - pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", - var->left_margin, var->xres, var->right_margin, var->hsync_len, - var->upper_margin, var->yres, var->lower_margin, var->vsync_len, - PICOS2KHZ(var->pixclock)); - - /* FIXME: Use user-provided configuration instead of EDID */ - var->width = width; - var->xres = lcd_cfg->xres; - var->xres_virtual = lcd_cfg->xres; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->height = height; - var->yres = lcd_cfg->yres; - var->yres_virtual = lcd_cfg->yres * 2; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; - - hdmi_external_video_param(hdmi); + + fb_edid_to_monspecs(edid, &hdmi->monspec); + + fb_get_options("sh_mobile_lcdc", &forced); + if (forced && *forced) { + /* Only primitive parsing so far */ + i = sscanf(forced, "%ux%u@%u", + &f_width, &f_height, &f_refresh); + if (i < 2) { + f_width = 0; + f_height = 0; + } + dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", + f_width, f_height, f_refresh); + } + + /* Walk monitor modes to find the best or the exact match */ + for (i = 0, mode = hdmi->monspec.modedb; + f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; + i++, mode++) { + unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); + + /* No interest in unmatching modes */ + if (f_width != mode->xres || f_height != mode->yres) + continue; + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) + /* + * Exact match if either the refresh rate matches or it + * hasn't been specified and we've found a mode, for + * which we can configure the clock precisely + */ + exact_match = true; + else if (found && found_rate_error <= rate_error) + /* + * We otherwise search for the closest matching clock + * rate - either if no refresh rate has been specified + * or we cannot find an exactly matching one + */ + continue; + + /* Check if supported: sufficient fb memory, supported clock-rate */ + fb_videomode_to_var(var, mode); + + if (info && info->fbops->fb_check_var && + info->fbops->fb_check_var(var, info)) { + exact_match = false; + continue; + } + + found = mode; + found_rate_error = rate_error; + } + + /* + * TODO 1: if no ->info is present, postpone running the config until + * after ->info first gets registered. + * TODO 2: consider registering the HDMI platform device from the LCDC + * driver, and passing ->info with HDMI platform data. + */ + if (info && !found) { + modelist = hdmi->info->modelist.next && + !list_empty(&hdmi->info->modelist) ? + list_entry(hdmi->info->modelist.next, + struct fb_modelist, list) : + NULL; + + if (modelist) { + found = &modelist->mode; + found_rate_error = sh_hdmi_rate_error(hdmi, found); + } + } + + /* No cookie today */ + if (!found) + return -ENXIO; + + dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", + modelist ? "default" : "EDID", found->xres, found->yres, + found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); + + if ((found->xres == 720 && found->yres == 480) || + (found->xres == 1280 && found->yres == 720) || + (found->xres == 1920 && found->yres == 1080)) + hdmi->preprogrammed_mode = true; + else + hdmi->preprogrammed_mode = false; + + fb_videomode_to_var(&hdmi->var, found); + sh_hdmi_external_video_param(hdmi); + + return 0; } static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) @@ -809,8 +852,8 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); if (printk_ratelimit()) - pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", - irq, status1, mask1, status2, mask2); + dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", + irq, status1, mask1, status2, mask2); if (!((status1 & mask1) | (status2 & mask2))) { return IRQ_NONE; @@ -821,7 +864,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) udelay(500); msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); - pr_debug("MSENS 0x%x\n", msens); + dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ @@ -857,83 +900,176 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) return IRQ_HANDLED; } -static void hdmi_display_on(void *arg, struct fb_info *info) +/* locking: called with info->lock held, or before register_framebuffer() */ +static void sh_hdmi_display_on(void *arg, struct fb_info *info) { + /* + * info is guaranteed to be valid, when we are called, because our + * FB_EVENT_FB_UNBIND notify is also called with info->lock held + */ struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + struct sh_mobile_lcdc_chan *ch = info->par; - if (info->var.xres != 1280 || info->var.yres != 720) { - dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", - info->var.xres, info->var.yres); - return; - } + dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, + pdata->lcd_dev, info->state); + + /* No need to lock */ + hdmi->info = info; - pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); /* - * FIXME: not a good place to store fb_info. And we cannot nullify it - * even on monitor disconnect. What should the lifecycle be? + * hp_state can be set to + * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug + * HDMI_HOTPLUG_CONNECTED: on monitor plug-in + * HDMI_HOTPLUG_EDID_DONE: on EDID read completion */ - hdmi->info = info; switch (hdmi->hp_state) { case HDMI_HOTPLUG_EDID_DONE: /* PS mode d->e. All functions are active */ hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); - pr_debug("HDMI running\n"); + dev_dbg(hdmi->dev, "HDMI running\n"); break; case HDMI_HOTPLUG_DISCONNECTED: info->state = FBINFO_STATE_SUSPENDED; default: - hdmi->var = info->var; + hdmi->var = ch->display_var; } } -static void hdmi_display_off(void *arg) +/* locking: called with info->lock held */ +static void sh_hdmi_display_off(void *arg) { struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); + dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); /* PS mode e->a */ hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); } +static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) +{ + struct fb_info *info = hdmi->info; + struct sh_mobile_lcdc_chan *ch = info->par; + struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; + struct fb_videomode mode1, mode2; + + fb_var_to_videomode(&mode1, old_var); + fb_var_to_videomode(&mode2, new_var); + + dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", + mode1.xres, mode1.yres, mode2.xres, mode2.yres); + + if (fb_mode_is_equal(&mode1, &mode2)) + return false; + + dev_dbg(info->dev, "Switching %u -> %u lines\n", + mode1.yres, mode2.yres); + *old_var = *new_var; + + return true; +} + +/** + * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock + * @hdmi: driver context + * @pixclock: pixel clock period in picoseconds + * return: configured positive rate if successful + * 0 if couldn't set the rate, but managed to enable the clock + * negative error, if couldn't enable the clock + */ +static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) +{ + long rate; + int ret; + + rate = PICOS2KHZ(pixclock) * 1000; + rate = clk_round_rate(hdmi->hdmi_clk, rate); + if (rate > 0) { + ret = clk_set_rate(hdmi->hdmi_clk, rate); + if (ret < 0) { + dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); + rate = 0; + } else { + dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); + } + } else { + rate = 0; + dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); + } + + ret = clk_enable(hdmi->hdmi_clk); + if (ret < 0) { + dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); + return ret; + } + + return rate; +} + /* Hotplug interrupt occurred, read EDID */ -static void edid_work_fn(struct work_struct *work) +static void sh_hdmi_edid_work_fn(struct work_struct *work) { struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + struct sh_mobile_lcdc_chan *ch; + int ret; - pr_debug("%s(%p): begin, hotplug status %d\n", __func__, - pdata->lcd_dev, hdmi->hp_state); + dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, + pdata->lcd_dev, hdmi->hp_state); if (!pdata->lcd_dev) return; + mutex_lock(&hdmi->mutex); + if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { - pm_runtime_get_sync(hdmi->dev); /* A device has been plugged in */ - sh_hdmi_read_edid(hdmi); + pm_runtime_get_sync(hdmi->dev); + + ret = sh_hdmi_read_edid(hdmi); + if (ret < 0) + goto out; + + /* Reconfigure the clock */ + clk_disable(hdmi->hdmi_clk); + ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); + if (ret < 0) + goto out; + msleep(10); sh_hdmi_configure(hdmi); /* Switched to another (d) power-save mode */ msleep(10); if (!hdmi->info) - return; + goto out; + + ch = hdmi->info->par; acquire_console_sem(); /* HDMI plug in */ - hdmi->info->var = hdmi->var; - if (hdmi->info->state != FBINFO_STATE_RUNNING) + if (!sh_hdmi_must_reconfigure(hdmi) && + hdmi->info->state == FBINFO_STATE_RUNNING) { + /* + * First activation with the default monitor - just turn + * on, if we run a resume here, the logo disappears + */ + if (lock_fb_info(hdmi->info)) { + sh_hdmi_display_on(hdmi, hdmi->info); + unlock_fb_info(hdmi->info); + } + } else { + /* New monitor or have to wake up */ fb_set_suspend(hdmi->info, 0); - else - hdmi_display_on(hdmi, hdmi->info); + } release_console_sem(); } else { + ret = 0; if (!hdmi->info) - return; + goto out; acquire_console_sem(); @@ -942,15 +1078,67 @@ static void edid_work_fn(struct work_struct *work) release_console_sem(); pm_runtime_put(hdmi->dev); + fb_destroy_modedb(hdmi->monspec.modedb); } - pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); +out: + if (ret < 0) + hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; + mutex_unlock(&hdmi->mutex); + + dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); +} + +static int sh_hdmi_notify(struct notifier_block *nb, + unsigned long action, void *data); + +static struct notifier_block sh_hdmi_notifier = { + .notifier_call = sh_hdmi_notify, +}; + +static int sh_hdmi_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct fb_event *event = data; + struct fb_info *info = event->info; + struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; + struct sh_hdmi *hdmi = board_cfg->board_data; + + if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) + return NOTIFY_DONE; + + switch(action) { + case FB_EVENT_FB_REGISTERED: + /* Unneeded, activation taken care by sh_hdmi_display_on() */ + break; + case FB_EVENT_FB_UNREGISTERED: + /* + * We are called from unregister_framebuffer() with the + * info->lock held. This is bad for us, because we can race with + * the scheduled work, which has to call fb_set_suspend(), which + * takes info->lock internally, so, sh_hdmi_edid_work_fn() + * cannot take and hold info->lock for the whole function + * duration. Using an additional lock creates a classical AB-BA + * lock up. Therefore, we have to release the info->lock + * temporarily, synchronise with the work queue and re-acquire + * the info->lock. + */ + unlock_fb_info(hdmi->info); + mutex_lock(&hdmi->mutex); + hdmi->info = NULL; + mutex_unlock(&hdmi->mutex); + lock_fb_info(hdmi->info); + return NOTIFY_OK; + } + return NOTIFY_DONE; } static int __init sh_hdmi_probe(struct platform_device *pdev) { struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct sh_mobile_lcdc_board_cfg *board_cfg; int irq = platform_get_irq(pdev, 0), ret; struct sh_hdmi *hdmi; long rate; @@ -964,10 +1152,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) return -ENOMEM; } - ret = snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); - if (ret < 0) - goto esndreg; + mutex_init(&hdmi->mutex); hdmi->dev = &pdev->dev; @@ -978,30 +1163,14 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } - rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; - - rate = clk_round_rate(hdmi->hdmi_clk, rate); + /* Some arbitrary relaxed pixclock just to get things started */ + rate = sh_hdmi_clk_configure(hdmi, 37037); if (rate < 0) { ret = rate; - dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate); goto erate; } - ret = clk_set_rate(hdmi->hdmi_clk, rate); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret); - goto erate; - } - - pr_debug("HDMI set frequency %lu\n", rate); - - ret = clk_enable(hdmi->hdmi_clk); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret); - goto eclkenable; - } - - dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); + dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { dev_err(&pdev->dev, "HDMI register region already claimed\n"); @@ -1018,18 +1187,18 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); -#if 1 /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); -#endif /* Set up LCDC callbacks */ - pdata->lcd_chan->board_cfg.board_data = hdmi; - pdata->lcd_chan->board_cfg.display_on = hdmi_display_on; - pdata->lcd_chan->board_cfg.display_off = hdmi_display_off; + board_cfg = &pdata->lcd_chan->board_cfg; + board_cfg->owner = THIS_MODULE; + board_cfg->board_data = hdmi; + board_cfg->display_on = sh_hdmi_display_on; + board_cfg->display_off = sh_hdmi_display_off; - INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); + INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); @@ -1041,8 +1210,17 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto ereqirq; } + ret = snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); + if (ret < 0) { + dev_err(&pdev->dev, "codec registration failed\n"); + goto ecodec; + } + return 0; +ecodec: + free_irq(irq, hdmi); ereqirq: pm_runtime_disable(&pdev->dev); iounmap(hdmi->base); @@ -1050,12 +1228,10 @@ emap: release_mem_region(res->start, resource_size(res)); ereqreg: clk_disable(hdmi->hdmi_clk); -eclkenable: erate: clk_put(hdmi->hdmi_clk); egetclk: - snd_soc_unregister_codec(&pdev->dev); -esndreg: + mutex_destroy(&hdmi->mutex); kfree(hdmi); return ret; @@ -1066,21 +1242,26 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; struct sh_hdmi *hdmi = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg; int irq = platform_get_irq(pdev, 0); snd_soc_unregister_codec(&pdev->dev); - pdata->lcd_chan->board_cfg.display_on = NULL; - pdata->lcd_chan->board_cfg.display_off = NULL; - pdata->lcd_chan->board_cfg.board_data = NULL; + board_cfg->display_on = NULL; + board_cfg->display_off = NULL; + board_cfg->board_data = NULL; + board_cfg->owner = NULL; + /* No new work will be scheduled, wait for running ISR */ free_irq(irq, hdmi); - pm_runtime_disable(&pdev->dev); + /* Wait for already scheduled work */ cancel_delayed_work_sync(&hdmi->edid_work); + pm_runtime_disable(&pdev->dev); clk_disable(hdmi->hdmi_clk); clk_put(hdmi->hdmi_clk); iounmap(hdmi->base); release_mem_region(res->start, resource_size(res)); + mutex_destroy(&hdmi->mutex); kfree(hdmi); return 0; diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7a1419279c8f..50963739a409 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/mm.h> -#include <linux/fb.h> #include <linux/clk.h> #include <linux/pm_runtime.h> #include <linux/platform_device.h> @@ -21,10 +20,12 @@ #include <linux/vmalloc.h> #include <linux/ioctl.h> #include <linux/slab.h> +#include <linux/console.h> #include <video/sh_mobile_lcdc.h> #include <asm/atomic.h> -#define PALETTE_NR 16 +#include "sh_mobile_lcdcfb.h" + #define SIDE_B_OFFSET 0x1000 #define MIRROR_OFFSET 0x2000 @@ -53,11 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) -/* per-channel registers */ -enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, - LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, - LDHAJR, - NR_CH_REGS }; +#define DEFAULT_XRES 1280 +#define DEFAULT_YRES 1024 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, @@ -112,23 +110,21 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { #define LDRCNTR_MRC 0x00000001 #define LDSR_MRS 0x00000100 -struct sh_mobile_lcdc_priv; -struct sh_mobile_lcdc_chan { - struct sh_mobile_lcdc_priv *lcdc; - unsigned long *reg_offs; - unsigned long ldmt1r_value; - unsigned long enabled; /* ME and SE in LDCNT2R */ - struct sh_mobile_lcdc_chan_cfg cfg; - u32 pseudo_palette[PALETTE_NR]; - unsigned long saved_ch_regs[NR_CH_REGS]; - struct fb_info *info; - dma_addr_t dma_handle; - struct fb_deferred_io defio; - struct scatterlist *sglist; - unsigned long frame_end; - unsigned long pan_offset; - wait_queue_head_t frame_end_wait; - struct completion vsync_completion; +static const struct fb_videomode default_720p = { + .name = "HDMI 720p", + .xres = 1280, + .yres = 720, + + .left_margin = 200, + .right_margin = 88, + .hsync_len = 48, + + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + + .pixclock = 13468, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, }; struct sh_mobile_lcdc_priv { @@ -409,8 +405,8 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) { - struct fb_var_screeninfo *var = &ch->info->var; - unsigned long h_total, hsync_pos; + struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; + unsigned long h_total, hsync_pos, display_h_total; u32 tmp; tmp = ch->ldmt1r_value; @@ -428,31 +424,33 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); /* horizontal configuration */ - h_total = var->xres + var->hsync_len + - var->left_margin + var->right_margin; + h_total = display_var->xres + display_var->hsync_len + + display_var->left_margin + display_var->right_margin; tmp = h_total / 8; /* HTCN */ - tmp |= (var->xres / 8) << 16; /* HDCN */ + tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ lcdc_write_chan(ch, LDHCNR, tmp); - hsync_pos = var->xres + var->right_margin; + hsync_pos = display_var->xres + display_var->right_margin; tmp = hsync_pos / 8; /* HSYNP */ - tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ + tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ lcdc_write_chan(ch, LDHSYNR, tmp); /* vertical configuration */ - tmp = var->yres + var->vsync_len + - var->upper_margin + var->lower_margin; /* VTLN */ - tmp |= var->yres << 16; /* VDLN */ + tmp = display_var->yres + display_var->vsync_len + + display_var->upper_margin + display_var->lower_margin; /* VTLN */ + tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ lcdc_write_chan(ch, LDVLNR, tmp); - tmp = var->yres + var->lower_margin; /* VSYNP */ - tmp |= var->vsync_len << 16; /* VSYNW */ + tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ + tmp |= display_var->vsync_len << 16; /* VSYNW */ lcdc_write_chan(ch, LDVSYNR, tmp); /* Adjust horizontal synchronisation for HDMI */ - tmp = ((var->xres & 7) << 24) | - ((h_total & 7) << 16) | - ((var->hsync_len & 7) << 8) | + display_h_total = display_var->xres + display_var->hsync_len + + display_var->left_margin + display_var->right_margin; + tmp = ((display_var->xres & 7) << 24) | + ((display_h_total & 7) << 16) | + ((display_var->hsync_len & 7) << 8) | hsync_pos; lcdc_write_chan(ch, LDHAJR, tmp); } @@ -460,7 +458,6 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; - struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; @@ -503,7 +500,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); - lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); + /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ + lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } @@ -518,7 +516,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; - lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; @@ -547,7 +544,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); - tmp &= ~(0x0001001f); + tmp &= ~0x0001001f; tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); @@ -591,8 +588,10 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) continue; board_cfg = &ch->cfg.board_cfg; - if (board_cfg->display_on) + if (try_module_get(board_cfg->owner) && board_cfg->display_on) { board_cfg->display_on(board_cfg->board_data, ch->info); + module_put(board_cfg->owner); + } } return 0; @@ -614,7 +613,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) * flush frame, and wait for frame end interrupt * clean up deferred io and enable clock */ - if (ch->info->fbdefio) { + if (ch->info && ch->info->fbdefio) { ch->frame_end = 0; schedule_delayed_work(&ch->info->deferred_work, 0); wait_event(ch->frame_end_wait, ch->frame_end); @@ -624,8 +623,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } board_cfg = &ch->cfg.board_cfg; - if (board_cfg->display_off) + if (try_module_get(board_cfg->owner) && board_cfg->display_off) { board_cfg->display_off(board_cfg->board_data); + module_put(board_cfg->owner); + } } /* stop the lcdc */ @@ -704,7 +705,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, return PTR_ERR(priv->dot_clk); } } - atomic_set(&priv->hw_usecnt, -1); /* Runtime PM support involves two step for this driver: * 1) Enable Runtime PM @@ -837,6 +837,102 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, return retval; } +static void sh_mobile_fb_reconfig(struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + struct fb_videomode mode1, mode2; + struct fb_event event; + int evnt = FB_EVENT_MODE_CHANGE_ALL; + + if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) + /* More framebuffer users are active */ + return; + + fb_var_to_videomode(&mode1, &ch->display_var); + fb_var_to_videomode(&mode2, &info->var); + + if (fb_mode_is_equal(&mode1, &mode2)) + return; + + /* Display has been re-plugged, framebuffer is free now, reconfigure */ + if (fb_set_var(info, &ch->display_var) < 0) + /* Couldn't reconfigure, hopefully, can continue as before */ + return; + + info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); + + /* + * fb_set_var() calls the notifier change internally, only if + * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a + * user event, we have to call the chain ourselves. + */ + event.info = info; + event.data = &mode2; + fb_notifier_call_chain(evnt, &event); +} + +/* + * Locking: both .fb_release() and .fb_open() are called with info->lock held if + * user == 1, or with console sem held, if user == 0. + */ +static int sh_mobile_release(struct fb_info *info, int user) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + mutex_lock(&ch->open_lock); + dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); + + ch->use_count--; + + /* Nothing to reconfigure, when called from fbcon */ + if (user) { + acquire_console_sem(); + sh_mobile_fb_reconfig(info); + release_console_sem(); + } + + mutex_unlock(&ch->open_lock); + + return 0; +} + +static int sh_mobile_open(struct fb_info *info, int user) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + mutex_lock(&ch->open_lock); + ch->use_count++; + + dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); + mutex_unlock(&ch->open_lock); + + return 0; +} + +static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + if (var->xres < 160 || var->xres > 1920 || + var->yres < 120 || var->yres > 1080 || + var->left_margin < 32 || var->left_margin > 320 || + var->right_margin < 12 || var->right_margin > 240 || + var->upper_margin < 12 || var->upper_margin > 120 || + var->lower_margin < 1 || var->lower_margin > 64 || + var->hsync_len < 32 || var->hsync_len > 240 || + var->vsync_len < 2 || var->vsync_len > 64 || + var->pixclock < 6000 || var->pixclock > 40000 || + var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { + dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", + var->xres, var->yres, + var->left_margin, var->right_margin, + var->upper_margin, var->lower_margin, + var->hsync_len, var->vsync_len, + var->pixclock); + return -EINVAL; + } + return 0; +} static struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, @@ -848,6 +944,9 @@ static struct fb_ops sh_mobile_lcdc_ops = { .fb_imageblit = sh_mobile_lcdc_imageblit, .fb_pan_display = sh_mobile_fb_pan_display, .fb_ioctl = sh_mobile_ioctl, + .fb_open = sh_mobile_open, + .fb_release = sh_mobile_release, + .fb_check_var = sh_mobile_check_var, }; static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) @@ -958,6 +1057,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { .runtime_resume = sh_mobile_lcdc_runtime_resume, }; +/* locking: called with info->lock held */ static int sh_mobile_lcdc_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -965,53 +1065,40 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, struct fb_info *info = event->info; struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; - struct fb_var_screeninfo *var; + int ret; if (&ch->lcdc->notifier != nb) - return 0; + return NOTIFY_DONE; dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", __func__, action, event->data); switch(action) { case FB_EVENT_SUSPEND: - if (board_cfg->display_off) + if (try_module_get(board_cfg->owner) && board_cfg->display_off) { board_cfg->display_off(board_cfg->board_data); + module_put(board_cfg->owner); + } pm_runtime_put(info->device); + sh_mobile_lcdc_stop(ch->lcdc); break; case FB_EVENT_RESUME: - var = &info->var; + mutex_lock(&ch->open_lock); + sh_mobile_fb_reconfig(info); + mutex_unlock(&ch->open_lock); /* HDMI must be enabled before LCDC configuration */ - if (board_cfg->display_on) - board_cfg->display_on(board_cfg->board_data, ch->info); - - /* Check if the new display is not in our modelist */ - if (ch->info->modelist.next && - !fb_match_mode(var, &ch->info->modelist)) { - struct fb_videomode mode; - int ret; - - /* Can we handle this display? */ - if (var->xres > ch->cfg.lcd_cfg.xres || - var->yres > ch->cfg.lcd_cfg.yres) - return -ENOMEM; - - /* Add to the modelist */ - fb_var_to_videomode(&mode, var); - ret = fb_add_videomode(&mode, &ch->info->modelist); - if (ret < 0) - return ret; + if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + board_cfg->display_on(board_cfg->board_data, info); + module_put(board_cfg->owner); } - pm_runtime_get_sync(info->device); - - sh_mobile_lcdc_geometry(ch); - - break; + ret = sh_mobile_lcdc_start(ch->lcdc); + if (!ret) + pm_runtime_get_sync(info->device); } - return 0; + return NOTIFY_OK; } static int sh_mobile_lcdc_remove(struct platform_device *pdev); @@ -1020,14 +1107,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) { struct fb_info *info; struct sh_mobile_lcdc_priv *priv; - struct sh_mobile_lcdc_info *pdata; - struct sh_mobile_lcdc_chan_cfg *cfg; + struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; struct resource *res; int error; void *buf; int i, j; - if (!pdev->dev.platform_data) { + if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -EINVAL; } @@ -1055,31 +1141,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } priv->irq = i; - pdata = pdev->dev.platform_data; + atomic_set(&priv->hw_usecnt, -1); j = 0; for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { - priv->ch[j].lcdc = priv; - memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); + struct sh_mobile_lcdc_chan *ch = priv->ch + j; + + ch->lcdc = priv; + memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); - error = sh_mobile_lcdc_check_interface(&priv->ch[j]); + error = sh_mobile_lcdc_check_interface(ch); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[j].frame_end_wait); - init_completion(&priv->ch[j].vsync_completion); - priv->ch[j].pan_offset = 0; + init_waitqueue_head(&ch->frame_end_wait); + init_completion(&ch->vsync_completion); + ch->pan_offset = 0; switch (pdata->ch[i].chan) { case LCDC_CHAN_MAINLCD: - priv->ch[j].enabled = 1 << 1; - priv->ch[j].reg_offs = lcdc_offs_mainlcd; + ch->enabled = 1 << 1; + ch->reg_offs = lcdc_offs_mainlcd; j++; break; case LCDC_CHAN_SUBLCD: - priv->ch[j].enabled = 1 << 2; - priv->ch[j].reg_offs = lcdc_offs_sublcd; + ch->enabled = 1 << 2; + ch->reg_offs = lcdc_offs_sublcd; j++; break; } @@ -1103,69 +1191,83 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct fb_var_screeninfo *var; - struct fb_videomode *lcd_cfg; - cfg = &priv->ch[i].cfg; + const struct fb_videomode *lcd_cfg, *max_cfg = NULL; + struct sh_mobile_lcdc_chan *ch = priv->ch + i; + struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; + const struct fb_videomode *mode = cfg->lcd_cfg; + unsigned long max_size = 0; + int k; - priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); - if (!priv->ch[i].info) { + ch->info = framebuffer_alloc(0, &pdev->dev); + if (!ch->info) { dev_err(&pdev->dev, "unable to allocate fb_info\n"); error = -ENOMEM; break; } - info = priv->ch[i].info; + info = ch->info; var = &info->var; - lcd_cfg = &cfg->lcd_cfg; info->fbops = &sh_mobile_lcdc_ops; - var->xres = var->xres_virtual = lcd_cfg->xres; - var->yres = lcd_cfg->yres; + info->par = ch; + + mutex_init(&ch->open_lock); + + for (k = 0, lcd_cfg = mode; + k < cfg->num_cfg && lcd_cfg; + k++, lcd_cfg++) { + unsigned long size = lcd_cfg->yres * lcd_cfg->xres; + + if (size > max_size) { + max_cfg = lcd_cfg; + max_size = size; + } + } + + if (!mode) + max_size = DEFAULT_XRES * DEFAULT_YRES; + else if (max_cfg) + dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", + max_cfg->xres, max_cfg->yres); + + info->fix = sh_mobile_lcdc_fix; + info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; + + if (!mode) + mode = &default_720p; + + fb_videomode_to_var(var, mode); /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; - var->width = cfg->lcd_size_cfg.width; - var->height = cfg->lcd_size_cfg.height; var->activate = FB_ACTIVATE_NOW; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); if (error) break; - info->fix = sh_mobile_lcdc_fix; - info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); - info->fix.smem_len = info->fix.line_length * - var->yres_virtual; - buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, - &priv->ch[i].dma_handle, GFP_KERNEL); + &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(&pdev->dev, "unable to allocate buffer\n"); error = -ENOMEM; break; } - info->pseudo_palette = &priv->ch[i].pseudo_palette; + info->pseudo_palette = &ch->pseudo_palette; info->flags = FBINFO_FLAG_DEFAULT; error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (error < 0) { dev_err(&pdev->dev, "unable to allocate cmap\n"); dma_free_coherent(&pdev->dev, info->fix.smem_len, - buf, priv->ch[i].dma_handle); + buf, ch->dma_handle); break; } - memset(buf, 0, info->fix.smem_len); - info->fix.smem_start = priv->ch[i].dma_handle; + info->fix.smem_start = ch->dma_handle; + info->fix.line_length = var->xres * (cfg->bpp / 8); info->screen_base = buf; info->device = &pdev->dev; - info->par = &priv->ch[i]; + ch->display_var = *var; } if (error) @@ -1179,6 +1281,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct sh_mobile_lcdc_chan *ch = priv->ch + i; + const struct fb_videomode *mode = ch->cfg.lcd_cfg; + + if (!mode) + mode = &default_720p; info = ch->info; @@ -1191,6 +1297,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } } + fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); error = register_framebuffer(info); if (error < 0) goto err1; @@ -1200,8 +1307,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? "mainlcd" : "sublcd", - (int) ch->cfg.lcd_cfg.xres, - (int) ch->cfg.lcd_cfg.yres, + info->var.xres, info->var.yres, ch->cfg.bpp); /* deferred io mode: disable clock to save power */ diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h new file mode 100644 index 000000000000..9ecee2fba1d7 --- /dev/null +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -0,0 +1,41 @@ +#ifndef SH_MOBILE_LCDCFB_H +#define SH_MOBILE_LCDCFB_H + +#include <linux/completion.h> +#include <linux/fb.h> +#include <linux/mutex.h> +#include <linux/wait.h> + +/* per-channel registers */ +enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, + LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, + LDHAJR, + NR_CH_REGS }; + +#define PALETTE_NR 16 + +struct sh_mobile_lcdc_priv; +struct fb_info; + +struct sh_mobile_lcdc_chan { + struct sh_mobile_lcdc_priv *lcdc; + unsigned long *reg_offs; + unsigned long ldmt1r_value; + unsigned long enabled; /* ME and SE in LDCNT2R */ + struct sh_mobile_lcdc_chan_cfg cfg; + u32 pseudo_palette[PALETTE_NR]; + unsigned long saved_ch_regs[NR_CH_REGS]; + struct fb_info *info; + dma_addr_t dma_handle; + struct fb_deferred_io defio; + struct scatterlist *sglist; + unsigned long frame_end; + unsigned long pan_offset; + wait_queue_head_t frame_end_wait; + struct completion vsync_completion; + struct fb_var_screeninfo display_var; + int use_count; + struct mutex open_lock; /* protects the use counter */ +}; + +#endif diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 7c7f42a12796..428d273be727 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -631,6 +631,8 @@ static void xenfb_backend_changed(struct xenbus_device *dev, switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index c356146bd712..4a291045ebac 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -409,11 +409,11 @@ config ALIM7101_WDT Most people will say N. config F71808E_WDT - tristate "Fintek F71808E and F71882FG Watchdog" + tristate "Fintek F71808E, F71882FG and F71889FG Watchdog" depends on X86 && EXPERIMENTAL help This is the driver for the hardware watchdog on the Fintek - F71808E and F71882FG Super I/O controllers. + F71808E, F71882FG and F71889FG Super I/O controllers. You can compile this driver directly into the kernel, or use it as a module. The module will be called f71808e_wdt. @@ -565,10 +565,11 @@ config IT87_WDT tristate "IT87 Watchdog Timer" depends on X86 && EXPERIMENTAL ---help--- - This is the driver for the hardware watchdog on the ITE IT8716, - IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. + This is the driver for the hardware watchdog on the ITE IT8702, + IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips. + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. To compile this driver as a module, choose M here: the module will be called it87_wdt. @@ -916,6 +917,16 @@ config OCTEON_WDT from the first interrupt, it is then only poked when the device is written. +config BCM63XX_WDT + tristate "Broadcom BCM63xx hardware watchdog" + depends on BCM63XX + help + Watchdog driver for the built in watchdog hardware in Broadcom + BCM63xx SoC. + + To compile this driver as a loadable module, choose M here. + The module will be called bcm63xx_wdt. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 8374503fcc6a..4b0ef386229d 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # MIPS Architecture obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o +obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c new file mode 100644 index 000000000000..a1debc89356b --- /dev/null +++ b/drivers/watchdog/bcm63xx_wdt.c @@ -0,0 +1,350 @@ +/* + * Broadcom BCM63xx SoC watchdog driver + * + * Copyright (C) 2007, Miguel Gaio <miguel.gaio@efixo.com> + * Copyright (C) 2008, Florian Fainelli <florian@openwrt.org> + * + * 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 <linux/bitops.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/reboot.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <linux/watchdog.h> +#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/resource.h> +#include <linux/platform_device.h> + +#include <bcm63xx_cpu.h> +#include <bcm63xx_io.h> +#include <bcm63xx_regs.h> +#include <bcm63xx_timer.h> + +#define PFX KBUILD_MODNAME + +#define WDT_HZ 50000000 /* Fclk */ +#define WDT_DEFAULT_TIME 30 /* seconds */ +#define WDT_MAX_TIME 256 /* seconds */ + +static struct { + void __iomem *regs; + struct timer_list timer; + int default_ticks; + unsigned long inuse; + atomic_t ticks; +} bcm63xx_wdt_device; + +static int expect_close; + +static int wdt_time = WDT_DEFAULT_TIME; +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +/* HW functions */ +static void bcm63xx_wdt_hw_start(void) +{ + bcm_writel(0xfffffffe, bcm63xx_wdt_device.regs + WDT_DEFVAL_REG); + bcm_writel(WDT_START_1, bcm63xx_wdt_device.regs + WDT_CTL_REG); + bcm_writel(WDT_START_2, bcm63xx_wdt_device.regs + WDT_CTL_REG); +} + +static void bcm63xx_wdt_hw_stop(void) +{ + bcm_writel(WDT_STOP_1, bcm63xx_wdt_device.regs + WDT_CTL_REG); + bcm_writel(WDT_STOP_2, bcm63xx_wdt_device.regs + WDT_CTL_REG); +} + +static void bcm63xx_wdt_isr(void *data) +{ + struct pt_regs *regs = get_irq_regs(); + + die(PFX " fire", regs); +} + +static void bcm63xx_timer_tick(unsigned long unused) +{ + if (!atomic_dec_and_test(&bcm63xx_wdt_device.ticks)) { + bcm63xx_wdt_hw_start(); + mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ); + } else + printk(KERN_CRIT PFX ": watchdog will restart system\n"); +} + +static void bcm63xx_wdt_pet(void) +{ + atomic_set(&bcm63xx_wdt_device.ticks, wdt_time); +} + +static void bcm63xx_wdt_start(void) +{ + bcm63xx_wdt_pet(); + bcm63xx_timer_tick(0); +} + +static void bcm63xx_wdt_pause(void) +{ + del_timer_sync(&bcm63xx_wdt_device.timer); + bcm63xx_wdt_hw_stop(); +} + +static int bcm63xx_wdt_settimeout(int new_time) +{ + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) + return -EINVAL; + + wdt_time = new_time; + + return 0; +} + +static int bcm63xx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &bcm63xx_wdt_device.inuse)) + return -EBUSY; + + bcm63xx_wdt_start(); + return nonseekable_open(inode, file); +} + +static int bcm63xx_wdt_release(struct inode *inode, struct file *file) +{ + if (expect_close == 42) + bcm63xx_wdt_pause(); + else { + printk(KERN_CRIT PFX + ": Unexpected close, not stopping watchdog!\n"); + bcm63xx_wdt_start(); + } + clear_bit(0, &bcm63xx_wdt_device.inuse); + expect_close = 0; + return 0; +} + +static ssize_t bcm63xx_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + bcm63xx_wdt_pet(); + } + return len; +} + +static struct watchdog_info bcm63xx_wdt_info = { + .identity = PFX, + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + + +static long bcm63xx_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_value, retval = -EINVAL; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &bcm63xx_wdt_info, + sizeof(bcm63xx_wdt_info)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_SETOPTIONS: + if (get_user(new_value, p)) + return -EFAULT; + + if (new_value & WDIOS_DISABLECARD) { + bcm63xx_wdt_pause(); + retval = 0; + } + if (new_value & WDIOS_ENABLECARD) { + bcm63xx_wdt_start(); + retval = 0; + } + + return retval; + + case WDIOC_KEEPALIVE: + bcm63xx_wdt_pet(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + + if (bcm63xx_wdt_settimeout(new_value)) + return -EINVAL; + + bcm63xx_wdt_pet(); + + case WDIOC_GETTIMEOUT: + return put_user(wdt_time, p); + + default: + return -ENOTTY; + + } +} + +static int bcm63xx_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + bcm63xx_wdt_pause(); + return NOTIFY_DONE; +} + +static const struct file_operations bcm63xx_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = bcm63xx_wdt_write, + .unlocked_ioctl = bcm63xx_wdt_ioctl, + .open = bcm63xx_wdt_open, + .release = bcm63xx_wdt_release, +}; + +static struct miscdevice bcm63xx_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &bcm63xx_wdt_fops, +}; + +static struct notifier_block bcm63xx_wdt_notifier = { + .notifier_call = bcm63xx_wdt_notify_sys, +}; + + +static int bcm63xx_wdt_probe(struct platform_device *pdev) +{ + int ret; + struct resource *r; + + setup_timer(&bcm63xx_wdt_device.timer, bcm63xx_timer_tick, 0L); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "failed to get resources\n"); + return -ENODEV; + } + + bcm63xx_wdt_device.regs = ioremap_nocache(r->start, r->end - r->start); + if (!bcm63xx_wdt_device.regs) { + dev_err(&pdev->dev, "failed to remap I/O resources\n"); + return -ENXIO; + } + + ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register wdt timer isr\n"); + goto unmap; + } + + if (bcm63xx_wdt_settimeout(wdt_time)) { + bcm63xx_wdt_settimeout(WDT_DEFAULT_TIME); + dev_info(&pdev->dev, + ": wdt_time value must be 1 <= wdt_time <= 256, using %d\n", + wdt_time); + } + + ret = register_reboot_notifier(&bcm63xx_wdt_notifier); + if (ret) { + dev_err(&pdev->dev, "failed to register reboot_notifier\n"); + goto unregister_timer; + } + + ret = misc_register(&bcm63xx_wdt_miscdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register watchdog device\n"); + goto unregister_reboot_notifier; + } + + dev_info(&pdev->dev, " started, timer margin: %d sec\n", + WDT_DEFAULT_TIME); + + return 0; + +unregister_reboot_notifier: + unregister_reboot_notifier(&bcm63xx_wdt_notifier); +unregister_timer: + bcm63xx_timer_unregister(TIMER_WDT_ID); +unmap: + iounmap(bcm63xx_wdt_device.regs); + return ret; +} + +static int bcm63xx_wdt_remove(struct platform_device *pdev) +{ + if (!nowayout) + bcm63xx_wdt_pause(); + + misc_deregister(&bcm63xx_wdt_miscdev); + + iounmap(bcm63xx_wdt_device.regs); + + unregister_reboot_notifier(&bcm63xx_wdt_notifier); + bcm63xx_timer_unregister(TIMER_WDT_ID); + + return 0; +} + +static struct platform_driver bcm63xx_wdt = { + .probe = bcm63xx_wdt_probe, + .remove = bcm63xx_wdt_remove, + .driver = { + .name = "bcm63xx-wdt", + } +}; + +static int __init bcm63xx_wdt_init(void) +{ + return platform_driver_register(&bcm63xx_wdt); +} + +static void __exit bcm63xx_wdt_exit(void) +{ + platform_driver_unregister(&bcm63xx_wdt); +} + +module_init(bcm63xx_wdt_init); +module_exit(bcm63xx_wdt_exit); + +MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("Driver for the Broadcom BCM63xx SoC watchdog"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_ALIAS("platform:bcm63xx-wdt"); diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 7e5c266cda48..65e579635dba 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -308,6 +308,12 @@ static int watchdog_start(void) superio_set_bit(watchdog.sioaddr, 0x29, 1); break; + case f71889fg: + /* set pin 40 to WDTRST# */ + superio_outb(watchdog.sioaddr, 0x2b, + superio_inb(watchdog.sioaddr, 0x2b) & 0xcf); + break; + default: /* * 'default' label to shut up the compiler and catch @@ -708,8 +714,10 @@ static int __init f71808e_find(int sioaddr) case SIO_F71882_ID: watchdog.type = f71882fg; break; - case SIO_F71862_ID: case SIO_F71889_ID: + watchdog.type = f71889fg; + break; + case SIO_F71862_ID: /* These have a watchdog, though it isn't implemented (yet). */ err = -ENOSYS; goto exit; diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 69de8713b8e4..f7e90fe47b71 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -146,6 +146,7 @@ enum iTCO_chipsets { TCO_CPT29, /* Cougar Point */ TCO_CPT30, /* Cougar Point */ TCO_CPT31, /* Cougar Point */ + TCO_PBG, /* Patsburg */ }; static struct { @@ -233,6 +234,7 @@ static struct { {"Cougar Point", 2}, {"Cougar Point", 2}, {"Cougar Point", 2}, + {"Patsburg", 2}, {NULL, 0} }; @@ -348,6 +350,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, + { ITCO_PCI_DEVICE(0x1d40, TCO_PBG)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); @@ -374,7 +377,7 @@ static char expect_release; static struct { /* this is private data for the iTCO_wdt device */ /* TCO version/generation */ unsigned int iTCO_version; - /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ + /* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ unsigned long ACPIBASE; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ unsigned long __iomem *gcs; @@ -467,7 +470,7 @@ static int iTCO_wdt_start(void) if (iTCO_wdt_unset_NO_REBOOT_bit()) { spin_unlock(&iTCO_wdt_private.io_lock); printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " - "reboot disabled by hardware\n"); + "reboot disabled by hardware/BIOS\n"); return -EIO; } @@ -781,8 +784,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, base_address &= 0x0000ff80; if (base_address == 0x00000000) { /* Something's wrong here, ACPIBASE has to be set */ - printk(KERN_ERR PFX "failed to get TCOBASE address\n"); - pci_dev_put(pdev); + printk(KERN_ERR PFX "failed to get TCOBASE address, " + "device disabled by hardware/BIOS\n"); return -ENODEV; } iTCO_wdt_private.iTCO_version = @@ -797,7 +800,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, if (iTCO_wdt_private.iTCO_version == 2) { pci_read_config_dword(pdev, 0xf0, &base_address); if ((base_address & 1) == 0) { - printk(KERN_ERR PFX "RCBA is disabled by hardware\n"); + printk(KERN_ERR PFX "RCBA is disabled by hardware" + "/BIOS, device disabled\n"); ret = -ENODEV; goto out; } @@ -808,7 +812,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* Check chipset's NO_REBOOT bit */ if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, " - "platform may have disabled it\n"); + "device disabled by hardware/BIOS\n"); ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ goto out_unmap; } @@ -819,7 +823,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ if (!request_region(SMI_EN, 4, "iTCO_wdt")) { printk(KERN_ERR PFX - "I/O address 0x%04lx already in use\n", SMI_EN); + "I/O address 0x%04lx already in use, " + "device disabled\n", SMI_EN); ret = -EIO; goto out_unmap; } @@ -831,8 +836,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) { - printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", - TCOBASE); + printk(KERN_ERR PFX "I/O address 0x%04lx already in use " + "device disabled\n", TCOBASE); ret = -EIO; goto unreg_smi_en; } @@ -880,7 +885,6 @@ out_unmap: if (iTCO_wdt_private.iTCO_version == 2) iounmap(iTCO_wdt_private.gcs); out: - pci_dev_put(iTCO_wdt_private.pdev); iTCO_wdt_private.ACPIBASE = 0; return ret; } @@ -921,7 +925,7 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev) } if (!found) - printk(KERN_INFO PFX "No card detected\n"); + printk(KERN_INFO PFX "No device detected.\n"); return ret; } diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index f52c162b1bea..b32c6c045b1a 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c @@ -75,15 +75,23 @@ static unsigned short address; #define WDT_CONFIG 0x72 /* WDT Register: Configuration */ #define WDT_TIMEOUT 0x73 /* WDT Register: Timeout Value */ -#define WDT_RESET_GAME 0x10 -#define WDT_RESET_KBD 0x20 -#define WDT_RESET_MOUSE 0x40 -#define WDT_RESET_CIR 0x80 +#define WDT_RESET_GAME 0x10 /* Reset timer on read or write to game port */ +#define WDT_RESET_KBD 0x20 /* Reset timer on keyboard interrupt */ +#define WDT_RESET_MOUSE 0x40 /* Reset timer on mouse interrupt */ +#define WDT_RESET_CIR 0x80 /* Reset timer on consumer IR interrupt */ #define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */ -#define WDT_OUT_PWROK 0x10 -#define WDT_OUT_KRST 0x40 +#define WDT_OUT_PWROK 0x10 /* Pulse PWROK on timeout */ +#define WDT_OUT_KRST 0x40 /* Pulse reset on timeout */ + +static int wdt_control_reg = WDT_RESET_GAME; +module_param(wdt_control_reg, int, 0); +MODULE_PARM_DESC(wdt_control_reg, "Value to write to watchdog control " + "register. The default WDT_RESET_GAME resets the timer on " + "game port reads that this driver generates. You can also " + "use KBD, MOUSE or CIR if you have some external way to " + "generate those interrupts."); static int superio_inb(int reg) { @@ -131,7 +139,8 @@ static inline void superio_exit(void) static inline void it8712f_wdt_ping(void) { - inb(address); + if (wdt_control_reg & WDT_RESET_GAME) + inb(address); } static void it8712f_wdt_update_margin(void) @@ -170,7 +179,7 @@ static void it8712f_wdt_enable(void) superio_enter(); superio_select(LDN_GPIO); - superio_outb(WDT_RESET_GAME, WDT_CONTROL); + superio_outb(wdt_control_reg, WDT_CONTROL); it8712f_wdt_update_margin(); diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index b709b3b2d1ef..dad29245a6a7 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -12,7 +12,7 @@ * http://www.ite.com.tw/ * * Support of the watchdog timers, which are available on - * IT8716, IT8718, IT8726 and IT8712 (J,K version). + * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,7 +45,7 @@ #include <asm/system.h> -#define WATCHDOG_VERSION "1.12" +#define WATCHDOG_VERSION "1.13" #define WATCHDOG_NAME "IT87 WDT" #define PFX WATCHDOG_NAME ": " #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" @@ -76,10 +76,12 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8702_ID 0x8702 #define IT8705_ID 0x8705 #define IT8712_ID 0x8712 #define IT8716_ID 0x8716 #define IT8718_ID 0x8718 +#define IT8720_ID 0x8720 #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ /* GPIO Configuration Registers LDN=0x07 */ @@ -92,7 +94,7 @@ #define WDT_CIRINT 0x80 #define WDT_MOUSEINT 0x40 #define WDT_KYBINT 0x20 -#define WDT_GAMEPORT 0x10 /* not it8718 */ +#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ #define WDT_FORCE 0x02 #define WDT_ZERO 0x01 @@ -132,7 +134,7 @@ #define WDTS_USE_GP 4 #define WDTS_EXPECTED 5 -static unsigned int base, gpact, ciract; +static unsigned int base, gpact, ciract, max_units; static unsigned long wdt_status; static DEFINE_SPINLOCK(spinlock); @@ -210,6 +212,33 @@ static inline void superio_outw(int val, int reg) outb(val, VAL); } +/* Internal function, should be called after superio_select(GPIO) */ +static void wdt_update_timeout(void) +{ + unsigned char cfg = WDT_KRST | WDT_PWROK; + int tm = timeout; + + if (testmode) + cfg = 0; + + if (tm <= max_units) + cfg |= WDT_TOV1; + else + tm /= 60; + + superio_outb(cfg, WDTCFG); + superio_outb(tm, WDTVALLSB); + if (max_units > 255) + superio_outb(tm>>8, WDTVALMSB); +} + +static int wdt_round_time(int t) +{ + t += 59; + t -= t % 60; + return t; +} + /* watchdog timer handling */ static void wdt_keepalive(void) @@ -234,12 +263,7 @@ static void wdt_start(void) superio_outb(WDT_GAMEPORT, WDTCTRL); else superio_outb(WDT_CIRINT, WDTCTRL); - if (!testmode) - superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); - else - superio_outb(WDT_TOV1, WDTCFG); - superio_outb(timeout>>8, WDTVALMSB); - superio_outb(timeout, WDTVALLSB); + wdt_update_timeout(); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); @@ -255,8 +279,9 @@ static void wdt_stop(void) superio_select(GPIO); superio_outb(0x00, WDTCTRL); superio_outb(WDT_TOV1, WDTCFG); - superio_outb(0x00, WDTVALMSB); superio_outb(0x00, WDTVALLSB); + if (max_units > 255) + superio_outb(0x00, WDTVALMSB); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); @@ -266,8 +291,8 @@ static void wdt_stop(void) * wdt_set_timeout - set a new timeout value with watchdog ioctl * @t: timeout value in seconds * - * The hardware device has a 16 bit watchdog timer, thus the - * timeout time ranges between 1 and 65535 seconds. + * The hardware device has a 8 or 16 bit watchdog timer (depends on + * chip version) that can be configured to count seconds or minutes. * * Used within WDIOC_SETTIMEOUT watchdog device ioctl. */ @@ -276,19 +301,19 @@ static int wdt_set_timeout(int t) { unsigned long flags; - if (t < 1 || t > 65535) + if (t < 1 || t > max_units * 60) return -EINVAL; - timeout = t; + if (t > max_units) + timeout = wdt_round_time(t); + else + timeout = t; spin_lock_irqsave(&spinlock, flags); if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { superio_enter(); - superio_select(GPIO); - superio_outb(t>>8, WDTVALMSB); - superio_outb(t, WDTVALLSB); - + wdt_update_timeout(); superio_exit(); } spin_unlock_irqrestore(&spinlock, flags); @@ -529,10 +554,13 @@ static struct notifier_block wdt_notifier = { static int __init it87_wdt_init(void) { int rc = 0; + int try_gameport = !nogameport; u16 chip_type; u8 chip_rev; unsigned long flags; + wdt_status = 0; + spin_lock_irqsave(&spinlock, flags); superio_enter(); chip_type = superio_inw(CHIPID); @@ -541,13 +569,21 @@ static int __init it87_wdt_init(void) spin_unlock_irqrestore(&spinlock, flags); switch (chip_type) { + case IT8702_ID: + max_units = 255; + break; + case IT8712_ID: + max_units = (chip_rev < 8) ? 255 : 65535; + break; case IT8716_ID: - case IT8718_ID: case IT8726_ID: + max_units = 65535; + break; + case IT8718_ID: + case IT8720_ID: + max_units = 65535; + try_gameport = 0; break; - case IT8712_ID: - if (chip_rev > 7) - break; case IT8705_ID: printk(KERN_ERR PFX "Unsupported Chip found, Chip %04x Revision %02x\n", @@ -571,7 +607,7 @@ static int __init it87_wdt_init(void) superio_outb(0x00, WDTCTRL); /* First try to get Gameport support */ - if (chip_type != IT8718_ID && !nogameport) { + if (try_gameport) { superio_select(GAMEPORT); base = superio_inw(BASEREG); if (!base) { @@ -623,13 +659,16 @@ static int __init it87_wdt_init(void) spin_unlock_irqrestore(&spinlock, flags); } - if (timeout < 1 || timeout > 65535) { + if (timeout < 1 || timeout > max_units * 60) { timeout = DEFAULT_TIMEOUT; printk(KERN_WARNING PFX "Timeout value out of range, use default %d sec\n", DEFAULT_TIMEOUT); } + if (timeout > max_units) + timeout = wdt_round_time(timeout); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { printk(KERN_ERR PFX @@ -656,7 +695,7 @@ static int __init it87_wdt_init(void) outb(0x09, CIR_IER(base)); } - printk(KERN_INFO PFX "Chip it%04x revision %d initialized. " + printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. " "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " "nogameport=%d)\n", chip_type, chip_rev, timeout, nowayout, testmode, exclusive, nogameport); @@ -676,7 +715,7 @@ err_out_region: spin_unlock_irqrestore(&spinlock, flags); } err_out: - if (chip_type != IT8718_ID && !nogameport) { + if (try_gameport) { spin_lock_irqsave(&spinlock, flags); superio_enter(); superio_select(GAMEPORT); @@ -698,8 +737,9 @@ static void __exit it87_wdt_exit(void) superio_select(GPIO); superio_outb(0x00, WDTCTRL); superio_outb(0x00, WDTCFG); - superio_outb(0x00, WDTVALMSB); superio_outb(0x00, WDTVALLSB); + if (max_units > 255) + superio_outb(0x00, WDTVALMSB); if (test_bit(WDTS_USE_GP, &wdt_status)) { superio_select(GAMEPORT); superio_outb(gpact, ACTREG); diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c index 2d118cf022fc..928035069396 100644 --- a/drivers/watchdog/machzwd.c +++ b/drivers/watchdog/machzwd.c @@ -143,7 +143,7 @@ static unsigned long next_heartbeat; #ifndef ZF_DEBUG # define dprintk(format, args...) #else -# define dprintk(format, args...) printk(KERN_DEBUG PFX +# define dprintk(format, args...) printk(KERN_DEBUG PFX \ ":%s:%d: " format, __func__, __LINE__ , ## args) #endif @@ -388,7 +388,7 @@ static struct notifier_block zf_notifier = { static void __init zf_show_action(int act) { - char *str[] = { "RESET", "SMI", "NMI", "SCI" }; + static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" }; printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]); } diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 909923800a02..945ee8300306 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -478,7 +478,7 @@ static void octeon_wdt_calc_parameters(int t) countdown_reset = periods > 2 ? periods - 2 : 0; heartbeat = t; - timeout_cnt = ((octeon_get_clock_rate() >> 8) * timeout_sec) >> 8; + timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * timeout_sec) >> 8; } static int octeon_wdt_set_heartbeat(int t) @@ -677,7 +677,7 @@ static int __init octeon_wdt_init(void) max_timeout_sec = 6; do { max_timeout_sec--; - timeout_cnt = ((octeon_get_clock_rate() >> 8) * max_timeout_sec) >> 8; + timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * max_timeout_sec) >> 8; } while (timeout_cnt > 65535); BUG_ON(timeout_cnt == 0); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 60d71e9abe9f..6e6180ccd726 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -74,6 +74,7 @@ config XEN_PLATFORM_PCI config SWIOTLB_XEN def_bool y - depends on SWIOTLB + depends on PCI + select SWIOTLB endmenu diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index fcaf838f54be..eb8a78d77d9d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -4,6 +4,7 @@ obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_features.o := $(nostackp) +obj-$(CONFIG_BLOCK) += biomerge.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o @@ -12,3 +13,4 @@ obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o +obj-$(CONFIG_XEN_DOM0) += pci.o diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c new file mode 100644 index 000000000000..ba6eda4b5143 --- /dev/null +++ b/drivers/xen/biomerge.c @@ -0,0 +1,13 @@ +#include <linux/bio.h> +#include <linux/io.h> +#include <xen/page.h> + +bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, + const struct bio_vec *vec2) +{ + unsigned long mfn1 = pfn_to_mfn(page_to_pfn(vec1->bv_page)); + unsigned long mfn2 = pfn_to_mfn(page_to_pfn(vec2->bv_page)); + + return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) && + ((mfn1 == mfn2) || ((mfn1+1) == mfn2)); +} diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 347f17edad77..97612f548a8e 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -16,7 +16,7 @@ * (typically dom0). * 2. VIRQs, typically used for timers. These are per-cpu events. * 3. IPIs. - * 4. Hardware interrupts. Not supported at present. + * 4. PIRQs - Hardware interrupts. * * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 */ @@ -28,12 +28,16 @@ #include <linux/string.h> #include <linux/bootmem.h> #include <linux/slab.h> +#include <linux/irqnr.h> +#include <linux/pci.h> #include <asm/desc.h> #include <asm/ptrace.h> #include <asm/irq.h> #include <asm/idle.h> +#include <asm/io_apic.h> #include <asm/sync_bitops.h> +#include <asm/xen/pci.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> @@ -73,7 +77,8 @@ enum xen_irq_type { * event channel - irq->event channel mapping * cpu - cpu this event channel is bound to * index - type-specific information: - * PIRQ - vector, with MSB being "needs EIO" + * PIRQ - vector, with MSB being "needs EIO", or physical IRQ of the HVM + * guest, or GSI (real passthrough IRQ) of the device. * VIRQ - virq number * IPI - IPI vector * EVTCHN - @@ -88,21 +93,30 @@ struct irq_info unsigned short virq; enum ipi_vector ipi; struct { + unsigned short pirq; unsigned short gsi; - unsigned short vector; + unsigned char vector; + unsigned char flags; } pirq; } u; }; +#define PIRQ_NEEDS_EOI (1 << 0) +#define PIRQ_SHAREABLE (1 << 1) -static struct irq_info irq_info[NR_IRQS]; +static struct irq_info *irq_info; +static int *pirq_to_irq; +static int nr_pirqs; -static int evtchn_to_irq[NR_EVENT_CHANNELS] = { - [0 ... NR_EVENT_CHANNELS-1] = -1 -}; +static int *evtchn_to_irq; struct cpu_evtchn_s { unsigned long bits[NR_EVENT_CHANNELS/BITS_PER_LONG]; }; -static struct cpu_evtchn_s *cpu_evtchn_mask_p; + +static __initdata struct cpu_evtchn_s init_evtchn_mask = { + .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul, +}; +static struct cpu_evtchn_s *cpu_evtchn_mask_p = &init_evtchn_mask; + static inline unsigned long *cpu_evtchn_mask(int cpu) { return cpu_evtchn_mask_p[cpu].bits; @@ -113,6 +127,7 @@ static inline unsigned long *cpu_evtchn_mask(int cpu) static struct irq_chip xen_dynamic_chip; static struct irq_chip xen_percpu_chip; +static struct irq_chip xen_pirq_chip; /* Constructor for packed IRQ information. */ static struct irq_info mk_unbound_info(void) @@ -138,11 +153,12 @@ static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq) .cpu = 0, .u.virq = virq }; } -static struct irq_info mk_pirq_info(unsigned short evtchn, +static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned short pirq, unsigned short gsi, unsigned short vector) { return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn, - .cpu = 0, .u.pirq = { .gsi = gsi, .vector = vector } }; + .cpu = 0, + .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } }; } /* @@ -184,6 +200,16 @@ static unsigned virq_from_irq(unsigned irq) return info->u.virq; } +static unsigned pirq_from_irq(unsigned irq) +{ + struct irq_info *info = info_for_irq(irq); + + BUG_ON(info == NULL); + BUG_ON(info->type != IRQT_PIRQ); + + return info->u.pirq.pirq; +} + static unsigned gsi_from_irq(unsigned irq) { struct irq_info *info = info_for_irq(irq); @@ -225,6 +251,15 @@ static unsigned int cpu_from_evtchn(unsigned int evtchn) return ret; } +static bool pirq_needs_eoi(unsigned irq) +{ + struct irq_info *info = info_for_irq(irq); + + BUG_ON(info->type != IRQT_PIRQ); + + return info->u.pirq.flags & PIRQ_NEEDS_EOI; +} + static inline unsigned long active_evtchns(unsigned int cpu, struct shared_info *sh, unsigned int idx) @@ -336,12 +371,40 @@ static void unmask_evtchn(int port) put_cpu(); } +static int get_nr_hw_irqs(void) +{ + int ret = 1; + +#ifdef CONFIG_X86_IO_APIC + ret = get_nr_irqs_gsi(); +#endif + + return ret; +} + +/* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs + * succeeded otherwise nr_pirqs won't hold the right value */ +static int find_unbound_pirq(void) +{ + int i; + for (i = nr_pirqs-1; i >= 0; i--) { + if (pirq_to_irq[i] < 0) + return i; + } + return -1; +} + static int find_unbound_irq(void) { struct irq_data *data; int irq, res; + int start = get_nr_hw_irqs(); - for (irq = 0; irq < nr_irqs; irq++) { + if (start == nr_irqs) + goto no_irqs; + + /* nr_irqs is a magic value. Must not use it.*/ + for (irq = nr_irqs-1; irq > start; irq--) { data = irq_get_irq_data(irq); /* only 0->15 have init'd desc; handle irq > 16 */ if (!data) @@ -354,8 +417,8 @@ static int find_unbound_irq(void) return irq; } - if (irq == nr_irqs) - panic("No available IRQ to bind to: increase nr_irqs!\n"); + if (irq == start) + goto no_irqs; res = irq_alloc_desc_at(irq, 0); @@ -363,6 +426,357 @@ static int find_unbound_irq(void) return -1; return irq; + +no_irqs: + panic("No available IRQ to bind to: increase nr_irqs!\n"); +} + +static bool identity_mapped_irq(unsigned irq) +{ + /* identity map all the hardware irqs */ + return irq < get_nr_hw_irqs(); +} + +static void pirq_unmask_notify(int irq) +{ + struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) }; + + if (unlikely(pirq_needs_eoi(irq))) { + int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); + WARN_ON(rc); + } +} + +static void pirq_query_unmask(int irq) +{ + struct physdev_irq_status_query irq_status; + struct irq_info *info = info_for_irq(irq); + + BUG_ON(info->type != IRQT_PIRQ); + + irq_status.irq = pirq_from_irq(irq); + if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) + irq_status.flags = 0; + + info->u.pirq.flags &= ~PIRQ_NEEDS_EOI; + if (irq_status.flags & XENIRQSTAT_needs_eoi) + info->u.pirq.flags |= PIRQ_NEEDS_EOI; +} + +static bool probing_irq(int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + return desc && desc->action == NULL; +} + +static unsigned int startup_pirq(unsigned int irq) +{ + struct evtchn_bind_pirq bind_pirq; + struct irq_info *info = info_for_irq(irq); + int evtchn = evtchn_from_irq(irq); + int rc; + + BUG_ON(info->type != IRQT_PIRQ); + + if (VALID_EVTCHN(evtchn)) + goto out; + + bind_pirq.pirq = pirq_from_irq(irq); + /* NB. We are happy to share unless we are probing. */ + bind_pirq.flags = info->u.pirq.flags & PIRQ_SHAREABLE ? + BIND_PIRQ__WILL_SHARE : 0; + rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq); + if (rc != 0) { + if (!probing_irq(irq)) + printk(KERN_INFO "Failed to obtain physical IRQ %d\n", + irq); + return 0; + } + evtchn = bind_pirq.port; + + pirq_query_unmask(irq); + + evtchn_to_irq[evtchn] = irq; + bind_evtchn_to_cpu(evtchn, 0); + info->evtchn = evtchn; + +out: + unmask_evtchn(evtchn); + pirq_unmask_notify(irq); + + return 0; +} + +static void shutdown_pirq(unsigned int irq) +{ + struct evtchn_close close; + struct irq_info *info = info_for_irq(irq); + int evtchn = evtchn_from_irq(irq); + + BUG_ON(info->type != IRQT_PIRQ); + + if (!VALID_EVTCHN(evtchn)) + return; + + mask_evtchn(evtchn); + + close.port = evtchn; + if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) + BUG(); + + bind_evtchn_to_cpu(evtchn, 0); + evtchn_to_irq[evtchn] = -1; + info->evtchn = 0; +} + +static void enable_pirq(unsigned int irq) +{ + startup_pirq(irq); +} + +static void disable_pirq(unsigned int irq) +{ +} + +static void ack_pirq(unsigned int irq) +{ + int evtchn = evtchn_from_irq(irq); + + move_native_irq(irq); + + if (VALID_EVTCHN(evtchn)) { + mask_evtchn(evtchn); + clear_evtchn(evtchn); + } +} + +static void end_pirq(unsigned int irq) +{ + int evtchn = evtchn_from_irq(irq); + struct irq_desc *desc = irq_to_desc(irq); + + if (WARN_ON(!desc)) + return; + + if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) == + (IRQ_DISABLED|IRQ_PENDING)) { + shutdown_pirq(irq); + } else if (VALID_EVTCHN(evtchn)) { + unmask_evtchn(evtchn); + pirq_unmask_notify(irq); + } +} + +static int find_irq_by_gsi(unsigned gsi) +{ + int irq; + + for (irq = 0; irq < nr_irqs; irq++) { + struct irq_info *info = info_for_irq(irq); + + if (info == NULL || info->type != IRQT_PIRQ) + continue; + + if (gsi_from_irq(irq) == gsi) + return irq; + } + + return -1; +} + +int xen_allocate_pirq(unsigned gsi, int shareable, char *name) +{ + return xen_map_pirq_gsi(gsi, gsi, shareable, name); +} + +/* xen_map_pirq_gsi might allocate irqs from the top down, as a + * consequence don't assume that the irq number returned has a low value + * or can be used as a pirq number unless you know otherwise. + * + * One notable exception is when xen_map_pirq_gsi is called passing an + * hardware gsi as argument, in that case the irq number returned + * matches the gsi number passed as second argument. + * + * Note: We don't assign an event channel until the irq actually started + * up. Return an existing irq if we've already got one for the gsi. + */ +int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) +{ + int irq = 0; + struct physdev_irq irq_op; + + spin_lock(&irq_mapping_update_lock); + + if ((pirq > nr_pirqs) || (gsi > nr_irqs)) { + printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", + pirq > nr_pirqs ? "nr_pirqs" :"", + gsi > nr_irqs ? "nr_irqs" : ""); + goto out; + } + + irq = find_irq_by_gsi(gsi); + if (irq != -1) { + printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", + irq, gsi); + goto out; /* XXX need refcount? */ + } + + /* If we are a PV guest, we don't have GSIs (no ACPI passed). Therefore + * we are using the !xen_initial_domain() to drop in the function.*/ + if (identity_mapped_irq(gsi) || (!xen_initial_domain() && + xen_pv_domain())) { + irq = gsi; + irq_alloc_desc_at(irq, 0); + } else + irq = find_unbound_irq(); + + set_irq_chip_and_handler_name(irq, &xen_pirq_chip, + handle_level_irq, name); + + irq_op.irq = irq; + irq_op.vector = 0; + + /* Only the privileged domain can do this. For non-priv, the pcifront + * driver provides a PCI bus that does the call to do exactly + * this in the priv domain. */ + if (xen_initial_domain() && + HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) { + irq_free_desc(irq); + irq = -ENOSPC; + goto out; + } + + irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector); + irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0; + pirq_to_irq[pirq] = irq; + +out: + spin_unlock(&irq_mapping_update_lock); + + return irq; +} + +#ifdef CONFIG_PCI_MSI +#include <linux/msi.h> +#include "../pci/msi.h" + +void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) +{ + spin_lock(&irq_mapping_update_lock); + + *irq = find_unbound_irq(); + if (*irq == -1) + goto out; + + *pirq = find_unbound_pirq(); + if (*pirq == -1) + goto out; + + set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, + handle_level_irq, name); + + irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0); + pirq_to_irq[*pirq] = *irq; + +out: + spin_unlock(&irq_mapping_update_lock); +} + +int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) +{ + int irq = -1; + struct physdev_map_pirq map_irq; + int rc; + int pos; + u32 table_offset, bir; + + memset(&map_irq, 0, sizeof(map_irq)); + map_irq.domid = DOMID_SELF; + map_irq.type = MAP_PIRQ_TYPE_MSI; + map_irq.index = -1; + map_irq.pirq = -1; + map_irq.bus = dev->bus->number; + map_irq.devfn = dev->devfn; + + if (type == PCI_CAP_ID_MSIX) { + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + + pci_read_config_dword(dev, msix_table_offset_reg(pos), + &table_offset); + bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); + + map_irq.table_base = pci_resource_start(dev, bir); + map_irq.entry_nr = msidesc->msi_attrib.entry_nr; + } + + spin_lock(&irq_mapping_update_lock); + + irq = find_unbound_irq(); + + if (irq == -1) + goto out; + + rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); + if (rc) { + printk(KERN_WARNING "xen map irq failed %d\n", rc); + + irq_free_desc(irq); + + irq = -1; + goto out; + } + irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index); + + set_irq_chip_and_handler_name(irq, &xen_pirq_chip, + handle_level_irq, + (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi"); + +out: + spin_unlock(&irq_mapping_update_lock); + return irq; +} +#endif + +int xen_destroy_irq(int irq) +{ + struct irq_desc *desc; + struct physdev_unmap_pirq unmap_irq; + struct irq_info *info = info_for_irq(irq); + int rc = -ENOENT; + + spin_lock(&irq_mapping_update_lock); + + desc = irq_to_desc(irq); + if (!desc) + goto out; + + if (xen_initial_domain()) { + unmap_irq.pirq = info->u.pirq.gsi; + unmap_irq.domid = DOMID_SELF; + rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); + if (rc) { + printk(KERN_WARNING "unmap irq failed %d\n", rc); + goto out; + } + } + irq_info[irq] = mk_unbound_info(); + + irq_free_desc(irq); + +out: + spin_unlock(&irq_mapping_update_lock); + return rc; +} + +int xen_vector_from_irq(unsigned irq) +{ + return vector_from_irq(irq); +} + +int xen_gsi_from_irq(unsigned irq) +{ + return gsi_from_irq(irq); } int bind_evtchn_to_irq(unsigned int evtchn) @@ -425,7 +839,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) } -static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) +int bind_virq_to_irq(unsigned int virq, unsigned int cpu) { struct evtchn_bind_virq bind_virq; int evtchn, irq; @@ -928,7 +1342,7 @@ void xen_clear_irq_pending(int irq) if (VALID_EVTCHN(evtchn)) clear_evtchn(evtchn); } - +EXPORT_SYMBOL(xen_clear_irq_pending); void xen_set_irq_pending(int irq) { int evtchn = evtchn_from_irq(irq); @@ -948,9 +1362,9 @@ bool xen_test_irq_pending(int irq) return ret; } -/* Poll waiting for an irq to become pending. In the usual case, the - irq will be disabled so it won't deliver an interrupt. */ -void xen_poll_irq(int irq) +/* Poll waiting for an irq to become pending with timeout. In the usual case, + * the irq will be disabled so it won't deliver an interrupt. */ +void xen_poll_irq_timeout(int irq, u64 timeout) { evtchn_port_t evtchn = evtchn_from_irq(irq); @@ -958,13 +1372,20 @@ void xen_poll_irq(int irq) struct sched_poll poll; poll.nr_ports = 1; - poll.timeout = 0; + poll.timeout = timeout; set_xen_guest_handle(poll.ports, &evtchn); if (HYPERVISOR_sched_op(SCHEDOP_poll, &poll) != 0) BUG(); } } +EXPORT_SYMBOL(xen_poll_irq_timeout); +/* Poll waiting for an irq to become pending. In the usual case, the + * irq will be disabled so it won't deliver an interrupt. */ +void xen_poll_irq(int irq) +{ + xen_poll_irq_timeout(irq, 0 /* no timeout */); +} void xen_irq_resume(void) { @@ -1001,6 +1422,26 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { .retrigger = retrigger_dynirq, }; +static struct irq_chip xen_pirq_chip __read_mostly = { + .name = "xen-pirq", + + .startup = startup_pirq, + .shutdown = shutdown_pirq, + + .enable = enable_pirq, + .unmask = enable_pirq, + + .disable = disable_pirq, + .mask = disable_pirq, + + .ack = ack_pirq, + .end = end_pirq, + + .set_affinity = set_affinity_irq, + + .retrigger = retrigger_dynirq, +}; + static struct irq_chip xen_percpu_chip __read_mostly = { .name = "xen-percpu", @@ -1051,11 +1492,32 @@ void xen_callback_vector(void) {} void __init xen_init_IRQ(void) { - int i; + int i, rc; + struct physdev_nr_pirqs op_nr_pirqs; cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), GFP_KERNEL); - BUG_ON(cpu_evtchn_mask_p == NULL); + irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); + + rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs); + if (rc < 0) { + nr_pirqs = nr_irqs; + if (rc != -ENOSYS) + printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc); + } else { + if (xen_pv_domain() && !xen_initial_domain()) + nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs); + else + nr_pirqs = op_nr_pirqs.nr_pirqs; + } + pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL); + for (i = 0; i < nr_pirqs; i++) + pirq_to_irq[i] = -1; + + evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), + GFP_KERNEL); + for (i = 0; i < NR_EVENT_CHANNELS; i++) + evtchn_to_irq[i] = -1; init_evtchn_cpu_bindings(); @@ -1066,7 +1528,12 @@ void __init xen_init_IRQ(void) if (xen_hvm_domain()) { xen_callback_vector(); native_init_IRQ(); + /* pci_xen_hvm_init must be called after native_init_IRQ so that + * __acpi_register_gsi can point at the right function */ + pci_xen_hvm_init(); } else { irq_ctx_init(smp_processor_id()); + if (xen_initial_domain()) + xen_setup_pirqs(); } } diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c new file mode 100644 index 000000000000..cef4bafc07dc --- /dev/null +++ b/drivers/xen/pci.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Author: Weidong Han <weidong.han@intel.com> + */ + +#include <linux/pci.h> +#include <xen/xen.h> +#include <xen/interface/physdev.h> +#include <xen/interface/xen.h> + +#include <asm/xen/hypervisor.h> +#include <asm/xen/hypercall.h> +#include "../pci/pci.h" + +static int xen_add_device(struct device *dev) +{ + int r; + struct pci_dev *pci_dev = to_pci_dev(dev); + +#ifdef CONFIG_PCI_IOV + if (pci_dev->is_virtfn) { + struct physdev_manage_pci_ext manage_pci_ext = { + .bus = pci_dev->bus->number, + .devfn = pci_dev->devfn, + .is_virtfn = 1, + .physfn.bus = pci_dev->physfn->bus->number, + .physfn.devfn = pci_dev->physfn->devfn, + }; + + r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, + &manage_pci_ext); + } else +#endif + if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { + struct physdev_manage_pci_ext manage_pci_ext = { + .bus = pci_dev->bus->number, + .devfn = pci_dev->devfn, + .is_extfn = 1, + }; + + r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, + &manage_pci_ext); + } else { + struct physdev_manage_pci manage_pci = { + .bus = pci_dev->bus->number, + .devfn = pci_dev->devfn, + }; + + r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add, + &manage_pci); + } + + return r; +} + +static int xen_remove_device(struct device *dev) +{ + int r; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct physdev_manage_pci manage_pci; + + manage_pci.bus = pci_dev->bus->number; + manage_pci.devfn = pci_dev->devfn; + + r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, + &manage_pci); + + return r; +} + +static int xen_pci_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + int r = 0; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + r = xen_add_device(dev); + break; + case BUS_NOTIFY_DEL_DEVICE: + r = xen_remove_device(dev); + break; + default: + break; + } + + return r; +} + +struct notifier_block device_nb = { + .notifier_call = xen_pci_notifier, +}; + +static int __init register_xen_pci_notifier(void) +{ + if (!xen_initial_domain()) + return 0; + + return bus_register_notifier(&pci_bus_type, &device_nb); +} + +arch_initcall(register_xen_pci_notifier); diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 7e49527189b6..cdacf923e073 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -50,6 +50,8 @@ const char *xenbus_strstate(enum xenbus_state state) [ XenbusStateConnected ] = "Connected", [ XenbusStateClosing ] = "Closing", [ XenbusStateClosed ] = "Closed", + [XenbusStateReconfiguring] = "Reconfiguring", + [XenbusStateReconfigured] = "Reconfigured", }; return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; } diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 132939f36020..deb9c4ba3a93 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -803,6 +803,7 @@ device_initcall(xenbus_probe_initcall); static int __init xenbus_init(void) { int err = 0; + unsigned long page = 0; DPRINTK(""); @@ -823,7 +824,31 @@ static int __init xenbus_init(void) * Domain0 doesn't have a store_evtchn or store_mfn yet. */ if (xen_initial_domain()) { - /* dom0 not yet supported */ + struct evtchn_alloc_unbound alloc_unbound; + + /* Allocate Xenstore page */ + page = get_zeroed_page(GFP_KERNEL); + if (!page) + goto out_error; + + xen_store_mfn = xen_start_info->store_mfn = + pfn_to_mfn(virt_to_phys((void *)page) >> + PAGE_SHIFT); + + /* Next allocate a local port which xenstored can bind to */ + alloc_unbound.dom = DOMID_SELF; + alloc_unbound.remote_dom = 0; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, + &alloc_unbound); + if (err == -ENOSYS) + goto out_error; + + BUG_ON(err); + xen_store_evtchn = xen_start_info->store_evtchn = + alloc_unbound.port; + + xen_store_interface = mfn_to_virt(xen_store_mfn); } else { if (xen_hvm_domain()) { uint64_t v = 0; @@ -869,6 +894,8 @@ static int __init xenbus_init(void) bus_unregister(&xenbus_frontend.bus); out_error: + if (page != 0) + free_page(page); return err; } diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index d6662b789b6b..f6339d11d59c 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -121,17 +121,17 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) return rc; } -static int xenfs_get_sb(struct file_system_type *fs_type, +static int xenfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_single(fs_type, flags, data, xenfs_fill_super, mnt); + return mount_single(fs_type, flags, data, xenfs_fill_super); } static struct file_system_type xenfs_type = { .owner = THIS_MODULE, .name = "xenfs", - .get_sb = xenfs_get_sb, + .mount = xenfs_mount, .kill_sb = kill_litter_super, }; |