From 1bcabbad76f35e43e0dee81ea9868fc4e6b5fbe4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 4 Nov 2011 17:43:18 +0800 Subject: [PATCH] Revert "temp revert rk change" This reverts commit 15f7fabcb88e67792e49279de0b28d70fcfca0cd. Conflicts: .gitignore arch/arm/boot/compressed/head.S arch/arm/common/gic.c arch/arm/kernel/Makefile arch/arm/mm/proc-v7.S arch/arm/tools/mach-types arch/arm/vfp/vfphw.S drivers/Kconfig drivers/Makefile drivers/char/Makefile drivers/cpufreq/cpufreq_ondemand.c drivers/gpio/gpiolib.c drivers/gpio/tps65910-gpio.c drivers/input/Makefile drivers/input/keyboard/Kconfig drivers/input/keyboard/Makefile drivers/input/touchscreen/Kconfig drivers/media/video/Makefile drivers/media/video/ov2640.c drivers/media/video/soc_camera.c drivers/media/video/uvc/uvc_v4l2.c drivers/media/video/v4l2-ioctl.c drivers/mfd/Kconfig drivers/mfd/Makefile drivers/mfd/wm831x-core.c drivers/mfd/wm831x-i2c.c drivers/mfd/wm831x-irq.c drivers/mfd/wm831x-spi.c drivers/mfd/wm8994-core.c drivers/misc/Kconfig drivers/misc/Makefile drivers/misc/pmem.c drivers/mmc/card/block.c drivers/mmc/core/core.c drivers/mmc/core/mmc.c drivers/mmc/core/sd.c drivers/mmc/core/sdio.c drivers/mmc/host/Makefile drivers/net/wireless/Kconfig drivers/net/wireless/Makefile drivers/net/wireless/bcm4329/bcmsdh_linux.c drivers/net/wireless/bcm4329/dhd.h drivers/net/wireless/bcm4329/dhd_linux.c drivers/net/wireless/bcm4329/wl_iw.c drivers/net/wireless/bcm4329/wl_iw.h drivers/power/wm831x_power.c drivers/regulator/Makefile drivers/regulator/core.c drivers/regulator/tps65910-regulator.c drivers/regulator/wm831x-dcdc.c drivers/regulator/wm831x-isink.c drivers/regulator/wm831x-ldo.c drivers/rtc/Kconfig drivers/rtc/Makefile drivers/serial/Kconfig drivers/serial/Makefile drivers/staging/Kconfig drivers/staging/Makefile drivers/usb/Makefile drivers/usb/gadget/Kconfig drivers/usb/gadget/android.c drivers/usb/gadget/f_mass_storage.c drivers/usb/serial/option.c drivers/video/backlight/wm831x_bl.c fs/fat/dir.c fs/fat/fatent.c fs/fat/inode.c fs/yaffs2/yaffs_fs.c fs/yaffs2/yaffs_mtdif2.c include/linux/i2c.h include/linux/mfd/wm831x/core.h include/linux/mfd/wm831x/pdata.h include/linux/mfd/wm8994/core.h include/linux/mfd/wm8994/pdata.h include/linux/regulator/consumer.h include/media/v4l2-chip-ident.h kernel/power/earlysuspend.c kernel/power/wakelock.c kernel/sys.c mm/page_alloc.c sound/soc/codecs/Kconfig sound/soc/codecs/Makefile sound/soc/codecs/wm8900.c sound/soc/codecs/wm8988.c sound/soc/codecs/wm8994.c sound/soc/codecs/wm8994.h sound/soc/codecs/wm_hubs.c sound/soc/soc-cache.c --- .gitignore | 2 + arch/arm/Kconfig | 1 + arch/arm/boot/compressed/head.S | 4 + arch/arm/common/gic.c | 17 + arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/head.S | 5 + arch/arm/mach-rk29/Makefile | 2 +- arch/arm/mach-rk29/board-rk29-ddr3sdk.c | 9 + arch/arm/mach-rk29/clock.c | 4 + arch/arm/mach-rk29/devices.c | 5 +- arch/arm/mach-rk29/gpio.c | 617 ---- arch/arm/mach-rk29/include/mach/board.h | 2 + arch/arm/mach-rk29/include/mach/debug-macro.S | 13 +- arch/arm/mach-rk29/include/mach/gpio.h | 19 +- arch/arm/mach-rk29/vpu_service.c | 1 + arch/arm/mm/proc-v7.S | 10 + arch/arm/tools/mach-types | 3 +- arch/arm/vfp/vfphw.S | 19 + drivers/Kconfig | 12 + drivers/Makefile | 7 + drivers/base/power/main.c | 6 + drivers/cpufreq/cpufreq_ondemand.c | 5 + drivers/gpio/Kconfig | 7 - drivers/gpio/Makefile | 2 +- drivers/gpio/gpio-rk29.c | 484 +++ drivers/gpio/gpiolib.c | 77 +- drivers/i2c/i2c-core.c | 21 +- drivers/input/Makefile | 5 + drivers/input/keyboard/Kconfig | 34 + drivers/input/keyboard/Makefile | 4 + drivers/input/misc/Kconfig | 10 - drivers/input/misc/Makefile | 2 +- drivers/input/misc/tps65910-pwrbutton.c | 148 - drivers/input/touchscreen/Kconfig | 269 ++ drivers/media/video/Makefile | 28 +- drivers/media/video/ov2640.c | 2967 +++++++++++++++++ drivers/media/video/soc_camera.c | 199 ++ drivers/media/video/uvc/uvc_v4l2.c | 17 +- drivers/media/video/v4l2-ioctl.c | 4 +- drivers/mfd/Kconfig | 11 + drivers/mfd/Makefile | 1 + drivers/mfd/tps65910-core.c | 801 ----- drivers/mfd/wm831x-core.c | 158 +- drivers/mfd/wm831x-i2c.c | 71 + drivers/mfd/wm831x-irq.c | 245 +- drivers/mfd/wm831x-spi.c | 46 + drivers/mfd/wm8994-core.c | 0 drivers/misc/Kconfig | 21 + drivers/misc/Makefile | 9 + drivers/misc/apanic.c | 19 +- drivers/misc/pmem.c | 4 +- drivers/mmc/card/block.c | 40 +- drivers/mmc/core/core.c | 49 + drivers/mmc/core/mmc.c | 37 + drivers/mmc/core/sd.c | 71 +- drivers/mmc/core/sdio.c | 13 +- drivers/mmc/host/Makefile | 6 + drivers/mmc/host/rk29_sdmmc.c | 4 + drivers/mmc/host/rk29_sdmmc_old.c | 4 + drivers/mtd/rknand/rknand_base_ko.c | 4 + drivers/net/wireless/Kconfig | 323 +- drivers/net/wireless/Makefile | 66 +- drivers/net/wireless/bcm4329/Kconfig | 2 +- drivers/net/wireless/bcm4329/Makefile | 11 +- drivers/net/wireless/bcm4329/bcmsdh_linux.c | 14 +- .../net/wireless/bcm4329/bcmsdh_sdmmc_linux.c | 10 +- drivers/net/wireless/bcm4329/bcmspibrcm.c | 1726 ++++++++++ drivers/net/wireless/bcm4329/dhd.h | 32 +- drivers/net/wireless/bcm4329/dhd_cdc.c | 3 + drivers/net/wireless/bcm4329/dhd_common.c | 141 +- .../net/wireless/bcm4329/dhd_custom_gpio.c | 95 +- drivers/net/wireless/bcm4329/dhd_linux.c | 226 +- drivers/net/wireless/bcm4329/dhd_sdio.c | 60 + .../net/wireless/bcm4329/include/epivers.h | 10 +- .../net/wireless/bcm4329/include/wlioctl.h | 25 +- drivers/net/wireless/bcm4329/linux_osl.c | 4 +- drivers/net/wireless/bcm4329/wl_iw.c | 390 +-- drivers/net/wireless/bcm4329/wl_iw.h | 61 +- drivers/power/wm831x_power.c | 705 +++- drivers/regulator/Kconfig | 7 - drivers/regulator/Makefile | 5 + drivers/regulator/core.c | 18 + drivers/regulator/wm831x-dcdc.c | 109 +- drivers/regulator/wm831x-isink.c | 23 +- drivers/regulator/wm831x-ldo.c | 96 +- drivers/rtc/Kconfig | 25 + drivers/rtc/Makefile | 3 + drivers/rtc/alarm.c | 15 + drivers/rtc/rtc-HYM8563.c | 19 +- drivers/rtc/rtc-tps65910.c | 698 ---- drivers/serial/rk29_serial.c | 834 ----- drivers/staging/Kconfig | 3 + drivers/staging/Makefile | 2 + drivers/staging/android/timed_gpio.c | 61 +- drivers/staging/android/timed_gpio.h | 1 + .../hal/os/linux/kernel/gc_hal_kernel_debug.c | 2 +- .../hal/os/linux/kernel/gc_hal_kernel_os.c | 2 +- drivers/tty/serial/Kconfig | 57 + drivers/tty/serial/Makefile | 2 + drivers/{ => tty}/serial/rk2818_serial.h | 0 drivers/{ => tty}/serial/rk_serial.c | 0 drivers/{ => tty}/serial/sc8800.c | 0 drivers/{ => tty}/serial/sc8800.h | 0 drivers/usb/Makefile | 1 + drivers/usb/core/usb.c | 1 + drivers/usb/dwc_otg/dwc_otg_hcd.c | 5 + drivers/usb/dwc_otg/dwc_otg_pcd.c | 18 +- drivers/usb/gadget/Kconfig | 18 +- drivers/usb/gadget/android.c | 4 +- drivers/usb/gadget/f_adb.c | 2 +- drivers/usb/gadget/f_mass_storage.c | 353 ++ drivers/usb/gadget/storage_common.c | 7 + drivers/usb/serial/option.c | 54 + drivers/usb/storage/usb.c | 0 drivers/video/backlight/rk29_backlight.c | 1 + drivers/video/backlight/wm831x_bl.c | 121 +- fs/fat/dir.c | 2 +- fs/fat/fatent.c | 4 +- fs/fat/inode.c | 4 +- fs/yaffs2/yaffs_mtdif2.c | 5 + fs/yaffs2/yaffs_vfs.c | 3 + include/linux/gfp.h | 2 - include/linux/i2c.h | 18 + include/linux/i2c/tps65910.h | 275 -- include/linux/mfd/wm831x/core.h | 60 + include/linux/mfd/wm831x/pdata.h | 32 + include/linux/mfd/wm8994/core.h | 54 +- include/linux/mfd/wm8994/pdata.h | 41 +- include/linux/mmc/host.h | 6 + include/linux/regulator/consumer.h | 10 + include/linux/wakelock.h | 2 + include/media/v4l2-chip-ident.h | 34 +- kernel/power/earlysuspend.c | 5 + kernel/power/process.c | 1 + kernel/power/wakelock.c | 32 +- kernel/sys.c | 33 +- sound/soc/codecs/Kconfig | 20 + sound/soc/codecs/Makefile | 10 + sound/soc/codecs/wm8900.c | 798 +++-- sound/soc/soc-cache.c | 1 + 140 files changed, 9469 insertions(+), 5111 deletions(-) delete mode 100755 arch/arm/mach-rk29/gpio.c create mode 100755 drivers/gpio/gpio-rk29.c delete mode 100644 drivers/input/misc/tps65910-pwrbutton.c delete mode 100644 drivers/mfd/tps65910-core.c mode change 100755 => 100644 drivers/mfd/wm8994-core.c mode change 100755 => 100644 drivers/misc/Kconfig mode change 100755 => 100644 drivers/misc/Makefile mode change 100644 => 100755 drivers/net/wireless/bcm4329/Makefile create mode 100644 drivers/net/wireless/bcm4329/bcmspibrcm.c delete mode 100644 drivers/rtc/rtc-tps65910.c delete mode 100755 drivers/serial/rk29_serial.c rename drivers/{ => tty}/serial/rk2818_serial.h (100%) rename drivers/{ => tty}/serial/rk_serial.c (100%) rename drivers/{ => tty}/serial/sc8800.c (100%) rename drivers/{ => tty}/serial/sc8800.h (100%) mode change 100755 => 100644 drivers/usb/core/usb.c mode change 100755 => 100644 drivers/usb/storage/usb.c mode change 100755 => 100644 include/linux/i2c.h delete mode 100644 include/linux/i2c/tps65910.h mode change 100755 => 100644 include/linux/regulator/consumer.h diff --git a/.gitignore b/.gitignore index 9dacde0a4b2d..43c7ee06e097 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ modules.builtin *.lzo *.patch *.gcno +Untitled Project.* # # Top-level generic files @@ -44,6 +45,7 @@ modules.builtin /System.map /Module.markers /Module.symvers +/kernel.img # # git files that we don't want to ignore even it they are dot-files diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 38d4c961e5af..413834f6b7bc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -862,6 +862,7 @@ config ARCH_RK29 bool "Rockchip Soc Rk29" select CPU_V7 select HAVE_CLK + select CLKDEV_LOOKUP select COMMON_CLKDEV select HAVE_SCHED_CLOCK select ARCH_HAS_CPUFREQ diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index e58603b00060..7140c2e648da 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -177,6 +177,10 @@ not_angel: #endif bl cache_on +#ifdef CONFIG_ARCH_RK29 + bl cache_off + bl cache_on +#endif restart: adr r0, LC0 ldmia r0, {r1, r2, r3, r6, r10, r11, r12} diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 4ddd0a6ac7ff..9e74d12057f1 100755 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -92,6 +92,9 @@ static void gic_mask_irq(struct irq_data *d) writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); if (gic_arch_extn.irq_mask) gic_arch_extn.irq_mask(d); +#ifdef CONFIG_ARCH_RK29 + dsb(); +#endif spin_unlock(&irq_controller_lock); } @@ -103,6 +106,9 @@ static void gic_unmask_irq(struct irq_data *d) if (gic_arch_extn.irq_unmask) gic_arch_extn.irq_unmask(d); writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); +#ifdef CONFIG_ARCH_RK29 + dsb(); +#endif spin_unlock(&irq_controller_lock); } @@ -115,6 +121,9 @@ static void gic_eoi_irq(struct irq_data *d) } writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); +#ifdef CONFIG_ARCH_RK29 + dsb(); +#endif } static int gic_set_type(struct irq_data *d, unsigned int type) @@ -203,6 +212,9 @@ static int gic_set_wake(struct irq_data *d, unsigned int on) { int ret = -ENXIO; +#ifdef CONFIG_ARCH_RK29 + return 0; +#endif if (gic_arch_extn.irq_set_wake) ret = gic_arch_extn.irq_set_wake(d, on); @@ -278,8 +290,13 @@ static void __init gic_dist_init(struct gic_chip_data *gic, * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ +#ifdef CONFIG_ARCH_RK29 + /* rk29 read GIC_DIST_CTR is 2, why? */ + gic_irqs = NR_AIC_IRQS; +#else gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; +#endif if (gic_irqs > 1020) gic_irqs = 1020; diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a5b31af5c2b8..64f12bdc46db 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg obj-y := elf.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o return_address.o setup.o signal.o \ - sys_arm.o stacktrace.o time.o traps.o + sys_arm.o stacktrace.o time.o traps.o dma.o obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0ebb2e..d9d6533da09b 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -42,7 +42,12 @@ .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 .macro pgtbl, rd, phys +#ifdef CONFIG_ARCH_RK29 + add \rd, \phys, #((TEXT_OFFSET - 0x4000) & 0xffff0000) + add \rd, \rd, #((TEXT_OFFSET - 0x4000) & 0x0000ffff) +#else add \rd, \phys, #TEXT_OFFSET - 0x4000 +#endif .endm #ifdef CONFIG_XIP_KERNEL diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile index e36d1e4d2bd3..11fbfae0c21d 100644 --- a/arch/arm/mach-rk29/Makefile +++ b/arch/arm/mach-rk29/Makefile @@ -1,4 +1,4 @@ -obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o ddr.o sram.o memcpy_dma.o reset.o +obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o ddr.o sram.o memcpy_dma.o reset.o obj-y += tests.o memtester.o obj-y += early_printk.o ifndef CONFIG_DEBUG_LL diff --git a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c index 08742acf0021..8ca56212d521 100755 --- a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c +++ b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c @@ -20,10 +20,13 @@ #include #include #include +#include #include #include #include +#ifdef CONFIG_USB_ANDROID #include +#endif #include #include @@ -2935,8 +2938,12 @@ static struct spi_board_info board_spi_devices[] = { static void __init rk29_gic_init_irq(void) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) + gic_init(0, 32, (void __iomem *)RK29_GICPERI_BASE, (void __iomem *)RK29_GICCPU_BASE); +#else gic_dist_init(0, (void __iomem *)RK29_GICPERI_BASE, 32); gic_cpu_init(0, (void __iomem *)RK29_GICCPU_BASE); +#endif } static void __init machine_rk29_init_irq(void) @@ -3016,9 +3023,11 @@ static void __init machine_rk29_mapio(void) } MACHINE_START(RK29, "RK29board") +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)) /* UART for LL DEBUG */ .phys_io = RK29_UART1_PHYS & 0xfff00000, .io_pg_offst = ((RK29_UART1_BASE) >> 18) & 0xfffc, +#endif .boot_params = RK29_SDRAM_PHYS + 0x88000, .fixup = machine_rk29_fixup, .map_io = machine_rk29_mapio, diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c index 327a321bfdcf..501fafe58b95 100755 --- a/arch/arm/mach-rk29/clock.c +++ b/arch/arm/mach-rk29/clock.c @@ -27,7 +27,11 @@ #include #include #include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +#include +#else #include +#endif #include #include #include diff --git a/arch/arm/mach-rk29/devices.c b/arch/arm/mach-rk29/devices.c index 9c51f9b87089..6e20d9290ab3 100644 --- a/arch/arm/mach-rk29/devices.c +++ b/arch/arm/mach-rk29/devices.c @@ -16,7 +16,9 @@ #include #include #include +#ifdef CONFIG_USB_ANDROID #include +#endif #include #include #include @@ -746,7 +748,7 @@ struct platform_device usb_mass_storage_device = { }; #endif - +#ifdef CONFIG_USB_ANDROID_RNDIS static struct usb_ether_platform_data rndis_pdata = { /* ethaddr is filled by board_serialno_setup */ .ethaddr = {0xf0, 0xde, 0xf1, 0x42, 0xe8, 0x10}, @@ -761,6 +763,7 @@ struct platform_device rk29_device_rndis = { .platform_data = &rndis_pdata, }, }; +#endif #ifdef CONFIG_USB11_HOST static struct resource usb11_host_resource[] = { diff --git a/arch/arm/mach-rk29/gpio.c b/arch/arm/mach-rk29/gpio.c deleted file mode 100755 index d37040a0bcbe..000000000000 --- a/arch/arm/mach-rk29/gpio.c +++ /dev/null @@ -1,617 +0,0 @@ -/* arch/arm/mach-rk29/gpio.c - * - * Copyright (C) 2010 ROCKCHIP, 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -#define to_rk29_gpio_chip(c) container_of(c, struct rk29_gpio_chip, chip) - -struct rk29_gpio_chip { - struct gpio_chip chip; - unsigned short id; - short irq; - unsigned char __iomem *regbase; /* Base of register bank */ - struct clk *clk; - u32 suspend_wakeup; - u32 saved_wakeup; -}; - -static struct lock_class_key gpio_lock_class; - -static void rk29_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip); -static void rk29_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val); -static int rk29_gpiolib_get(struct gpio_chip *chip, unsigned offset); -static int rk29_gpiolib_direction_output(struct gpio_chip *chip,unsigned offset, int val); -static int rk29_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); -static int rk29_gpiolib_PullUpDown(struct gpio_chip *chip, unsigned offset, unsigned enable); -static int rk29_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); - -#define RK29_GPIO_CHIP(ID) \ - { \ - .chip = { \ - .label = "gpio" #ID, \ - .direction_input = rk29_gpiolib_direction_input, \ - .direction_output = rk29_gpiolib_direction_output, \ - .get = rk29_gpiolib_get, \ - .set = rk29_gpiolib_set, \ - .pull_updown = rk29_gpiolib_PullUpDown, \ - .dbg_show = rk29_gpiolib_dbg_show, \ - .to_irq = rk29_gpiolib_to_irq, \ - .base = PIN_BASE + ID*NUM_GROUP, \ - .ngpio = NUM_GROUP, \ - }, \ - .id = ID, \ - .irq = IRQ_GPIO##ID, \ - .regbase = (unsigned char __iomem *) RK29_GPIO##ID##_BASE, \ - } - -static struct rk29_gpio_chip rk29gpio_chip[] = { - RK29_GPIO_CHIP(0), - RK29_GPIO_CHIP(1), - RK29_GPIO_CHIP(2), - RK29_GPIO_CHIP(3), - RK29_GPIO_CHIP(4), - RK29_GPIO_CHIP(5), - RK29_GPIO_CHIP(6), -}; - -static inline void rk29_gpio_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val) -{ - __raw_writel(val,regbase + regOff); -} - -static inline unsigned int rk29_gpio_read(unsigned char __iomem *regbase, unsigned int regOff) -{ - return __raw_readl(regbase + regOff); -} - -static inline void rk29_gpio_bitOp(unsigned char __iomem *regbase, unsigned int regOff,unsigned int mask,unsigned char opFlag) -{ - unsigned int valTemp = 0; - - if(opFlag == 0)//¶Ô¼Ä´æÆ÷ÏàӦλ½øÐÐÓë0²Ù×÷ - { - valTemp = rk29_gpio_read(regbase,regOff); - valTemp &= (~mask);; - rk29_gpio_write(regbase,regOff,valTemp); - } - else if(opFlag == 1)//¶Ô¼Ä´æÆ÷ÏàӦλ½øÐлò1²Ù×÷ - { - valTemp = rk29_gpio_read(regbase,regOff); - valTemp |= mask; - rk29_gpio_write(regbase,regOff,valTemp); - } -} - -static inline struct gpio_chip *pin_to_gpioChip(unsigned pin) -{ - if(pin < PIN_BASE) - return NULL; - - pin -= PIN_BASE; - pin /= NUM_GROUP; - if (likely(pin < MAX_BANK)) - return &(rk29gpio_chip[pin].chip); - return NULL; -} - -static inline unsigned pin_to_mask(unsigned pin) -{ - if(pin < PIN_BASE) - return 0; - pin -= PIN_BASE; - return 1ul << (pin % NUM_GROUP); -} - -static inline unsigned offset_to_mask(unsigned offset) -{ - return 1ul << (offset % NUM_GROUP); -} - -static int GPIOSetPinLevel(struct gpio_chip *chip, unsigned int mask,eGPIOPinLevel_t level) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - unsigned long flags; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - local_irq_save(flags); - rk29_gpio_bitOp(gpioRegBase,GPIO_SWPORT_DDR,mask,1); - rk29_gpio_bitOp(gpioRegBase,GPIO_SWPORT_DR,mask,level); - local_irq_restore(flags); - - return 0; -} - -static int GPIOGetPinLevel(struct gpio_chip *chip, unsigned int mask) -{ - unsigned int valTemp; - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - valTemp = rk29_gpio_read(gpioRegBase,GPIO_EXT_PORT); - return ((valTemp & mask) != 0); -} - -static int GPIOSetPinDirection(struct gpio_chip *chip, unsigned int mask,eGPIOPinDirection_t direction) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - unsigned long flags; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - local_irq_save(flags); - rk29_gpio_bitOp(gpioRegBase,GPIO_SWPORT_DDR,mask,direction); - /* Enable debounce may halt cpu on wfi, disable it by default */ - //rk29_gpio_bitOp(gpioRegBase,GPIO_DEBOUNCE,mask,1); - local_irq_restore(flags); - - return 0; -} - -static int GPIOEnableIntr(struct gpio_chip *chip, unsigned int mask) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - rk29_gpio_bitOp(gpioRegBase,GPIO_INTEN,mask,1); - - return 0; -} - -static int GPIODisableIntr(struct gpio_chip *chip, unsigned int mask) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - rk29_gpio_bitOp(gpioRegBase,GPIO_INTEN,mask,0); - - return 0; -} - -static int GPIOSetIntrType(struct gpio_chip *chip, unsigned int mask, eGPIOIntType_t IntType) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - switch ( IntType ) - { - case GPIOLevelLow: - rk29_gpio_bitOp(gpioRegBase,GPIO_INT_POLARITY,mask,0); - rk29_gpio_bitOp(gpioRegBase,GPIO_INTTYPE_LEVEL,mask,0); - break; - case GPIOLevelHigh: - rk29_gpio_bitOp(gpioRegBase,GPIO_INTTYPE_LEVEL,mask,0); - rk29_gpio_bitOp(gpioRegBase,GPIO_INT_POLARITY,mask,1); - break; - case GPIOEdgelFalling: - rk29_gpio_bitOp(gpioRegBase,GPIO_INTTYPE_LEVEL,mask,1); - rk29_gpio_bitOp(gpioRegBase,GPIO_INT_POLARITY,mask,0); - break; - case GPIOEdgelRising: - rk29_gpio_bitOp(gpioRegBase,GPIO_INTTYPE_LEVEL,mask,1); - rk29_gpio_bitOp(gpioRegBase,GPIO_INT_POLARITY,mask,1); - break; - default: - return(-1); - } - return(0); -} - -static int gpio_irq_set_wake(unsigned int irq, unsigned int on) -{ - unsigned int pin = irq_to_gpio(irq); - unsigned bank = (pin - PIN_BASE) / NUM_GROUP; - struct rk29_gpio_chip *rk29_gpio; - unsigned mask = pin_to_mask(pin); - - if (unlikely(bank >= MAX_BANK)) - return -EINVAL; - - rk29_gpio = &rk29gpio_chip[bank]; - if (on) - rk29_gpio->suspend_wakeup |= mask; - else - rk29_gpio->suspend_wakeup &= ~mask; - - set_irq_wake(rk29_gpio->irq, on); - - return 0; -} - -static int gpio_irq_type(unsigned irq, unsigned type) -{ - unsigned int pin = irq_to_gpio(irq); - struct gpio_chip *chip = pin_to_gpioChip(pin); - unsigned mask = pin_to_mask(pin); - - if(!chip || !mask) - return -EINVAL; - //ÉèÖÃΪÖжÏ֮ǰ£¬±ØÐëÏÈÉèÖÃΪÊäÈë״̬ - GPIOSetPinDirection(chip,mask,GPIO_IN); - - switch (type) { - case IRQ_TYPE_NONE: - break; - case IRQ_TYPE_EDGE_RISING: - GPIOSetIntrType(chip,mask,GPIOEdgelRising); - break; - case IRQ_TYPE_EDGE_FALLING: - GPIOSetIntrType(chip,mask,GPIOEdgelFalling); - break; - case IRQ_TYPE_EDGE_BOTH: - break; - case IRQ_TYPE_LEVEL_HIGH: - GPIOSetIntrType(chip,mask,GPIOLevelHigh); - break; - case IRQ_TYPE_LEVEL_LOW: - GPIOSetIntrType(chip,mask,GPIOLevelLow); - break; - default: - return -EINVAL; - } - - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __set_irq_handler_unlocked(irq, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __set_irq_handler_unlocked(irq, handle_edge_irq); - - return 0; -} - -static int GPIOAckIntr(struct gpio_chip *chip, unsigned int mask) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *gpioRegBase = rk29_gpio->regbase; - - if(!rk29_gpio || !gpioRegBase) - { - return -1; - } - - rk29_gpio_bitOp(gpioRegBase,GPIO_PORTS_EOI,mask,1); - return 0; -} - -static void gpio_irq_unmask(unsigned irq) -{ - unsigned int pin = irq_to_gpio(irq); - struct gpio_chip *chip = pin_to_gpioChip(pin); - unsigned mask = pin_to_mask(pin); - - if(chip && mask) - GPIOEnableIntr(chip,mask); -} - -static void gpio_irq_mask(unsigned irq) -{ - unsigned int pin = irq_to_gpio(irq); - struct gpio_chip *chip = pin_to_gpioChip(pin); - unsigned mask = pin_to_mask(pin); - - if(chip && mask) - GPIODisableIntr(chip,mask); -} - -static void gpio_ack_irq(u32 irq) -{ - unsigned int pin = irq_to_gpio(irq); - struct gpio_chip *chip = pin_to_gpioChip(pin); - unsigned mask = pin_to_mask(pin); - - if(chip && mask) - GPIOAckIntr(chip,mask); -} - -static int GPIOPullUpDown(struct gpio_chip *chip, unsigned int offset, unsigned enable) -{ - unsigned int temp = 0; - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - unsigned char __iomem *pGrfRegBase = (unsigned char __iomem *)RK29_GRF_BASE; - unsigned long flags; - - if(!rk29_gpio || !pGrfRegBase) - { - return -1; - } - - if(offset >= 32) - { - return -1; - } - - local_irq_save(flags); - temp = __raw_readl(pGrfRegBase + 0x78 +(rk29_gpio->id)*4); - if(!enable) - temp |= 1<id)*4); - local_irq_restore(flags); - - return 0; -} - - -static int rk29_gpiolib_direction_output(struct gpio_chip *chip,unsigned offset, int val) -{ - unsigned mask = offset_to_mask(offset); - - if(GPIOSetPinDirection(chip,mask,GPIO_OUT) == 0) - { - return GPIOSetPinLevel(chip,mask,val); - } - else - { - return -1; - } -} - -static int rk29_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset) -{ - unsigned mask = offset_to_mask(offset); - - return GPIOSetPinDirection(chip,mask,GPIO_IN); -} - - -static int rk29_gpiolib_get(struct gpio_chip *chip, unsigned offset) -{ - unsigned mask = offset_to_mask(offset); - - return GPIOGetPinLevel(chip,mask); -} - -static void rk29_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) -{ - unsigned mask = offset_to_mask(offset); - - GPIOSetPinLevel(chip,mask,val); -} - -static int rk29_gpiolib_PullUpDown(struct gpio_chip *chip, unsigned offset, unsigned enable) -{ - return GPIOPullUpDown(chip, offset, enable); -} - -static int rk29_gpiolib_to_irq(struct gpio_chip *chip, - unsigned offset) -{ - struct rk29_gpio_chip *rk29_gpio = to_rk29_gpio_chip(chip); - - if(!rk29_gpio) - { - return -1; - } - - return offset + NR_IRQS; -} - -static void rk29_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) -{ - - int i; - - for (i = 0; i < chip->ngpio; i++) { - unsigned pin = chip->base + i; - struct gpio_chip *chip = pin_to_gpioChip(pin); - unsigned mask = pin_to_mask(pin); - const char *gpio_label; - - if(!chip ||!mask) - return; - - gpio_label = gpiochip_is_requested(chip, i); - if (gpio_label) { - seq_printf(s, "[%s] GPIO%s%d: ", - gpio_label, chip->label, i); - - if (!chip || !mask) - { - seq_printf(s, "!chip || !mask\t"); - return; - } - - GPIOSetPinDirection(chip,mask,GPIO_IN); - seq_printf(s, "pin=%d,level=%d\t", pin,GPIOGetPinLevel(chip,mask)); - seq_printf(s, "\t"); - } - } -} - -static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) -{ - unsigned gpio_irq; - struct rk29_gpio_chip *rk29_gpio; - u32 isr; - - rk29_gpio = get_irq_chip_data(irq+13); - - // temporarily mask parent IRQ - desc->chip->mask(irq); - if(desc->chip->ack) - desc->chip->ack(irq); - - isr = rk29_gpio_read(rk29_gpio->regbase, GPIO_INT_STATUS); - - gpio_irq = gpio_to_irq(rk29_gpio->chip.base); - - while (isr) { - int irqoffset = fls(isr) - 1; - generic_handle_irq(gpio_irq + irqoffset); - isr &= ~(1 << irqoffset); - } - - desc->chip->unmask(irq); - /* now it may re-trigger */ -} - -static struct irq_chip rk29gpio_irqchip = { - .name = "GPIO", - .ack = gpio_ack_irq, - .disable = gpio_irq_mask, - .mask = gpio_irq_mask, - .unmask = gpio_irq_unmask, - .set_type = gpio_irq_type, - .set_wake = gpio_irq_set_wake, -}; - -static void __init rk29_gpio_irq_setup(void) -{ - unsigned int i, j, pin; - struct rk29_gpio_chip *this; - - this = rk29gpio_chip; - pin = NR_AIC_IRQS; - for (i = 0; i < MAX_BANK; i++) { - rk29_gpio_write(this->regbase,GPIO_INTEN,0); - for (j = 0; j < 32; j++) { - lockdep_set_class(&irq_desc[pin+j].lock, &gpio_lock_class); - set_irq_chip(pin+j, &rk29gpio_irqchip); - set_irq_handler(pin+j, handle_level_irq); - set_irq_flags(pin+j, IRQF_VALID); - } - - set_irq_chip_data(NR_AIC_IRQS + this->id, this); - set_irq_chained_handler(this->irq, gpio_irq_handler); - this += 1; - pin += 32; - } - printk("rk29_gpio_irq_setup: %d gpio irqs in 7 banks\n", pin - PIN_BASE); -} - -void __init rk29_gpio_init(void) -{ - unsigned i; - struct rk29_gpio_chip *rk29_gpio; - - for (i = 0; i < MAX_BANK; i++) { - rk29_gpio = &rk29gpio_chip[i]; - rk29_gpio->clk = clk_get(NULL, rk29_gpio->chip.label); - clk_enable(rk29_gpio->clk); - gpiochip_add(&rk29_gpio->chip); - } - rk29_gpio_irq_setup(); -} - -__weak void rk29_setgpio_suspend_board(void) -{ -} - -__weak void rk29_setgpio_resume_board(void) -{ -} - -#ifdef CONFIG_PM -static int rk29_gpio_suspend(struct sys_device *dev, pm_message_t mesg) -{ - unsigned i; - - rk29_setgpio_suspend_board(); - - for (i = 0; i < MAX_BANK; i++) { - struct rk29_gpio_chip *rk29_gpio = &rk29gpio_chip[i]; - - rk29_gpio->saved_wakeup = rk29_gpio_read(rk29_gpio->regbase, GPIO_INTEN); - rk29_gpio_write(rk29_gpio->regbase, GPIO_INTEN, rk29_gpio->suspend_wakeup); - - if (!rk29_gpio->suspend_wakeup) - clk_disable(rk29_gpio->clk); - } - - return 0; -} - -static int rk29_gpio_resume(struct sys_device *dev) -{ - unsigned i; - for (i = 0; i < MAX_BANK; i++) { - struct rk29_gpio_chip *rk29_gpio = &rk29gpio_chip[i]; - - if (!rk29_gpio->suspend_wakeup) - clk_enable(rk29_gpio->clk); - - /* keep enable for resume irq */ - rk29_gpio_write(rk29_gpio->regbase, GPIO_INTEN, rk29_gpio->saved_wakeup | (rk29_gpio->suspend_wakeup & rk29_gpio_read(rk29_gpio->regbase, GPIO_INT_STATUS))); - } - rk29_setgpio_resume_board(); - return 0; -} - -static struct sysdev_class rk29_gpio_sysclass = { - .name = "gpio", - .suspend = rk29_gpio_suspend, - .resume = rk29_gpio_resume, -}; - -static struct sys_device rk29_gpio_device = { - .cls = &rk29_gpio_sysclass, -}; - -static int __init rk29_gpio_sysinit(void) -{ - int ret = sysdev_class_register(&rk29_gpio_sysclass); - if (ret == 0) - ret = sysdev_register(&rk29_gpio_device); - return ret; -} - -arch_initcall(rk29_gpio_sysinit); -#endif diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index 7cec44db21f5..d56c42310dba 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -124,6 +124,7 @@ struct rk29_bl_info{ unsigned int delay_ms; /* in milliseconds */ }; +#ifndef _LINUX_WLAN_PLAT_H_ struct wifi_platform_data { int (*set_power)(int val); int (*set_reset)(int val); @@ -131,6 +132,7 @@ struct wifi_platform_data { void *(*mem_prealloc)(int section, unsigned long size); int (*get_mac_addr)(unsigned char *buf); }; +#endif struct rk29_sdmmc_platform_data { unsigned int host_caps; diff --git a/arch/arm/mach-rk29/include/mach/debug-macro.S b/arch/arm/mach-rk29/include/mach/debug-macro.S index 9c86875157c7..a58b1399e13c 100644 --- a/arch/arm/mach-rk29/include/mach/debug-macro.S +++ b/arch/arm/mach-rk29/include/mach/debug-macro.S @@ -18,12 +18,12 @@ #include #include - /* note, for the boot process to work we have to keep the UART - * virtual address aligned to an 1MiB boundary for the L1 - * mapping the head code makes. We keep the UART virtual address - * aligned and add in the offset when we load the value here. - */ - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + .macro addruart, rp, rv + ldr \rp, = RK29_UART1_PHYS + ldr \rv, = RK29_UART1_BASE + .endm +#else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) .macro addruart, rx, tmp #else @@ -34,6 +34,7 @@ ldreq \rx, = RK29_UART1_PHYS ldrne \rx, = RK29_UART1_BASE .endm +#endif #define UART_SHIFT 2 #include diff --git a/arch/arm/mach-rk29/include/mach/gpio.h b/arch/arm/mach-rk29/include/mach/gpio.h index 1efd3f0ce0b4..a0f0309cbe8f 100755 --- a/arch/arm/mach-rk29/include/mach/gpio.h +++ b/arch/arm/mach-rk29/include/mach/gpio.h @@ -14,7 +14,8 @@ */ #ifndef __ARCH_ARM_MACH_RK29_GPIO_H #define __ARCH_ARM_MACH_RK29_GPIO_H -#include + +#include typedef enum eGPIOPinLevel { @@ -67,7 +68,7 @@ typedef enum GPIOIntType { #define RK29_ID_GPIO6 6 #define NUM_GROUP 32 -#define PIN_BASE 0 +#define PIN_BASE NR_AIC_IRQS #define MAX_BANK 7 #define RK29_TOTOL_GPIO_NUM (NUM_GROUP*MAX_BANK) @@ -105,7 +106,7 @@ typedef enum GPIOIntType { #endif //¶¨ÒåGPIOµÄPIN¿Ú×î´óÊýÄ¿¡£CONFIG_SPI_FPGA_GPIO_NUM±íʾFPGAµÄPIN½ÅÊý¡£ -#define ARCH_NR_GPIOS (RK29_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM+CONFIG_GPIO_WM8994_NUM) +#define ARCH_NR_GPIOS (PIN_BASE + RK29_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM+CONFIG_GPIO_WM8994_NUM) #define RK29_PIN0_PA0 (0*NUM_GROUP + PIN_BASE + 0) @@ -506,7 +507,6 @@ extern void __init rk29_gpio_init(void); #include #include /* cansleep wrappers */ -#include #define gpio_get_value __gpio_get_value #define gpio_set_value __gpio_set_value @@ -514,15 +514,14 @@ extern void __init rk29_gpio_init(void); static inline int gpio_to_irq(unsigned gpio) { - return (gpio + NR_AIC_IRQS); + return gpio - PIN_BASE + NR_AIC_IRQS; } static inline int irq_to_gpio(unsigned irq) { - return (irq - NR_AIC_IRQS); + return irq - NR_AIC_IRQS + PIN_BASE; } -#endif /* __ASSEMBLY__ */ - -#endif - +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/arm/mach-rk29/vpu_service.c b/arch/arm/mach-rk29/vpu_service.c index b3242e0e9dce..eb1eda5a8358 100644 --- a/arch/arm/mach-rk29/vpu_service.c +++ b/arch/arm/mach-rk29/vpu_service.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 089c0b5e454f..628198281cea 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -375,6 +375,16 @@ __v7_setup: ALT_SMP(orr r8, r8, #TTB_FLAGS_SMP) ALT_UP(orr r8, r8, #TTB_FLAGS_UP) mcr p15, 0, r8, c2, c0, 1 @ load TTB1 +#ifdef CONFIG_ARCH_RK29 + /* Setup L2 cache */ + mrc p15, 1, r5, c9, c0, 2 + bic r5, r5, #1 << 29 @ L2 data RAM read multiplexer select: 0 = two cycles + bic r5, r5, #7 << 6 + bic r5, r5, #15 + orr r5, r5, #2 << 6 @ Tag RAM latency: b010 = 3 cycles + orr r5, r5, #3 @ Data RAM latency: b0011 = 4 cycles + mcr p15, 1, r5, c9, c0, 2 +#endif ldr r5, =PRRR @ PRRR ldr r6, =NMRR @ NMRR mcr p15, 0, r5, c10, c2, 0 @ write PRRR diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 3b3776d0a1a7..9afa8404fd79 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -569,7 +569,8 @@ smdkv310 MACH_SMDKV310 SMDKV310 2925 siemens_l0 MACH_SIEMENS_L0 SIEMENS_L0 2926 ventana MACH_VENTANA VENTANA 2927 wm8505_7in_netbook MACH_WM8505_7IN_NETBOOK WM8505_7IN_NETBOOK 2928 -ec4350sdb MACH_EC4350SDB EC4350SDB 2929 +rk29 MACH_RK29 RK29 2929 +#ec4350sdb MACH_EC4350SDB EC4350SDB 2929 mimas MACH_MIMAS MIMAS 2930 titan MACH_TITAN TITAN 2931 craneboard MACH_CRANEBOARD CRANEBOARD 2932 diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 9897dcfc16d6..f879b7ac2a4e 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -206,6 +206,25 @@ ENTRY(vfp_save_state) mov pc, lr ENDPROC(vfp_save_state) +#ifdef CONFIG_ARCH_RK29 +ENTRY(vfp_load_state) + @ Save the current VFP state + @ r0 - save location + @ r1 - FPEXC + DBGSTR1 "save VFP state %p", r0 + VFPFLDMIA r0, r2 @ save the working registers + ldmia r0, {r1,r2,r3,r12} + tst r1, #FPEXC_EX @ is there additional state to save? + beq 1f + tst r1, #FPEXC_FP2V @ is there an FPINST2 to read? + beq 1f +1: + VFPFMXR FPSCR, r2 + VFPFMXR FPEXC, r1 + mov pc, lr +ENDPROC(vfp_load_state) +#endif + .align last_VFP_context_address: .word last_VFP_context diff --git a/drivers/Kconfig b/drivers/Kconfig index d0258eb26d8b..a95047a6fe0a 100755 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,10 @@ source "drivers/i2c/Kconfig" source "drivers/spi/Kconfig" +source "drivers/adc/Kconfig" + +source "drivers/headset_observe/Kconfig" + source "drivers/pps/Kconfig" source "drivers/ptp/Kconfig" @@ -128,4 +132,12 @@ source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" +source "drivers/cmmb/Kconfig" + +source "drivers/testcode/Kconfig" + +source "drivers/smc/Kconfig" + +source "drivers/cir/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 4ea4ac9e57af..8e593d120cab 100755 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_TARGET_CORE) += target/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_SPI) += spi/ +obj-y += headset_observe/ obj-y += net/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_FUSION) += message/ @@ -77,6 +78,7 @@ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_RTC_LIB) += rtc/ obj-y += i2c/ media/ +obj-y += adc/ obj-$(CONFIG_PPS) += pps/ obj-$(CONFIG_PTP_1588_CLOCK) += ptp/ obj-$(CONFIG_W1) += w1/ @@ -123,3 +125,8 @@ obj-y += ieee802154/ obj-y += clk/ obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ +obj-$(CONFIG_CMMB) += cmmb/ +obj-$(CONFIG_TEST_CODE) += testcode/ +obj-y += smc/ +obj-y += cir/ +obj-y += dbg/ diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 4282d442d352..0a02634fb0f1 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_ARCH_RK29 +#include +#endif #include "../base.h" #include "power.h" @@ -608,6 +611,9 @@ static void dpm_drv_timeout(unsigned long data) printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev), (dev->driver ? dev->driver->name : "no driver")); +#ifdef CONFIG_ARCH_RK29 + resume_console(); +#endif printk(KERN_EMERG "dpm suspend stack:\n"); show_stack(tsk, NULL); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 891360edecdd..ce0b7a41f73c 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -32,8 +32,13 @@ #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (100000) +#ifdef CONFIG_ARCH_RK29 +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define MICRO_FREQUENCY_UP_THRESHOLD (80) +#else #define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) #define MICRO_FREQUENCY_UP_THRESHOLD (95) +#endif #define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) #define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9fed5e895514..3b8f6043bf0c 100755 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -268,13 +268,6 @@ config GPIO_TWL4030 Say yes here to access the GPIO signals of various multi-function power management chips from Texas Instruments. -config GPIO_TPS65910 - bool "TPS65910 GPIOs" - depends on TPS65910_CORE - help - Say yes here to access the GPIO signal of TPS65910x multi-function - power management chips from Texas Instruments. - config GPIO_WM831X tristate "WM831x GPIOs" depends on MFD_WM831X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 862b7b266897..c579c8bf5dc8 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o -obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_CS5535) += cs5535-gpio.o @@ -46,6 +45,7 @@ obj-$(CONFIG_GPIO_SCH) += sch_gpio.o obj-$(CONFIG_MACH_U300) += gpio-u300.o obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o +obj-$(CONFIG_ARCH_RK29) += gpio-rk29.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/gpio-rk29.c b/drivers/gpio/gpio-rk29.c new file mode 100755 index 000000000000..9609618a5c24 --- /dev/null +++ b/drivers/gpio/gpio-rk29.c @@ -0,0 +1,484 @@ +/* arch/arm/mach-rk29/gpio.c + * + * Copyright (C) 2010 ROCKCHIP, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAX_PIN RK29_PIN6_PD7 + +#define to_rk29_gpio_bank(c) container_of(c, struct rk29_gpio_bank, chip) + +struct rk29_gpio_bank { + struct gpio_chip chip; + unsigned short id; + short irq; + void __iomem *regbase; /* Base of register bank */ + struct clk *clk; + u32 suspend_wakeup; + u32 saved_wakeup; + spinlock_t lock; +}; + +static struct lock_class_key gpio_lock_class; + +static void rk29_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip); +static void rk29_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val); +static int rk29_gpiolib_get(struct gpio_chip *chip, unsigned offset); +static int rk29_gpiolib_direction_output(struct gpio_chip *chip,unsigned offset, int val); +static int rk29_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); +static int rk29_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable); +static int rk29_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); + +#define RK29_GPIO_BANK(ID) \ + { \ + .chip = { \ + .label = "gpio" #ID, \ + .direction_input = rk29_gpiolib_direction_input, \ + .direction_output = rk29_gpiolib_direction_output, \ + .get = rk29_gpiolib_get, \ + .set = rk29_gpiolib_set, \ + .pull_updown = rk29_gpiolib_pull_updown, \ + .dbg_show = rk29_gpiolib_dbg_show, \ + .to_irq = rk29_gpiolib_to_irq, \ + .base = PIN_BASE + ID*NUM_GROUP, \ + .ngpio = NUM_GROUP, \ + }, \ + .id = ID, \ + .irq = IRQ_GPIO##ID, \ + .regbase = (unsigned char __iomem *) RK29_GPIO##ID##_BASE, \ + } + +static struct rk29_gpio_bank rk29_gpio_banks[] = { + RK29_GPIO_BANK(0), + RK29_GPIO_BANK(1), + RK29_GPIO_BANK(2), + RK29_GPIO_BANK(3), + RK29_GPIO_BANK(4), + RK29_GPIO_BANK(5), + RK29_GPIO_BANK(6), +}; + +static inline void rk29_gpio_bit_op(void __iomem *regbase, unsigned int offset, u32 bit, unsigned char flag) +{ + u32 val = __raw_readl(regbase + offset); + if (flag) + val |= bit; + else + val &= ~bit; + __raw_writel(val, regbase + offset); +} + +static inline struct gpio_chip *pin_to_gpio_chip(unsigned pin) +{ + if (pin < PIN_BASE || pin > MAX_PIN) + return NULL; + + pin -= PIN_BASE; + pin /= NUM_GROUP; + if (likely(pin < ARRAY_SIZE(rk29_gpio_banks))) + return &(rk29_gpio_banks[pin].chip); + return NULL; +} + +static inline unsigned gpio_to_bit(unsigned gpio) +{ + gpio -= PIN_BASE; + return 1u << (gpio % NUM_GROUP); +} + +static inline unsigned offset_to_bit(unsigned offset) +{ + return 1u << offset; +} + +static void GPIOSetPinLevel(void __iomem *regbase, unsigned int bit, eGPIOPinLevel_t level) +{ + rk29_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, 1); + rk29_gpio_bit_op(regbase, GPIO_SWPORT_DR, bit, level); +} + +static int GPIOGetPinLevel(void __iomem *regbase, unsigned int bit) +{ + return ((__raw_readl(regbase + GPIO_EXT_PORT) & bit) != 0); +} + +static void GPIOSetPinDirection(void __iomem *regbase, unsigned int bit, eGPIOPinDirection_t direction) +{ + rk29_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, direction); + /* Enable debounce may halt cpu on wfi, disable it by default */ + //rk29_gpio_bit_op(regbase, GPIO_DEBOUNCE, bit, 1); +} + +static void GPIOEnableIntr(void __iomem *regbase, unsigned int bit) +{ + rk29_gpio_bit_op(regbase, GPIO_INTEN, bit, 1); +} + +static void GPIODisableIntr(void __iomem *regbase, unsigned int bit) +{ + rk29_gpio_bit_op(regbase, GPIO_INTEN, bit, 0); +} + +static void GPIOAckIntr(void __iomem *regbase, unsigned int bit) +{ + rk29_gpio_bit_op(regbase, GPIO_PORTS_EOI, bit, 1); +} + +static void GPIOSetIntrType(void __iomem *regbase, unsigned int bit, eGPIOIntType_t type) +{ + switch (type) { + case GPIOLevelLow: + rk29_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); + rk29_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); + break; + case GPIOLevelHigh: + rk29_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); + rk29_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); + break; + case GPIOEdgelFalling: + rk29_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); + rk29_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); + break; + case GPIOEdgelRising: + rk29_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); + rk29_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); + break; + } +} + +static int rk29_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct rk29_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + eGPIOIntType_t int_type; + unsigned long flags; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + int_type = GPIOEdgelRising; + break; + case IRQ_TYPE_EDGE_FALLING: + int_type = GPIOEdgelFalling; + break; + case IRQ_TYPE_LEVEL_HIGH: + int_type = GPIOLevelHigh; + break; + case IRQ_TYPE_LEVEL_LOW: + int_type = GPIOLevelLow; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&bank->lock, flags); + //ÉèÖÃΪÖжÏ֮ǰ£¬±ØÐëÏÈÉèÖÃΪÊäÈë״̬ + GPIOSetPinDirection(bank->regbase, bit, GPIO_IN); + GPIOSetIntrType(bank->regbase, bit, int_type); + spin_unlock_irqrestore(&bank->lock, flags); + + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + __irq_set_handler_locked(d->irq, handle_level_irq); + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __irq_set_handler_locked(d->irq, handle_edge_irq); + + return 0; +} + +static int rk29_gpio_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct rk29_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + if (on) + bank->suspend_wakeup |= bit; + else + bank->suspend_wakeup &= ~bit; + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static void rk29_gpio_irq_unmask(struct irq_data *d) +{ + struct rk29_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOEnableIntr(bank->regbase, bit); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static void rk29_gpio_irq_mask(struct irq_data *d) +{ + struct rk29_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIODisableIntr(bank->regbase, bit); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static void rk29_gpio_irq_ack(struct irq_data *d) +{ + struct rk29_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + + GPIOAckIntr(bank->regbase, bit); +} + +static int rk29_gpiolib_direction_output(struct gpio_chip *chip, unsigned offset, int val) +{ + struct rk29_gpio_bank *bank = to_rk29_gpio_bank(chip); + u32 bit = offset_to_bit(offset); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinDirection(bank->regbase, bit, GPIO_OUT); + GPIOSetPinLevel(bank->regbase, bit, val); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + +static int rk29_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset) +{ + struct rk29_gpio_bank *bank = to_rk29_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinDirection(bank->regbase, offset_to_bit(offset), GPIO_IN); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + + +static int rk29_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + return GPIOGetPinLevel(to_rk29_gpio_bank(chip)->regbase, offset_to_bit(offset)); +} + +static void rk29_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct rk29_gpio_bank *bank = to_rk29_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinLevel(bank->regbase, offset_to_bit(offset), val); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static int rk29_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable) +{ + struct rk29_gpio_bank *bank = to_rk29_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + rk29_gpio_bit_op((void *__iomem) RK29_GRF_BASE, 0x78 + bank->id * 4, offset_to_bit(offset), !enable); + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static int rk29_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return chip->base + offset; +} + +static void rk29_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ +#if 0 + int i; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + struct gpio_chip *chip = pin_to_gpioChip(pin); + u32 bit = pin_to_bit(pin); + const char *gpio_label; + + if(!chip ||!bit) + return; + + gpio_label = gpiochip_is_requested(chip, i); + if (gpio_label) { + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + + if (!chip || !bit) + { + seq_printf(s, "!chip || !bit\t"); + return; + } + + GPIOSetPinDirection(chip,bit,GPIO_IN); + seq_printf(s, "pin=%d,level=%d\t", pin,GPIOGetPinLevel(chip,bit)); + seq_printf(s, "\t"); + } + } +#endif +} + +static void rk29_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct rk29_gpio_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned gpio_irq; + u32 isr, ilr; + unsigned pin; + unsigned unmasked = 0; + + chained_irq_enter(chip, desc); + + isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); + ilr = __raw_readl(bank->regbase + GPIO_INTTYPE_LEVEL); + + gpio_irq = gpio_to_irq(bank->chip.base); + + while (isr) { + pin = fls(isr) - 1; + /* if gpio is edge triggered, clear condition + * before executing the hander so that we don't + * miss edges + */ + if (ilr & (1 << pin)) { + unmasked = 1; + chained_irq_exit(chip, desc); + } + + generic_handle_irq(gpio_irq + pin); + isr &= ~(1 << pin); + } + + if (!unmasked) + chained_irq_exit(chip, desc); +} + +static struct irq_chip rk29_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = rk29_gpio_irq_ack, + .irq_disable = rk29_gpio_irq_mask, + .irq_mask = rk29_gpio_irq_mask, + .irq_unmask = rk29_gpio_irq_unmask, + .irq_set_type = rk29_gpio_irq_set_type, + .irq_set_wake = rk29_gpio_irq_set_wake, +}; + +void __init rk29_gpio_init(void) +{ + unsigned int i, j, pin; + struct rk29_gpio_bank *bank; + + bank = rk29_gpio_banks; + pin = PIN_BASE; + + for (i = 0; i < ARRAY_SIZE(rk29_gpio_banks); i++, bank++, pin += 32) { + spin_lock_init(&bank->lock); + bank->clk = clk_get(NULL, bank->chip.label); + clk_enable(bank->clk); + gpiochip_add(&bank->chip); + + __raw_writel(0, bank->regbase + GPIO_INTEN); + for (j = 0; j < 32; j++) { + unsigned int irq = gpio_to_irq(pin + j); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, bank); + irq_set_chip_and_handler(irq, &rk29_gpio_irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + + irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler(bank->irq, rk29_gpio_irq_handler); + } + printk("%s: %d gpio irqs in %d banks\n", __func__, pin - PIN_BASE, ARRAY_SIZE(rk29_gpio_banks)); +} + +#ifdef CONFIG_PM +__weak void rk29_setgpio_suspend_board(void) +{ +} + +__weak void rk29_setgpio_resume_board(void) +{ +} + +static int rk29_gpio_suspend(void) +{ + unsigned i; + + rk29_setgpio_suspend_board(); + + for (i = 0; i < ARRAY_SIZE(rk29_gpio_banks); i++) { + struct rk29_gpio_bank *bank = &rk29_gpio_banks[i]; + + bank->saved_wakeup = __raw_readl(bank->regbase + GPIO_INTEN); + __raw_writel(bank->suspend_wakeup, bank->regbase + GPIO_INTEN); + + if (!bank->suspend_wakeup) + clk_disable(bank->clk); + } + + return 0; +} + +static void rk29_gpio_resume(void) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(rk29_gpio_banks); i++) { + struct rk29_gpio_bank *bank = &rk29_gpio_banks[i]; + u32 isr; + + if (!bank->suspend_wakeup) + clk_enable(bank->clk); + + /* keep enable for resume irq */ + isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); + __raw_writel(bank->saved_wakeup | (bank->suspend_wakeup & isr), bank->regbase + GPIO_INTEN); + } + + rk29_setgpio_resume_board(); +} + +static struct syscore_ops rk29_gpio_syscore_ops = { + .suspend = rk29_gpio_suspend, + .resume = rk29_gpio_resume, +}; + +static int __init rk29_gpio_sysinit(void) +{ + register_syscore_ops(&rk29_gpio_syscore_ops); + return 0; +} + +arch_initcall(rk29_gpio_sysinit); +#endif diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a971e3d043ba..05c523cd2694 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1429,6 +1429,8 @@ int gpio_direction_output(unsigned gpio, int value) spin_lock_irqsave(&gpio_lock, flags); + if (value !=0 && value !=1) + goto fail; if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; @@ -1475,6 +1477,67 @@ fail: } EXPORT_SYMBOL_GPL(gpio_direction_output); +/* +gpio pull up or pull down +value = 0, normal +value = 1, pull up +value = 2, pull down +*/ +int gpio_pull_updown(unsigned gpio, unsigned value) +{ + unsigned long flags; + struct gpio_chip *chip; + struct gpio_desc *desc = &gpio_desc[gpio]; + int status = -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); + + if (value >3) + goto fail; + if (!gpio_is_valid(gpio)) + goto fail; + chip = desc->chip; + if (!chip || !chip->get || !chip->pull_updown) + goto fail; + gpio -= chip->base; + if (gpio >= chip->ngpio) + goto fail; + status = gpio_ensure_requested(desc, gpio); + if (status < 0) + goto fail; + + /* now we know the gpio is valid and chip won't vanish */ + + spin_unlock_irqrestore(&gpio_lock, flags); + + might_sleep_if(extra_checks && chip->can_sleep); + + if (status) { + status = chip->request(chip, gpio); + if (status < 0) { + pr_debug("GPIO-%d: chip request fail, %d\n", + chip->base + gpio, status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ + goto lose; + } + } + status = chip->pull_updown(chip, gpio,value); + if (status == 0) + clear_bit(FLAG_IS_OUT, &desc->flags); + +lose: + return status; +fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) + pr_debug("%s: gpio-%d status %d\n", + __func__, gpio, status); + return status; +} +EXPORT_SYMBOL_GPL(gpio_pull_updown); + /** * gpio_set_debounce - sets @debounce time for a @gpio * @gpio: the gpio to set debounce time @@ -1555,6 +1618,8 @@ int __gpio_get_value(unsigned gpio) struct gpio_chip *chip; int value; + if (!gpio_is_valid(gpio)) + return -1; chip = gpio_to_chip(gpio); WARN_ON(chip->can_sleep); value = chip->get ? chip->get(chip, gpio - chip->base) : 0; @@ -1576,6 +1641,10 @@ void __gpio_set_value(unsigned gpio, int value) { struct gpio_chip *chip; + if(value !=0 && value !=1) + return; + if (!gpio_is_valid(gpio)) + return; chip = gpio_to_chip(gpio); WARN_ON(chip->can_sleep); trace_gpio_value(gpio, 0, value); @@ -1614,9 +1683,13 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep); int __gpio_to_irq(unsigned gpio) { struct gpio_chip *chip; - + + if (!gpio_is_valid(gpio)) + return -1; + chip = gpio_to_chip(gpio); - return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; + + return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -1; } EXPORT_SYMBOL_GPL(__gpio_to_irq); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index be7a00c60e55..45b2c77ca6c8 100755 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1426,8 +1426,9 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } } EXPORT_SYMBOL(i2c_transfer); + #if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29) -int i2c_master_send(struct i2c_client *client,const char *buf ,int count) +int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap=client->adapter; @@ -1445,7 +1446,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) } EXPORT_SYMBOL(i2c_master_send); -int i2c_master_recv(struct i2c_client *client, char *buf ,int count) +int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; @@ -1464,7 +1465,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) } EXPORT_SYMBOL(i2c_master_recv); -int i2c_master_normal_send(struct i2c_client *client,const char *buf ,int count, int scl_rate) +int i2c_master_normal_send(const struct i2c_client *client, const char *buf, int count, int scl_rate) { int ret; struct i2c_adapter *adap=client->adapter; @@ -1482,7 +1483,7 @@ int i2c_master_normal_send(struct i2c_client *client,const char *buf ,int count, } EXPORT_SYMBOL(i2c_master_normal_send); -int i2c_master_normal_recv(struct i2c_client *client, char *buf ,int count, int scl_rate) +int i2c_master_normal_recv(const struct i2c_client *client, char *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; @@ -1501,7 +1502,7 @@ int i2c_master_normal_recv(struct i2c_client *client, char *buf ,int count, int } EXPORT_SYMBOL(i2c_master_normal_recv); -int i2c_master_reg8_send(struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate) +int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; @@ -1526,7 +1527,7 @@ int i2c_master_reg8_send(struct i2c_client *client, const char reg, const char * } EXPORT_SYMBOL(i2c_master_reg8_send); -int i2c_master_reg8_recv(struct i2c_client *client, const char reg, char *buf, int count, int scl_rate) +int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msgs[2]; @@ -1554,13 +1555,13 @@ int i2c_master_reg8_recv(struct i2c_client *client, const char reg, char *buf, i EXPORT_SYMBOL(i2c_master_reg8_recv); -int i2c_master_reg8_direct_send(struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate) +int i2c_master_reg8_direct_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate) { return i2c_master_reg8_send(client, reg, buf, count, scl_rate); } EXPORT_SYMBOL(i2c_master_reg8_direct_send); -int i2c_master_reg8_direct_recv(struct i2c_client *client, const char reg, char *buf, int count, int scl_rate) +int i2c_master_reg8_direct_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; @@ -1581,7 +1582,7 @@ int i2c_master_reg8_direct_recv(struct i2c_client *client, const char reg, char } EXPORT_SYMBOL(i2c_master_reg8_direct_recv); -int i2c_master_reg16_send(struct i2c_client *client, const short regs, const short *buf, int count, int scl_rate) +int i2c_master_reg16_send(const struct i2c_client *client, const short regs, const short *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; @@ -1605,7 +1606,7 @@ int i2c_master_reg16_send(struct i2c_client *client, const short regs, const sho } EXPORT_SYMBOL(i2c_master_reg16_send); -int i2c_master_reg16_recv(struct i2c_client *client, const short regs, short *buf, int count, int scl_rate) +int i2c_master_reg16_recv(const struct i2c_client *client, const short regs, short *buf, int count, int scl_rate) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msgs[2]; diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 5d4593d3101d..7b058fb4b7f4 100755 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -22,6 +22,11 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ +obj-$(CONFIG_G_SENSOR_DEVICE) += gsensor/ +obj-$(CONFIG_GYRO_SENSOR_DEVICE) += gyroscope/ +obj-$(CONFIG_INPUT_JOGBALL) += jogball/ +obj-$(CONFIG_LIGHT_SENSOR_DEVICE) += lightsensor/ +obj-$(CONFIG_MAG_SENSORS) += magnetometer/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4dee9d5a055..05ab0606bcd6 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,6 +12,25 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD +config KEYS_RK29 + tristate "rk29 keyboard" + depends on ARCH_RK29 + default y + help + rk29 keyboard drivers(gpio and adc) + +config KEYS_RK29_NEWTON + tristate "rk29 newton keyboard" + depends on ARCH_RK29 + help + rk29 newton keyboard drivers(gpio and adc) + +config SYNAPTICS_SO340010 + tristate "Synaptics So340010 TouchPad KEY" + depends on I2C + help + Synaptics So340010 Touch Key (I2C) driver + config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 @@ -203,6 +222,21 @@ config KEYBOARD_GPIO_POLLED To compile this driver as a module, choose M here: the module will be called gpio_keys_polled. +config KEYBOARD_WM831X_GPIO + tristate "WM831X_GPIO Buttons" + depends on GENERIC_GPIO + help + This driver implements support for buttons connected + to GPIO pins of various CPUs (and some other chips). + + Say Y here if your device has buttons connected + directly to such GPIO pins. Your board-specific + setup logic must also provide a platform device, + with configuration data saying which GPIOs are used. + + To compile this driver as a module, choose M here: the + module will be called wm831x_gpio_keys. + config KEYBOARD_TCA6416 tristate "TCA6416/TCA6408A Keypad Support" depends on I2C diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index ddde0fd476f7..b90ddded626d 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,6 +4,8 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_KEYS_RK29) += rk29_keys.o +obj-$(CONFIG_KEYS_RK29_NEWTON) += rk29_newton_keys.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o @@ -15,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o +obj-$(CONFIG_KEYBOARD_WM831X_GPIO) += wm831x_gpio_keys.o obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o @@ -51,3 +54,4 @@ obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o +obj-$(CONFIG_SYNAPTICS_SO340010) += synaptics_so340010.o diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7ce1e9672633..46651a249695 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -271,16 +271,6 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. -config INPUT_TPS65910_PWRBUTTON - tristate "TPS65910 Power button Driver" - depends on TPS65910_CORE - help - Say Y here if you want to enable power key reporting via the - TPS65910 family of chips. - - To compile this driver as a module, choose M here. The module will - be called tps65910_pwrbutton. - config INPUT_TWL4030_PWRBUTTON tristate "TWL4030 Power button Driver" depends on TWL4030_CORE diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 41136b497844..d17fcab89d61 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -42,7 +42,6 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o -obj-$(CONFIG_INPUT_TPS65910_PWRBUTTON) += tps65910-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o @@ -50,3 +49,4 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o + diff --git a/drivers/input/misc/tps65910-pwrbutton.c b/drivers/input/misc/tps65910-pwrbutton.c deleted file mode 100644 index 587de971dc9a..000000000000 --- a/drivers/input/misc/tps65910-pwrbutton.c +++ /dev/null @@ -1,148 +0,0 @@ -/** - * tps65910-pwrbutton.c - TPS65910 Power Button Input Driver - * - * Copyright (C) 2010 Mistral Solutions Pvt Ltd - * - * Based on twl4030-pwrbutton.c - * - * Written by Srinath.R - * - * 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. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#define TPS65910_PWR_PWRON_IRQ (1 << 2) - - -static irqreturn_t powerbutton_irq(int irq, void *_pwr) -{ - struct input_dev *pwr = _pwr; - int err; - u8 value; - -#ifdef CONFIG_LOCKDEP - /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which - * we don't want and can't tolerate since this is a threaded - * IRQ and can sleep due to the i2c reads it has to issue. - * Although it might be friendlier not to borrow this thread - * context... - */ - local_irq_enable(); -#endif - err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &value, - TPS65910_REG_INT_STS); - if (!err && (value & TPS65910_PWR_PWRON_IRQ)) { - - if (value & TPS65910_PWR_PWRON_IRQ) { - - input_report_key(pwr, KEY_POWER, - TPS65910_PWR_PWRON_IRQ); - input_sync(pwr); - return IRQ_HANDLED; - } - } else { - dev_err(pwr->dev.parent, "tps65910: i2c error %d while reading" - " TPS65910_REG_INT_STS register\n", err); - } - return IRQ_HANDLED; -} - -static int __devinit tps65910_pwrbutton_probe(struct platform_device *pdev) -{ - struct input_dev *pwr; - int irq = platform_get_irq(pdev, 0); - int err; - - pwr = input_allocate_device(); - if (!pwr) { - dev_dbg(&pdev->dev, "Can't allocate power button\n"); - return -ENOMEM; - } - - pwr->evbit[0] = BIT_MASK(EV_KEY); - pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); - pwr->name = "tps65910_pwrbutton"; - pwr->phys = "tps65910_pwrbutton/input0"; - pwr->dev.parent = &pdev->dev; - - err = request_irq(irq, powerbutton_irq, - (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | - IRQF_SHARED), "tps65910_pwrbutton", pwr); - if (err < 0) { - dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); - goto free_input_dev; - } - - err = input_register_device(pwr); - if (err) { - dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); - goto free_irq; - } - - platform_set_drvdata(pdev, pwr); - - return 0; - -free_irq: - free_irq(irq, NULL); -free_input_dev: - input_free_device(pwr); - return err; -} - -static int __devexit tps65910_pwrbutton_remove(struct platform_device *pdev) -{ - struct input_dev *pwr = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - free_irq(irq, pwr); - input_unregister_device(pwr); - - return 0; -} - -struct platform_driver tps65910_pwrbutton_driver = { - .probe = tps65910_pwrbutton_probe, - .remove = __devexit_p(tps65910_pwrbutton_remove), - .driver = { - .name = "tps65910_pwrbutton", - .owner = THIS_MODULE, - }, -}; - -static int __init tps65910_pwrbutton_init(void) -{ - return platform_driver_register(&tps65910_pwrbutton_driver); -} -module_init(tps65910_pwrbutton_init); - -static void __exit tps65910_pwrbutton_exit(void) -{ - platform_driver_unregister(&tps65910_pwrbutton_driver); -} -module_exit(tps65910_pwrbutton_exit); - -MODULE_ALIAS("platform:tps65910_pwrbutton"); -MODULE_DESCRIPTION("TPS65910 Power Button"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Srinath R "); - diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 410410396700..846f9603f0ca 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,6 +11,58 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN +config TOUCHSCREEN_XPT2046_SPI + tristate "XPT2046 based touchscreens:SPI Interface" + depends on SPIM_RK29 + + config TOUCHSCREEN_XPT2046_NORMAL_SPI + tristate "normal mode" + depends on TOUCHSCREEN_XPT2046_SPI + + config TOUCHSCREEN_480X800 + tristate "480X800 resolution" + depends on TOUCHSCREEN_XPT2046_NORMAL_SPI + + config TOUCHSCREEN_800X480 + tristate "800X480 resolution" + depends on TOUCHSCREEN_XPT2046_NORMAL_SPI + + config TOUCHSCREEN_320X480 + tristate "320X480 resolution" + depends on TOUCHSCREEN_XPT2046_NORMAL_SPI + + config TOUCHSCREEN_XPT2046_TSLIB_SPI + tristate "tslib mode" + depends on TOUCHSCREEN_XPT2046_SPI + + config TOUCHSCREEN_480X800 + tristate "480X800 resolution" + depends on TOUCHSCREEN_XPT2046_TSLIB_SPI + + config TOUCHSCREEN_800X480 + tristate "800X480 resolution" + depends on TOUCHSCREEN_XPT2046_TSLIB_SPI + + config TOUCHSCREEN_320X480 + tristate "320X480 resolution" + depends on TOUCHSCREEN_XPT2046_TSLIB_SPI + + config TOUCHSCREEN_XPT2046_CBN_SPI + tristate "calibration mode" + depends on TOUCHSCREEN_XPT2046_SPI + + config TOUCHSCREEN_480X800 + tristate "480X800 resolution" + depends on TOUCHSCREEN_XPT2046_CBN_SPI + + config TOUCHSCREEN_800X480 + tristate "800X480 resolution" + depends on TOUCHSCREEN_XPT2046_CBN_SPI + + config TOUCHSCREEN_320X480 + tristate "320X480 resolution" + depends on TOUCHSCREEN_XPT2046_CBN_SPI + config TOUCHSCREEN_88PM860X tristate "Marvell 88PM860x touchscreen" depends on MFD_88PM860X @@ -55,6 +107,28 @@ config TOUCHSCREEN_AD7877 To compile this driver as a module, choose M here: the module will be called ad7877. +config TOUCHSCREEN_ILI2102_IIC + tristate "ili2102 based touchscreens: IIC Interface" + help + Say Y here if you have a touchscreen interface using the + hx8520 controller, and your board-specific initialization + code includes that in its table of IIC devices. + + If unsure, say N (but it's safe to say "Y"). + +config RK28_I2C_TS_NTP070 + tristate "NTP070 based touchscreens: NTP070 Interface" + depends on I2C_RK2818 + +config TOUCHSCREEN_IT7250 + tristate "IT7250 based touchscreens: IT7250 Interface" + help + Say Y here if you have a touchscreen interface using the + xpt2046 controller, and your board-specific initialization + code includes that in its table of SPI devices. + + If unsure, say N (but it's safe to say "Y"). + config TOUCHSCREEN_AD7879 tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface" help @@ -732,4 +806,199 @@ config TOUCHSCREEN_TPS6507X To compile this driver as a module, choose M here: the module will be called tps6507x_ts. +config HANNSTAR_P1003 + tristate "Hannstar P1003 touchscreen" + depends on I2C2_RK29 + help + RK29 hannstar touch + + config HANNSTAR_MAX_X + int "hannstar touch x max" + depends on HANNSTAR_P1003 + default 1087 + help + RK29 hannstar touch max X size + + config HANNSTAR_MAX_Y + int "hannstar touch Y max" + depends on HANNSTAR_P1003 + default 800 + help + RK29 hannstar touch max Y size + + config HANNSTAR_DEBUG + bool "hannstar debug" + depends on HANNSTAR_P1003 + default n + help + RK29 hannstar touch debug + +config ATMEL_MXT224 + tristate "Atmel mXT224 touchscreen" + depends on I2C2_RK29 + help + RK29 Atmel_mXT224 touch + + config MXT224_MAX_X + int "atmel_mxt224 touch X max" + depends on ATMEL_MXT224 + default 4095 + help + RK29 atmel_mxt224 touch max X size + + config MXT224_MAX_Y + int "atmel_mxt224 touch Y max" + depends on ATMEL_MXT224 + default 4095 + help + RK29 atmel_mxt224 touch max Y size + +config SINTEK_3FA16 + tristate "Sintek 3FA16 touchscreen" + depends on I2C2_RK29 + help + RK29 Sintek touch + + config HANNSTAR_MAX_X + int "Sintek touch x max" + depends on SINTEK_3FA16 + default 1024 + help + RK29 hannstar touch max X size + + config HANNSTAR_MAX_Y + int "Sintek touch Y max" + depends on SINTEK_3FA16 + default 600 + help + RK29 hannstar touch max Y size + + config HANNSTAR_DEBUG + bool "Sintek debug" + depends on SINTEK_3FA16 + default n + help + RK29 hannstar touch debug + +config EETI_EGALAX + tristate "EETI_EGALAX touchscreen panel support" + depends on I2C + help + Say Y here to enable support for I2C connected EETI touch panels. + + To compile this driver as a module, choose M here: the + module will be called eeti_egalax_ts. + + config EETI_EGALAX_MAX_X + int "EETI_EGALAX_MAX_X" + depends on EETI_EGALAX + default 2047 + help + RK29 EETI_EGALAX touch max X size + + config EETI_EGALAX_MAX_Y + int "EETI_EGALAX_MAX_Y" + depends on EETI_EGALAX + default 2047 + help + RK29 EETI_EGALAX touch max Y size + + config EETI_EGALAX_DEBUG + bool "EETI_EGALAX debug" + depends on EETI_EGALAX + default n + help + RK29 EETI_EGALAX touch debug + +config TOUCHSCREEN_IT7260 + tristate "IT7260 based touchscreens: IT7260 Interface" + depends on I2C2_RK29 + help + Say Y here if you have a touchscreen interface using the + it7260 controller, and your board-specific initialization + code includes that in its table of I2C devices. + + If unsure, say N (but it's safe to say "Y"). + +config TOUCHSCREEN_IT7260_I2C + tristate "IT7260 based touchscreens: IT7260 I2C Interface" + depends on I2C_RK29 + help + Say Y here if you have a touchscreen interface using the + IT7260 controller, and your board-specific initialization + code includes that in its table of I2C devices. + + If unsure, say N (but it's safe to say "Y"). + +config TOUCHSCREEN_NAS + tristate "NAS based touchscreens: NAS Interface" + depends on I2C2_RK29 + help + Say Y here if you have a touchscreen interface using the + nas controller, and your board-specific initialization + code includes that in its table of I2C devices. + + If unsure, say N (but it's safe to say "Y"). + +config LAIBAO_TS + tristate "LAIBAO touchscreen" + depends on I2C2_RK29 + help + RK29 LAIBAO touchscreen + +config TOUCHSCREEN_GT801_IIC + tristate "GT801_IIC based touchscreens" + depends on I2C2_RK29 + +config TOUCHSCREEN_GT818_IIC + tristate "GT818_IIC based touchscreens" + depends on I2C2_RK29 + +config D70_L3188A + tristate "D70-L3188A based touchscreens" + depends on I2C2_RK29 + +config TOUCHSCREEN_GT819 + tristate "GT819 based touchscreens" + depends on I2C2_RK29 + +config TOUCHSCREEN_FT5406 + tristate "FT5406 based touchscreens: FT5406 Interface" + depends on I2C2_RK29 + help + say Y here if you have a touchscreen interface using the FT5406 + controller,and your board-specific initialization code includes that + in its table of I2C devices. + + If unsure, say N(but it's safe to say "Y"). + +config ATMEL_MXT1386 + tristate "ATMEL_MXT1386 touchscreen panel support" + depends on I2C + help + Say Y here to enable support for I2C connected ATMEL_MXT1386 touch panels. + + To compile this driver as a module, choose M here: the + module will be called atmel_mxt1386_ts. + + config ATMEL_MXT1386_MAX_X + int "ATMEL_MXT1386_MAX_X" + depends on ATMEL_MXT1386 + default 4095 + help + RK29 ATMEL_MXT1386 touch max X size + + config ATMEL_MXT1386_MAX_Y + int "ATMEL_MXT1386_MAX_Y" + depends on ATMEL_MXT1386 + default 4095 + help + RK29 ATMEL_MXT1386 touch max Y size + + config ATMEL_MXT1386_DEBUG + bool "ATMEL_MXT1386 debug" + depends on ATMEL_MXT1386 + default n + help + RK29 ATMEL_MXT1386 touch debug endif diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index f0fecd6f6a33..70ffad500741 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -74,9 +74,14 @@ obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o +obj-$(CONFIG_SOC_CAMERA_MT9M112) += mt9m112.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o +obj-$(CONFIG_SOC_CAMERA_MT9T111) += mt9t111.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_SOC_CAMERA_MT9P111) += mt9p111.o +obj-$(CONFIG_SOC_CAMERA_MT9D112) += mt9d112.o +obj-$(CONFIG_SOC_CAMERA_MT9D113) += mt9d113.o obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o @@ -84,7 +89,25 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o - +obj-$(CONFIG_SOC_CAMERA_OV7675) += ov7675.o +obj-$(CONFIG_SOC_CAMERA_OV2655) += ov2655.o +obj-$(CONFIG_SOC_CAMERA_OV2659) += ov2659.o +obj-$(CONFIG_SOC_CAMERA_OV9650) += ov9650.o +obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o +obj-$(CONFIG_SOC_CAMERA_OV3640) += ov3640.o +obj-$(CONFIG_SOC_CAMERA_OV5640) += ov5640.o +obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o +obj-$(CONFIG_SOC_CAMERA_S5K6AA) += s5k6aa.o +obj-$(CONFIG_SOC_CAMERA_GT2005) += gt2005.o +obj-$(CONFIG_SOC_CAMERA_GC0307) += gc0307.o +obj-$(CONFIG_SOC_CAMERA_GC0308) += gc0308.o +obj-$(CONFIG_SOC_CAMERA_GC0309) += gc0309.o +obj-$(CONFIG_SOC_CAMERA_GC2015) += gc2015.o +obj-$(CONFIG_SOC_CAMERA_SIV120B) += siv120b.o +obj-$(CONFIG_SOC_CAMERA_SID130B) += sid130B.o +obj-$(CONFIG_SOC_CAMERA_HI253) += hi253.o +obj-$(CONFIG_SOC_CAMERA_HI704) += hi704.o +obj-$(CONFIG_SOC_CAMERA_NT99250) += nt99250.o # And now the v4l2 drivers: obj-$(CONFIG_VIDEO_BT848) += bt8xx/ @@ -163,6 +186,9 @@ obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o +obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk29_camera_oneframe.o +obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk29_camera_pingpong.o +obj-$(CONFIG_VIDEO_RK29XX_VOUT) += rk29xx/ obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 0cea0cf36679..9b2ac56310ef 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -1,4 +1,5 @@ /* +<<<<<<< HEAD * ov2640 Camera Driver * * Copyright (C) 2010 Alberto Panizzo @@ -7,12 +8,18 @@ * * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2006, OmniVision +======= +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski +>>>>>>> parent of 15f7fab... temp revert rk change * * 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. */ +<<<<<<< HEAD #include #include #include @@ -1203,3 +1210,2963 @@ module_exit(ov2640_module_exit); MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); MODULE_AUTHOR("Alberto Panizzo"); MODULE_LICENSE("GPL v2"); +======= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_OV2640 +#define SENSOR_V4L2_IDENT V4L2_IDENT_OV2640 +#define SENSOR_ID 0x2642 +#define SENSOR_ID1 0x2641 +#define SENSOR_MIN_WIDTH 640 +#define SENSOR_MIN_HEIGHT 480 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 0 +#define CONFIG_SENSOR_Brightness 1 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 1 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 0 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init 800*600 SVGA */ +static struct reginfo sensor_init_data[] = +{ +#if 1 + {0xff,0x01}, + {0x12,0x80}, + {0xff,0x00}, + {0x2c,0xff}, + {0x2e,0xdf}, + {0xff,0x01}, + + {0x03,0x4f}, + {0x0f,0x4b}, + + + {0x3c,0x32}, + {0x11,0x00}, + {0x09,0x02}, + {0x04,0xF8},//b7,b6 directs + {0x13,0xe5}, + {0x14,0x48}, + {0x2c,0x0c}, + {0x33,0x78}, + {0x3a,0x33}, + {0x3b,0xfB}, + {0x3e,0x00}, + {0x43,0x11}, + {0x16,0x10}, + {0x39,0x02}, + {0x35,0x88}, + {0x22,0x09}, + {0x37,0x40}, + {0x23,0x00}, + {0x34,0xa0}, + {0x36,0x1a}, + {0x06,0x02}, + {0x07,0xc0}, + {0x0d,0xb7}, + {0x0e,0x01}, + {0x4c,0x00}, + {0x4a,0x81}, + {0x21,0x99}, + + //{0x24,0x58}, + //{0x25,0x50}, + //{0x26,0x92}, + + {0x24, 0x70}, + {0x25, 0x60}, + {0x26, 0xa4}, + + {0x5c,0x00}, + {0x63,0x00}, + {0x46,0x3f}, + {0x0c,0x3c}, + {0x61,0x70}, + {0x62,0x80}, + {0x7c,0x05}, + {0x20,0x80}, + {0x28,0x30}, + {0x6c,0x00}, + {0x6d,0x80}, + {0x6e,0x00}, + {0x70,0x02}, + {0x71,0x94}, + {0x73,0xc1}, + {0x3d,0x34}, + {0x5a,0x57}, + {0x4f,0xbb}, + {0x50,0x9c}, + {0xff,0x00}, + {0xe5,0x7f}, + {0xf9,0xc0}, + {0x41,0x24}, + {0xe0,0x14}, + {0x76,0xff}, + {0x33,0xa0}, + {0x42,0x20}, + {0x43,0x18}, + {0x4c,0x00}, + {0x87,0xd0}, + {0x88,0x3f}, + {0xd7,0x03}, + {0xd9,0x10}, + {0xd3,0x82}, + {0xc8,0x08}, + {0xc9,0x80}, + {0x7c,0x00}, + {0x7d,0x00},//0x00//0x07 + {0x7c,0x03}, + {0x7d,0x48},//0x48//0x40 + {0x7d,0x48},//0x48//0x40 + {0x7c,0x08}, + {0x7d,0x20}, + {0x7d,0x10},//0x10 + {0x7d,0x0e},//0x0e + + {0x92,0x00}, + {0x93,0x06}, + {0x93,0xc8},//e3 + {0x93,0x05}, + {0x93,0x05}, + {0x93,0x00}, + {0x93,0x04}, + {0x93,0x00}, + {0x93,0x00}, + {0x93,0x00}, + {0x93,0x00}, + {0x93,0x00}, + {0x93,0x00}, + {0x93,0x00}, + {0x96,0x00}, + {0x97,0x08}, + {0x97,0x19}, + {0x97,0x02}, + {0x97,0x0c}, + {0x97,0x24}, + {0x97,0x30}, + {0x97,0x28}, + {0x97,0x26}, + {0x97,0x02}, + {0x97,0x98}, + {0x97,0x80}, + {0x97,0x00}, + {0x97,0x00}, + {0xc3,0xef},//ed + {0xa4,0x00}, + {0xa8,0x00}, + + {0xbf, 0x00}, + {0xba, 0xdc}, + {0xbb, 0x08}, + {0xb6, 0x20}, + {0xb8, 0x30}, + {0xb7, 0x20}, + {0xb9, 0x30}, + {0xb3, 0xb4}, + {0xb4, 0xca}, + {0xb5, 0x34}, + {0xb0, 0x46}, + {0xb1, 0x46}, + {0xb2, 0x06}, + {0xc7, 0x00}, + {0xc6, 0x51}, + {0xc5, 0x11}, + {0xc4, 0x9c}, +//// + {0xc0,0xc8}, + {0xc1,0x96}, + {0x86,0x3d}, + {0x50,0x92}, + {0x51,0x90}, + {0x52,0x2c}, + {0x53,0x00}, + {0x54,0x00}, + {0x55,0x88}, + {0x57,0x00}, + {0x5a,0x50}, + {0x5b,0x3c}, + {0x5c,0x00}, + {0xc3,0xed}, + {0x7f,0x00}, + {0xda,0x01}, + {0xe5,0x1f}, + {0xe1,0x67}, + {0xe0,0x00}, + {0xdd,0xff}, + {0x05,0x00}, + +#endif +#if 1 + {0xff, 0x01}, + {0x5d, 0x00}, + {0x5e, 0x3c}, + {0x5f, 0x28}, + {0x60, 0x55}, + + + {0xff, 0x00}, + {0xc3, 0xef}, + {0xa6, 0x00}, + {0xa7, 0x0f}, + {0xa7, 0x4e}, + {0xa7, 0x7a}, + {0xa7, 0x33}, + {0xa7, 0x00}, + {0xa7, 0x23}, + {0xa7, 0x27}, + {0xa7, 0x3a}, + {0xa7, 0x70}, + {0xa7, 0x33}, + {0xa7, 0x00},//L + {0xa7, 0x23}, + {0xa7, 0x20}, + {0xa7, 0x0c}, + {0xa7, 0x66}, + {0xa7, 0x33}, + {0xa7, 0x00}, + {0xa7, 0x23}, + {0xc3, 0xef}, +#endif + + +#if 1 + {0xff,0x00}, + {0x92,0x00}, + {0x93,0x06}, + {0x93,0xc1},//e + {0x93,0x02}, + {0x93,0x02}, + {0x93,0x00}, + {0x93,0x04}, +#endif + + {0x03, 0x0f}, + {0xe0, 0x04}, + {0xc0, 0xc8}, + {0xc1, 0x96}, + {0x86, 0x3d}, + {0x50, 0x89}, + {0x51, 0x90}, + {0x52, 0x2c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5a, 0xa0}, + {0x5b, 0x78}, + {0x5c, 0x00}, + {0xd3, 0x04}, + {0xe0, 0x00}, + + {0x0, 0x0} //end flag + +}; + +/* 1600X1200 UXGA */ +static struct reginfo sensor_uxga[] = +{ + {0xff, 0x00}, + {0xe0, 0x04}, + {0xc0, 0xc8}, + {0xc1, 0x96}, + {0x86, 0x3d}, + {0x50, 0x00}, + {0x51, 0x90}, + {0x52, 0x2c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5a, 0x90}, + {0x5b, 0x2c}, + {0x5c, 0x05}, + {0xd3, 0x82}, + {0xe0, 0x00}, + {0x0, 0x0} //end flag +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0xff, 0x00}, + {0xe0, 0x04}, + {0xc0, 0xc8}, + {0xc1, 0x96}, + {0x86, 0x3d}, + {0x50, 0x00}, + {0x51, 0x90}, + {0x52, 0x2c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5a, 0x40}, + {0x5b, 0x00}, + {0x5c, 0x05}, + {0xd3, 0x82}, + {0xe0, 0x00}, + {0x0, 0x0} //end flag +}; + + +static struct reginfo sensor_xga[] = +{ + {0xff, 0x00}, + {0xe0, 0x04}, + {0xc0, 0xc8}, + {0xc1, 0x96}, + {0x86, 0x3d}, + {0x50, 0x00}, + {0x51, 0x90}, + {0x52, 0x2c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5a, 0x40}, + {0x5b, 0x00}, + {0x5c, 0x05}, + {0xd3, 0x82}, + {0xe0, 0x00}, + {0x0, 0x0} //end flag + + +}; + + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0x0, 0x0} //end flag +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {0x0, 0x0} //end flag + }; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0x0, 0x0} //end flag +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0x0, 0x0} //end flag +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0x0, 0x0} //end flag +}; +#if 0 +/* 160X120 QQVGA*/ +static struct reginfo ov2655_qqvga[] = +{ + + {0x300E, 0x34}, + {0x3011, 0x01}, + {0x3012, 0x10}, + {0x302a, 0x02}, + {0x302b, 0xE6}, + {0x306f, 0x14}, + {0x3362, 0x90}, + + {0x3070, 0x5d}, + {0x3072, 0x5d}, + {0x301c, 0x07}, + {0x301d, 0x07}, + + {0x3020, 0x01}, + {0x3021, 0x18}, + {0x3022, 0x00}, + {0x3023, 0x06}, + {0x3024, 0x06}, + {0x3025, 0x58}, + {0x3026, 0x02}, + {0x3027, 0x61}, + {0x3088, 0x00}, + {0x3089, 0xa0}, + {0x308a, 0x00}, + {0x308b, 0x78}, + {0x3316, 0x64}, + {0x3317, 0x25}, + {0x3318, 0x80}, + {0x3319, 0x08}, + {0x331a, 0x0a}, + {0x331b, 0x07}, + {0x331c, 0x80}, + {0x331d, 0x38}, + {0x3100, 0x00}, + {0x3302, 0x11}, + + {0x0, 0x0}, +}; + + + +static struct reginfo ov2655_Sharpness_auto[] = +{ + {0x3306, 0x00}, +}; + +static struct reginfo ov2655_Sharpness1[] = +{ + {0x3306, 0x08}, + {0x3371, 0x00}, +}; + +static struct reginfo ov2655_Sharpness2[][3] = +{ + //Sharpness 2 + {0x3306, 0x08}, + {0x3371, 0x01}, +}; + +static struct reginfo ov2655_Sharpness3[] = +{ + //default + {0x3306, 0x08}, + {0x332d, 0x02}, +}; +static struct reginfo ov2655_Sharpness4[]= +{ + //Sharpness 4 + {0x3306, 0x08}, + {0x332d, 0x03}, +}; + +static struct reginfo ov2655_Sharpness5[] = +{ + //Sharpness 5 + {0x3306, 0x08}, + {0x332d, 0x04}, +}; +#endif + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + //{0x4300, 0x30}, + {0x00, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + //{0x4300, 0x32}, + {0x00, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x3406, 0x00}, //AWB auto, bit[1]:0,auto + {0x0000, 0x00} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x3406, 0x01}, + {0x3400, 0x07}, + {0x3401, 0x08}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x05}, + {0x3405, 0x00}, + {0x0000, 0x00} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + {0x3406, 0x01}, + {0x3400, 0x07}, + {0x3401, 0x02}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x05}, + {0x3405, 0x15}, + {0x0000, 0x00} +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + {0x3406, 0x01}, + {0x3400, 0x06}, + {0x3401, 0x2a}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x07}, + {0x3405, 0x24}, + {0x0000, 0x00} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + {0x3406, 0x01}, + {0x3400, 0x04}, + {0x3401, 0x58}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x07}, + {0x3405, 0x24}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0xff, 0x01}, + {0x24, 0x34}, + {0x25, 0x22}, + {0x26, 0x70}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + + {0xff, 0x01}, + {0x24, 0x58}, + {0x25, 0x50}, + {0x26, 0x92}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + + {0xff, 0x01}, + {0x24, 0xa8}, + {0x25, 0x90}, + {0x26, 0xd6}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + + {0xff, 0x01}, + {0x24, 0x48}, + {0x25, 0x40}, + {0x26, 0x81}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + + {0xff, 0x01}, + {0x24, 0x58}, + {0x25, 0x50}, + {0x26, 0x92}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0xff, 0x01}, + {0x24, 0x70}, + {0x25, 0x60}, + {0x26, 0xa4}, + {0x0, 0x0} //end flag +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0xff,0x00}, + {0x7c,0x00}, + {0x7d,0x00}, + {0x7c,0x05}, + {0x7d,0x80}, + {0x7d,0x80}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0xff,0x00}, + {0x7c,0x00}, + {0x7d,0x18}, + {0x7c,0x05}, + {0x7d,0x80}, + {0x7d,0x80}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0xff,0x00}, + {0x7c,0x00}, + {0x7d,0x18}, + {0x7c,0x05}, + {0x7d,0x40}, + {0x7d,0xc0}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + {0xff,0x00}, + {0x7c,0x00}, + {0x7d,0x40}, + {0x7c,0x05}, + {0x7d,0x80}, + {0x7d,0x80}, + {0x0, 0x0} //end flag +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + {0Xff, 0X00}, + {0X7c, 0X00}, + {0X7d, 0X18}, + {0X7c, 0X05}, + {0X7d, 0Xa0}, + {0X7d, 0X40}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Effect_Green[] = +{ + {0Xff, 0X00}, + {0X7c, 0X00}, + {0X7d, 0X18}, + {0X7c, 0X05}, + {0X7d, 0X40}, + {0X7d, 0X40}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Effect_Exp_Windows_Half[] = +{ + {0xff, 0x01}, + {0x5d, 0x00}, + {0x5e, 0x3c}, + {0x5f, 0x28}, + {0x60, 0x55}, + {0x0, 0x0} //end flag +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure1[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0xff, 0x00}, + {0x90, 0x00}, + {0x91, 0x0e}, + {0x91, 0x1a}, + {0x91, 0x31}, + {0x91, 0x5a}, + {0x91, 0x69}, + {0x91, 0x75}, + {0x91, 0x7e}, + {0x91, 0x88}, + {0x91, 0x8f}, + {0x91, 0x96}, + {0x91, 0xa3}, + {0x91, 0xaf}, + {0x91, 0xc4}, + {0x91, 0xd7}, + {0x91, 0xe8}, + {0x91, 0x20}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0xff, 0x00}, + {0x90, 0x00}, + {0x91, 0x03}, + {0x91, 0x0a}, + {0x91, 0x1a}, + {0x91, 0x3f}, + {0x91, 0x4e}, + {0x91, 0x5b}, + {0x91, 0x68}, + {0x91, 0x75}, + {0x91, 0x7f}, + {0x91, 0x89}, + {0x91, 0x9a}, + {0x91, 0xa6}, + {0x91, 0xbd}, + {0x91, 0xd3}, + {0x91, 0xe5}, + {0x91, 0x24}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0xff, 0x00}, + {0x90, 0x00}, + {0x91, 0x04}, + {0x91, 0x07}, + {0x91, 0x10}, + {0x91, 0x28}, + {0x91, 0x36}, + {0x91, 0x44}, + {0x91, 0x52}, + {0x91, 0x60}, + {0x91, 0x6c}, + {0x91, 0x78}, + {0x91, 0x8c}, + {0x91, 0x9e}, + {0x91, 0xbb}, + {0x91, 0xd3}, + {0x91, 0xe5}, + {0x91, 0x24}, + {0x0, 0x0} //end flag +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x10}, + {0x7d, 0x4a}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag + +}; + +static struct reginfo sensor_Contrast1[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x14}, + {0x7d, 0x40}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast2[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x18}, + {0x7d, 0x34}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast3[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x1c}, + {0x7d, 0x2a}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast4[]= +{ + {0xff,0x00}, + {0x7c,0x00}, + {0x7d,0x04}, + {0x7c,0x07}, + {0x7d,0x20}, + {0x7d,0x24}, + {0x7d,0x16}, + {0x7d,0x06}, + {0x0, 0x0} //end flag +}; + + +static struct reginfo sensor_Contrast5[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x20}, + {0x7d, 0x20}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast6[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x24}, + {0x7d, 0x16}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + + +static struct reginfo sensor_Contrast7[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x28}, + {0x7d, 0x0c}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast8[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x2c}, + {0x7d, 0x02}, + {0x7d, 0x06}, + {0x0, 0x0} //end flag +}; + +static struct reginfo sensor_Contrast9[]= +{ + {0xff, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x04}, + {0x7c, 0x07}, + {0x7d, 0x20}, + {0x7d, 0x30}, + {0x7d, 0x08}, + {0x7d, 0x0e}, + {0x0, 0x0} //end flag +}; + + + +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0x0000, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0x0000, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0x0000, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + {0x3a00, 0x78}, + {0x0000, 0x00} +}; + +static struct reginfo sensor_SceneNight[] = +{ + {0x3003, 0x80}, + {0x3004, 0x20}, + {0x3005, 0x18}, + {0x3006, 0x0d}, + {0x3a00, 0x7c}, + {0x3a02 ,0x07}, + {0x3a03 ,0x38}, + {0x3a14 ,0x07}, + {0x3a15 ,0x38}, + {0x0000, 0x00} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x0, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG} +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + struct sensor_datafmt fmt; + +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-->0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + u8 buf[1]; + struct i2c_msg msg[2]; + + buf[0] = reg ;//>> 8; + // buf[1] = 0; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2;//0x55; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + while ((cnt-->0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != 0) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +#endif +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + const struct sensor_datafmt *fmt; + char value; + int ret,pid = 0; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + ret = sensor_write(client, 0xff, 1); + ret |= sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds + /* check if it is an sensor sensor */ + ret = sensor_write(client, 0xff, 1); + ret |= sensor_read(client, 0x0a, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid = value << 8; + ret = sensor_read(client, 0x0b, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + pid |= (value & 0xff); + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if ((pid == SENSOR_ID)||(pid == SENSOR_ID1)) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + + return 0; +sensor_INIT_ERR: + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ +#if 0 + sensor_task_lock(client, 1); + sensor_write(client, 0x3000, reg_val&0xfc); + sensor_write(client, 0x3001, 0x00); + sensor_task_lock(client, 0); +#endif + sensor_ioctrl(icd, Sensor_PowerDown, 1); + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + msleep(100); + return 0; +} + +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1024) && (set_h <= 768)) && sensor_xga[0].reg) + { + winseqe_set_addr = sensor_xga; + set_w = 1024; + set_h = 768; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,mf->width,mf->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + #endif + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,mf) == true) { /* ddl@rock-chips.com : Video */ + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + #if CONFIG_SENSOR_Effect + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + #endif + #if CONFIG_SENSOR_WhiteBalance + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + #endif + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + mf->colorspace = fmt->colorspace; + + return ret; +} + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV2655 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char value; + int ret,pid = 0; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + ret = sensor_write(client, 0xff, 0x1); + if (ret != 0) { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + mdelay(5); //delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_read(client, 0x0a, &value); + if (ret != 0) { + SENSOR_TR("read chip id high byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + pid = value << 8; + + ret = sensor_read(client, 0x0b, &value); + if (ret != 0) { + SENSOR_TR("read chip id low byte failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + pid |= (value & 0xff); + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + + if ((pid == SENSOR_ID)||(pid == SENSOR_ID1)) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + return 0; + +sensor_video_probe_err: + + return ret; +} + +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } + +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + sensor->info_priv.fmt = sensor_colour_fmts[0]; + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + +>>>>>>> parent of 15f7fab... temp revert rk change diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 4e4d4122d9a6..372bd75bc4b3 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -484,6 +484,7 @@ static int soc_camera_open(struct file *file) icd->current_fmt->host_fmt->fourcc, }, }; +<<<<<<< HEAD ret = soc_camera_power_set(icd, icl, 1); if (ret < 0) @@ -492,6 +493,20 @@ static int soc_camera_open(struct file *file) /* The camera could have been already on, try to reset */ if (icl->reset) icl->reset(icd->pdev); +======= + /* ddl@rock-chips.com : accelerate device open */ + if ((file->f_flags & O_ACCMODE) == O_RDWR) { + if (icl->power) { + ret = icl->power(icd->pdev, 1); + if (ret < 0) + goto epower; + } + + /* The camera could have been already on, try to reset */ + if (icl->reset) + icl->reset(icd->pdev); + } +>>>>>>> parent of 15f7fab... temp revert rk change ret = ici->ops->add(icd); if (ret < 0) { @@ -504,6 +519,7 @@ static int soc_camera_open(struct file *file) if (ret < 0 && ret != -ENOSYS) goto eresume; + if ((file->f_flags & O_ACCMODE) == O_RDWR) { /* * Try to configure with default parameters. Notice: this is the * very first open, so, we cannot race against other calls, @@ -513,6 +529,7 @@ static int soc_camera_open(struct file *file) ret = soc_camera_set_fmt(icd, &f); if (ret < 0) goto esfmt; +<<<<<<< HEAD if (ici->ops->init_videobuf) { ici->ops->init_videobuf(&icd->vb_vidq, icd); @@ -521,6 +538,9 @@ static int soc_camera_open(struct file *file) if (ret < 0) goto einitvb; } +======= + } +>>>>>>> parent of 15f7fab... temp revert rk change } file->private_data = icd; @@ -562,7 +582,14 @@ static int soc_camera_close(struct file *file) if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); +<<<<<<< HEAD soc_camera_power_set(icd, icl, 0); +======= + if ((file->f_flags & O_ACCMODE) == O_RDWR) { + if (icl->power) + icl->power(icd->pdev, 0); + } +>>>>>>> parent of 15f7fab... temp revert rk change } if (icd->streamer == file) @@ -653,8 +680,14 @@ static struct v4l2_file_operations soc_camera_fops = { static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { +<<<<<<< HEAD struct soc_camera_device *icd = file->private_data; int ret; +======= + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + int ret,i; +>>>>>>> parent of 15f7fab... temp revert rk change WARN_ON(priv != file->private_data); @@ -666,10 +699,31 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, if (icd->streamer && icd->streamer != file) return -EBUSY; +<<<<<<< HEAD if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) { +======= + #if 1 + if (icf->vb_vidq.bufs[0]) { +>>>>>>> parent of 15f7fab... temp revert rk change dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); return -EBUSY; } + #else + + /* ddl@rock-chips.com : + Judge queue initialised by Judge icf->vb_vidq.bufs[0] whether is NULL , it is error. */ + + i = 0; + while (icf->vb_vidq.bufs[i] && (ivb_vidq.bufs[i]->state != VIDEOBUF_NEEDS_INIT) { + dev_err(&icd->dev, "S_FMT denied: queue initialised, icf->vb_vidq.bufs[%d]->state:0x%x\n",i,icf->vb_vidq.bufs[i]->state); + ret = -EBUSY; + goto unlock; + } + i++; + } + + #endif ret = soc_camera_set_fmt(icd, f); @@ -678,7 +732,27 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, return ret; } +static int soc_camera_enum_frameintervals (struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + const struct soc_camera_data_format *format; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret; + + WARN_ON(priv != file->private_data); + ret = v4l2_subdev_call(sd, video, enum_frameintervals, fival); + if (ret == -ENOIOCTLCMD) + if (ici->ops->enum_frameinervals) + ret = ici->ops->enum_frameinervals(icd, fival); + else + ret = -ENOIOCTLCMD; + + return ret; +} static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -739,6 +813,8 @@ static int soc_camera_streamon(struct file *file, void *priv, struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); int ret; WARN_ON(priv != file->private_data); @@ -746,9 +822,17 @@ static int soc_camera_streamon(struct file *file, void *priv, if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; +<<<<<<< HEAD if (icd->streamer != file) return -EBUSY; +======= + mutex_lock(&icd->video_lock); + + v4l2_subdev_call(sd, video, s_stream, 1); + if (ici->ops->s_stream) + ici->ops->s_stream(icd, 1); /* ddl@rock-chips.com : Add stream control for host */ +>>>>>>> parent of 15f7fab... temp revert rk change /* This calls buf_queue from host driver's videobuf_queue_ops */ if (ici->ops->init_videobuf) ret = videobuf_streamon(&icd->vb_vidq); @@ -766,15 +850,25 @@ static int soc_camera_streamoff(struct file *file, void *priv, { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); +<<<<<<< HEAD struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); +======= + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); +>>>>>>> parent of 15f7fab... temp revert rk change WARN_ON(priv != file->private_data); if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; +<<<<<<< HEAD if (icd->streamer != file) return -EBUSY; +======= + + mutex_lock(&icd->video_lock); +>>>>>>> parent of 15f7fab... temp revert rk change /* * This calls buf_release from host driver's videobuf_queue_ops for all @@ -786,7 +880,15 @@ static int soc_camera_streamoff(struct file *file, void *priv, vb2_streamoff(&icd->vb2_vidq, i); v4l2_subdev_call(sd, video, s_stream, 0); + if (ici->ops->s_stream) + ici->ops->s_stream(icd, 0); /* ddl@rock-chips.com : Add stream control for host */ +<<<<<<< HEAD +======= + videobuf_mmap_free(&icf->vb_vidq); /* ddl@rock-chips.com : free video buf */ + mutex_unlock(&icd->video_lock); + +>>>>>>> parent of 15f7fab... temp revert rk change return 0; } @@ -821,6 +923,40 @@ static int soc_camera_queryctrl(struct file *file, void *priv, return -EINVAL; } +/* ddl@rock-chips.com : Add ioctrl -VIDIOC_QUERYMENU */ +static int soc_camera_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *qm) +{ + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + struct v4l2_queryctrl qctrl; + int i,j; + + qctrl.id = qm->id; + + if (soc_camera_queryctrl(file,priv, &qctrl) == 0) { + for (i = 0; i < icd->ops->num_menus; i++) { + if (qm->id == icd->ops->menus[i].id) { + for (j=0; j<=(qctrl.maximum - qctrl.minimum); j++) { + + if (qm->index == icd->ops->menus[i].index) { + snprintf(qm->name, sizeof(qm->name), icd->ops->menus[i].name); + qm->reserved = 0; + + return 0; + } else { + i++; + if ( i >= icd->ops->num_menus) + return -EINVAL; + } + } + } + } + } + + return -EINVAL; +} + static int soc_camera_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { @@ -859,6 +995,64 @@ static int soc_camera_s_ctrl(struct file *file, void *priv, return v4l2_subdev_call(sd, core, s_ctrl, ctrl); } + + /* ddl@rock-chips.com : Add ioctrl -VIDIOC_XXX_ext_ctrl for soc-camera */ +static int soc_camera_try_ext_ctrl(struct file *file, void *priv, + struct v4l2_ext_controls *ctrl) +{ + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + const struct v4l2_queryctrl *qctrl; + int i; + + WARN_ON(priv != file->private_data); + + if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA) + return -EINVAL; + + for (i=0; icount; i++) { + qctrl = soc_camera_find_qctrl(icd->ops, ctrl->controls[i].id); + if (!qctrl) + return -EINVAL; + + if ((ctrl->controls[i].value < qctrl->minimum) ||(ctrl->controls[i].value > qctrl->minimum)) + return -ERANGE; + } + + return 0; +} + /* ddl@rock-chips.com : Add ioctrl -VIDIOC_XXX_ext_ctrl for soc-camera */ +static int soc_camera_g_ext_ctrl(struct file *file, void *priv, + struct v4l2_ext_controls *ctrl) +{ + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + WARN_ON(priv != file->private_data); + + if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA) + return -EINVAL; + + return v4l2_subdev_call(sd, core, g_ext_ctrls, ctrl); +} + /* ddl@rock-chips.com : Add ioctrl -VIDIOC_XXX_ext_ctrl for soc-camera */ +static int soc_camera_s_ext_ctrl(struct file *file, void *priv, + struct v4l2_ext_controls *ctrl) +{ + struct soc_camera_file *icf = file->private_data; + struct soc_camera_device *icd = icf->icd; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + WARN_ON(priv != file->private_data); + + if (ctrl->ctrl_class != V4L2_CTRL_CLASS_CAMERA) + return -EINVAL; + + return v4l2_subdev_call(sd, core, s_ext_ctrls, ctrl); +} + + static int soc_camera_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) { @@ -1471,8 +1665,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, .vidioc_queryctrl = soc_camera_queryctrl, + .vidioc_querymenu = soc_camera_querymenu, /* ddl@rock-chips.com: Add ioctrl - vidioc_querymenu for soc-camera */ .vidioc_g_ctrl = soc_camera_g_ctrl, .vidioc_s_ctrl = soc_camera_s_ctrl, + .vidioc_g_ext_ctrls = soc_camera_g_ext_ctrl, /* ddl@rock-chips.com: Add ioctrl - vidioc_g_ext_ctrls for soc-camera */ + .vidioc_s_ext_ctrls = soc_camera_s_ext_ctrl, /* ddl@rock-chips.com: Add ioctrl - vidioc_s_ext_ctrls for soc-camera */ + .vidioc_try_ext_ctrls = soc_camera_try_ext_ctrl,/* ddl@rock-chips.com: Add ioctrl - vidioc_try_ext_ctrls for soc-camera */ + .vidioc_enum_frameintervals = soc_camera_enum_frameintervals,/* ddl@rock-chips.com: Add ioctrl - VIDIOC_ENUM_FRAMEINTERVALS for soc-camera */ .vidioc_cropcap = soc_camera_cropcap, .vidioc_g_crop = soc_camera_g_crop, .vidioc_s_crop = soc_camera_s_crop, diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 543a80395b7f..82dc041d99a8 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -295,8 +295,10 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, struct uvc_frame *frame; int ret; - if (fmt->type != stream->type) + if (fmt->type != stream->type) { + printk("uvc_v4l2_set_format, fmt->type(%d) != stream->type(%d)\n",fmt->type,stream->type); return -EINVAL; + } ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); if (ret < 0) @@ -305,6 +307,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, mutex_lock(&stream->mutex); if (uvc_queue_allocated(&stream->queue)) { + printk("uvc_queue_allocated failed\n"); ret = -EBUSY; goto done; } @@ -799,8 +802,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_S_FMT: - if ((ret = uvc_acquire_privileges(handle)) < 0) + if ((ret = uvc_acquire_privileges(handle)) < 0) { + printk("uvc_acquire_privileges error."); return ret; + } return uvc_v4l2_set_format(stream, arg); @@ -974,14 +979,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_QBUF: - if (!uvc_has_privileges(handle)) + if (!uvc_has_privileges(handle)) { + printk("uvcvideo: VIDIOC_QBUF uvc_has_privileges failed\n"); return -EBUSY; + } return uvc_queue_buffer(&stream->queue, arg); case VIDIOC_DQBUF: - if (!uvc_has_privileges(handle)) + if (!uvc_has_privileges(handle)) { + printk("uvcvideo: VIDIOC_DQBUF uvc_has_privileges failed\n"); return -EBUSY; + } return uvc_dequeue_buffer(&stream->queue, arg, file->f_flags & O_NONBLOCK); diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 69e8c6ffcc49..5ea5514c94ff 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -821,10 +821,10 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_S_FMT: { struct v4l2_format *f = (struct v4l2_format *)arg; - + /* FIXME: Should be one dump per type */ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.pix); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6ca938a6bf94..b91fe3180fd6 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -385,6 +385,17 @@ config MFD_WM831X_SPI for accessing the device, additional drivers must be enabled in order to use the functionality of the device. +config MFD_WM831X_SPI_A22 + bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI for A22" + #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 depends on GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d7d47d2a4c76..670e4c0fca63 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -26,6 +26,7 @@ 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 +obj-$(CONFIG_MFD_WM831X_SPI_A22) += wm831x-spi-a22.o wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o wm8350-objs += wm8350-irq.o obj-$(CONFIG_MFD_WM8350) += wm8350.o diff --git a/drivers/mfd/tps65910-core.c b/drivers/mfd/tps65910-core.c deleted file mode 100644 index 01c6439603c4..000000000000 --- a/drivers/mfd/tps65910-core.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * tps65910-core.c -- Multifunction core driver for TPS65910x chips - * - * Copyright (C) 2010 Mistral solutions Pvt Ltd - * - * Based on twl-core.c - * - * 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 -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DBG(x...) printk(KERN_INFO x) -#else -#define DBG(x...) -#endif -#define TPS65910_SPEED 400 * 1000 - - -#define DRIVER_NAME "tps659102" - -#if defined(CONFIG_GPIO_TPS65910) -#define tps65910_has_gpio() true -#else -#define tps65910_has_gpio() false -#endif - -#if defined(CONFIG_REGULATOR_TPS65910) -#define tps65910_has_regulator() true -#else -#define tps65910_has_regulator() false -#endif - -#if defined(CONFIG_RTC_DRV_TPS65910) -#define tps65910_has_rtc() true -#else -#define tps65910_has_rtc() false -#endif - -#define TPS65910_GENERAL 0 -#define TPS65910_SMARTREFLEX 1 - - -struct tps65910_platform_data *gtps65910_platform = NULL; - -enum tps65910x_model { - TPS65910, /* TI processors OMAP3 family */ - TPS659101, /* Samsung - S5PV210, S5PC1xx */ - TPS659102, /* Samsung - S3C64xx */ - TPS659103, /* Reserved */ - TPS659104, /* Reserved */ - TPS659105, /* TI processors - DM643x, DM644x */ - TPS659106, /* Reserved */ - TPS659107, /* Reserved */ - TPS659108, /* Reserved */ - TPS659109, /* Freescale - i.MX51 */ - -}; - -static bool inuse; -static struct work_struct core_work; -static struct mutex work_lock; - -/* Structure for each TPS65910 Slave */ -struct tps65910_client { - struct i2c_client *client; - u8 address; - /* max numb of i2c_msg required for read = 2 */ - struct i2c_msg xfer_msg[2]; - /* To lock access to xfer_msg */ - struct mutex xfer_lock; -}; -static struct tps65910_client tps65910_modules[TPS65910_NUM_SLAVES]; - -/* bbch = Back-up battery charger control register */ -int tps65910_enable_bbch(u8 voltage) -{ - u8 val = 0; - int err; - - if (voltage == TPS65910_BBSEL_3P0 || voltage == TPS65910_BBSEL_2P52 || - voltage == TPS65910_BBSEL_3P15 || - voltage == TPS65910_BBSEL_VBAT) { - val = (voltage | TPS65910_BBCHEN); - err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, - TPS65910_REG_BBCH); - if (err) { - printk(KERN_ERR "Unable write TPS65910_REG_BBCH reg\n"); - return -EIO; - } - } else { - printk(KERN_ERR"Invalid argumnet for %s \n", __func__); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(tps65910_enable_bbch); - -int tps65910_disable_bbch(void) -{ - u8 val = 0; - int err; - - err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_BBCH); - - if (!err) { - val &= ~TPS65910_BBCHEN; - - err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, - TPS65910_REG_BBCH); - if (err) { - printk(KERN_ERR "Unable write TPS65910_REG_BBCH \ - reg\n"); - return -EIO; - } - } else { - printk(KERN_ERR "Unable to read TPS65910_REG_BBCH reg\n"); - return -EIO; - } - return 0; -} -EXPORT_SYMBOL(tps65910_disable_bbch); - -int tps65910_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) -{ - struct tps65910_client *tps65910; - int ret; - - switch (mod_no) { - case TPS65910_I2C_ID0: - tps65910 = &tps65910_modules[0]; - tps65910->address = TPS65910_I2C_ID0; - break; - case TPS65910_I2C_ID1: - tps65910 = &tps65910_modules[1]; - tps65910->address = TPS65910_I2C_ID1; - break; - default: - printk(KERN_ERR "Invalid Slave address for TPS65910\n"); - return -ENODEV; - } - - ret = i2c_master_reg8_recv(tps65910->client, reg, (char *)value, 1, TPS65910_SPEED); - DBG("%s: ret=%d, slave_addr=0x%x, reg=0x%x, value=0x%x\n", __FUNCTION__, (ret > 0 ? 0: -EINVAL), mod_no, reg, *value); - - return (ret > 0 ? 0: -EINVAL); -} -EXPORT_SYMBOL(tps65910_i2c_read_u8); - -int tps65910_i2c_write_u8(u8 slave_addr, u8 value, u8 reg) -{ - struct tps65910_client *tps65910; - int ret; - - switch (slave_addr) { - case TPS65910_I2C_ID0: - tps65910 = &tps65910_modules[0]; - tps65910->address = TPS65910_I2C_ID0; - break; - case TPS65910_I2C_ID1: - tps65910 = &tps65910_modules[1]; - tps65910->address = TPS65910_I2C_ID1; - break; - default: - printk(KERN_ERR "Invalid Slave address for TPS65910\n"); - return -ENODEV; - } - - ret = i2c_master_reg8_send(tps65910->client, reg, (char *)&value, 1, TPS65910_SPEED); - DBG("%s: ret=%d, slave_addr=0x%x, reg=0x%x, value=0x%x\n", __FUNCTION__, ret, slave_addr, reg, value); - - if (ret < 0) - return -EIO; - else - return 0; -} -EXPORT_SYMBOL(tps65910_i2c_write_u8); - - -int tps65910_enable_irq(int irq) -{ - u8 mask = 0x00; - - if (irq > 7) { - irq -= 8; - tps65910_i2c_read_u8(TPS65910_I2C_ID0, - &mask, TPS65910_REG_INT_MSK2); - mask &= ~(1 << irq); - return tps65910_i2c_write_u8(TPS65910_I2C_ID0, - mask, TPS65910_REG_INT_MSK2); - } else { - tps65910_i2c_read_u8(TPS65910_I2C_ID0, - &mask, TPS65910_REG_INT_MSK); - mask &= ~(1 << irq); - return tps65910_i2c_write_u8(TPS65910_I2C_ID0, - mask, TPS65910_REG_INT_MSK); - } -} -EXPORT_SYMBOL(tps65910_enable_irq); - -int tps65910_disable_irq(int irq) -{ - u8 mask = 0x00; - - if (irq > 7) { - irq -= 8; - tps65910_i2c_read_u8(TPS65910_I2C_ID0, - &mask, TPS65910_REG_INT_MSK2); - mask |= (1 << irq); - return tps65910_i2c_write_u8(TPS65910_I2C_ID0, - mask, TPS65910_REG_INT_MSK2); - } else { - tps65910_i2c_read_u8(TPS65910_I2C_ID0, - &mask, TPS65910_REG_INT_MSK); - mask = (1 << irq); - return tps65910_i2c_write_u8(TPS65910_I2C_ID0, - mask, TPS65910_REG_INT_MSK); - } -} -EXPORT_SYMBOL(tps65910_disable_irq); - -int tps65910_add_irq_work(int irq, - void (*handler)(void *data)) -{ - int ret = 0; - gtps65910_platform->handlers[irq] = handler; - ret = tps65910_enable_irq(irq); - - return ret; -} -EXPORT_SYMBOL(tps65910_add_irq_work); - -int tps65910_remove_irq_work(int irq) -{ - int ret = 0; - ret = tps65910_disable_irq(irq); - gtps65910_platform->handlers[irq] = NULL; - return ret; -} -EXPORT_SYMBOL(tps65910_remove_irq_work); - -static void tps65910_core_work(struct work_struct *work) -{ - /* Read the status register and take action */ - u8 status = 0x00; - u8 status2 = 0x00; - u8 mask = 0x00; - u8 mask2 = 0x00; - u16 isr = 0x00; - u16 irq = 0; - void (*handler)(void *data) = NULL; - - DBG("Enter::%s %d\n",__FUNCTION__,__LINE__); - mutex_lock(&work_lock); - while (1) { - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status2, - TPS65910_REG_INT_STS2); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &mask2, - TPS65910_REG_INT_MSK2); - status2 &= (~mask2); - isr = (status2 << 8); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status, - TPS65910_REG_INT_STS); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &mask, - TPS65910_REG_INT_MSK); - status &= ~(mask); - isr |= status; - if (!isr) - break; - - while (isr) { - irq = fls(isr) - 1; - isr &= ~(1 << irq); - handler = gtps65910_platform->handlers[irq]; - if (handler) - handler(gtps65910_platform); - } - } - enable_irq(gtps65910_platform->irq_num); - mutex_unlock(&work_lock); -} - - -static irqreturn_t tps65910_isr(int irq, void *data) -{ - disable_irq_nosync(irq); - (void) schedule_work(&core_work); - return IRQ_HANDLED; -} - - -static struct device *add_numbered_child(unsigned chip, const char *name, - int num, void *pdata, unsigned pdata_len, bool can_wakeup, int irq) -{ - - struct platform_device *pdev; - struct tps65910_client *tps65910 = &tps65910_modules[chip]; - int status; - - pdev = platform_device_alloc(name, num); - if (!pdev) { - dev_dbg(&tps65910->client->dev, "can't alloc dev\n"); - status = -ENOMEM; - goto err; - } - device_init_wakeup(&pdev->dev, can_wakeup); - pdev->dev.parent = &tps65910->client->dev; - - if (pdata) { - status = platform_device_add_data(pdev, pdata, pdata_len); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add platform_data\n"); - goto err; - } - } - status = platform_device_add(pdev); - -err: - if (status < 0) { - platform_device_put(pdev); - dev_err(&tps65910->client->dev, "can't add %s dev\n", name); - return ERR_PTR(status); - } - return &pdev->dev; - -} - -static inline struct device *add_child(unsigned chip, const char *name, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq) -{ - return add_numbered_child(chip, name, -1, pdata, pdata_len, - can_wakeup, irq); -} - -static -struct device *add_regulator_linked(int num, struct regulator_init_data *pdata, - struct regulator_consumer_supply *consumers, - unsigned num_consumers) -{ - /* regulator framework demands init_data */ - if (!pdata) - return NULL; - - if (consumers) { - pdata->consumer_supplies = consumers; - pdata->num_consumer_supplies = num_consumers; - } - - return add_numbered_child(TPS65910_GENERAL, "tps65910_regulator", num, - pdata, sizeof(*pdata), false, TPS65910_HOST_IRQ); -} - - static struct device * -add_regulator(int num, struct regulator_init_data *pdata) -{ - return add_regulator_linked(num, pdata, NULL, 0); -} - -static int -add_children(struct tps65910_platform_data *pdata, unsigned long features) -{ - int status; - struct device *child; - - struct platform_device *pdev = NULL; - - DBG("cwz add_children: tps65910 add children.\n"); - - if (tps65910_has_gpio() && (pdata->gpio != NULL)) { - - pdev = platform_device_alloc("tps65910_gpio", -1); - if (!pdev) { - status = -ENOMEM; - goto err; - } - pdev->dev.parent = &tps65910_modules[0].client->dev; - device_init_wakeup(&pdev->dev, 0); - if (pdata) { - status = platform_device_add_data(pdev, pdata, - sizeof(*pdata)); - if (status < 0) { - dev_dbg(&pdev->dev, - "can't add platform_data\n"); - goto err; - } - } - } - if (tps65910_has_rtc()) { - child = add_child(TPS65910_GENERAL, "tps65910_rtc", - NULL, 0, true, pdata->irq_num); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (tps65910_has_regulator()) { - child = add_regulator(TPS65910_VIO, pdata->vio); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDD1, pdata->vdd1); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDD2, pdata->vdd2); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDD3, pdata->vdd3); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDIG1, pdata->vdig1); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDIG2, pdata->vdig2); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VAUX33, pdata->vaux33); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VMMC, pdata->vmmc); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VAUX1, pdata->vaux1); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VAUX2, pdata->vaux2); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VDAC, pdata->vdac); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TPS65910_VPLL, pdata->vpll); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - return 0; -err: - return -1; -} - -static int tps65910_remove(struct i2c_client *client) -{ - unsigned i; - - for (i = 0; i < TPS65910_NUM_SLAVES; i++) { - - struct tps65910_client *tps65910 = &tps65910_modules[i]; - - if (tps65910->client && tps65910->client != client) - i2c_unregister_device(tps65910->client); - - tps65910_modules[i].client = NULL; - } - inuse = false; - return 0; -} - -static int __init -tps65910_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int status; - unsigned i; - struct tps65910_platform_data *pdata; - - pdata = client->dev.platform_data; - gtps65910_platform = pdata; - - DBG("cwz: tps65910_i2c_probe\n"); - - if (!pdata) { - dev_dbg(&client->dev, "no platform data?\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(client->adapter,I2C_FUNC_I2C)) { - dev_dbg(&client->dev, "can't talk I2C?\n"); - return -EIO; - } - - if (inuse) { - dev_dbg(&client->dev, "driver is already in use\n"); - return -EBUSY; - } - for (i = 0; i < TPS65910_NUM_SLAVES; i++) { - - struct tps65910_client *tps65910 = &tps65910_modules[i]; - - tps65910->address = client->addr; - - if (i == 0) - tps65910->client = client; - else { - tps65910->client = i2c_new_dummy(client->adapter, - tps65910->address); - - if (!tps65910->client) { - dev_err(&client->dev, - "can't attach client %d\n", i); - status = -ENOMEM; - goto fail; - } - } - mutex_init(&tps65910->xfer_lock); - } - - inuse = true; - - if (pdata->board_tps65910_config != NULL) - pdata->board_tps65910_config(pdata); - - if (pdata->irq_num) { - /* TPS65910 power ON interrupt(s) would have already been - * occurred, so immediately after request_irq the control will - * be transferred to tps65910_isr, if we do core_work - * initialization after requesting IRQ, the system crashes - * and does not boot; to avoid this we do core_work - * initialization before requesting IRQ - */ - mutex_init(&work_lock); - - if(gpio_request(client->irq, "tps65910 irq")) - { - dev_err(&client->dev, "gpio request fail\n"); - gpio_free(client->irq); - goto fail; - } - - pdata->irq_num = gpio_to_irq(client->irq); - gpio_pull_updown(client->irq,GPIOPullUp); - - status = request_irq(pdata->irq_num, tps65910_isr, - IRQF_TRIGGER_FALLING, client->dev.driver->name, pdata); - if (status < 0) { - pr_err("tps65910: could not claim irq%d: %d\n", - pdata->irq_num, status); - goto fail; - } - enable_irq_wake(pdata->irq_num); - INIT_WORK(&core_work, tps65910_core_work); - } - - status = add_children(pdata, 0x00); - if (status < 0) - goto fail; - - return 0; - -fail: - if (status < 0) - tps65910_remove(client); - - return status; -} - - -static int tps65910_i2c_remove(struct i2c_client *client) -{ - unsigned i; - - for (i = 0; i < TPS65910_NUM_SLAVES; i++) { - - struct tps65910_client *tps65910 = &tps65910_modules[i]; - - if (tps65910->client && tps65910->client != client) - i2c_unregister_device(tps65910->client); - - tps65910_modules[i].client = NULL; - } - inuse = false; - return 0; -} - -/* chip-specific feature flags, for i2c_device_id.driver_data */ -static const struct i2c_device_id tps65910_i2c_ids[] = { - { "tps65910", TPS65910 }, - { "tps659101", TPS659101 }, - { "tps659102", TPS659102 }, - { "tps659103", TPS659103 }, - { "tps659104", TPS659104 }, - { "tps659105", TPS659105 }, - { "tps659106", TPS659106 }, - { "tps659107", TPS659107 }, - { "tps659108", TPS659108 }, - { "tps659109", TPS659109 }, - {/* end of list */ }, -}; -MODULE_DEVICE_TABLE(i2c, tps65910_i2c_ids); - -/* One Client Driver ,3 Clients - Regulator, RTC , GPIO */ -static struct i2c_driver tps65910_i2c_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .id_table = tps65910_i2c_ids, - .probe = tps65910_i2c_probe, - .remove = __devexit_p(tps65910_i2c_remove), -}; - -static int __init tps65910_init(void) -{ - int res; - - res = i2c_add_driver(&tps65910_i2c_driver); - if (res < 0) { - pr_err(DRIVER_NAME ": driver registration failed\n"); - return res; - } - - return 0; -} -subsys_initcall_sync(tps65910_init); - -static void __exit tps65910_exit(void) -{ - i2c_del_driver(&tps65910_i2c_driver); -} -module_exit(tps65910_exit); - - -#ifdef CONFIG_PROC_FS -#include -#include - -static int proc_tps65910_show(struct seq_file *s, void *v) -{ - u8 val = 0; - - seq_printf(s, "\n\nTPS65910 Registers is:\n"); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_REF); - seq_printf(s, "REF_REG=0x%x, Value=0x%x\n", TPS65910_REG_REF, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VRTC); - seq_printf(s, "VRTC_REG=0x%x, Value=0x%x\n", TPS65910_REG_VRTC, val); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD1); - seq_printf(s, "VDD1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD1, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD1_OP); - seq_printf(s, "VDD1_OP_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD1_OP, val); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD2); - seq_printf(s, "VDD2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD2, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD2_OP); - seq_printf(s, "VDD2_OP_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD2_OP, val); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VIO); - seq_printf(s, "VIO_REG=0x%x, Value=0x%x\n", TPS65910_REG_VIO, val); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDIG1); - seq_printf(s, "VDIG1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDIG1, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDIG2); - seq_printf(s, "VDIG2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDIG2, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX1); - seq_printf(s, "VAUX1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX1, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX2); - seq_printf(s, "VAUX2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX2, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX33); - seq_printf(s, "VAUX33_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX33, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VMMC); - seq_printf(s, "VMMC_REG=0x%x, Value=0x%x\n", TPS65910_REG_VMMC, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VPLL); - seq_printf(s, "VPLL_REG=0x%x, Value=0x%x\n", TPS65910_REG_VPLL, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDAC); - seq_printf(s, "VDAC_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDAC, val); - - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL); - seq_printf(s, "DEVCTRL_REG=0x%x, Value=0x%x\n", TPS65910_REG_DEVCTRL, val); - tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL2); - seq_printf(s, "DEVCTRL2_REG=0x%x, Value=0x%x\n", TPS65910_REG_DEVCTRL2, val); - -#if 0 // cwz 1 test vcore -{ - struct regulator *vldo; - - vldo = regulator_get(NULL, "vcore"); - if (!IS_ERR(vldo)) - { - int uV = 0; -#if 0 - seq_printf(s, "Set VCORE.\n"); - regulator_set_voltage(vldo,1350000,1350000); -#endif - uV = regulator_get_voltage(vldo); - seq_printf(s, "Get VCORE=%d(uV).\n", uV); - } -} -#endif - -#if 0 -{ - struct regulator *vldo; - -#if 1 - vldo = regulator_get(NULL, "vaux1"); - if (!IS_ERR(vldo)) - { - seq_printf(s, "Disable VAUX1.\n"); - regulator_disable(vldo); - } -#endif - -#if 1 - vldo = regulator_get(NULL, "vdig1"); - if (!IS_ERR(vldo)) - { - seq_printf(s, "Disable VDIG1.\n"); - regulator_disable(vldo); - } - - vldo = regulator_get(NULL, "vdig2"); - if (!IS_ERR(vldo)) - { - seq_printf(s, "Disable VDIG2.\n"); - regulator_disable(vldo); - } -#endif - -#if 0 // fih board is for hdmi - vldo = regulator_get(NULL, "vdac"); - if (!IS_ERR(vldo)) - { - seq_printf(s, "Disable VDAC.\n"); - regulator_disable(vldo); - } -#endif - -#if 1 - vldo = regulator_get(NULL, "vaux2"); - if (!IS_ERR(vldo)) - { - seq_printf(s, "Disable VAUX2.\n"); - regulator_disable(vldo); - } -#endif -} -#endif - - return 0; -} - -static int proc_tps65910_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_tps65910_show, NULL); -} - -static const struct file_operations proc_tps65910_fops = { - .open = proc_tps65910_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_tps65910_init(void) -{ - proc_create("tps65910", 0, NULL, &proc_tps65910_fops); - return 0; -} -late_initcall(proc_tps65910_init); -#endif /* CONFIG_PROC_FS */ - -MODULE_AUTHOR("cwz "); -MODULE_DESCRIPTION("I2C Core interface for TPS65910"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 265f75fc6a25..11a390a02e28 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,10 +26,13 @@ #include #include #include +#include + /* Current settings - values are 2*2^(reg_val/4) microamps. These are * exported since they are used by multiple drivers. */ + extern int reboot_cmd_get(void); int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { 2, 2, @@ -383,7 +387,7 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) * the notification of the interrupt may be delayed by * threaded IRQ handling. */ if (!wait_for_completion_timeout(&wm831x->auxadc_done, - msecs_to_jiffies(500))) { + msecs_to_jiffies(2000))) { dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); ret = -EBUSY; goto disable; @@ -997,6 +1001,20 @@ static struct mfd_cell wm8310_devs[] = { .num_resources = ARRAY_SIZE(wm831x_wdt_resources), .resources = wm831x_wdt_resources, }, +#if defined(CONFIG_KEYBOARD_WM831X_GPIO) + { + .name = "wm831x_gpio-keys", + .num_resources = 0, + }, +#endif +#if defined(CONFIG_WM831X_CHARGER_DISPLAY) + { + .name = "wm831x_charger_display", + .num_resources = 0, + }, +#endif + + }; static struct mfd_cell wm8311_devs[] = { @@ -1455,11 +1473,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); goto err; } - switch (ret) { - case 0x6204: - case 0x6246: - break; - default: + if (ret != 0x6204) { dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); ret = -EINVAL; goto err; @@ -1489,12 +1503,15 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) switch (ret) { case WM8310: parent = WM8310; - wm831x->num_gpio = 16; + wm831x->num_gpio = 12; wm831x->charger_irq_wake = 1; if (rev > 0) { wm831x->has_gpio_ena = 1; wm831x->has_cs_sts = 1; } + //ILIM = 900ma + ret = wm831x_reg_read(wm831x, WM831X_POWER_STATE) & 0xffff; + wm831x_reg_write(wm831x, WM831X_POWER_STATE, (ret&0xfff8) | 0x04); dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev); break; @@ -1541,12 +1558,15 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev); break; +<<<<<<< HEAD case WM8326: parent = WM8326; wm831x->num_gpio = 12; dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev); break; +======= +>>>>>>> parent of 15f7fab... temp revert rk change default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; @@ -1632,7 +1652,13 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8326: ret = mfd_add_devices(wm831x->dev, -1, wm8320_devs, ARRAY_SIZE(wm8320_devs), - NULL, wm831x->irq_base); + NULL, 0); + break; + + case WM8325: + ret = mfd_add_devices(wm831x->dev, -1, + wm8320_devs, ARRAY_SIZE(wm8320_devs), + NULL, 0); break; default: @@ -1658,7 +1684,11 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) wm831x_otp_init(wm831x); if (pdata && pdata->post_init) { + wm831x_reg_unlock(wm831x); + wm831x_set_bits(wm831x, WM831X_RESET_CONTROL,0x0010,0x0000); + wm831x_set_bits(wm831x, WM831X_LDO_ENABLE,0Xf800,0Xf800); ret = pdata->post_init(wm831x); + wm831x_reg_lock(wm831x); if (ret != 0) { dev_err(wm831x->dev, "post_init() failed: %d\n", ret); goto err_irq; @@ -1688,6 +1718,22 @@ void wm831x_device_exit(struct wm831x *wm831x) int wm831x_device_suspend(struct wm831x *wm831x) { int reg, mask; + int i; + + //mask some intterupt avoid wakeing up system while suspending + for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { + /* If there's been a change in the mask write it back + * to the hardware. */ + //printk("irq_masks_cur[%d]=0x%x\n",i,wm831x->irq_masks_cur[i]); + + if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { + wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; + wm831x_reg_write(wm831x, + WM831X_INTERRUPT_STATUS_1_MASK + i, + wm831x->irq_masks_cur[i]); + } + + } /* If the charger IRQs are a wake source then make sure we ack * them even if they're not actively being used (eg, no power @@ -1720,6 +1766,102 @@ int wm831x_device_suspend(struct wm831x *wm831x) return 0; } +<<<<<<< HEAD +======= +void wm831x_enter_sleep(void){ +#if 1//def CONFIG_RK2818_SOC_PM + struct regulator *dcdc; + int i; + dcdc=regulator_get(NULL, "dcdc1"); + struct wm831x_dcdc *dc = regulator_get_drvdata(dcdc); + struct wm831x *wm831x = dc->wm831x; + if(wm831x){ + wm831x_set_bits(wm831x, WM831X_POWER_STATE, 0x4000, 0x4000); // SYSTEM SLEEP MODE + for (i=0; i<5; i++) + wm831x_reg_write(wm831x,WM831X_INTERRUPT_STATUS_1+i, 0xffff); // INTRUPT FLAG CLEAR + + printk("%s:complete! \n",__func__); + + }else{ + printk("%s:error!",__func__); + } + regulator_put(dcdc); +#endif +} +EXPORT_SYMBOL_GPL(wm831x_enter_sleep); + +void wm831x_exit_sleep(void){ +#if 1//def CONFIG_RK2818_SOC_PM + struct regulator *dcdc; + dcdc=regulator_get(NULL, "dcdc1"); + struct wm831x_dcdc *dc = regulator_get_drvdata(dcdc); + struct wm831x *wm831x = dc->wm831x; + if(wm831x){ + wm831x_set_bits(wm831x, WM831X_POWER_STATE, 0x4000, 0); // SYSTEM ON MODE + printk("%s:complete! \n",__func__); + + }else{ + printk("%s:error!",__func__); + } + regulator_put(dcdc); +#endif +} +EXPORT_SYMBOL_GPL(wm831x_exit_sleep); + +int wm831x_device_shutdown(struct wm831x *wm831x) +{ + struct wm831x_pdata *pdata = wm831x->dev->platform_data; + int ret = 0; + + printk("pre WM831X_POWER_STATE = 0x%x\n", wm831x_reg_read(wm831x, WM831X_POWER_STATE)); + + if (pdata && pdata->last_deinit) { + ret = pdata->last_deinit(wm831x); + if (ret != 0) { + dev_info(wm831x->dev, "last_deinit() failed: %d\n", ret); + //goto err_irq; + } + } + + //if(0 == reboot_cmd_get()) + { + if(wm831x_set_bits(wm831x, WM831X_POWER_STATE, WM831X_CHIP_ON_MASK, 0) < 0) + printk("%s wm831x_set_bits err\n", __FUNCTION__); + //printk("post WM831X_POWER_STATE = 0x%x\n", wm831x_reg_read(wm831x, WM831X_POWER_STATE)); + } + + return 0; +} + +EXPORT_SYMBOL_GPL(wm831x_device_shutdown); + + +int wm831x_read_usb(struct wm831x *wm831x) +{ + int ret, usb_chg = 0, wall_chg = 0; + + ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS); + if (ret < 0) + return ret; + + if (ret & WM831X_PWR_USB) + usb_chg = 1; + if (ret & WM831X_PWR_WALL) + wall_chg = 1; + + return ((usb_chg | wall_chg) ? 1 : 0); + +} + + +int wm831x_device_restart(struct wm831x *wm831x) +{ + wm831x_reg_write(wm831x,WM831X_RESET_ID, 0xffff); + + return 0; +} + +>>>>>>> parent of 15f7fab... temp revert rk change MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index a06cbc739716..a905baf527bb 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -51,6 +52,7 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct i2c_client *i2c = wm831x->control_data; +<<<<<<< HEAD struct i2c_msg xfer[2]; int ret; @@ -70,6 +72,19 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, if (ret < 0) return ret; if (ret != 2) +======= + 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) +>>>>>>> parent of 15f7fab... temp revert rk change return -EIO; return 0; @@ -79,18 +94,44 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm831x *wm831x; +<<<<<<< HEAD + +======= + int ret,gpio,irq; +>>>>>>> parent of 15f7fab... temp revert rk change wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) return -ENOMEM; i2c_set_clientdata(i2c, wm831x); +<<<<<<< HEAD +======= + + gpio = i2c->irq; + ret = gpio_request(gpio, "wm831x"); + if (ret) { + printk( "failed to request rk gpio irq for wm831x \n"); + return ret; + } + gpio_pull_updown(gpio, GPIOPullUp); + if (ret) { + printk("failed to pull up gpio irq for wm831x \n"); + return ret; + } + irq = gpio_to_irq(gpio); + +>>>>>>> parent of 15f7fab... temp revert rk change wm831x->dev = &i2c->dev; wm831x->control_data = i2c; wm831x->read_dev = wm831x_i2c_read_device; wm831x->write_dev = wm831x_i2c_write_device; +<<<<<<< HEAD return wm831x_device_init(wm831x, id->driver_data, i2c->irq); +======= + return wm831x_device_init(wm831x, id->driver_data, irq); +>>>>>>> parent of 15f7fab... temp revert rk change } static int wm831x_i2c_remove(struct i2c_client *i2c) @@ -109,6 +150,33 @@ static int wm831x_i2c_suspend(struct device *dev) return wm831x_device_suspend(wm831x); } +static int wm831x_i2c_resume(struct device *dev) +{ + struct wm831x *wm831x = dev_get_drvdata(dev); + int i; + //set some intterupt again while resume + for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { + //printk("irq_masks_cur[%d]=0x%x\n",i,wm831x->irq_masks_cur[i]); + + if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { + wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; + wm831x_reg_write(wm831x, + WM831X_INTERRUPT_STATUS_1_MASK + i, + wm831x->irq_masks_cur[i]); + } + + } + + return 0; +} + +void wm831x_i2c_shutdown(struct i2c_client *i2c) +{ + struct wm831x *wm831x = i2c_get_clientdata(i2c); + printk("%s\n", __FUNCTION__); + wm831x_device_shutdown(wm831x); +} + static const struct i2c_device_id wm831x_i2c_id[] = { { "wm8310", WM8310 }, { "wm8311", WM8311 }, @@ -123,6 +191,7 @@ MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); static const struct dev_pm_ops wm831x_pm_ops = { .suspend = wm831x_i2c_suspend, + .resume = wm831x_i2c_resume, }; static struct i2c_driver wm831x_i2c_driver = { @@ -133,6 +202,7 @@ static struct i2c_driver wm831x_i2c_driver = { }, .probe = wm831x_i2c_probe, .remove = wm831x_i2c_remove, + .shutdown = wm831x_i2c_shutdown, .id_table = wm831x_i2c_id, }; @@ -140,6 +210,7 @@ static int __init wm831x_i2c_init(void) { int ret; + printk("%s \n", __FUNCTION__); ret = i2c_add_driver(&wm831x_i2c_driver); if (ret != 0) pr_err("Failed to register wm831x I2C driver: %d\n", ret); diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 42b928ec891e..5baffaaef70f 100755 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -25,6 +25,19 @@ #include #include +<<<<<<< HEAD +======= +#include +/* + * Since generic IRQs don't currently support interrupt controllers on + * interrupt driven buses we don't use genirq but instead provide an + * interface that looks very much like the standard ones. This leads + * to some bodges, including storing interrupt handler information in + * the static irq_data table we use to look up the data for individual + * interrupts, but hopefully won't last too long. + */ +#define WM831X_IRQ_TYPE IRQF_TRIGGER_LOW +>>>>>>> parent of 15f7fab... temp revert rk change struct wm831x_irq_data { int primary; @@ -32,6 +45,12 @@ struct wm831x_irq_data { int mask; }; +struct wm831x_handle_irq +{ + int irq; + struct list_head queue; +}; + static struct wm831x_irq_data wm831x_irqs[] = { [WM831X_IRQ_TEMP_THW] = { .primary = WM831X_TEMP_INT, @@ -373,6 +392,7 @@ static void wm831x_irq_enable(struct irq_data *data) data->irq); wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; + //printk("%s:irq=%d\n",__FUNCTION__,irq); } static void wm831x_irq_disable(struct irq_data *data) @@ -382,6 +402,16 @@ static void wm831x_irq_disable(struct irq_data *data) data->irq); wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; + //printk("%s:irq=%d\n",__FUNCTION__,irq); +} + +static void wm831x_irq_disable(unsigned int irq) +{ + struct wm831x *wm831x = get_irq_chip_data(irq); + struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); + + wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; + //printk("%s:irq=%d\n",__FUNCTION__,irq); } static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) @@ -389,16 +419,21 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) struct wm831x *wm831x = irq_data_get_irq_chip_data(data); int val, irq; +<<<<<<< HEAD irq = data->irq - wm831x->irq_base; if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { +======= + irq = irq - wm831x->irq_base; + if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_12) { +>>>>>>> parent of 15f7fab... temp revert rk change /* Ignore internal-only IRQs */ if (irq >= 0 && irq < WM831X_NUM_IRQS) return 0; else return -EINVAL; } - + //printk("wm831x_irq_set_type:type=%x,irq=%d\n",type,irq); switch (type) { case IRQ_TYPE_EDGE_BOTH: val = WM831X_GPN_INT_MODE; @@ -413,29 +448,106 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq, + return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq - 1, WM831X_GPN_INT_MODE | WM831X_GPN_POL, val); } +static int wm831x_irq_set_wake(unsigned irq, unsigned state) +{ + struct wm831x *wm831x = get_irq_chip_data(irq); + + //only wm831x irq + if ((irq > wm831x->irq_base + WM831X_IRQ_TEMP_THW) &&( irq < wm831x->irq_base + WM831X_NUM_IRQS)) + { + if(state) + wm831x_irq_unmask(irq); + else + wm831x_irq_mask(irq); + return 0; + } + else + { + printk("%s:irq number err!irq=%d\n",__FUNCTION__,irq); + return -EINVAL; + } + + +} + static struct irq_chip wm831x_irq_chip = { +<<<<<<< HEAD .name = "wm831x", .irq_bus_lock = wm831x_irq_lock, .irq_bus_sync_unlock = wm831x_irq_sync_unlock, .irq_disable = wm831x_irq_disable, .irq_enable = wm831x_irq_enable, .irq_set_type = wm831x_irq_set_type, +======= + .name = "wm831x", + .bus_lock = wm831x_irq_lock, + .bus_sync_unlock = wm831x_irq_sync_unlock, + .disable = wm831x_irq_disable, + .mask = wm831x_irq_mask, + .unmask = wm831x_irq_unmask, + .set_type = wm831x_irq_set_type, + .set_wake = wm831x_irq_set_wake, +>>>>>>> parent of 15f7fab... temp revert rk change }; -/* The processing of the primary interrupt occurs in a thread so that - * we can interact with the device over I2C or SPI. */ -static irqreturn_t wm831x_irq_thread(int irq, void *data) +#if WM831X_IRQ_LIST +static void wm831x_handle_worker(struct work_struct *work) { - struct wm831x *wm831x = data; + struct wm831x *wm831x = container_of(work, struct wm831x, handle_work); + int irq; + + while (1) { + unsigned long flags; + struct wm831x_handle_irq *hd = NULL; + + spin_lock_irqsave(&wm831x->work_lock, flags); + if (!list_empty(&wm831x->handle_queue)) { + hd = list_first_entry(&wm831x->handle_queue, struct wm831x_handle_irq, queue); + list_del(&hd->queue); + } + spin_unlock_irqrestore(&wm831x->work_lock, flags); + + if (!hd) // trans_queue empty + break; + + irq = hd->irq; //get wm831x intterupt status + //printk("%s:irq=%d\n",__FUNCTION__,irq); + + /*start to handle wm831x intterupt*/ + handle_nested_irq(wm831x->irq_base + irq); + + kfree(hd); + + } +} +#endif +/* Main interrupt handling occurs in a workqueue since we need + * interrupts enabled to interact with the chip. */ +static void wm831x_irq_worker(struct work_struct *work) +{ + struct wm831x *wm831x = container_of(work, struct wm831x, irq_work); unsigned int i; int primary; int status_regs[WM831X_NUM_IRQ_REGS] = { 0 }; int read[WM831X_NUM_IRQ_REGS] = { 0 }; int *status; + unsigned long flags; + struct wm831x_handle_irq *hd; + int ret; + +#if (WM831X_IRQ_TYPE != IRQF_TRIGGER_LOW) + /*mask wm831x irq at first*/ + ret = wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, + WM831X_IRQ_IM_MASK, WM831X_IRQ_IM_EANBLE); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to mask irq: %d\n", ret); + goto out; + } +#endif primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS); if (primary < 0) { @@ -443,6 +555,8 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) primary); goto out; } + + mutex_lock(&wm831x->irq_lock); /* The touch interrupts are visible in the primary register as * an optimisation; open code this to avoid complicating the @@ -458,10 +572,10 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { int offset = wm831x_irqs[i].reg - 1; - + if (!(primary & wm831x_irqs[i].primary)) continue; - + status = &status_regs[offset]; /* Hopefully there should only be one register to read @@ -473,7 +587,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) dev_err(wm831x->dev, "Failed to read IRQ status: %d\n", *status); - goto out; + goto out_lock; } read[offset] = 1; @@ -482,11 +596,39 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) /* Report it if it isn't masked, or forget the status. */ if ((*status & ~wm831x->irq_masks_cur[offset]) & wm831x_irqs[i].mask) + { + #if WM831X_IRQ_LIST + /*add intterupt handle on list*/ + hd = kzalloc(sizeof(struct wm831x_handle_irq), GFP_KERNEL); + if (!hd) + { + printk("err:%s:ENOMEM\n",__FUNCTION__); + return ; + } + + if(i == WM831X_IRQ_ON) + wake_lock(&wm831x->handle_wake); //keep wake while handle WM831X_IRQ_ON + hd->irq = i; + spin_lock_irqsave(&wm831x->work_lock, flags); + list_add_tail(&hd->queue, &wm831x->handle_queue); + spin_unlock_irqrestore(&wm831x->work_lock, flags); + queue_work(wm831x->handle_wq, &wm831x->handle_work); + + #else + if(i == WM831X_IRQ_ON) + wake_lock(&wm831x->handle_wake); //keep wake while handle WM831X_IRQ_ON handle_nested_irq(wm831x->irq_base + i); + + #endif + } + else *status &= ~wm831x_irqs[i].mask; } - + +out_lock: + mutex_unlock(&wm831x->irq_lock); + out: /* Touchscreen interrupts are handled specially in the driver */ status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); @@ -496,7 +638,45 @@ out: wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, status_regs[i]); } + +#if (WM831X_IRQ_TYPE != IRQF_TRIGGER_LOW) + ret = wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, + WM831X_IRQ_IM_MASK, 0); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to open irq: %d\n", ret); + } +#endif +#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW) + enable_irq(wm831x->irq); +#endif + wake_unlock(&wm831x->irq_wake); +} +/* The processing of the primary interrupt occurs in a thread so that + * we can interact with the device over I2C or SPI. */ +static irqreturn_t wm831x_irq_thread(int irq, void *data) +{ + struct wm831x *wm831x = data; + int msdelay = 0; + /* Shut the interrupt to the CPU up and schedule the actual + * handler; we can't check that the IRQ is asserted. */ +#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW) + disable_irq_nosync(irq); +#endif + wake_lock(&wm831x->irq_wake); + if(wm831x->flag_suspend) + { + spin_lock(&wm831x->flag_lock); + wm831x->flag_suspend = 0; + spin_unlock(&wm831x->flag_lock); + msdelay = 50; //wait for spi/i2c resume + printk("%s:msdelay=%d\n",__FUNCTION__,msdelay); + } + else + msdelay = 0; + + queue_delayed_work(wm831x->irq_wq, &wm831x->irq_work, msecs_to_jiffies(msdelay)); + //printk("%s\n",__FUNCTION__); return IRQ_HANDLED; } @@ -504,7 +684,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) { struct wm831x_pdata *pdata = wm831x->dev->platform_data; int i, cur_irq, ret; - + printk( "wm831x_irq_init:irq=%d,%d\n",irq,pdata->irq_base); mutex_init(&wm831x->irq_lock); /* Mask the individual interrupt sources */ @@ -521,6 +701,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) return 0; } +<<<<<<< HEAD if (pdata->irq_cmos) i = 0; else @@ -540,9 +721,32 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) ret); } +======= + wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq"); + if (!wm831x->irq_wq) { + dev_err(wm831x->dev, "Failed to allocate IRQ worker\n"); + return -ESRCH; + } + + +>>>>>>> parent of 15f7fab... temp revert rk change wm831x->irq = irq; + wm831x->flag_suspend = 0; wm831x->irq_base = pdata->irq_base; + INIT_DELAYED_WORK(&wm831x->irq_work, wm831x_irq_worker); + wake_lock_init(&wm831x->irq_wake, WAKE_LOCK_SUSPEND, "wm831x_irq_wake"); + wake_lock_init(&wm831x->handle_wake, WAKE_LOCK_SUSPEND, "wm831x_handle_wake"); +#if WM831X_IRQ_LIST + wm831x->handle_wq = create_rt_workqueue("wm831x_handle_wq"); + if (!wm831x->handle_wq) { + printk("cannot create workqueue\n"); + return -EBUSY; + } + INIT_WORK(&wm831x->handle_work, wm831x_handle_worker); + INIT_LIST_HEAD(&wm831x->handle_queue); +#endif + /* Register them with genirq */ for (cur_irq = wm831x->irq_base; cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; @@ -560,6 +764,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) irq_set_noprobe(cur_irq); #endif } +<<<<<<< HEAD if (irq) { ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, @@ -577,6 +782,24 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) +======= +#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW) + ret = request_threaded_irq(wm831x->irq, wm831x_irq_thread, NULL, + IRQF_TRIGGER_LOW| IRQF_ONESHOT,//IRQF_TRIGGER_FALLING, // + "wm831x", wm831x); +#else + ret = request_threaded_irq(wm831x->irq, wm831x_irq_thread, NULL, + IRQF_TRIGGER_FALLING, //IRQF_TRIGGER_LOW| IRQF_ONESHOT,// + "wm831x", wm831x); +#endif + if (ret != 0) { + dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", + wm831x->irq, ret); + return ret; + } + + enable_irq_wake(wm831x->irq); // so wm831x irq can wake up system +>>>>>>> parent of 15f7fab... temp revert rk change /* Enable top level interrupts, we mask at secondary level */ wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index eed8e4f7a5a1..97c8dab6c954 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -28,14 +29,24 @@ static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { +<<<<<<< HEAD tx_val = r | 0x8000; +======= + tx_val = cpu_to_be16(r | 0x8000); + //printk("read:reg=0x%x,",reg); +>>>>>>> parent of 15f7fab... temp revert rk change ret = spi_write_then_read(wm831x->control_data, (u8 *)&tx_val, 2, (u8 *)d, 2); if (ret != 0) return ret; +<<<<<<< HEAD *d = be16_to_cpu(*d); +======= + //printk("rec=0x%x\n",be16_to_cpu(*d)); + //*d = be16_to_cpu(*d); +>>>>>>> parent of 15f7fab... temp revert rk change d++; } @@ -53,9 +64,15 @@ static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { +<<<<<<< HEAD data[0] = r; data[1] = *s++; +======= + data[0] = cpu_to_be16(r); + data[1] = *s++; + //printk("write:reg=0x%x,send=0x%x\n",reg, data[0]); +>>>>>>> parent of 15f7fab... temp revert rk change ret = spi_write(spi, (char *)&data, sizeof(data)); if (ret != 0) return ret; @@ -68,7 +85,12 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) { struct wm831x *wm831x; enum wm831x_parent type; +<<<<<<< HEAD + +======= + int ret,gpio,irq; +>>>>>>> parent of 15f7fab... temp revert rk change /* Currently SPI support for ID tables is unmerged, we're faking it */ if (strcmp(spi->modalias, "wm8310") == 0) type = WM8310; @@ -96,13 +118,33 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) spi->bits_per_word = 16; spi->mode = SPI_MODE_0; +<<<<<<< HEAD +======= + gpio = spi->irq; + ret = gpio_request(gpio, "wm831x"); + if (ret) { + printk( "failed to request rk gpio irq for wm831x \n"); + return ret; + } + gpio_pull_updown(gpio, GPIOPullUp); + if (ret) { + printk("failed to pull up gpio irq for wm831x \n"); + return ret; + } + irq = gpio_to_irq(gpio); + +>>>>>>> parent of 15f7fab... temp revert rk change 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; +<<<<<<< HEAD return wm831x_device_init(wm831x, type, spi->irq); +======= + return wm831x_device_init(wm831x, type, irq); +>>>>>>> parent of 15f7fab... temp revert rk change } static int __devexit wm831x_spi_remove(struct spi_device *spi) @@ -118,6 +160,10 @@ static int wm831x_spi_suspend(struct device *dev) { struct wm831x *wm831x = dev_get_drvdata(dev); + spin_lock(&wm831x->flag_lock); + wm831x->flag_suspend = 1; + spin_unlock(&wm831x->flag_lock); + return wm831x_device_suspend(wm831x); } diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c old mode 100755 new mode 100644 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig old mode 100755 new mode 100644 index 68f367184ab5..a9a94491b028 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -535,9 +535,30 @@ config APANIC_PLABEL If your platform uses a different flash partition label for storing crashdumps, enter it here. +config STE + bool "STE modem control driver" + +config MTK23D + bool "MTK6223D modem control driver" + +config FM580X + bool "FM rda580x driver" + +config MU509 + bool "MU509 modem control driver" + +config MW100 + bool "MW100 modem control driver" + +config RK29_NEWTON + bool "RK29_NEWTON misc driver" + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" +source "drivers/misc/rk29_modem/Kconfig" +source "drivers/misc/gps/Kconfig" +source "drivers/misc/mpu3050/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile old mode 100755 new mode 100644 index 2d430484519c..c4ed797a893b --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -52,3 +52,12 @@ obj-y += carma/ obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o obj-$(CONFIG_APANIC) += apanic.o obj-$(CONFIG_SENSORS_AK8975) += akm8975.o +obj-$(CONFIG_MTK23D) += mtk23d.o +obj-$(CONFIG_FM580X) += fm580x.o +obj-$(CONFIG_MU509) += mu509.o +obj-$(CONFIG_MW100) += MW100.o +obj-$(CONFIG_STE) += ste.o +obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ +obj-$(CONFIG_GPS_GNS7560) += gps/ +obj-y += mpu3050/ +obj-$(CONFIG_RK29_NEWTON) += newton.o diff --git a/drivers/misc/apanic.c b/drivers/misc/apanic.c index ca875f89da7a..4a9f48ac7480 100644 --- a/drivers/misc/apanic.c +++ b/drivers/misc/apanic.c @@ -193,8 +193,13 @@ static int apanic_proc_read(char *buffer, char **start, off_t offset, ctx->mtd->writesize, &len, ctx->bounce); +#ifdef CONFIG_MTD_RKNAND + if (count > (ctx->mtd->writesize - page_offset)) + count = ctx->mtd->writesize - page_offset; +#else if (page_offset) count -= page_offset; +#endif memcpy(buffer, ctx->bounce + page_offset, count); *start = count; @@ -209,6 +214,11 @@ static int apanic_proc_read(char *buffer, char **start, off_t offset, static void mtd_panic_erase(void) { struct apanic_data *ctx = &drv_ctx; +#ifdef CONFIG_MTD_RKNAND + size_t wlen; + memset(ctx->bounce, 0, ctx->mtd->writesize); + ctx->mtd->write(ctx->mtd, 0, ctx->mtd->writesize, &wlen, ctx->bounce); +#else struct erase_info erase; DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; @@ -260,6 +270,7 @@ static void mtd_panic_erase(void) schedule(); remove_wait_queue(&wait_q, &wait); } +#endif printk(KERN_DEBUG "apanic: %s partition erased\n", CONFIG_APANIC_PLABEL); out: @@ -331,14 +342,18 @@ static void mtd_panic_notify_add(struct mtd_info *mtd) if (hdr->magic != PANIC_MAGIC) { printk(KERN_INFO "apanic: No panic data available\n"); +#ifndef CONFIG_MTD_RKNAND mtd_panic_erase(); +#endif return; } if (hdr->version != PHDR_VERSION) { printk(KERN_INFO "apanic: Version mismatch (%d != %d)\n", hdr->version, PHDR_VERSION); +#ifndef CONFIG_MTD_RKNAND mtd_panic_erase(); +#endif return; } @@ -378,8 +393,10 @@ static void mtd_panic_notify_add(struct mtd_info *mtd) } } +#ifndef CONFIG_MTD_RKNAND if (!proc_entry_created) mtd_panic_erase(); +#endif return; out_err: @@ -511,7 +528,7 @@ static int apanic(struct notifier_block *this, unsigned long event, printk(KERN_EMERG "Crash partition in use!\n"); goto out; } - console_offset = ctx->mtd->writesize; + console_offset = ctx->mtd->erasesize; /* * Write out the console diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c index abb73c143164..b47acd333f35 100644 --- a/drivers/misc/pmem.c +++ b/drivers/misc/pmem.c @@ -1087,8 +1087,8 @@ static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 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); + //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; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c779503e7578..c8ddf2dfe9a0 100755 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -521,6 +521,13 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) return result; } +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) //Deleted by xbw@2011-03-21 +//static u32 get_card_status(struct mmc_card *card, struct request *req) +//{ +// return 0; +//} + +#else static u32 get_card_status(struct mmc_card *card, struct request *req) { struct mmc_command cmd = {0}; @@ -532,10 +539,11 @@ static u32 get_card_status(struct mmc_card *card, struct request *req) cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) - printk(KERN_ERR "%s: error %d sending status command", + printk(KERN_DEBUG "%s: error %d sending status command", req->rq_disk->disk_name, err); return cmd.resp[0]; } +#endif static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { @@ -689,6 +697,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; + #if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + brq.cmd.retries = 2; //suppot retry read-write; added by xbw@2011-03-21 + #endif + brq.cmd.arg = blk_rq_pos(req); if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; @@ -799,6 +811,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) mmc_queue_bounce_post(mq); + #if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + //not turn CMD18 to CMD17. deleted by xbw at 2011-04-21 + + #else + /* * Check for errors here, but don't jump to cmd_err * until later as we need to wait for the card to leave @@ -808,7 +825,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) brq.data.error || brq.stop.error) { if (brq.data.blocks > 1 && rq_data_dir(req) == READ) { /* Redo read one sector at a time */ - printk(KERN_WARNING "%s: retrying using single " + printk(KERN_DEBUG "%s: retrying using single " "block read\n", req->rq_disk->disk_name); disable_multi = 1; continue; @@ -817,6 +834,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) } else if (disable_multi == 1) { disable_multi = 0; } + #endif if (brq.sbc.error) { printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT " @@ -826,7 +844,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) } if (brq.cmd.error) { - printk(KERN_ERR "%s: error %d sending read/write " + printk(KERN_DEBUG "%s: error %d sending read/write " "command, response %#x, card status %#x\n", req->rq_disk->disk_name, brq.cmd.error, brq.cmd.resp[0], status); @@ -836,7 +854,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) if (brq.data.error == -ETIMEDOUT && brq.mrq.stop) /* 'Stop' response contains card status */ status = brq.mrq.stop->resp[0]; - printk(KERN_ERR "%s: error %d transferring data," + printk(KERN_DEBUG "%s: error %d transferring data," " sector %u, nr %u, card status %#x\n", req->rq_disk->disk_name, brq.data.error, (unsigned)blk_rq_pos(req), @@ -844,12 +862,16 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) } if (brq.stop.error) { - printk(KERN_ERR "%s: error %d sending stop command, " + printk(KERN_DEBUG "%s: error %d sending stop command, " "response %#x, card status %#x\n", req->rq_disk->disk_name, brq.stop.error, brq.stop.resp[0], status); } + #if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + //Deleted by xbw@2011-03-21 + + #else if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { int err; @@ -859,7 +881,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { - printk(KERN_ERR "%s: error %d requesting status\n", + printk(KERN_DEBUG "%s: error %d requesting status\n", req->rq_disk->disk_name, err); goto cmd_err; } @@ -879,6 +901,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) goto cmd_err; #endif } +#endif if (brq.cmd.error || brq.stop.error || brq.data.error) { if (rq_data_dir(req) == READ) { @@ -1063,6 +1086,11 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), "mmcblk%d%s", md->name_idx, subname ? subname : ""); +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + printk("%s..%d **** devidx=%d, dev_use[0]=%lu, disk_name=%s *** ==xbw[%s]==\n",\ + __FUNCTION__,__LINE__, devidx, dev_use[0], md->disk->disk_name,mmc_hostname(card->host)); +#endif + blk_queue_logical_block_size(md->queue.queue, 512); set_capacity(md->disk, size); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 7c3444a37070..b453ecc9710b 100755 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -215,6 +215,9 @@ static void mmc_wait_done(struct mmc_request *mrq) */ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) { + unsigned long datasize, waittime = 0xFFFF; + u32 multi, unit; + DECLARE_COMPLETION_ONSTACK(complete); mrq->done_data = &complete; @@ -222,7 +225,47 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) mmc_start_request(host, mrq); +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + if( strncmp( mmc_hostname(host) ,"mmc0" , strlen("mmc0")) ) + { + multi = (mrq->cmd->retries>0)?mrq->cmd->retries:1; + waittime = wait_for_completion_timeout(&complete,HZ*7*multi); //sdio; for cmd dead. Modifyed by xbw at 2011-06-02 + } + else + { + //calculate the timeout value for SDMMC; added by xbw at 2011-09-27 + if(mrq->data) + { + unit = 3*(1<<20);// unit=3MB + datasize = mrq->data->blksz*mrq->data->blocks; + multi = datasize/unit; + multi += (datasize%unit)?1:0; + multi = (multi>0) ? multi : 1; + multi += (mrq->cmd->retries>0)?1:0; + waittime = wait_for_completion_timeout(&complete,HZ*7*multi); //It should be longer than bottom driver's time,due to the sum of two cmd time. + //modifyed by xbw at 2011-10-08 + // + //example: + //rk29_sdmmc_request_end..2336... CMD12 wait busy timeout!!!!! ====xbw=[sd_mmc]==== + //mmc_wait_for_req..236.. !!!!! wait for CMD25 timeout ===xbw[mmc0]=== + } + else + { + multi = (mrq->cmd->retries>0)?mrq->cmd->retries:1; + waittime = wait_for_completion_timeout(&complete,HZ*7*multi); + } + } + + if(waittime <= 1) + { + host->doneflag = 0; + mrq->cmd->error = -EIO; + printk("%s..%d.. !!!!! wait for CMD%d timeout ===xbw[%s]===\n",\ + __FUNCTION__, __LINE__, mrq->cmd->opcode, mmc_hostname(host)); + } +#else wait_for_completion(&complete); +#endif } EXPORT_SYMBOL(mmc_wait_for_req); @@ -1869,6 +1912,11 @@ int mmc_resume_host(struct mmc_host *host) } } BUG_ON(!host->bus_ops->resume); +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + //panic if the card is being removed during the resume, deleted by xbw at 2011-06-20 + host->bus_ops->resume(host); + +#else err = host->bus_ops->resume(host); if (err) { printk(KERN_WARNING "%s: error %d during resume " @@ -1876,6 +1924,7 @@ int mmc_resume_host(struct mmc_host *host) mmc_hostname(host), err); err = 0; } +#endif } host->pm_flags &= ~MMC_PM_KEEP_POWER; mmc_bus_put(host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index aa7d1d79b8c5..406f29efde3a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -559,7 +559,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* The extra bit indicates that we support high capacity */ err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr); if (err) + { +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + printk("%s..%d.. ====*Identify the card as MMC , but OCR error, so fail to initialize.===xbw[%s]===\n",\ + __FUNCTION__, __LINE__, mmc_hostname(host)); +#endif goto err; + } /* * For SPI, enable CRC as appropriate. @@ -734,6 +740,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + //in order to expand the compatibility of card. Added by xbw@2011-03-21 + card->csd.max_dtr = (card->csd.max_dtr > MMC_FPP_FREQ) ? MMC_FPP_FREQ : (card->csd.max_dtr); +#endif max_dtr = card->csd.max_dtr; } @@ -1012,6 +1022,9 @@ int mmc_attach_mmc(struct mmc_host *host) { int err; u32 ocr; +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + int retry_times = 3; +#endif BUG_ON(!host); WARN_ON(!host->claimed); @@ -1062,10 +1075,34 @@ int mmc_attach_mmc(struct mmc_host *host) goto err; mmc_release_host(host); + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) +//modifyed by xbw at 2011--04-11 +Retry_add: + err = mmc_add_card(host->card); + mmc_claim_host(host); + if (err) + { + //retry add the card; Added by xbw + if((--retry_times >= 0)) + { + printk("\n%s..%s..%d ****error in add partition, so retry. ===xbw[%s]===\n",__FUNCTION__,__FILE__,__LINE__, mmc_hostname(host)); + /* sleep some time */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + + goto Retry_add; + } + + goto remove_card; + + } +#else err = mmc_add_card(host->card); mmc_claim_host(host); if (err) goto remove_card; +#endif return 0; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 5decf4972bcb..550092d600ae 100755 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -718,8 +718,13 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) try_again: err = mmc_send_app_op_cond(host, ocr, rocr); - if (err) + if (err) { +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + printk("%s..%d.. ====*Identify the card as SD , but OCR error, so fail to initialize.===xbw[%s]===\n", \ + __FUNCTION__, __LINE__, mmc_hostname(host)); +#endif return err; + } /* * In case CCS and S18A in the response is set, start Signal Voltage @@ -807,6 +812,13 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, printk(KERN_WARNING "%s: read switch failed (attempt %d)\n", mmc_hostname(host), retries); + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + if(0 == host->re_initialized_flags) + { + break; //Added by xbw at 2011-06-21 + } +#endif } } #else @@ -859,6 +871,11 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card) if (max_dtr > card->sw_caps.hs_max_dtr) max_dtr = card->sw_caps.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + //in order to expand the compatibility of card. Added by xbw@2011-03-21 + card->csd.max_dtr = (card->csd.max_dtr > SD_FPP_FREQ) ? SD_FPP_FREQ : (card->csd.max_dtr); +#endif max_dtr = card->csd.max_dtr; } @@ -1029,6 +1046,15 @@ static void mmc_sd_detect(struct mmc_host *host) err = mmc_send_status(host->card, NULL); if (err) { retries--; + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + if(0 == host->re_initialized_flags) + { + retries = 0; + break; //Added by xbw at 2011-06-21 + } +#endif + udelay(5); continue; } @@ -1096,6 +1122,13 @@ static int mmc_sd_resume(struct mmc_host *host) mmc_hostname(host), err, retries); mdelay(5); retries--; + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + if(0 == host->re_initialized_flags) + { + break; //Added by xbw at 2011-06-21 + } +#endif continue; } break; @@ -1154,6 +1187,10 @@ int mmc_attach_sd(struct mmc_host *host) { int err; u32 ocr; +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + int retry_times = 3; +#endif + #ifdef CONFIG_MMC_PARANOID_SD_INIT int retries; #endif @@ -1227,6 +1264,14 @@ int mmc_attach_sd(struct mmc_host *host) err = mmc_sd_init_card(host, host->ocr, NULL); if (err) { retries--; + + #if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + if(0 == host->re_initialized_flags) + { + retries = 0; + break; //Added by xbw at 2011-06-21 + } + #endif continue; } break; @@ -1244,10 +1289,34 @@ int mmc_attach_sd(struct mmc_host *host) #endif mmc_release_host(host); + +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) +//modifyed by xbw at 2011--04-11 +Retry_add: + err = mmc_add_card(host->card); + mmc_claim_host(host); + if (err) + { + //retry add the card; Added by xbw + if((--retry_times >= 0)) + { + printk("\n%s..%s..%d ****error in add partition, so retry. ===xbw[%s]===\n",__FUNCTION__,__FILE__,__LINE__, mmc_hostname(host)); + /* sleep some time */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + + goto Retry_add; + } + + goto remove_card; + + } +#else err = mmc_add_card(host->card); mmc_claim_host(host); if (err) goto remove_card; +#endif return 0; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 7da522e958a0..689a465cd43d 100755 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -351,8 +351,13 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ if (!powered_resume) { err = mmc_send_io_op_cond(host, host->ocr, &ocr); - if (err) + if (err) { +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + printk("%s..%d.. ====*Identify the card as SDIO , but OCR error, so fail to initialize.===xbw[%s]===\n", \ + __FUNCTION__, __LINE__, mmc_hostname(host)); +#endif goto err; + } } /* @@ -405,6 +410,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (err) goto remove; +#if !defined(CONFIG_SDMMC_RK29) || defined(CONFIG_SDMMC_RK29_OLD) /* * Update oldcard with the new RCA received from the SDIO * device -- we're doing this so that it's updated in the @@ -412,6 +418,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ if (oldcard) oldcard->rca = card->rca; +#endif mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } @@ -932,6 +939,10 @@ int sdio_reset_comm(struct mmc_card *card) printk("%s():\n", __func__); mmc_claim_host(host); +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + host->sdmmc_host_hw_init(mmc_priv(host)); //added by xbw , at 2011-10-18 +#endif + mmc_go_idle(host); mmc_set_clock(host, host->f_min); diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 58a5cf73d6e9..f626b3fcc9f5 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -2,6 +2,12 @@ # Makefile for MMC/SD host controller drivers # +ifeq ($(CONFIG_SDMMC_RK29_OLD),y) +obj-$(CONFIG_SDMMC_RK29) += rk29_sdmmc_old.o +else +obj-$(CONFIG_SDMMC_RK29) += rk29_sdmmc.o +endif + obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index a338f31d289c..ae92103ddb65 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -3177,8 +3177,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) /* * We can do SGIO */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + mmc->max_segs = 64; +#else mmc->max_phys_segs = 64; mmc->max_hw_segs = 64; +#endif /* * Block size can be up to 2048 bytes, but must be a power of two. diff --git a/drivers/mmc/host/rk29_sdmmc_old.c b/drivers/mmc/host/rk29_sdmmc_old.c index 2e2e109de32c..0685f70e701b 100755 --- a/drivers/mmc/host/rk29_sdmmc_old.c +++ b/drivers/mmc/host/rk29_sdmmc_old.c @@ -1404,8 +1404,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) mmc->f_max = host->bus_hz; mmc->ocr_avail = pdata->host_ocr_avail; mmc->caps = pdata->host_caps; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + mmc->max_segs = 64; +#else mmc->max_phys_segs = 64; mmc->max_hw_segs = 64; +#endif mmc->max_blk_size = 4096; mmc->max_blk_count = 65535; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; diff --git a/drivers/mtd/rknand/rknand_base_ko.c b/drivers/mtd/rknand/rknand_base_ko.c index 483e8a977102..5effa3d67160 100755 --- a/drivers/mtd/rknand/rknand_base_ko.c +++ b/drivers/mtd/rknand/rknand_base_ko.c @@ -310,7 +310,11 @@ static int rk29xxnand_add_partitions(struct rknand_info *nand_info) rknand_parts[num_partitions - 1].size = rknand_mtd.size - rknand_parts[num_partitions - 1].offset; g_num_partitions = num_partitions; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + return mtd_device_register(&rknand_mtd, rknand_parts, num_partitions); +#else return add_mtd_partitions(&(rknand_mtd), rknand_parts, num_partitions); +#endif } #endif return 0; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f1d88c571bc4..991df931d4aa 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -17,280 +17,53 @@ menuconfig WLAN if WLAN -config PCMCIA_RAYCS - tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV +config WLAN_80211 + bool "Wireless LAN (IEEE 802.11)" + depends on NETDEVICES ---help--- - Say Y here if you intend to attach an Aviator/Raytheon PCMCIA - (PC-card) wireless Ethernet networking card to your computer. - Please read the file for - details. + Say Y if you have any 802.11 wireless LAN hardware. + + This option does not affect the kernel build, it only + lets you choose drivers. + +choice + prompt "WiFi device driver support" + default WIFI_NONE + + config WIFI_NONE + bool "No WiFi" + + config BCM4329 + depends on WLAN_80211 && MMC + select WIRELESS_EXT + select WEXT_PRIV + select IEEE80211 + select FW_LOADER + bool "Broadcom BCM4329 WiFi/BT Combo SDIO" + ---help--- + A library for Broadcom BCM4329 SDIO WLAN/BT combo devices. + So far, the following modules have been verified: + (1) Samsung SWL-B23 + + config MV8686 + depends on WLAN_80211 && MMC + select WIRELESS_EXT + select IEEE80211 + select FW_LOADER + bool "Marvell MV8686 SDIO" + ---help--- + A library for Marvell 8686 SDIO WLAN devices. + So far, the following modules have been verified: + (1) Samsung SWL-2480 + (2) Azurewave AW-GH321 + (3) USI WM-G-MR-09 + (4) Murata SP-8HEP-P + +source "drivers/net/wireless/bcm4319/Kconfig" +source "drivers/net/wireless/rtl8192c/Kconfig" +endchoice + +#source "drivers/net/wireless/bcm4329/Kconfig" + +endif - To compile this driver as a module, choose M here: the module will be - called ray_cs. If unsure, say N. - -config LIBERTAS_THINFIRM - tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" - depends on MAC80211 - select FW_LOADER - ---help--- - A library for Marvell Libertas 8xxx devices using thinfirm. - -config LIBERTAS_THINFIRM_DEBUG - bool "Enable full debugging output in the Libertas thin firmware module." - depends on LIBERTAS_THINFIRM - ---help--- - Debugging support. - -config LIBERTAS_THINFIRM_USB - tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware" - depends on LIBERTAS_THINFIRM && USB - ---help--- - A driver for Marvell Libertas 8388 USB devices using thinfirm. - -config AIRO - tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on ISA_DMA_API && (PCI || BROKEN) - select WIRELESS_EXT - select CRYPTO - select WEXT_SPY - select WEXT_PRIV - ---help--- - This is the standard Linux driver to support Cisco/Aironet ISA and - PCI 802.11 wireless cards. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - - The driver can be compiled as a module and will be named "airo". - -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - ---help--- - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - ---help--- - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - -config AT76C50X_USB - tristate "Atmel at76c503/at76c505/at76c505a USB cards" - depends on MAC80211 && USB - select FW_LOADER - ---help--- - Enable support for USB Wireless devices using Atmel at76c503, - at76c505 or at76c505a chips. - -config AIRO_CS - tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on PCMCIA && (BROKEN || !M32R) - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_AES - ---help--- - This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet - driver part of the Linux Pcmcia package. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also - supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom - 802.11b cards. - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - -config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' - depends on PCI && EXPERIMENTAL - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - ---help--- - This enables support for FullMAC PCI/Cardbus prism54 devices. This - driver is now deprecated in favor for the SoftMAC driver, p54pci. - p54pci supports FullMAC PCI/Cardbus devices as well. For details on - the scheduled removal of this driver on the kernel see the feature - removal schedule: - - Documentation/feature-removal-schedule.txt - - For more information refer to the p54 wiki: - - http://wireless.kernel.org/en/users/Drivers/p54 - - Note: You need a motherboard with DMA support to use any of these cards - - When built as module you get the module prism54 - -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - ---help--- - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - -config USB_NET_RNDIS_WLAN - tristate "Wireless RNDIS USB support" - depends on USB && EXPERIMENTAL - depends on CFG80211 - select USB_USBNET - select USB_NET_CDCETHER - select USB_NET_RNDIS_HOST - ---help--- - This is a driver for wireless RNDIS devices. - These are USB based adapters found in devices such as: - - Buffalo WLI-U2-KG125S - U.S. Robotics USR5421 - Belkin F5D7051 - Linksys WUSB54GSv2 - Linksys WUSB54GSC - Asus WL169gE - Eminent EM4045 - BT Voyager 1055 - Linksys WUSB54GSv1 - U.S. Robotics USR5420 - BUFFALO WLI-USB-G54 - - All of these devices are based on Broadcom 4320 chip which is the - only wireless RNDIS chip known to date. - - If you choose to build a module, it'll be called rndis_wlan. - -source "drivers/net/wireless/rtl818x/Kconfig" - -config ADM8211 - tristate "ADMtek ADM8211 support" - depends on MAC80211 && PCI && EXPERIMENTAL - select CRC32 - select EEPROM_93CX6 - ---help--- - This driver is for ADM8211A, ADM8211B, and ADM8211C based cards. - These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as: - - Xterasys Cardbus XN-2411b - Blitz NetWave Point PC - TrendNet 221pc - Belkin F5D6001 - SMC 2635W - Linksys WPC11 v1 - Fiberline FL-WL-200X - 3com Office Connect (3CRSHPW796) - Corega WLPCIB-11 - SMC 2602W V2 EU - D-Link DWL-520 Revision C - - However, some of these cards have been replaced with other chips - like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or - the Ralink RT2400 (SMC2635W) without a model number change. - - Thanks to Infineon-ADMtek for their support of this driver. - -config MAC80211_HWSIM - tristate "Simulated radio testing tool for mac80211" - depends on MAC80211 - ---help--- - This driver is a developer testing tool that can be used to test - IEEE 802.11 networking stack (mac80211) functionality. This is not - needed for normal wireless LAN usage and is only for testing. See - Documentation/networking/mac80211_hwsim for more information on how - to use this tool. - - To compile this driver as a module, choose M here: the module will be - called mac80211_hwsim. If unsure, say N. - -config MWL8K - tristate "Marvell 88W8xxx PCI/PCIe Wireless support" - depends on MAC80211 && PCI && EXPERIMENTAL - ---help--- - This driver supports Marvell TOPDOG 802.11 wireless cards. - - To compile this driver as a module, choose M here: the module - will be called mwl8k. If unsure, say N. - -config WIFI_CONTROL_FUNC - bool "Enable WiFi control function abstraction" - help - Enables Power/Reset/Carddetect function abstraction - -source "drivers/net/wireless/ath/Kconfig" -source "drivers/net/wireless/b43/Kconfig" -source "drivers/net/wireless/b43legacy/Kconfig" -source "drivers/net/wireless/bcm4329/Kconfig" -source "drivers/net/wireless/bcmdhd/Kconfig" -source "drivers/net/wireless/hostap/Kconfig" -source "drivers/net/wireless/ipw2x00/Kconfig" -source "drivers/net/wireless/iwlwifi/Kconfig" -source "drivers/net/wireless/iwlegacy/Kconfig" -source "drivers/net/wireless/iwmc3200wifi/Kconfig" -source "drivers/net/wireless/libertas/Kconfig" -source "drivers/net/wireless/orinoco/Kconfig" -source "drivers/net/wireless/p54/Kconfig" -source "drivers/net/wireless/rt2x00/Kconfig" -source "drivers/net/wireless/rtlwifi/Kconfig" -source "drivers/net/wireless/wl1251/Kconfig" -source "drivers/net/wireless/wl12xx/Kconfig" -source "drivers/net/wireless/zd1211rw/Kconfig" -source "drivers/net/wireless/mwifiex/Kconfig" - -endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 8ceae0a8ba0f..f463629aa9c2 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -1,63 +1,9 @@ # # Makefile for the Linux Wireless network device drivers. # - -obj-$(CONFIG_IPW2100) += ipw2x00/ -obj-$(CONFIG_IPW2200) += ipw2x00/ - -obj-$(CONFIG_HERMES) += orinoco/ - -obj-$(CONFIG_AIRO) += airo.o -obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o - -obj-$(CONFIG_ATMEL) += atmel.o -obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o -obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o - -obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o - -obj-$(CONFIG_PRISM54) += prism54/ - -obj-$(CONFIG_HOSTAP) += hostap/ -obj-$(CONFIG_B43) += b43/ -obj-$(CONFIG_B43LEGACY) += b43legacy/ -obj-$(CONFIG_ZD1211RW) += zd1211rw/ -obj-$(CONFIG_RTL8180) += rtl818x/ -obj-$(CONFIG_RTL8187) += rtl818x/ -obj-$(CONFIG_RTLWIFI) += rtlwifi/ - -# 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o -obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o - -obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o - -obj-$(CONFIG_USB_ZD1201) += zd1201.o -obj-$(CONFIG_LIBERTAS) += libertas/ - -obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ - -obj-$(CONFIG_ADM8211) += adm8211.o - -obj-$(CONFIG_MWL8K) += mwl8k.o - -obj-$(CONFIG_IWLAGN) += iwlwifi/ -obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/ -obj-$(CONFIG_RT2X00) += rt2x00/ - -obj-$(CONFIG_P54_COMMON) += p54/ - -obj-$(CONFIG_ATH_COMMON) += ath/ - -obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o - -obj-$(CONFIG_WL1251) += wl1251/ -obj-$(CONFIG_WL12XX) += wl12xx/ -obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ - -obj-$(CONFIG_IWM) += iwmc3200wifi/ - -obj-$(CONFIG_MWIFIEX) += mwifiex/ - -obj-$(CONFIG_BCM4329) += bcm4329/ -obj-$(CONFIG_BCMDHD) += bcmdhd/ +obj-y += wifi_sys/rkwifi_sys_iface.o +obj-$(CONFIG_BCM4329) += bcm4329/ +obj-$(CONFIG_MV8686) += mv8686/ +obj-$(CONFIG_BCM4319) += bcm4319/ +obj-$(CONFIG_RTL8192CU) += rtl8192c/ +#obj-m += wlan/ diff --git a/drivers/net/wireless/bcm4329/Kconfig b/drivers/net/wireless/bcm4329/Kconfig index ca5760d32385..aa4355a6225e 100644 --- a/drivers/net/wireless/bcm4329/Kconfig +++ b/drivers/net/wireless/bcm4329/Kconfig @@ -22,6 +22,6 @@ config BCM4329_FW_PATH config BCM4329_NVRAM_PATH depends on BCM4329 string "NVRAM path" - default "/proc/calibration" + default "/system/etc/firmware/nvram_B23.txt" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile old mode 100644 new mode 100755 index 5a662be7fc53..fd04754d70b1 --- a/drivers/net/wireless/bcm4329/Makefile +++ b/drivers/net/wireless/bcm4329/Makefile @@ -3,13 +3,16 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \ -DUNRELEASEDCHIP -Dlinux -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 \ -DDHD_FIRSTREAD=64 -DDHD_GPL -DDHD_SCHED -DBDC -DTOE -DDHD_BCMEVENTS \ -DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \ - -Wall -Wstrict-prototypes -Werror -DOOB_INTR_ONLY -DCUSTOMER_HW2 \ - -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DDHD_DEBUG_TRAP -DSOFTAP \ + -Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 \ + -DDHD_USE_STATIC_BUF -DDHD_DEBUG_TRAP -DSOFTAP -DSDIO_ISR_THREAD \ -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \ - -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP -DCSCAN -DHW_OOB \ - -DKEEP_ALIVE -DPNO_SUPPORT \ + -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP -DCSCAN \ + -DKEEP_ALIVE -DCONFIG_US_NON_DFS_CHANNELS_ONLY \ -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include +#options defines dependent on platform board and applicantion requirements: +#-DOOB_INTR_ONLY -DMMC_SDIO_ABORT -DHW_OOB + DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ wl_iw.o siutils.o sbutils.o aiutils.o hndpmu.o bcmwifi.o dhd_sdio.o \ dhd_linux_sched.o dhd_cdc.o bcmsdh_sdmmc.o bcmsdh.o bcmsdh_linux.o \ diff --git a/drivers/net/wireless/bcm4329/bcmsdh_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_linux.c index 6d6097b78f7d..cdb2c5e1f1ec 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_linux.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_linux.c @@ -301,7 +301,7 @@ int bcmsdh_remove(struct device *dev) MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); osl_detach(osh); -#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) +#if !defined(BCMLXSDMMC) dev_set_drvdata(dev, NULL); #endif /* !defined(BCMLXSDMMC) */ @@ -636,7 +636,7 @@ int bcmsdh_register_oob_intr(void * dhdp) if (error) return -ENODEV; - enable_irq_wake(sdhcinfo->oob_irq); + set_irq_wake(sdhcinfo->oob_irq, 1); sdhcinfo->oob_irq_registered = TRUE; } @@ -661,12 +661,10 @@ void bcmsdh_unregister_oob_intr(void) { SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - if (sdhcinfo->oob_irq_registered) { - disable_irq_wake(sdhcinfo->oob_irq); - disable_irq(sdhcinfo->oob_irq); /* just in case.. */ - free_irq(sdhcinfo->oob_irq, NULL); - sdhcinfo->oob_irq_registered = FALSE; - } + set_irq_wake(sdhcinfo->oob_irq, 0); + disable_irq(sdhcinfo->oob_irq); /* just in case.. */ + free_irq(sdhcinfo->oob_irq, NULL); + sdhcinfo->oob_irq_registered = FALSE; } #endif /* defined(OOB_INTR_ONLY) */ /* Module parameters specific to each host-controller driver */ diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c index 5a1a46c93571..8992a4267f9f 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c @@ -82,6 +82,7 @@ PBCMSDH_SDMMC_INSTANCE gInstance; extern int bcmsdh_probe(struct device *dev); extern int bcmsdh_remove(struct device *dev); +struct device sdmmc_dev; static int bcmsdh_sdmmc_probe(struct sdio_func *func, const struct sdio_device_id *id) @@ -101,7 +102,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, if(func->device == 0x4) { /* 4318 */ gInstance->func[2] = NULL; sd_trace(("NIC found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + ret = bcmsdh_probe(&sdmmc_dev); } } @@ -109,7 +110,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, if (func->num == 2) { sd_trace(("F2 found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + ret = bcmsdh_probe(&sdmmc_dev); } return ret; @@ -125,7 +126,7 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) if (func->num == 2) { sd_trace(("F2 found, calling bcmsdh_remove...\n")); - bcmsdh_remove(&func->dev); + bcmsdh_remove(&sdmmc_dev); } } @@ -249,8 +250,10 @@ int sdio_function_init(void) if (!gInstance) return -ENOMEM; + bzero(&sdmmc_dev, sizeof(sdmmc_dev)); error = sdio_register_driver(&bcmsdh_sdmmc_driver); + return error; } @@ -262,6 +265,7 @@ void sdio_function_cleanup(void) { sd_trace(("%s Enter\n", __FUNCTION__)); + sdio_unregister_driver(&bcmsdh_sdmmc_driver); if (gInstance) diff --git a/drivers/net/wireless/bcm4329/bcmspibrcm.c b/drivers/net/wireless/bcm4329/bcmspibrcm.c new file mode 100644 index 000000000000..0f131a40f4b8 --- /dev/null +++ b/drivers/net/wireless/bcm4329/bcmspibrcm.c @@ -0,0 +1,1726 @@ +/* + * Broadcom BCMSDH to gSPI Protocol Conversion Layer + * + * Copyright (C) 2010, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: bcmspibrcm.c,v 1.11.2.10.2.9.6.11 2009/05/21 13:21:57 Exp $ + */ + +#define HSMODE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ +#include + +#include + + +#include +#include + +#define F0_RESPONSE_DELAY 16 +#define F1_RESPONSE_DELAY 16 +#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY + +#define CMDLEN 4 + +#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) + +/* Globals */ +uint sd_msglevel = 0; + +uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ +uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ +uint sd_f2_blocksize = 64; /* Default blocksize */ + + +uint sd_divisor = 2; +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ + +uint8 spi_outbuf[SPI_MAX_PKT_LEN]; +uint8 spi_inbuf[SPI_MAX_PKT_LEN]; + +/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits + * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. + */ +#define BUF2_PKT_LEN 128 +uint8 spi_outbuf2[BUF2_PKT_LEN]; +uint8 spi_inbuf2[BUF2_PKT_LEN]; + +/* Prototypes */ +static bool bcmspi_test_card(sdioh_info_t *sd); +static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); +static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); +static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen); +static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 *data); +static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 data); +static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, + uint8 *data); +static int bcmspi_driver_init(sdioh_info_t *sd); +static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data); +static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, + uint32 *data); +static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); +static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, void *bar0, uint irq) +{ + sdioh_info_t *sd; + + sd_trace(("%s\n", __FUNCTION__)); + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + if (spi_osinit(sd) != 0) { + sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } + + sd->bar0 = bar0; + sd->irq = irq; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + sd->intr_handler_valid = FALSE; + + /* Set defaults */ + sd->use_client_ints = TRUE; + sd->sd_use_dma = FALSE; /* DMA Not supported */ + + /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit + * mode + */ + sd->wordlen = 2; + + if (!spi_hw_attach(sd)) { + sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (bcmspi_driver_init(sd) != SUCCESS) { + sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (spi_register_irq(sd, irq) != SUCCESS) { + sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + sd_trace(("%s: Done\n", __FUNCTION__)); + + return sd; +} + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if (sd) { + sd_err(("%s: detaching from hardware\n", __FUNCTION__)); + spi_free_irq(sd->irq, sd); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return 0; +} +#endif + +extern SDIOH_API_RC +sdioh_query_device(sdioh_info_t *sd) +{ + /* Return a BRCM ID appropriate to the dongle class */ + return (sd->num_funcs > 1) ? BCM4329_D11NDUAL_ID : BCM4318_D11G_ID; +} + +/* Provide dstatus bits of spi-transaction for dhd layers. */ +extern uint32 +sdioh_get_dstatus(sdioh_info_t *sd) +{ + return sd->card_dstatus; +} + +extern void +sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) +{ + sd->chip = chip; + sd->chiprev = chiprev; +} + +extern void +sdioh_dwordmode(sdioh_info_t *sd, bool set) +{ + uint8 reg = 0; + int status; + + if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } + + if (set) { + reg |= DWORD_PKT_LEN_EN; + sd->dwordmode = TRUE; + sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ + } else { + reg &= ~DWORD_PKT_LEN_EN; + sd->dwordmode = FALSE; + sd->client_block_size[SPI_FUNC_2] = 2048; + } + + if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } +} + + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_SPIERRSTATS, + IOV_RESP_DELAY_ALL +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, + {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, + {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; +/* + sdioh_regs_t *regs; +*/ + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + if (!spi_start_clock(si, (uint16)sd_divisor)) { + sd_err(("%s: set clock failed\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + } + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + + if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { + sd_err(("%s: Failed changing highspeed mode to %d.\n", + __FUNCTION__, sd_hiok)); + bcmerror = BCME_ERROR; + return ERROR; + } + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)si->local_intrcount; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + + case IOV_GVAL(IOV_SPIERRSTATS): + { + bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); + break; + } + + case IOV_SVAL(IOV_SPIERRSTATS): + { + bzero(&si->spierrstats, sizeof(struct spierrstats_t)); + break; + } + + case IOV_GVAL(IOV_RESP_DELAY_ALL): + int_val = (int32)si->resp_delay_all; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RESP_DELAY_ALL): + si->resp_delay_all = (bool)int_val; + int_val = STATUS_ENABLE|INTR_WITH_STATUS; + if (si->resp_delay_all) + int_val |= RESP_DELAY_ALL; + else { + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, + F1_RESPONSE_DELAY) != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + } + + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) + != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + + if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { + uint8 dummy_data; + status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); + if (status) { + sd_err(("sdioh_cfg_read() failed.\n")); + return status; + } + } + + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 cis_byte; + uint16 *cis = (uint16 *)cisd; + uint bar0 = SI_ENUM_BASE; + int status; + uint8 data; + + sd_trace(("%s: Func %d\n", __FUNCTION__, func)); + + spi_lock(sd); + + /* Set sb window address to 0x18000000 */ + data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); + if (status == SUCCESS) { + data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + if (status == SUCCESS) { + data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + offset = CC_OTP; /* OTP offset in chipcommon. */ + for (count = 0; count < length/2; count++) { + if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + *cis = (uint16)cis_byte; + cis++; + offset += 2; + } + + spi_unlock(sd); + + return (BCME_OK); +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + spi_lock(sd); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, rw, func, + regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, + cmd_arg, &data, 1)) != SUCCESS) { + spi_unlock(sd); + return status; + } + + if (rw == SDIOH_READ) + *byte = (uint8)data; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int status; + + spi_lock(sd); + + if (rw == SDIOH_READ) + status = bcmspi_card_regread(sd, func, addr, nbytes, word); + else + status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); + + spi_unlock(sd); + return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) +{ + int len; + int buflen = (int)buflen_u; + bool fifo = (fix_inc == SDIOH_DATA_FIX); + + spi_lock(sd); + + ASSERT(reg_width == 4); + ASSERT(buflen_u < (1 << 30)); + ASSERT(sd->client_block_size[func]); + + sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", + __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', + buflen_u, sd->r_cnt, sd->t_cnt, pkt)); + + /* Break buffer down into blocksize chunks. */ + while (buflen > 0) { + len = MIN(sd->client_block_size[func], buflen); + if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { + sd_err(("%s: bcmspi_card_buf %s failed\n", + __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); + spi_unlock(sd); + return SDIOH_API_RC_FAIL; + } + buffer += len; + buflen -= len; + if (!fifo) + addr += len; + } + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. + * Its main aim is to have simpler spi writes rather than recursive writes. + * e.g. When there is a need to program response delay on the fly after detecting the SPI-func + * this call will allow to program the response delay. + */ +static int +bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) +{ + uint32 cmd_arg; + uint32 datalen = 1; + uint32 hostlen; + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf2 = bcmswap32(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)spi_outbuf2 = bcmswap16(cmd_arg & 0xffff); + *(uint16 *)&spi_outbuf2[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16); + if (datalen & 0x1) + datalen++; + } else { + sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (datalen != 0) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = bcmswap32(byte); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)&spi_outbuf2[CMDLEN] = bcmswap16(byte & 0xffff); + *(uint16 *)&spi_outbuf2[CMDLEN + 2] = + bcmswap16((byte & 0xffff0000) >> 16); + } + } + + /* +4 for cmd, +4 for dstatus */ + hostlen = datalen + 8; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) | + (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16)); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +/* Program the response delay corresponding to the spi function */ +static int +bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) +{ + if (sd->resp_delay_all == FALSE) + return (BCME_OK); + + if (sd->prev_fun == func) + return (BCME_OK); + + if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) + return (BCME_OK); + + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); + + /* Remember function for which to avoid reprogramming resp-delay in next iteration */ + sd->prev_fun = func; + + return (BCME_OK); + +} + +#define GSPI_RESYNC_PATTERN 0x0 + +/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. + * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is + * synchronised and all queued resuests are cancelled. + */ +static int +bcmspi_resync_f1(sdioh_info_t *sd) +{ + uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + *(uint32 *)spi_outbuf2 = cmd_arg; + + /* for Write, put the data into the output buffer */ + *(uint32 *)&spi_outbuf2[CMDLEN] = data; + + /* +4 for cmd, +4 for dstatus */ + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) | + (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16)); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +uint32 dstatus_count = 0; + +static int +bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) +{ + uint32 dstatus = sd->card_dstatus; + struct spierrstats_t *spierrstats = &sd->spierrstats; + int err = SUCCESS; + + sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); + + /* Store dstatus of last few gSPI transactions */ + spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; + spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; + dstatus_count++; + + if (sd->card_init_done == FALSE) + return err; + + if (dstatus & STATUS_DATA_NOT_AVAILABLE) { + spierrstats->dna++; + sd_trace(("Read data not available on F1 addr = 0x%x\n", + GFIELD(cmd_arg, SPI_REG_ADDR))); + /* Clear dna bit */ + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); + } + + if (dstatus & STATUS_UNDERFLOW) { + spierrstats->rdunderflow++; + sd_err(("FIFO underflow happened due to current F2 read command.\n")); + } + + if (dstatus & STATUS_OVERFLOW) { + spierrstats->wroverflow++; + sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); + if ((sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 0)) { + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); + bcmspi_resync_f1(sd); + sd_err(("Recovering from F1 FIFO overflow.\n")); + } else { + err = ERROR_OF; + } + } + + if (dstatus & STATUS_F2_INTR) { + spierrstats->f2interrupt++; + sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_F3_INTR) { + spierrstats->f3interrupt++; + sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_HOST_CMD_DATA_ERR) { + spierrstats->hostcmddataerr++; + sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); + } + + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + spierrstats->f2pktavailable++; + sd_trace(("Packet is available/ready in F2 TX FIFO\n")); + sd_trace(("Packet length = %d\n", sd->dwordmode ? + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); + } + + if (dstatus & STATUS_F3_PKT_AVAILABLE) { + spierrstats->f3pktavailable++; + sd_err(("Packet is available/ready in F3 TX FIFO\n")); + sd_err(("Packet length = %d\n", + (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); + } + + return err; +} + +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ + return 0; +} + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + return SUCCESS; +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + return SUCCESS; +} + + + +/* + * Private/Static work routines + */ +static int +bcmspi_host_init(sdioh_info_t *sd) +{ + + /* Default power on mode */ + sd->sd_mode = SDIOH_MODE_SPI; + sd->polled_mode = TRUE; + sd->host_init_done = TRUE; + sd->card_init_done = FALSE; + sd->adapter_slot = 1; + + return (SUCCESS); +} + +static int +get_client_blocksize(sdioh_info_t *sd) +{ + uint32 regdata[2]; + int status; + + /* Find F1/F2/F3 max packet size */ + if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, + 8, regdata)) != SUCCESS) { + return status; + } + + sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", + regdata[0], regdata[1])); + + sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; + sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); + ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); + + sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; + sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); + ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); + + sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; + sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); + ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); + + return 0; +} + +static int +bcmspi_client_init(sdioh_info_t *sd) +{ + uint32 status_en_reg = 0; + sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); + +#ifdef HSMODE + if (!spi_start_clock(sd, (uint16)sd_divisor)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#else + /* Start at ~400KHz clock rate for initialization */ + if (!spi_start_clock(sd, 128)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + if (!bcmspi_host_device_init_adapt(sd)) { + sd_err(("bcmspi_host_device_init_adapt failed\n")); + return ERROR; + } + + if (!bcmspi_test_card(sd)) { + sd_err(("bcmspi_test_card failed\n")); + return ERROR; + } + + sd->num_funcs = SPI_MAX_IOFUNCS; + + get_client_blocksize(sd); + + /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ + bcmspi_resync_f1(sd); + + sd->dwordmode = FALSE; + + bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); + + sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); + status_en_reg |= INTR_WITH_STATUS; + + + if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, + status_en_reg & 0xff) != SUCCESS) { + sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); + return ERROR; + } + + +#ifndef HSMODE + /* After configuring for High-Speed mode, set the desired clock rate. */ + if (!spi_start_clock(sd, 4)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + sd->card_init_done = TRUE; + + + return SUCCESS; +} + +static int +bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, + 4, ®data)) != SUCCESS) + return status; + + sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); + + + if (hsmode == TRUE) { + sd_trace(("Attempting to enable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + sd_trace(("Device is already in High-Speed mode.\n")); + return status; + } else { + regdata |= HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) { + return status; + } + } + } else { + sd_trace(("Attempting to disable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + regdata &= ~HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) + return status; + } + else { + sd_trace(("Device is already in Low-Speed mode.\n")); + return status; + } + } + + spi_controller_highspeed_mode(sd, hsmode); + + return TRUE; +} + +#define bcmspi_find_curr_mode(sd) { \ + sd->wordlen = 2; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd->wordlen = 4; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd_trace(("Silicon testability issue: regdata = 0x%x." \ + " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ + OSL_DELAY(100000); \ +} + +#define INIT_ADAPT_LOOP 100 + +/* Adapt clock-phase-speed-bitwidth between host and device */ +static bool +bcmspi_host_device_init_adapt(sdioh_info_t *sd) +{ + uint32 wrregdata, regdata = 0; + int status; + int i; + + /* Due to a silicon testability issue, the first command from the Host + * to the device will get corrupted (first bit will be lost). So the + * Host should poll the device with a safe read request. ie: The Host + * should try to read F0 addr 0x14 using the Fixed address mode + * (This will prevent a unintended write command to be detected by device) + */ + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + /* If device was not power-cycled it will stay in 32bit mode with + * response-delay-all bit set. Alternate the iteration so that + * read either with or without response-delay for F0 to succeed. + */ + bcmspi_find_curr_mode(sd); + sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = TRUE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = FALSE; + } + + /* Bail out, device not detected */ + if (i == INIT_ADAPT_LOOP) + return FALSE; + + /* Softreset the spid logic */ + if ((sd->dwordmode) || (sd->wordlen == 4)) { + bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); + bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); + sd_trace(("reset reg read = 0x%x\n", regdata)); + sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, + sd->wordlen, sd->resp_delay_all)); + /* Restore default state after softreset */ + sd->wordlen = 2; + sd->dwordmode = FALSE; + } + + if (sd->wordlen == 4) { + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != + SUCCESS) + return FALSE; + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", + regdata)); + sd_trace(("Spid power was left on.\n")); + } else { + sd_err(("Spid power was left on but signature read failed." + " Value read = 0x%x\n", regdata)); + return FALSE; + } + } else { + sd->wordlen = 2; + +#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ + + wrregdata = (CTRL_REG_DEFAULT); + sd->resp_delay_all = TRUE; + if (sd->resp_delay_all == TRUE) { + /* Enable response delay for all */ + wrregdata |= (RESP_DELAY_ALL << 16); + /* Program response delay value */ + wrregdata &= 0xffff00ff; + wrregdata |= (F1_RESPONSE_DELAY << 8); + sd->prev_fun = SPI_FUNC_1; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + } + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); + +#ifndef HSMODE + wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); + wrregdata &= ~HIGH_SPEED_MODE; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); +#endif /* HSMODE */ + + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { + sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, + ®data)) != SUCCESS) + return FALSE; + } + OSL_DELAY(1000); + } + + + /* Change to host controller intr-polarity of active-low */ + wrregdata &= ~INTR_POLARITY; + sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", + wrregdata)); + /* Change to 32bit mode */ + wrregdata |= WORD_LENGTH_32; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + + /* Change command/data packaging in 32bit LE mode */ + sd->wordlen = 4; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); + sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); + } else { + sd_err(("Stale spid reg values read as it was kept powered. Value read =" + "0x%x\n", regdata)); + return FALSE; + } + } + + + return TRUE; +} + +static bool +bcmspi_test_card(sdioh_info_t *sd) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == (TEST_RO_DATA_32BIT_LE)) + sd_trace(("32bit LE regdata = 0x%x\n", regdata)); + else { + sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); + return FALSE; + } + + +#define RW_PATTERN1 0xA0A1A2A3 +#define RW_PATTERN2 0x4B5B6B7B + + regdata = RW_PATTERN1; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN1) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN1, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + regdata = RW_PATTERN2; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN2) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN2, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + return TRUE; +} + +static int +bcmspi_driver_init(sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if ((bcmspi_host_init(sd)) != SUCCESS) { + return ERROR; + } + + if (bcmspi_client_init(sd) != SUCCESS) { + return ERROR; + } + + return SUCCESS; +} + +/* Read device reg */ +static int +bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func, + regaddr, *data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) + != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +static int +bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + int status; + uint32 cmd_arg; + uint32 dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) + != SUCCESS) + return status; + + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func, + regaddr, *data)); + + bcmspi_cmd_getdstatus(sd, &dstatus); + sd_trace(("dstatus =0x%x\n", dstatus)); + return SUCCESS; +} + +/* write a device register */ +static int +bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 1, func, + regaddr, data)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) + != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +/* write a device register - 1 byte */ +static int +bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, func, + regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, + cmd_arg, &data, 1)) != SUCCESS) { + return status; + } + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +void +bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) +{ + *dstatus_buffer = sd->card_dstatus; +} + +/* 'data' is of type uint32 whereas other buffers are of type uint8 */ +static int +bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen) +{ + uint32 i, j; + uint8 resp_delay = 0; + int err = SUCCESS; + uint32 hostlen; + uint32 spilen = 0; + uint32 dstatus_idx = 0; + uint16 templen, buslen, len, *ptr = NULL; + + sd_trace(("spi cmd = 0x%x\n", cmd_arg)); + + if (DWORDMODE_ON) { + spilen = GFIELD(cmd_arg, SPI_LEN); + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || + (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) + dstatus_idx = spilen * 3; + + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + spilen = spilen << 2; + dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; + /* convert len to mod16 size */ + spilen = ROUNDUP(spilen, 16); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } + } + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf = bcmswap32(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)spi_outbuf = bcmswap16(cmd_arg & 0xffff); + *(uint16 *)&spi_outbuf[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16); + if (datalen & 0x1) + datalen++; + if (datalen < 4) + datalen = ROUNDUP(datalen, 4); + } else { + sd_err(("Host is %d bit spid, could not create SPI command.\n", + 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { + /* We send len field of hw-header always a mod16 size, both from host and dongle */ + if (DWORDMODE_ON) { + if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + /* ASSERT(*ptr == ~*(ptr + 1)); */ + templen = ROUNDUP(templen, 16); + *ptr = templen; + sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); + } + } + + if (datalen != 0) { + for (i = 0; i < datalen/4; i++) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + bcmswap32(data[i]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)&spi_outbuf[i * 4 + CMDLEN] = + bcmswap16(data[i] & 0xffff); + *(uint16 *)&spi_outbuf[i * 4 + CMDLEN + 2] = + bcmswap16((data[i] & 0xffff0000) >> 16); + } + } + } + } + + /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { + int func = GFIELD(cmd_arg, SPI_FUNCTION); + switch (func) { + case 0: + resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; + break; + case 1: + resp_delay = F1_RESPONSE_DELAY; + break; + case 2: + resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; + break; + default: + ASSERT(0); + break; + } + /* Program response delay */ + bcmspi_prog_resp_delay(sd, func, resp_delay); + } + + /* +4 for cmd and +4 for dstatus */ + hostlen = datalen + 8 + resp_delay; + hostlen += dstatus_idx; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); + + /* for Read, get the data into the input buffer */ + if (datalen != 0) { + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ + for (j = 0; j < datalen/4; j++) { + if (sd->wordlen == 4) { /* 32bit spid */ + data[j] = bcmswap32(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + data[j] = (bcmswap16(*(uint16 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay])) | + ((bcmswap16(*(uint16 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay + 2])) << 16); + } + } + + if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + buslen = len = ~(*(ptr + 1)); + buslen = ROUNDUP(buslen, 16); + /* populate actual len in hw-header */ + if (templen == buslen) + *ptr = len; + } + } + } + + /* Restore back the len field of the hw header */ + if (DWORDMODE_ON) { + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + ptr = (uint16 *)&data[0]; + *ptr = (uint16)(~*(ptr+1)); + } + } + + dstatus_idx += (datalen + CMDLEN + resp_delay); + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx]) | + (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx + 2]) << 16)); + } else { + sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", + 8 * sd->wordlen)); + return ERROR; + } + if (sd->card_dstatus == 0xffffffff) { + sd_err(("looks like not a GSPI device or device is not powered.\n")); + } + + err = bcmspi_update_stats(sd, cmd_arg); + + return err; + +} + +static int +bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data) +{ + int status; + uint32 cmd_arg; + bool write = rw == SDIOH_READ ? 0 : 1; + uint retries = 0; + + bool enable; + uint32 spilen; + + cmd_arg = 0; + + ASSERT(nbytes); + ASSERT(nbytes <= sd->client_block_size[func]); + + if (write) sd->t_cnt++; else sd->r_cnt++; + + if (func == 2) { + /* Frame len check limited by gSPI. */ + if ((nbytes > 2000) && write) { + sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); + } + /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ + /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ + if (write) { + uint32 dstatus; + /* check F2 ready with cached one */ + bcmspi_cmd_getdstatus(sd, &dstatus); + if ((dstatus & STATUS_F2_RX_READY) == 0) { + retries = WAIT_F2RXFIFORDY; + enable = 0; + while (retries-- && !enable) { + OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); + bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, + &dstatus); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + if (!enable) { + struct spierrstats_t *spierrstats = &sd->spierrstats; + spierrstats->f2rxnotready++; + sd_err(("F2 FIFO is not ready to receive data.\n")); + return ERROR; + } + sd_trace(("No of retries on F2 ready %d\n", + (WAIT_F2RXFIFORDY - retries))); + } + } + } + + /* F2 transfers happen on 0 addr */ + addr = (func == 2) ? 0 : addr; + + /* In pio mode buffer is read using fixed address fifo in func 1 */ + if ((func == 1) && (fifo)) + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); + else + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); + + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); + spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); + if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + /* convert len to mod4 size */ + spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } else + cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); + + if ((func == 2) && (fifo == 1)) { + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + } + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, + data, nbytes)) != SUCCESS) { + sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, + (write ? "write" : "read"))); + return status; + } + + /* gSPI expects that hw-header-len is equal to spi-command-len */ + if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { + ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); + ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); + } + + if ((nbytes > 2000) && !write) { + sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); + } + + return SUCCESS; +} + +/* Reset and re-initialize the device */ +int +sdioh_sdio_reset(sdioh_info_t *si) +{ + si->card_init_done = FALSE; + return bcmspi_client_init(si); +} diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h index 95b334fd62f2..2be7ea08a40c 100644 --- a/drivers/net/wireless/bcm4329/dhd.h +++ b/drivers/net/wireless/bcm4329/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h,v 1.32.4.7.2.4.14.49.4.9 2011/01/14 22:40:45 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.49.4.7 2010/11/12 22:48:36 Exp $ */ /**************** @@ -165,7 +165,7 @@ typedef struct dhd_pub { char * pktfilter[100]; int pktfilter_count; - wl_country_t dhd_cspec; /* Current Locale info */ + uint8 country_code[WLC_CNTRY_BUF_SZ]; char eventmask[WL_EVENTING_MASK_LEN]; } dhd_pub_t; @@ -180,7 +180,7 @@ typedef struct dhd_pub { wait_event_interruptible_timeout(a, FALSE, HZ/100); \ } \ } while (0) - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) + #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) @@ -215,20 +215,6 @@ typedef struct dhd_pub { #define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ -inline static void NETIF_ADDR_LOCK(struct net_device *dev) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)) - netif_addr_lock_bh(dev); -#endif -} - -inline static void NETIF_ADDR_UNLOCK(struct net_device *dev) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)) - netif_addr_unlock_bh(dev); -#endif -} - /* Wakelock Functions */ extern int dhd_os_wake_lock(dhd_pub_t *pub); extern int dhd_os_wake_unlock(dhd_pub_t *pub); @@ -449,16 +435,4 @@ extern char nv_path[MOD_PARAM_PATHLEN]; extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); -/* dhd_commn arp offload wrapers */ -extern void dhd_arp_cleanup(dhd_pub_t *dhd); -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, u32 ipaddr); - -#define DHD_UNICAST_FILTER_NUM 0 -#define DHD_BROADCAST_FILTER_NUM 1 -#define DHD_MULTICAST4_FILTER_NUM 2 -#define DHD_MULTICAST6_FILTER_NUM 3 -extern int net_os_set_packet_filter(struct net_device *dev, int val); -extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); - #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcm4329/dhd_cdc.c b/drivers/net/wireless/bcm4329/dhd_cdc.c index 61f6a6f393a9..a68ad61c58b4 100644 --- a/drivers/net/wireless/bcm4329/dhd_cdc.c +++ b/drivers/net/wireless/bcm4329/dhd_cdc.c @@ -41,6 +41,8 @@ #include #include +uint8 wlan_mac_addr[ETHER_ADDR_LEN]; + extern int dhd_preinit_ioctls(dhd_pub_t *dhd); /* Packet alignment for most efficient SDIO (can change based on platform) */ @@ -502,6 +504,7 @@ dhd_prot_init(dhd_pub_t *dhd) return ret; } memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + memcpy(wlan_mac_addr, buf, ETHER_ADDR_LEN); dhd_os_proto_unblock(dhd); diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c index f7cd372d68c8..47e29969126a 100644 --- a/drivers/net/wireless/bcm4329/dhd_common.c +++ b/drivers/net/wireless/bcm4329/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c,v 1.5.6.8.2.6.6.69.4.25 2011-02-11 21:16:02 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.69.4.20 2010/12/20 23:37:28 Exp $ */ #include #include @@ -39,6 +39,9 @@ #include +#define CONFIG_BCM4329_FW_PATH "/system/etc/firmware/fw_bcm4329.bin" +#define CONFIG_BCM4329_NVRAM_PATH "/system/etc/firmware/nvram_B23.txt" + #ifdef SET_RANDOM_MAC_SOFTAP #include #include @@ -992,9 +995,6 @@ dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_ wl_pkt_filter_enable_t enable_parm; wl_pkt_filter_enable_t * pkt_filterp; - if (!arg) - return; - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; @@ -1068,9 +1068,6 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) char *arg_save = 0, *arg_org = 0; #define BUF_SIZE 2048 - if (!arg) - return; - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; @@ -1226,82 +1223,6 @@ dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) } #endif - -void dhd_arp_cleanup(dhd_pub_t *dhd) -{ -#ifdef ARP_OFFLOAD_SUPPORT - int ret = 0; - int iov_len = 0; - char iovbuf[128]; - - if (dhd == NULL) return; - - dhd_os_proto_block(dhd); - - iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - - iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - - dhd_os_proto_unblock(dhd); - -#endif /* ARP_OFFLOAD_SUPPORT */ -} - -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, u32 ipaddr) -{ -#ifdef ARP_OFFLOAD_SUPPORT - int iov_len = 0; - char iovbuf[32]; - int retcode; - - dhd_os_proto_block(dhd); - - iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf)); - retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len); - - dhd_os_proto_unblock(dhd); - - if (retcode) - DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: ARP ipaddr entry added\n", - __FUNCTION__)); -#endif /* ARP_OFFLOAD_SUPPORT */ -} - - -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen) -{ -#ifdef ARP_OFFLOAD_SUPPORT - int retcode; - int iov_len = 0; - - if (!buf) - return -1; - - dhd_os_proto_block(dhd); - - iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); - retcode = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, buflen); - - dhd_os_proto_unblock(dhd); - - if (retcode) { - DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, retcode)); - - return -1; - } -#endif /* ARP_OFFLOAD_SUPPORT */ - return 0; -} - - int dhd_preinit_ioctls(dhd_pub_t *dhd) { @@ -1368,11 +1289,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* SET_RANDOM_MAC_SOFTAP */ - /* Set Country code */ - if (dhd->dhd_cspec.ccode[0] != 0) { - bcm_mkiovar("country", (char *)&dhd->dhd_cspec, \ - sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { + /* Set Country code + * "US" ---> 11 channels, this is default setting. + * "EU" ---> 13 channels + * "JP" ---> 14 channels + */ + strcpy(dhd->country_code, "EU"); + if (dhd->country_code[0] != 0) { + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY, + dhd->country_code, sizeof(dhd->country_code)) < 0) { DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); } } @@ -1979,7 +1904,6 @@ int dhd_pno_clean(dhd_pub_t *dhd) int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) { char iovbuf[128]; - uint8 bssid[6]; int ret = -1; if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { @@ -1987,20 +1911,6 @@ int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) return ret; } - memset(iovbuf, 0, sizeof(iovbuf)); - - /* Check if disassoc to enable pno */ - if ((pfn_enabled) && \ - ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, \ - (char *)&bssid, ETHER_ADDR_LEN)) == BCME_NOTASSOCIATED)) { - DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__)); - } - else if (pfn_enabled) { - DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n", \ - __FUNCTION__, ret)); - return ret; - } - /* Enable/disable PNO */ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { @@ -2019,8 +1929,7 @@ int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) /* Function to execute combined scan */ int -dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, \ - int pno_repeat, int pno_freq_expo_max) +dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) { int err = -1; char iovbuf[128]; @@ -2065,23 +1974,12 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, pfn_param.version = htod32(PFN_VERSION); pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); - /* check and set extra pno params */ - if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat_scan = htod32(pno_repeat); - pfn_param.max_freq_adjust = htod32(pno_freq_expo_max); - } - /* set up pno scan fr */ if (scan_fr != 0) pfn_param.scan_freq = htod32(scan_fr); - if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { - DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC)); - return err; - } - if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { - DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); + if (pfn_param.scan_freq > PNO_SCAN_MAX_FW) { + DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW)); return err; } @@ -2093,6 +1991,8 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); pfn_element.infra = htod32(1); memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); @@ -2108,9 +2008,8 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, return err; } else - DHD_ERROR(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", \ - __FUNCTION__, pfn_param.scan_freq, \ - pfn_param.repeat_scan, pfn_param.max_freq_adjust)); + DHD_ERROR(("%s set OK with PNO time=%d\n", __FUNCTION__, \ + pfn_param.scan_freq)); } else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); } diff --git a/drivers/net/wireless/bcm4329/dhd_custom_gpio.c b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c index 4d32863e2982..8c6ec470b8bd 100644 --- a/drivers/net/wireless/bcm4329/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c @@ -20,7 +20,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * -* $Id: dhd_custom_gpio.c,v 1.1.4.8.4.4 2011/01/20 20:23:09 Exp $ +* $Id: dhd_custom_gpio.c,v 1.1.4.8.4.1 2010/09/02 23:13:16 Exp $ */ @@ -47,7 +47,6 @@ int wifi_set_carddetect(int on); int wifi_set_power(int on, unsigned long msec); int wifi_get_irq_number(unsigned long *irq_flags_ptr); int wifi_get_mac_addr(unsigned char *buf); -void *wifi_get_country_code(char *ccode); #endif #if defined(OOB_INTR_ONLY) @@ -178,95 +177,3 @@ dhd_custom_get_mac_address(unsigned char *buf) return ret; } #endif /* GET_CUSTOM_MAC_ENABLE */ - -/* Customized Locale table : OPTIONAL feature */ -const struct cntry_locales_custom translate_custom_table[] = { -/* Table should be filled out based on custom platform regulatory requirement */ -#ifdef EXAMPLE_TABLE - {"", "XY", 4}, /* universal */ - {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ - {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ - {"EU", "EU", 5}, /* European union countries */ - {"AT", "EU", 5}, - {"BE", "EU", 5}, - {"BG", "EU", 5}, - {"CY", "EU", 5}, - {"CZ", "EU", 5}, - {"DK", "EU", 5}, - {"EE", "EU", 5}, - {"FI", "EU", 5}, - {"FR", "EU", 5}, - {"DE", "EU", 5}, - {"GR", "EU", 5}, - {"HU", "EU", 5}, - {"IE", "EU", 5}, - {"IT", "EU", 5}, - {"LV", "EU", 5}, - {"LI", "EU", 5}, - {"LT", "EU", 5}, - {"LU", "EU", 5}, - {"MT", "EU", 5}, - {"NL", "EU", 5}, - {"PL", "EU", 5}, - {"PT", "EU", 5}, - {"RO", "EU", 5}, - {"SK", "EU", 5}, - {"SI", "EU", 5}, - {"ES", "EU", 5}, - {"SE", "EU", 5}, - {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */ - {"IL", "IL", 0}, - {"CH", "CH", 0}, - {"TR", "TR", 0}, - {"NO", "NO", 0}, - {"KR", "XY", 3}, - {"AU", "XY", 3}, - {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ - {"TW", "XY", 3}, - {"AR", "XY", 3}, - {"MX", "XY", 3} -#endif /* EXAMPLE_TABLE */ -}; - - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) -{ -#ifdef CUSTOMER_HW2 - struct cntry_locales_custom *cloc_ptr; - - if (!cspec) - return; - - cloc_ptr = wifi_get_country_code(country_iso_code); - if (cloc_ptr) { - strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = cloc_ptr->custom_locale_rev; - } - return; -#else - int size, i; - - size = ARRAYSIZE(translate_custom_table); - - if (cspec == 0) - return; - - if (size == 0) - return; - - for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - return; - } - } - memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[0].custom_locale_rev; - return; -#endif -} diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c index 5c1384bdc215..be7298846bc7 100644 --- a/drivers/net/wireless/bcm4329/dhd_linux.c +++ b/drivers/net/wireless/bcm4329/dhd_linux.c @@ -22,9 +22,12 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104.4.40 2011/02/03 19:55:18 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104.4.35 2010/11/17 03:13:21 Exp $ */ +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include +#endif #include #include #include @@ -40,12 +43,11 @@ #include #include #include -#include -#include #include #include +#include #include #include #include @@ -60,14 +62,18 @@ #ifdef CONFIG_HAS_WAKELOCK #include #endif -#ifdef CUSTOMER_HW2 -#include -#ifdef CONFIG_WIFI_CONTROL_FUNC -#include -static struct wifi_platform_data *wifi_control_data = NULL; -#endif +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) +//#include +#include + struct semaphore wifi_control_sem; +struct dhd_bus *g_bus; + +extern void bcm4329_power_save_exit(void); +extern void bcm4329_power_save_init(void); + +static struct wifi_platform_data *wifi_control_data = NULL; static struct resource *wifi_irqres = NULL; int wifi_get_irq_number(unsigned long *irq_flags_ptr) @@ -86,22 +92,18 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr) int wifi_set_carddetect(int on) { printk("%s = %d\n", __FUNCTION__, on); -#ifdef CONFIG_WIFI_CONTROL_FUNC if (wifi_control_data && wifi_control_data->set_carddetect) { wifi_control_data->set_carddetect(on); } -#endif return 0; } int wifi_set_power(int on, unsigned long msec) { printk("%s = %d\n", __FUNCTION__, on); -#ifdef CONFIG_WIFI_CONTROL_FUNC if (wifi_control_data && wifi_control_data->set_power) { wifi_control_data->set_power(on); } -#endif if (msec) mdelay(msec); return 0; @@ -110,11 +112,9 @@ int wifi_set_power(int on, unsigned long msec) int wifi_set_reset(int on, unsigned long msec) { DHD_TRACE(("%s = %d\n", __FUNCTION__, on)); -#ifdef CONFIG_WIFI_CONTROL_FUNC if (wifi_control_data && wifi_control_data->set_reset) { wifi_control_data->set_reset(on); } -#endif if (msec) mdelay(msec); return 0; @@ -125,38 +125,20 @@ int wifi_get_mac_addr(unsigned char *buf) DHD_TRACE(("%s\n", __FUNCTION__)); if (!buf) return -EINVAL; -#ifdef CONFIG_WIFI_CONTROL_FUNC if (wifi_control_data && wifi_control_data->get_mac_addr) { return wifi_control_data->get_mac_addr(buf); } -#endif return -EOPNOTSUPP; } -void *wifi_get_country_code(char *ccode) -{ - DHD_TRACE(("%s\n", __FUNCTION__)); -#ifdef CONFIG_WIFI_CONTROL_FUNC - if (!ccode) - return NULL; - if (wifi_control_data && wifi_control_data->get_country_code) { - return wifi_control_data->get_country_code(ccode); - } -#endif - return NULL; -} - static int wifi_probe(struct platform_device *pdev) { -#ifdef CONFIG_WIFI_CONTROL_FUNC struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - wifi_control_data = wifi_ctrl; -#endif - DHD_TRACE(("## %s\n", __FUNCTION__)); wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + wifi_control_data = wifi_ctrl; wifi_set_power(1, 0); /* Power On */ wifi_set_carddetect(1); /* CardDetect (0->1) */ @@ -167,34 +149,26 @@ static int wifi_probe(struct platform_device *pdev) static int wifi_remove(struct platform_device *pdev) { -#ifdef CONFIG_WIFI_CONTROL_FUNC struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - wifi_control_data = wifi_ctrl; -#endif DHD_TRACE(("## %s\n", __FUNCTION__)); + wifi_control_data = wifi_ctrl; + wifi_set_power(0, 0); /* Power Off */ wifi_set_carddetect(0); /* CardDetect (1->0) */ up(&wifi_control_sem); return 0; } - static int wifi_suspend(struct platform_device *pdev, pm_message_t state) { DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(0); -#endif /* (OOB_INTR_ONLY) */ return 0; } static int wifi_resume(struct platform_device *pdev) { DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ return 0; } @@ -219,14 +193,8 @@ void wifi_del_dev(void) DHD_TRACE(("## Unregister platform_driver_register\n")); platform_driver_unregister(&wifi_device); } -#endif /* defined(CUSTOMER_HW2) */ - -static int dhd_device_event(struct notifier_block *this, unsigned long event, - void *ptr); +#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ -static struct notifier_block dhd_notifier = { - .notifier_call = dhd_device_event -}; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #include @@ -412,7 +380,7 @@ uint dhd_roam = 1; uint dhd_radio_up = 1; /* Network inteface name */ -char iface_name[IFNAMSIZ]; +char iface_name[IFNAMSIZ] = "wlan0"; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) @@ -800,13 +768,13 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ASSERT(dhd && dhd->iflist[ifidx]); dev = dhd->iflist[ifidx]->net; - NETIF_ADDR_LOCK(dev); + netif_addr_lock_bh(dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) cnt = netdev_mc_count(dev); #else cnt = dev->mc_count; #endif - NETIF_ADDR_UNLOCK(dev); + netif_addr_unlock_bh(dev); /* Determine initial value of allmulti flag */ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; @@ -826,7 +794,7 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) memcpy(bufp, &cnt, sizeof(cnt)); bufp += sizeof(cnt); - NETIF_ADDR_LOCK(dev); + netif_addr_lock_bh(dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) netdev_for_each_mc_addr(ha, dev) { if (!cnt) @@ -836,12 +804,12 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) cnt--; } #else - for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) { + for (mclist = dev->mc_list;(mclist && (cnt > 0)); cnt--, mclist = mclist->next) { memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); bufp += ETHER_ADDR_LEN; } #endif - NETIF_ADDR_UNLOCK(dev); + netif_addr_unlock_bh(dev); memset(&ioc, 0, sizeof(ioc)); ioc.cmd = WLC_SET_VAR; @@ -1939,11 +1907,10 @@ dhd_open(struct net_device *net) wl_control_wl_start(net); ifidx = dhd_net2idx(dhd, net); + if (ifidx == DHD_BAD_IF) + return -1; DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - if (ifidx == DHD_BAD_IF) - return -1; - if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) { DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); return -1; @@ -2044,7 +2011,6 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) up(&dhd->sysioc_sem); } - dhd_pub_t * dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) { @@ -2187,6 +2153,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) */ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) + g_bus = bus; +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) register_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ @@ -2198,8 +2167,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) register_early_suspend(&dhd->early_suspend); #endif - register_inetaddr_notifier(&dhd_notifier); - return &dhd->pub; fail: @@ -2225,15 +2192,12 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("%s: \n", __FUNCTION__)); - dhd_os_sdlock(dhdp); - /* try to download image and nvram to the dongle */ if (dhd->pub.busstate == DHD_BUS_DOWN) { if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); - dhd_os_sdunlock(dhdp); return -1; } } @@ -2243,9 +2207,8 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { + if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) { DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); - dhd_os_sdunlock(dhdp); return ret; } #if defined(OOB_INTR_ONLY) @@ -2254,7 +2217,6 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd->wd_timer_valid = FALSE; del_timer_sync(&dhd->timer); DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); - dhd_os_sdunlock(dhdp); return -ENODEV; } @@ -2267,12 +2229,9 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd->wd_timer_valid = FALSE; del_timer_sync(&dhd->timer); DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); - dhd_os_sdunlock(dhdp); return -ENODEV; } - dhd_os_sdunlock(dhdp); - #ifdef EMBEDDED_PLATFORM bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); @@ -2304,12 +2263,9 @@ dhd_bus_start(dhd_pub_t *dhdp) /* enable dongle roaming event */ setbit(dhdp->eventmask, WLC_E_ROAM); - dhdp->pktfilter_count = 4; + dhdp->pktfilter_count = 1; /* Setup filter to allow only unicast */ dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00"; - dhdp->pktfilter[1] = NULL; - dhdp->pktfilter[2] = NULL; - dhdp->pktfilter[3] = NULL; #endif /* EMBEDDED_PLATFORM */ /* Bus is ready, do any protocol initialization */ @@ -2363,48 +2319,6 @@ static struct net_device_ops dhd_ops_virt = { }; #endif -static int dhd_device_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - - if (!ifa) - return NOTIFY_DONE; - - dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); - dhd_pub = &dhd->pub; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) - if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) { -#else - if (ifa->ifa_dev->dev->open == &dhd_open) { -#endif - switch (event) { - case NETDEV_UP: - DHD_TRACE(("%s: [%s] Up IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - dhd_arp_cleanup(dhd_pub); - break; - - case NETDEV_DOWN: - DHD_TRACE(("%s: [%s] Down IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - dhd_arp_cleanup(dhd_pub); - break; - - default: - DHD_TRACE(("%s: [%s] Event: %lu\n", - __FUNCTION__, ifa->ifa_label, event)); - break; - } - } - return NOTIFY_DONE; -} - int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { @@ -2478,7 +2392,6 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2], dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); - #if defined(CONFIG_WIRELESS_EXT) #if defined(CONFIG_FIRST_SCAN) #ifdef SOFTAP @@ -2544,8 +2457,6 @@ dhd_detach(dhd_pub_t *dhdp) dhd_if_t *ifp; int i; - unregister_inetaddr_notifier(&dhd_notifier); - #if defined(CONFIG_HAS_EARLYSUSPEND) if (dhd->early_suspend.suspend) unregister_early_suspend(&dhd->early_suspend); @@ -2610,8 +2521,8 @@ dhd_detach(dhd_pub_t *dhdp) } } -static void __exit -dhd_module_cleanup(void) +void +rockchip_wifi_exit_module(void) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2621,15 +2532,17 @@ dhd_module_cleanup(void) #endif /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); + bcm4329_power_save_exit(); } -static int __init -dhd_module_init(void) +int +rockchip_wifi_init_module(void) { int error; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + printk("BCM4329 Wi-Fi driver (Powered by Rockchip,Ver %s) init.\n", BCM4329_DRV_VERSION); /* Sanity check on the module parameters */ do { /* Both watchdog and DPC as tasklets are ok */ @@ -2688,6 +2601,8 @@ dhd_module_init(void) goto fail_2; } #endif + bcm4329_power_save_init(); + return error; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) fail_2: @@ -2705,8 +2620,23 @@ fail_0: return error; } -module_init(dhd_module_init); -module_exit(dhd_module_cleanup); +//module_init(dhd_module_init); +//module_exit(dhd_module_cleanup); +int mv88w8686_if_sdio_init_module(void) +{ + return rockchip_wifi_init_module(); +} + +void mv88w8686_if_sdio_exit_module(void) +{ + rockchip_wifi_exit_module(); +} + +EXPORT_SYMBOL(rockchip_wifi_init_module); +EXPORT_SYMBOL(rockchip_wifi_exit_module); +EXPORT_SYMBOL(mv88w8686_if_sdio_init_module); +EXPORT_SYMBOL(mv88w8686_if_sdio_exit_module); + /* * OS specific functions required to implement DHD driver in OS independent way @@ -3080,35 +3010,6 @@ int net_os_set_dtim_skip(struct net_device *dev, int val) return 0; } -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - char *filterp = NULL; - int ret = 0; - - if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) - return ret; - if (num >= dhd->pub.pktfilter_count) - return -EINVAL; - if (add_remove) { - switch (num) { - case DHD_BROADCAST_FILTER_NUM: - filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; - break; - case DHD_MULTICAST4_FILTER_NUM: - filterp = "102 0 0 0 0xFFFFFF 0x01005E"; - break; - case DHD_MULTICAST6_FILTER_NUM: - filterp = "103 0 0 0 0xFFFF 0x3333"; - break; - default: - return -EINVAL; - } - } - dhd->pub.pktfilter[num] = filterp; - return ret; -} - int net_os_set_packet_filter(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -3162,12 +3063,11 @@ dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) /* Linux wrapper to call common dhd_pno_set */ int -dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max) +dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); + return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr)); } /* Linux wrapper to get pno status */ @@ -3195,20 +3095,20 @@ int net_os_send_hang_message(struct net_device *dev) return ret; } -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) +void dhd_bus_country_set(struct net_device *dev, char *country_code) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd && dhd->pub.up) - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); + strncpy(dhd->pub.country_code, country_code, WLC_CNTRY_BUF_SZ); } char *dhd_bus_country_get(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - if (dhd && (dhd->pub.dhd_cspec.ccode[0] != 0)) - return dhd->pub.dhd_cspec.ccode; + if (dhd && (dhd->pub.country_code[0] != 0)) + return dhd->pub.country_code; return NULL; } diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c index 1380dd389cf6..78dff1c489b8 100644 --- a/drivers/net/wireless/bcm4329/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329/dhd_sdio.c @@ -428,6 +428,7 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start); #ifdef DHD_DEBUG_TRAP static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size); +static int dhdsdio_mem_dump(dhd_bus_t *bus); #endif /* DHD_DEBUG_TRAP */ static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); @@ -1844,6 +1845,11 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); } + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); + } + done: if (mbuffer) MFREE(bus->dhd->osh, mbuffer, msize); @@ -1852,6 +1858,60 @@ done: return bcmerror; } + +static int +dhdsdio_mem_dump(dhd_bus_t *bus) +{ + int ret = 0; + int size; /* Full mem size */ + int start = 0; /* Start address */ + int read_size = 0; /* Read size of each iteration */ + uint8 *buf = NULL, *databuf = NULL; + + /* Get full mem size */ + size = bus->ramsize; + buf = MALLOC(bus->dhd->osh, size); + if (!buf) { + printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size); + return -1; + } + + /* Read mem content */ + printf("Dump dongle memory"); + databuf = buf; + while (size) + { + read_size = MIN(MEMBLOCK, size); + if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) + { + printf("%s: Error membytes %d\n", __FUNCTION__, ret); + if (buf) { + MFREE(bus->dhd->osh, buf, size); + } + return -1; + } + printf("."); + + /* Decrement size and increment start address */ + size -= read_size; + start += read_size; + databuf += read_size; + } + printf("Done\n"); + +#ifdef DHD_DEBUG + /* free buf before return !!! */ + if (write_to_file(bus->dhd, buf, bus->ramsize)) + { + printf("%s: Error writing to files\n", __FUNCTION__); + return -1; + } + /* buf free handled in write_to_file, not here */ +#else + MFREE(bus->dhd->osh, buf, size); +#endif + return 0; +} #endif /* DHD_DEBUG_TRAP */ #ifdef DHD_DEBUG diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h index cd66a9501cb6..23ee514a7b6b 100644 --- a/drivers/net/wireless/bcm4329/include/epivers.h +++ b/drivers/net/wireless/bcm4329/include/epivers.h @@ -33,16 +33,16 @@ #define EPI_RC_NUMBER 248 -#define EPI_INCREMENTAL_NUMBER 23 +#define EPI_INCREMENTAL_NUMBER 18 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 248, 23 +#define EPI_VERSION 4, 218, 248, 18 -#define EPI_VERSION_NUM 0x04daf817 +#define EPI_VERSION_NUM 0x04daf812 -#define EPI_VERSION_STR "4.218.248.23" -#define EPI_ROUTER_VERSION_STR "4.219.248.23" +#define EPI_VERSION_STR "4.218.248.18" +#define EPI_ROUTER_VERSION_STR "4.219.248.18" #endif diff --git a/drivers/net/wireless/bcm4329/include/wlioctl.h b/drivers/net/wireless/bcm4329/include/wlioctl.h index 00c61f10782f..cd7725a70db4 100644 --- a/drivers/net/wireless/bcm4329/include/wlioctl.h +++ b/drivers/net/wireless/bcm4329/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h,v 1.601.4.15.2.14.2.62.4.3 2011/02/09 23:31:02 Exp $ + * $Id: wlioctl.h,v 1.601.4.15.2.14.2.62.4.1 2010/11/17 03:09:28 Exp $ */ @@ -254,11 +254,6 @@ typedef struct wl_join_params { #define WLC_CNTRY_BUF_SZ 4 -typedef struct wl_country { - char country_abbrev[WLC_CNTRY_BUF_SZ]; - int32 rev; - char ccode[WLC_CNTRY_BUF_SZ]; -} wl_country_t; typedef enum sup_auth_status { @@ -862,7 +857,7 @@ typedef struct wl_ioctl { #define PM_MAX 1 #define PM_FAST 2 -#define LISTEN_INTERVAL 10 +#define LISTEN_INTERVAL 20 #define INTERFERE_NONE 0 #define NON_WLAN 1 @@ -1314,16 +1309,12 @@ enum { #define ENABLE_BKGRD_SCAN_BIT 2 #define IMMEDIATE_SCAN_BIT 3 #define AUTO_CONNECT_BIT 4 -#define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 #define SORT_CRITERIA_MASK 0x01 #define AUTO_NET_SWITCH_MASK 0x02 #define ENABLE_BKGRD_SCAN_MASK 0x04 #define IMMEDIATE_SCAN_MASK 0x08 #define AUTO_CONNECT_MASK 0x10 -#define ENABLE_BD_SCAN_MASK 0x20 -#define ENABLE_ADAPTSCAN_MASK 0x40 #define PFN_VERSION 1 @@ -1336,8 +1327,6 @@ typedef struct wl_pfn_param { int32 lost_network_timeout; int16 flags; int16 rssi_margin; - int32 repeat_scan; - int32 max_freq_adjust; } wl_pfn_param_t; typedef struct wl_pfn { @@ -1347,12 +1336,14 @@ typedef struct wl_pfn { int32 auth; uint32 wpa_auth; int32 wsec; +#ifdef WLPFN_AUTO_CONNECT + union { + wl_wsec_key_t sec_key; + wsec_pmk_t wpa_sec_key; + } pfn_security; +#endif } wl_pfn_t; -#define PNO_SCAN_MAX_FW 508*1000 -#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 -#define PNO_SCAN_MIN_FW_SEC 10 - #define TOE_TX_CSUM_OL 0x00000001 #define TOE_RX_CSUM_OL 0x00000002 diff --git a/drivers/net/wireless/bcm4329/linux_osl.c b/drivers/net/wireless/bcm4329/linux_osl.c index cf72a077bd90..980416baf918 100644 --- a/drivers/net/wireless/bcm4329/linux_osl.c +++ b/drivers/net/wireless/bcm4329/linux_osl.c @@ -247,10 +247,8 @@ void* osl_pktget(osl_t *osh, uint len) { struct sk_buff *skb; - gfp_t flags; - flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - if ((skb = __dev_alloc_skb(len, flags))) { + if ((skb = dev_alloc_skb(len))) { skb_put(skb, len); skb->priority = 0; diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c index 434e584f830c..146dffd52976 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.c +++ b/drivers/net/wireless/bcm4329/wl_iw.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.78 2011/02/11 21:27:52 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.69 2010/12/21 03:00:08 Exp $ */ @@ -54,11 +54,10 @@ typedef const struct si_pub si_t; #define WL_INFORM(x) #define WL_WSEC(x) #define WL_SCAN(x) -#define WL_PNO(x) #define WL_TRACE_COEX(x) #include - +#include #ifndef IW_ENCODE_ALG_SM4 @@ -116,6 +115,10 @@ static int g_onoff = G_WLAN_SET_ON; wl_iw_extra_params_t g_wl_iw_params; static struct mutex wl_cache_lock; +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY +static bool use_non_dfs_channels = true; +#endif + extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen); #include @@ -158,13 +161,12 @@ extern int dhd_wait_pend8021x(struct net_device *dev); #endif static void *g_scan = NULL; -static volatile uint g_scan_specified_ssid; -static wlc_ssid_t g_specific_ssid; +static volatile uint g_scan_specified_ssid; +static wlc_ssid_t g_specific_ssid; static wlc_ssid_t g_ssid; -bool btcoex_is_sco_active(struct net_device *dev); -static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; +static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; #if defined(CONFIG_FIRST_SCAN) static volatile uint g_first_broadcast_scan; static volatile uint g_first_counter_scans; @@ -592,36 +594,6 @@ wl_iw_set_passive_scan( return error; } - -static int -wl_iw_set_txpower( - struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra -) -{ - int error = 0; - char *p = extra; - int txpower = -1; - - txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1); - if ((txpower >= 0) && (txpower <= 127)) { - txpower |= WL_TXPWR_OVERRIDE; - txpower = htod32(txpower); - - error = dev_wlc_intvar_set(dev, "qtxpower", txpower); - p += snprintf(p, MAX_WX_STRING, "OK"); - WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower)); - } else { - WL_ERROR(("%s: set tx power failed\n", __FUNCTION__)); - p += snprintf(p, MAX_WX_STRING, "FAIL"); - } - - wrqu->data.length = p - extra + 1; - return error; -} - static int wl_iw_get_macaddr( struct net_device *dev, @@ -647,6 +619,31 @@ wl_iw_get_macaddr( return error; } +static int +wl_iw_set_country_code(struct net_device *dev, char *ccode) +{ + char country_code[WLC_CNTRY_BUF_SZ]; + int ret = -1; + + WL_TRACE(("%s\n", __FUNCTION__)); + if (!ccode) + ccode = dhd_bus_country_get(dev); + strncpy(country_code, ccode, sizeof(country_code)); + if (ccode && (country_code[0] != 0)) { +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY + if (use_non_dfs_channels && !strncmp(country_code, "US", 2)) + strncpy(country_code, "Q2", WLC_CNTRY_BUF_SZ); + if (!use_non_dfs_channels && !strncmp(country_code, "Q2", 2)) + strncpy(country_code, "US", WLC_CNTRY_BUF_SZ); +#endif + ret = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, &country_code, sizeof(country_code)); + if (ret >= 0) { + WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); + dhd_bus_country_set(dev, &country_code[0]); + } + } + return ret; +} static int wl_iw_set_country( @@ -661,39 +658,25 @@ wl_iw_set_country( char *p = extra; int country_offset; int country_code_size; - wl_country_t cspec = {{0}, 0, {0}}; - char smbuf[WLC_IOCTL_SMLEN]; - cspec.rev = -1; + WL_TRACE(("%s\n", __FUNCTION__)); memset(country_code, 0, sizeof(country_code)); - memset(smbuf, 0, sizeof(smbuf)); country_offset = strcspn(extra, " "); country_code_size = strlen(extra) - country_offset; if (country_offset != 0) { - strncpy(country_code, extra + country_offset +1, + strncpy(country_code, extra + country_offset + 1, MIN(country_code_size, sizeof(country_code))); - - - memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - - get_customized_country_code((char *)&cspec.country_abbrev, &cspec); - - if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec, \ - sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) { + error = wl_iw_set_country_code(dev, country_code); + if (error >= 0) { p += snprintf(p, MAX_WX_STRING, "OK"); - WL_ERROR(("%s: set country for %s as %s rev %d is OK\n", \ - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - dhd_bus_country_set(dev, &cspec); + WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); goto exit; } } - WL_ERROR(("%s: set country for %s as %s rev %d failed\n", \ - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - + WL_ERROR(("%s: set country %s failed code %d\n", __FUNCTION__, country_code, error)); p += snprintf(p, MAX_WX_STRING, "FAIL"); exit: @@ -701,6 +684,33 @@ exit: return error; } +static int +wl_iw_get_country( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + char *ccode; + int current_channels; + + WL_TRACE(("%s\n", __FUNCTION__)); + + ccode = dhd_bus_country_get(dev); + if(ccode){ + if(0 == strcmp(ccode, "Q2")) + current_channels = 11; + else if(0 == strcmp(ccode, "EU")) + current_channels = 13; + else if(0 == strcmp(ccode, "JP")) + current_channels = 14; + } + sprintf(extra, "Scan-Channels = %d", current_channels); + printk("Get Channels return %d,(country code = %s)\n",current_channels, ccode); + return 0; +} + #ifdef CUSTOMER_HW2 static int wl_iw_set_power_mode( @@ -755,40 +765,26 @@ wl_iw_set_power_mode( #endif -bool btcoex_is_sco_active(struct net_device *dev) +static bool btcoex_is_sco_active(struct net_device *dev) { int ioc_res = 0; bool res = false; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n", - __FUNCTION__, i, param27)); + int temp = 0; - if (ioc_res < 0) { - WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__)); - break; - } + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 4, &temp); - if ((param27 & 0x6) == 2) { - sco_id_cnt++; - } + if (ioc_res == 0) { + WL_TRACE_COEX(("%s: read btc_params[4] = %x\n", __FUNCTION__, temp)); - if (sco_id_cnt > 2) { - WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", - __FUNCTION__, sco_id_cnt, i)); + if ((temp > 0xea0) && (temp < 0xed8)) { + WL_TRACE_COEX(("%s: BT SCO/eSCO is ACTIVE\n", __FUNCTION__)); res = true; - break; + } else { + WL_TRACE_COEX(("%s: BT SCO/eSCO is NOT detected\n", __FUNCTION__)); } - - msleep(5); + } else { + WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__)); } - return res; } @@ -1074,6 +1070,21 @@ wl_iw_set_suspend( return ret; } +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY +static int +wl_iw_set_dfs_channels( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + use_non_dfs_channels = *(extra + strlen(SETDFSCHANNELS_CMD) + 1) - '0'; + use_non_dfs_channels = (use_non_dfs_channels != 0) ? false : true; + wl_iw_set_country_code(dev, NULL); + return 0; +} +#endif int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) @@ -1359,10 +1370,9 @@ wl_iw_set_pno_set( int nssid = 0; cmd_tlv_t *cmd_tlv_temp; char *str_ptr; + char *str_ptr_end; int tlv_size_left; int pno_time; - int pno_repeat; - int pno_freq_expo_max; #ifdef PNO_SET_DEBUG int i; @@ -1376,10 +1386,6 @@ wl_iw_set_pno_set( 'G', 'O', 'O', 'G', 'T', '1','E', - 'R', - '2', - 'M', - '2', 0x00 }; #endif @@ -1423,7 +1429,6 @@ wl_iw_set_pno_set( cmd_tlv_temp = (cmd_tlv_t *)str_ptr; memset(ssids_local, 0, sizeof(ssids_local)); - pno_repeat = pno_freq_expo_max = 0; if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \ (cmd_tlv_temp->version == PNO_TLV_VERSION) && \ @@ -1444,28 +1449,9 @@ wl_iw_set_pno_set( goto exit_proc; } str_ptr++; - pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); - - if (str_ptr[0] != 0) { - if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { - WL_ERROR(("%s pno repeat : corrupted field\n", \ - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); - if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { - WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", \ - __FUNCTION__)); - goto exit_proc; - } - str_ptr++; - pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - WL_PNO(("%s: pno_freq_expo_max=%d\n", \ - __FUNCTION__, pno_freq_expo_max)); - } + pno_time = simple_strtoul(str_ptr, &str_ptr_end, 16); + WL_ERROR((" got %d bytes left pno_time %d or %#x\n", \ + tlv_size_left, pno_time, pno_time)); } } else { @@ -1473,7 +1459,7 @@ wl_iw_set_pno_set( goto exit_proc; } - res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); + res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time); exit_proc: net_os_wake_unlock(dev); @@ -1760,79 +1746,6 @@ int hstr_2_buf(const char *txt, u8 *buf, int len) return 0; } -#if defined(SOFTAP) && defined(SOFTAP_TLV_CFG) - -static int wl_iw_softap_cfg_tlv( - struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra -) -{ - int res = -1; - char *str_ptr; - int tlv_size_left; - - -#define SOFTAP_TLV_DEBUG 1 -#ifdef SOFTAP_TLV_DEBUG -char softap_cmd_example[] = { - - 'S', 'O', 'F', 'T', 'A', 'P', 'S', 'E', 'T', ' ', - - SOFTAP_TLV_PREFIX, SOFTAP_TLV_VERSION, - SOFTAP_TLV_SUBVERSION, SOFTAP_TLV_RESERVED, - - TLV_TYPE_SSID, 9, 'B', 'R', 'C', 'M', ',', 'G', 'O', 'O', 'G', - - TLV_TYPE_SECUR, 4, 'O', 'P', 'E', 'N', - - TLV_TYPE_KEY, 4, 0x31, 0x32, 0x33, 0x34, - - TLV_TYPE_CHANNEL, 4, 0x06, 0x00, 0x00, 0x00 -}; -#endif - - -#ifdef SOFTAP_TLV_DEBUG - { - int i; - if (!(extra = kmalloc(sizeof(softap_cmd_example) +10, GFP_KERNEL))) - return -ENOMEM; - memcpy(extra, softap_cmd_example, sizeof(softap_cmd_example)); - wrqu->data.length = sizeof(softap_cmd_example); - print_buf(extra, wrqu->data.length, 16); - for (i = 0; i < wrqu->data.length; i++) - printf("%c ", extra[i]); - printf("\n"); - } -#endif - - WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", - __FUNCTION__, info->cmd, info->flags, - wrqu->data.pointer, wrqu->data.length)); - - if (g_onoff == G_WLAN_SET_OFF) { - WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); - return -1; - } - - if (wrqu->data.length < (strlen(SOFTAP_SET_CMD) + sizeof(cmd_tlv_t))) { - WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__, - wrqu->data.length, strlen(SOFTAP_SET_CMD) + sizeof(cmd_tlv_t))); - return -1; - } - - str_ptr = extra + strlen(SOFTAP_SET_CMD)+1; - tlv_size_left = wrqu->data.length - (strlen(SOFTAP_SET_CMD)+1); - - memset(&my_ap, 0, sizeof(my_ap)); - - return res; -} -#endif - - #ifdef SOFTAP int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) { @@ -3800,7 +3713,6 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1); wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); - kfree(buf); #endif break; } @@ -5842,7 +5754,7 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); WL_SCAN(("\n###################\n")); } -#endif +#endif if (params_size > WLC_IOCTL_MEDLEN) { WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \ @@ -5882,11 +5794,6 @@ static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info return -1; } -#ifdef PNO_SET_DEBUG - wl_iw_set_pno_set(dev, info, wrqu, extra); - return 0; -#endif - if (wrqu->data.length != 0) { char *str_ptr; @@ -6414,8 +6321,16 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } if (strlen(ap->country_code)) { - WL_ERROR(("%s: Igonored: Country MUST be specified \ - COUNTRY command with \n", __FUNCTION__)); + int error = 0; + if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, + ap->country_code, sizeof(ap->country_code))) >= 0) { + WL_SOFTAP(("%s: set country %s OK\n", + __FUNCTION__, ap->country_code)); + dhd_bus_country_set(dev, &ap->country_code[0]); + } else { + WL_ERROR(("%s: ERROR:%d setting country %s\n", + __FUNCTION__, error, ap->country_code)); + } } else { WL_SOFTAP(("%s: Country code is not specified," " will use Radio's default\n", @@ -7157,6 +7072,30 @@ int wl_iw_process_private_ascii_cmd( } #endif +#define BCM4329_WAKELOCK_NAME "bcm4329_wifi_wakelock" + +static struct wake_lock bcm4329_suspend_lock; + +int bcm4329_wakelock_init = 0; + +void bcm4329_power_save_init(void) +{ + wake_lock_init(&bcm4329_suspend_lock, WAKE_LOCK_SUSPEND, BCM4329_WAKELOCK_NAME); + wake_lock(&bcm4329_suspend_lock); + + bcm4329_wakelock_init = 2; +} + +void bcm4329_power_save_exit(void) +{ + bcm4329_wakelock_init = 0; + msleep(100); + + if (bcm4329_wakelock_init == 2) + wake_unlock(&bcm4329_suspend_lock); + wake_lock_destroy(&bcm4329_suspend_lock); +} + static int wl_iw_set_priv( struct net_device *dev, struct iw_request_info *info, @@ -7182,6 +7121,11 @@ static int wl_iw_set_priv( if (dwrq->length && extra) { if (strnicmp(extra, "START", strlen("START")) == 0) { + if (bcm4329_wakelock_init == 1) + { + wake_lock(&bcm4329_suspend_lock); + bcm4329_wakelock_init = 2; + } wl_iw_control_wl_on(dev, info); WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); } @@ -7213,8 +7157,16 @@ static int wl_iw_set_priv( ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0) ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) + else if (strnicmp(extra, "SCAN-CHANNELS", strlen("SCAN-CHANNELS")) == 0) + ret = wl_iw_get_country(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, "STOP", strlen("STOP")) == 0){ ret = wl_iw_control_wl_off(dev, info); + if (bcm4329_wakelock_init == 2) + { + wake_unlock(&bcm4329_suspend_lock); + bcm4329_wakelock_init = 1; + } + } else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) @@ -7225,8 +7177,10 @@ static int wl_iw_set_priv( ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0) - ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra); +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY + else if (strnicmp(extra, SETDFSCHANNELS_CMD, strlen(SETDFSCHANNELS_CMD)) == 0) + ret = wl_iw_set_dfs_channels(dev, info, (union iwreq_data *)dwrq, extra); +#endif #if defined(PNO_SUPPORT) else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); @@ -7236,40 +7190,21 @@ static int wl_iw_set_priv( ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); #endif #if defined(CSCAN) - else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) + else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra); -#endif +#endif #ifdef CUSTOMER_HW2 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) { - WL_TRACE_COEX(("%s:got Framwrork cmd: 'BTCOEXMODE'\n", __FUNCTION__)); + else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); - } #else else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); #endif else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0) ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, RXFILTER_START_CMD, strlen(RXFILTER_START_CMD)) == 0) - ret = net_os_set_packet_filter(dev, 1); - else if (strnicmp(extra, RXFILTER_STOP_CMD, strlen(RXFILTER_STOP_CMD)) == 0) - ret = net_os_set_packet_filter(dev, 0); - else if (strnicmp(extra, RXFILTER_ADD_CMD, strlen(RXFILTER_ADD_CMD)) == 0) { - int filter_num = *(extra + strlen(RXFILTER_ADD_CMD) + 1) - '0'; - ret = net_os_rxfilter_add_remove(dev, TRUE, filter_num); - } - else if (strnicmp(extra, RXFILTER_REMOVE_CMD, strlen(RXFILTER_REMOVE_CMD)) == 0) { - int filter_num = *(extra + strlen(RXFILTER_REMOVE_CMD) + 1) - '0'; - ret = net_os_rxfilter_add_remove(dev, FALSE, filter_num); - } #ifdef SOFTAP -#ifdef SOFTAP_TLV_CFG - else if (strnicmp(extra, SOFTAP_SET_CMD, strlen(SOFTAP_SET_CMD)) == 0) { - wl_iw_softap_cfg_tlv(dev, info, (union iwreq_data *)dwrq, extra); - } -#endif else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) { wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra); } else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) { @@ -7790,10 +7725,9 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) uint32 datalen = ntoh32(e->datalen); uint32 status = ntoh32(e->status); uint32 toto; -#if defined(ROAM_NOT_USED) static uint32 roam_no_success = 0; static bool roam_no_success_send = FALSE; -#endif + memset(&wrqu, 0, sizeof(wrqu)); memset(extra, 0, sizeof(extra)); @@ -7864,14 +7798,10 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; case WLC_E_ROAM: if (status == WLC_E_STATUS_SUCCESS) { - WL_ASSOC(("%s: WLC_E_ROAM: success\n", __FUNCTION__)); -#if defined(ROAM_NOT_USED) - roam_no_success_send = FALSE; - roam_no_success = 0; -#endif - goto wl_iw_event_end; + memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + cmd = SIOCGIWAP; } -#if defined(ROAM_NOT_USED) else if (status == WLC_E_STATUS_NO_NETWORKS) { roam_no_success++; if ((roam_no_success == 5) && (roam_no_success_send == FALSE)) { @@ -7886,7 +7816,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) goto wl_iw_event_end; } } -#endif break; case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: @@ -7942,10 +7871,8 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) wl_iw_send_priv_event(priv_dev, "AP_UP"); } else { WL_TRACE(("STA_LINK_UP\n")); -#if defined(ROAM_NOT_USED) roam_no_success_send = FALSE; roam_no_success = 0; -#endif } #endif WL_TRACE(("Link UP\n")); @@ -8073,6 +8000,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) #endif #if WIRELESS_EXT > 14 + memset(extra, 0, sizeof(extra)); if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { cmd = IWEVCUSTOM; diff --git a/drivers/net/wireless/bcm4329/wl_iw.h b/drivers/net/wireless/bcm4329/wl_iw.h index ee6c699936ea..928291fe589a 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.h +++ b/drivers/net/wireless/bcm4329/wl_iw.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.h,v 1.5.34.1.6.36.4.18 2011/02/10 19:33:12 Exp $ + * $Id: wl_iw.h,v 1.5.34.1.6.36.4.15 2010/11/17 03:13:51 Exp $ */ @@ -52,11 +52,7 @@ #define PNOSETUP_SET_CMD "PNOSETUP " #define PNOENABLE_SET_CMD "PNOFORCE" #define PNODEBUG_SET_CMD "PNODEBUG" -#define TXPOWER_SET_CMD "TXPOWER" -#define RXFILTER_START_CMD "RXFILTER-START" -#define RXFILTER_STOP_CMD "RXFILTER-STOP" -#define RXFILTER_ADD_CMD "RXFILTER-ADD" -#define RXFILTER_REMOVE_CMD "RXFILTER-REMOVE" +#define SETDFSCHANNELS_CMD "SETDFSCHANNELS" #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" @@ -66,12 +62,6 @@ typedef struct wl_iw_extra_params { int target_channel; } wl_iw_extra_params_t; -struct cntry_locales_custom { - char iso_abbrev[WLC_CNTRY_BUF_SZ]; - char custom_locale[WLC_CNTRY_BUF_SZ]; - int32 custom_locale_rev; -}; - #define WL_IW_RSSI_MINVAL -200 #define WL_IW_RSSI_NO_SIGNAL -91 #define WL_IW_RSSI_VERY_LOW -80 @@ -143,13 +133,13 @@ typedef struct wl_iw_ss_cache { } wl_iw_ss_cache_t; typedef struct wl_iw_ss_cache_ctrl { - wl_iw_ss_cache_t *m_cache_head; - int m_link_down; - int m_timer_expired; - char m_active_bssid[ETHER_ADDR_LEN]; - uint m_prev_scan_mode; - uint m_cons_br_scan_cnt; - struct timer_list *m_timer; + wl_iw_ss_cache_t *m_cache_head; + int m_link_down; + int m_timer_expired; + char m_active_bssid[ETHER_ADDR_LEN]; + uint m_prev_scan_mode; + uint m_cons_br_scan_cnt; + struct timer_list *m_timer; } wl_iw_ss_cache_ctrl_t; typedef enum broadcast_first_scan { @@ -175,7 +165,7 @@ struct ap_profile { }; -#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_DISABLED 0 #define MACLIST_MODE_DENY 1 #define MACLIST_MODE_ALLOW 2 struct mflist { @@ -208,7 +198,8 @@ extern int net_os_wake_lock_timeout_enable(struct net_device *dev); extern int net_os_set_suspend_disable(struct net_device *dev, int val); extern int net_os_set_suspend(struct net_device *dev, int val); extern int net_os_set_dtim_skip(struct net_device *dev, int val); -extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); +extern int net_os_set_packet_filter(struct net_device *dev, int val); +extern void dhd_bus_country_set(struct net_device *dev, char *country_code); extern char *dhd_bus_country_get(struct net_device *dev); extern int dhd_get_dtim_skip(dhd_pub_t *dhd); @@ -230,15 +221,13 @@ extern int dhd_get_dtim_skip(dhd_pub_t *dhd); extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, \ - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr); extern int dhd_pno_get_status(dhd_pub_t *dhd); extern int dhd_dev_pno_reset(struct net_device *dev); extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, \ - int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); + int nssid, ushort scan_fr); extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); extern int dhd_dev_get_pno_status(struct net_device *dev); -extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); #define PNO_TLV_PREFIX 'S' #define PNO_TLV_VERSION '1' @@ -246,9 +235,8 @@ extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); #define PNO_TLV_RESERVED '0' #define PNO_TLV_TYPE_SSID_IE 'S' #define PNO_TLV_TYPE_TIME 'T' -#define PNO_TLV_FREQ_REPEAT 'R' -#define PNO_TLV_FREQ_EXPO_MAX 'M' -#define PNO_EVENT_UP "PNO_EVENT" +#define PNO_EVENT_UP "PNO_EVENT" +#define PNO_SCAN_MAX_FW 508 typedef struct cmd_tlv { char prefix; @@ -257,19 +245,6 @@ typedef struct cmd_tlv { char reserved; } cmd_tlv_t; -#ifdef SOFTAP_TLV_CFG -#define SOFTAP_SET_CMD "SOFTAPSET " -#define SOFTAP_TLV_PREFIX 'A' -#define SOFTAP_TLV_VERSION '1' -#define SOFTAP_TLV_SUBVERSION '0' -#define SOFTAP_TLV_RESERVED '0' - -#define TLV_TYPE_SSID 'S' -#define TLV_TYPE_SECUR 'E' -#define TLV_TYPE_KEY 'K' -#define TLV_TYPE_CHANNEL 'C' -#endif - #if defined(CSCAN) typedef struct cscan_tlv { @@ -304,6 +279,6 @@ extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num); -#endif +#endif -#endif +#endif diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index ddf8cf5f3204..1fd5e93204d2 100755 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -18,14 +18,110 @@ #include #include #include +#include + +#define WM831X_DEBUG +#undef WM831X_DEBUG + +#ifdef WM831X_DEBUG +#define WM_BATT_DBG(x...) printk(KERN_INFO x) +#else +#define WM_BATT_DBG(x...) do {} while (0) +#endif + +#define WM831X_CHG_SYSLO_SHIFT 4 +#define WM831X_CHG_SYSOK_SHIFT 0 +#define WM831X_CHG_SYSLO_MASK ~(0x7 << 4) +#define WM831X_CHG_SYSOK_MASK ~(0x7 << 0) + +#define batt_num 52 + +static int batt_step_table[batt_num] = { + 3400,3420,3440,3475,3505,3525, + 3540,3557,3570,3580,3610, + 3630,3640,3652,3662,3672, + 3680,3687,3693,3699,3705, + 3710,3714,3718,3722,3726, + 3730,3734,3738,3742,3746, + 3750,3756,3764,3774,3786, + 3800,3808,3817,3827,3838, + 3950,3964,3982,4002,4026, + 4050,4074,4098,4123,4149,4178 +}; + +static int batt_disp_table[batt_num] = { + 0,1,2,3,5,7, + 9,11,13,15,17, + 19,21,23,25,27, + 29,31,33,35,37, + 39,41,43,45,47, + 49,51,53,55,57, + 59,61,63,65,67, + 69,71,73,75,77, + 79,81,83,85,87, + 89,91,93,95,97,100 +}; + +static int batt_chg_step_table[batt_num] = { + 3530,3565,3600,3635,3655,3680,//+160 + 3700,3717,3734,3745,3755,//+150 + 3770,3778,3786,3795,3803,//+140 + 3810,3814,3818,3822,3825,//+130 + 3830,3832,3834,3836,3837,//+120 + 3840,3842,3844,3846,3847,//+110 + 3850,3857,3864,3871,3876,//+100 + 3890,3897,3904,3911,3918,//+90 + 4030,4047,4064,4080,4096,//+80 + 4120,4132,4144,4156,4170,4180//+70 +}; + + + +#define TIMER_MS_COUNTS 1000 +struct wm_batt_priv_data { + int online; + int status; + int health; + int level; + int temp; + int voltage; +}; struct wm831x_power { struct wm831x *wm831x; struct power_supply wall; struct power_supply usb; struct power_supply battery; + struct work_struct batt_work; + struct timer_list timer; + struct wm_batt_priv_data batt_info; + struct wake_lock syslo_wake; + int interval; }; +struct wm831x_power *g_wm831x_power; + +static int power_test_sysfs_init(void); +extern void wm831x_batt_vol_level(struct wm831x_power *power, int batt_vol, int *level); +static DEFINE_MUTEX(charging_mutex); + +int wm831x_read_on_pin_status(void) +{ + int ret; + + if(!g_wm831x_power) + { + printk("err:%s:g_wm831x_power address is 0\n",__FUNCTION__); + return -1; + } + + ret = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_ON_PIN_CONTROL); + if (ret < 0) + return ret; + + return !(ret & WM831X_ON_PIN_STS) ? 1 : 0; +} + static int wm831x_power_check_online(struct wm831x *wm831x, int supply, union power_supply_propval *val) { @@ -43,18 +139,54 @@ static int wm831x_power_check_online(struct wm831x *wm831x, int supply, return 0; } +int wm831x_read_chg_status(void) +{ + int ret, usb_chg = 0, wall_chg = 0; + + if(!g_wm831x_power) + { + printk("err:%s:g_wm831x_power address is 0\n",__FUNCTION__); + return -1; + } + + ret = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_SYSTEM_STATUS); + if (ret < 0) + return ret; + + if (ret & WM831X_PWR_USB) + usb_chg = 1; + if (ret & WM831X_PWR_WALL) + wall_chg = 1; + + return ((usb_chg | wall_chg) ? 1 : 0); +} + static int wm831x_power_read_voltage(struct wm831x *wm831x, enum wm831x_auxadc src, union power_supply_propval *val) { int ret; - ret = wm831x_auxadc_read_uv(wm831x, src); if (ret >= 0) - val->intval = ret; + val->intval = ret / 1000; + + return ret ; +} - return ret; +int wm831x_read_batt_voltage(void) +{ + int ret = 0; + + if(!g_wm831x_power) + { + printk("err:%s:g_wm831x_power address is 0\n",__FUNCTION__); + return -1; + } + + ret = wm831x_auxadc_read_uv(g_wm831x_power->wm831x, WM831X_AUX_BATT); + return ret / 1000; } +//EXPORT_SYMBOL_GPL(wm831x_get_batt_voltage); /********************************************************************* * WALL Power @@ -190,13 +322,34 @@ static struct chg_map chg_times[] = { { 510, 15 << WM831X_CHG_TIME_SHIFT }, }; +static struct chg_map chg_syslos[] = { + { 2800, 0 << WM831X_CHG_SYSLO_SHIFT}, + { 2900, 1 << WM831X_CHG_SYSLO_SHIFT}, + { 3000, 2 << WM831X_CHG_SYSLO_SHIFT}, + { 3100, 3 << WM831X_CHG_SYSLO_SHIFT}, + { 3200, 4 << WM831X_CHG_SYSLO_SHIFT}, + { 3300, 5 << WM831X_CHG_SYSLO_SHIFT}, + { 3400, 6 << WM831X_CHG_SYSLO_SHIFT}, + { 3500, 7 << WM831X_CHG_SYSLO_SHIFT}, +}; + +static struct chg_map chg_sysoks[] = { + { 2800, 0 << WM831X_CHG_SYSOK_SHIFT}, + { 2900, 1 << WM831X_CHG_SYSOK_SHIFT}, + { 3000, 2 << WM831X_CHG_SYSOK_SHIFT}, + { 3100, 3 << WM831X_CHG_SYSOK_SHIFT}, + { 3200, 4 << WM831X_CHG_SYSOK_SHIFT}, + { 3300, 5 << WM831X_CHG_SYSOK_SHIFT}, + { 3400, 6 << WM831X_CHG_SYSOK_SHIFT}, + { 3500, 7 << WM831X_CHG_SYSOK_SHIFT}, +}; + static void wm831x_battey_apply_config(struct wm831x *wm831x, struct chg_map *map, int count, int val, int *reg, const char *name, const char *units) { int i; - for (i = 0; i < count; i++) if (val == map[i].val) break; @@ -213,7 +366,7 @@ static void wm831x_config_battery(struct wm831x *wm831x) { struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; struct wm831x_battery_pdata *pdata; - int ret, reg1, reg2; + int ret, reg1, reg2, reg3; if (!wm831x_pdata || !wm831x_pdata->battery) { dev_warn(wm831x->dev, @@ -225,6 +378,7 @@ static void wm831x_config_battery(struct wm831x *wm831x) reg1 = 0; reg2 = 0; + reg3 = 0; if (!pdata->enable) { dev_info(wm831x->dev, "Battery charger disabled\n"); @@ -258,6 +412,14 @@ static void wm831x_config_battery(struct wm831x *wm831x) pdata->timeout, ®2, "charger timeout", "min"); + wm831x_battey_apply_config(wm831x, chg_syslos, ARRAY_SIZE(chg_syslos), + pdata->syslo, ®3, + "syslo voltage", "mV"); + + wm831x_battey_apply_config(wm831x, chg_sysoks, ARRAY_SIZE(chg_sysoks), + pdata->sysok, ®3, + "sysok voltage", "mV"); + ret = wm831x_reg_unlock(wm831x); if (ret != 0) { dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); @@ -269,10 +431,10 @@ static void wm831x_config_battery(struct wm831x *wm831x) WM831X_CHG_FAST_MASK | WM831X_CHG_ITERM_MASK, reg1); - if (ret != 0) + if (ret != 0) { dev_err(wm831x->dev, "Failed to set charger control 1: %d\n", ret); - + } ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2, WM831X_CHG_OFF_MSK | WM831X_CHG_TIME_MASK | @@ -280,9 +442,18 @@ static void wm831x_config_battery(struct wm831x *wm831x) WM831X_CHG_TRKL_ILIM_MASK | WM831X_CHG_VSEL_MASK, reg2); - if (ret != 0) + if (ret != 0) { dev_err(wm831x->dev, "Failed to set charger control 2: %d\n", ret); + } + + ret = wm831x_set_bits(wm831x, WM831X_SYSVDD_CONTROL, + WM831X_CHG_SYSLO_MASK | + WM831X_CHG_SYSOK_MASK, + reg3); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to set sysvdd control reg: %d\n",ret); + } wm831x_reg_lock(wm831x); } @@ -320,10 +491,53 @@ static int wm831x_bat_check_status(struct wm831x *wm831x, int *status) return 0; } +int wm831x_read_bat_charging_status(void) +{ + int ret, status; + + if(!g_wm831x_power) + { + printk("err:%s:g_wm831x_power address is 0\n",__FUNCTION__); + return -1; + } + + ret = wm831x_bat_check_status(g_wm831x_power->wm831x, &status); + if (ret < 0) + return ret; + if (status == POWER_SUPPLY_STATUS_CHARGING) + return 1; + return 0; +} static int wm831x_bat_check_type(struct wm831x *wm831x, int *type) { int ret; +#ifdef WM831X_DEBUG_0 + ret = wm831x_reg_read(wm831x, WM831X_POWER_STATE); + if (ret < 0) + return ret; + WM_BATT_DBG("%s: wm831x power status %#x\n", __FUNCTION__, ret); + + ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS); + if (ret < 0) + return ret; + WM_BATT_DBG("%s: wm831x system status %#x\n", __FUNCTION__, ret); + + ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1); + if (ret < 0) + return ret; + WM_BATT_DBG("%s: wm831x charger control1 %#x\n", __FUNCTION__, ret); + + ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_2); + if (ret < 0) + return ret; + WM_BATT_DBG("%s: wm831x charger control2 %#x\n", __FUNCTION__, ret); + + ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS); + if (ret < 0) + return ret; + WM_BATT_DBG("%s: wm831x charger status %#x\n\n", __FUNCTION__, ret); +#endif ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS); if (ret < 0) @@ -396,20 +610,36 @@ static int wm831x_bat_get_prop(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: ret = wm831x_bat_check_status(wm831x, &val->intval); + //val->intval = wm831x_power->batt_info.status; break; + case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_ONLINE: - ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT, - val); + //ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT, val); + val->intval = wm831x_power->batt_info.online; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val); + //ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val); + val->intval = wm831x_power->batt_info.voltage*1000;//uV break; case POWER_SUPPLY_PROP_HEALTH: - ret = wm831x_bat_check_health(wm831x, &val->intval); + //ret = wm831x_bat_check_health(wm831x, &val->intval); + val->intval = wm831x_power->batt_info.health; break; case POWER_SUPPLY_PROP_CHARGE_TYPE: ret = wm831x_bat_check_type(wm831x, &val->intval); break; + case POWER_SUPPLY_PROP_CAPACITY: + //ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val); + //wm831x_batt_vol_level(wm831x_power, val->intval, &level); + //val->intval = level; + val->intval = wm831x_power->batt_info.level; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; default: ret = -EINVAL; break; @@ -420,12 +650,16 @@ static int wm831x_bat_get_prop(struct power_supply *psy, static enum power_supply_property wm831x_bat_props[] = { POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_CHARGE_TYPE, }; +#ifdef CONFIG_WM831X_WITH_BATTERY static const char *wm831x_bat_irqs[] = { "BATT HOT", "BATT COLD", @@ -441,16 +675,18 @@ static irqreturn_t wm831x_bat_irq(int irq, void *data) { struct wm831x_power *wm831x_power = data; struct wm831x *wm831x = wm831x_power->wm831x; - - dev_dbg(wm831x->dev, "Battery status changed: %d\n", irq); - + int irq0; + + irq0 = wm831x->irq_base + WM831X_IRQ_CHG_BATT_HOT + 1; + dev_crit(wm831x->dev, "battery changed: i=%d\n", irq-irq0); + /* The battery charger is autonomous so we don't need to do * anything except kick user space */ power_supply_changed(&wm831x_power->battery); return IRQ_HANDLED; } - +#endif /********************************************************************* * Initialisation @@ -463,8 +699,8 @@ static irqreturn_t wm831x_syslo_irq(int irq, void *data) /* Not much we can actually *do* but tell people for * posterity, we're probably about to run out of power. */ - dev_crit(wm831x->dev, "SYSVDD under voltage\n"); - + dev_crit(wm831x->dev, "SYSVDD under voltage and wake lock 60s\n"); + wake_lock_timeout(&wm831x_power->syslo_wake,60*HZ);//wait for android closing system return IRQ_HANDLED; } @@ -474,7 +710,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data) struct wm831x *wm831x = wm831x_power->wm831x; dev_dbg(wm831x->dev, "Power source changed\n"); - + WM_BATT_DBG("%s:Power source changed\n", __FUNCTION__); /* Just notify for everything - little harm in overnotifying. */ power_supply_changed(&wm831x_power->battery); power_supply_changed(&wm831x_power->usb); @@ -483,6 +719,289 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data) return IRQ_HANDLED; } +static void wm831x_batt_timer_handler(unsigned long data) +{ + struct wm831x_power *wm831x_power = (struct wm831x_power*)data; + schedule_work(&wm831x_power->batt_work); + mod_timer(&wm831x_power->timer, jiffies + msecs_to_jiffies(wm831x_power->interval)); +} + +void wm831x_batt_vol_level(struct wm831x_power *wm831x_power, int batt_vol, int *level) +{ + int i, ret, status; + static int chg_plus = 1000; + static int chg_minus = 1000; + static int chg_curr = 0; + static int chg_num = 60; + static int disp_plus = 1000; + static int disp_minus = 1000; + static int disp_curr = 0; + static int disp_num = 50; + + + *level = wm831x_power->batt_info.level; + ret = wm831x_bat_check_status(wm831x_power->wm831x, &status); + if (ret < 0) { + printk("%s: check bat status failer...err = %d\n", __FUNCTION__, ret); + return; + } + + if (status == POWER_SUPPLY_STATUS_NOT_CHARGING + && batt_vol >= batt_step_table[batt_num-1]) { + *level = 100; + return; + } + + if (status == POWER_SUPPLY_STATUS_CHARGING) + { + disp_plus = 0; + disp_minus = 0; + disp_curr = 0; + + for(i = 0; i < batt_num; i++){ + if((batt_chg_step_table[i] <= batt_vol) && + (batt_chg_step_table[i+1] > batt_vol)) + break; + } + *level = batt_disp_table[i]; + + if (batt_vol <= batt_chg_step_table[0]) + *level = 0; + if (batt_vol >= batt_chg_step_table[batt_num - 1]) + *level = 100; + + // ³õʼ״̬ + if ((chg_plus == 1000) && (chg_minus == 1000)) + { + *level = *level; + chg_plus = 0; + chg_minus = 0; + chg_curr = 0; + } + else + { + + if (*level >= (wm831x_power->batt_info.level+1)) + { + chg_minus = 0; + chg_curr = 0; + + if (++chg_plus > chg_num) + { + *level = wm831x_power->batt_info.level + 1; + chg_plus = 0; + + if(*level < 85) + chg_num = 60; + else + chg_num = 20; + + } + else + { + *level = wm831x_power->batt_info.level; + } + } + + else if (*level >= wm831x_power->batt_info.level) + { + chg_plus = 0; + chg_minus = 0; + + if (++chg_curr > chg_num) + { + *level = *level; + chg_curr = 0; + } + else + { + *level = wm831x_power->batt_info.level; + } + } + else if (*level < (wm831x_power->batt_info.level-1)) + { + chg_plus = 0; + chg_curr = 0; + + if (++chg_minus > (chg_num<<1)) + { + *level = wm831x_power->batt_info.level - 1; + chg_minus = 0; + + if(*level < 85) + chg_num = 60; + else + chg_num = 20; + + } + else + { + *level = wm831x_power->batt_info.level; + } + } + else + { + chg_plus = 0; + chg_minus = 0; + chg_curr = 0; + *level = wm831x_power->batt_info.level; + } + } + + + if (*level >= 100) + *level = 100; + if (*level < 0) + *level = 0; + } + else + { + chg_plus = 0; + chg_minus = 0; + chg_curr = 0; + + for(i = 0; i < batt_num; i++){ + if(batt_vol >= batt_step_table[i] && + batt_vol < batt_step_table[i+1]) + break; + } + *level = batt_disp_table[i]; + + if (batt_vol <= batt_step_table[0]) + *level = 0; + if (batt_vol >= batt_step_table[batt_num - 1]) + *level = 100; + + // ³õʼ״̬ + if ((disp_plus == 1000) && (disp_minus == 1000)) + { + *level = *level; + disp_plus = 0; + disp_minus = 0; + disp_curr = 0; + } + else + { + + if (*level <= (wm831x_power->batt_info.level-1)) + { + disp_plus = 0; + disp_curr = 0; + + if (++disp_minus > disp_num) + { + *level = wm831x_power->batt_info.level - 1; + disp_minus = 0; + + if((*level < 17) || (*level > 85)) + disp_num = 10; + else + disp_num = 50; + + } + else + { + *level = wm831x_power->batt_info.level; + } + } + else if (*level <= wm831x_power->batt_info.level) + { + disp_plus = 0; + disp_minus = 0; + + if (++disp_curr > disp_num) + { + *level = *level; + disp_curr = 0; + } + else + { + *level = wm831x_power->batt_info.level; + } + } + else if (*level >= (wm831x_power->batt_info.level+1)) + { + disp_minus = 0; + disp_curr = 0; + + if (++disp_plus > (disp_num<<1)) + { + *level = wm831x_power->batt_info.level + 1; + disp_plus = 0; + if((*level < 17) || (*level > 85)) + disp_num = 10; + else + disp_num = 50; + } + else + { + *level = wm831x_power->batt_info.level; + } + } + else + { + disp_plus = 0; + disp_minus = 0; + disp_curr = 0; + *level = wm831x_power->batt_info.level; + } + } + + if (*level >= 100) + *level = 100; + if (*level < 0) + *level = 0; + } +} + +static void wm831x_batt_work(struct work_struct *work) +{ + int online, status,health,level, ret; + union power_supply_propval val; + struct wm831x_power *power = container_of(work, struct wm831x_power, batt_work); + + ret = wm831x_power_check_online(power->wm831x, WM831X_PWR_SRC_BATT, &val); + if (ret < 0) { + printk("%s: check bat online failer... err = %d\n", __FUNCTION__, ret); + return; + } + online = val.intval; + + ret = wm831x_bat_check_status(power->wm831x, &status); + if (ret < 0) { + printk("%s: check bat status failer... err = %d\n", __FUNCTION__, ret); + return; + } + + ret = wm831x_bat_check_health(power->wm831x, &health); + if (ret < 0) { + printk("%s: check bat health failer... err = %d\n", __FUNCTION__, ret); + return; + } + + ret = wm831x_power_read_voltage(power->wm831x, WM831X_AUX_BATT, &val); + if (ret < 0) { + printk("%s: read bat voltage failer...err = %d\n", __FUNCTION__, ret); + return; + } + power->batt_info.voltage = val.intval; + + wm831x_batt_vol_level(power, val.intval, &level); + //mod_timer(&power->timer, jiffies + msecs_to_jiffies(power->interval)); + + if (online != power->batt_info.online || status != power->batt_info.status + || health != power->batt_info.health || level != power->batt_info.level) + { + power->batt_info.online = online; + power->batt_info.status = status; + power->batt_info.health = health; + power->batt_info.level = level; + + power_supply_changed(&power->battery); + } + +} + static __devinit int wm831x_power_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); @@ -555,12 +1074,14 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev) goto err_syslo; } +#ifdef CONFIG_WM831X_WITH_BATTERY for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); ret = request_threaded_irq(irq, NULL, wm831x_bat_irq, IRQF_TRIGGER_RISING, wm831x_bat_irqs[i], power); + WM_BATT_DBG("%s: %s irq no %d\n", __FUNCTION__, wm831x_bat_irqs[i], irq); if (ret != 0) { dev_err(&pdev->dev, "Failed to request %s IRQ %d: %d\n", @@ -568,9 +1089,27 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev) goto err_bat_irq; } } - +#endif + + power->interval = TIMER_MS_COUNTS; + power->batt_info.level = 100; + power->batt_info.voltage = 4200; + power->batt_info.online = 1; + power->batt_info.status = POWER_SUPPLY_STATUS_DISCHARGING; + power->batt_info.health = POWER_SUPPLY_HEALTH_GOOD; + + wake_lock_init(&power->syslo_wake, WAKE_LOCK_SUSPEND, "wm831x_syslo_wake"); + INIT_WORK(&power->batt_work, wm831x_batt_work); + setup_timer(&power->timer, wm831x_batt_timer_handler, (unsigned long)power); + power->timer.expires = jiffies + msecs_to_jiffies(1000); + add_timer(&power->timer); + + g_wm831x_power = power; + printk("%s:wm831x_power initialized\n",__FUNCTION__); + power_test_sysfs_init(); return ret; - + +#ifdef CONFIG_WM831X_WITH_BATTERY err_bat_irq: for (; i >= 0; i--) { irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); @@ -578,6 +1117,8 @@ err_bat_irq: } irq = platform_get_irq_byname(pdev, "PWR SRC"); free_irq(irq, power); +#endif + err_syslo: irq = platform_get_irq_byname(pdev, "SYSLO"); free_irq(irq, power); @@ -596,12 +1137,12 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev) { struct wm831x_power *wm831x_power = platform_get_drvdata(pdev); int irq, i; - +#ifdef CONFIG_WM831X_WITH_BATTERY for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); free_irq(irq, wm831x_power); } - +#endif irq = platform_get_irq_byname(pdev, "PWR SRC"); free_irq(irq, wm831x_power); @@ -615,14 +1156,36 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int wm831x_battery_suspend(struct platform_device *dev, pm_message_t state) +{ + struct wm831x_power *power = (struct wm831x_power *)platform_get_drvdata(dev); + flush_scheduled_work(); + del_timer(&power->timer); + return 0; +} + +static int wm831x_battery_resume(struct platform_device *dev) +{ + struct wm831x_power *power = (struct wm831x_power *)platform_get_drvdata(dev); + power->timer.expires = jiffies + msecs_to_jiffies(power->interval); + add_timer(&power->timer); + return 0; +} +#else +#define wm831x_battery_suspend NULL +#define wm831x_battery_resume NULL +#endif + static struct platform_driver wm831x_power_driver = { .probe = wm831x_power_probe, .remove = __devexit_p(wm831x_power_remove), + .suspend = wm831x_battery_suspend, + .resume = wm831x_battery_resume, .driver = { .name = "wm831x-power", }, }; - static int __init wm831x_power_init(void) { return platform_driver_register(&wm831x_power_driver); @@ -635,6 +1198,96 @@ static void __exit wm831x_power_exit(void) } module_exit(wm831x_power_exit); + +static ssize_t power_prop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int level, power_status, system_status, chg_ctl1, chg_ctl2, chg_status; + union power_supply_propval val; + + if (!g_wm831x_power) + return -1; + power_status = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_POWER_STATE); + if (power_status < 0) + return power_status; + //printk("wm831x power status %#x\n", ret); + + system_status = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_SYSTEM_STATUS); + if (system_status < 0) + return system_status; + //printk("wm831x system status %#x\n", ret); + + chg_ctl1 = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_CHARGER_CONTROL_1); + if (chg_ctl1 < 0) + return chg_ctl1; + //printk("wm831x charger control1 %#x\n", ret); + + chg_ctl2 = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_CHARGER_CONTROL_2); + if (chg_ctl2 < 0) + return chg_ctl2; + //printk("wm831x charger control2 %#x\n", ret); + + chg_status = wm831x_reg_read(g_wm831x_power->wm831x, WM831X_CHARGER_STATUS); + if (chg_status < 0) + return chg_status; + //printk("wm831x charger status %#x\n", ret); + + ret = wm831x_power_read_voltage(g_wm831x_power->wm831x, WM831X_AUX_BATT, &val); + if (ret < 0) + return ret; + wm831x_batt_vol_level(g_wm831x_power, val.intval, &level); + //printk("batt_vol = %d batt_level = %d\n", val.intval, level); + // + sprintf(buf, "power_status=%#x\n" + "system_status=%#x\n" + "chg_ctl1=%#x\n" + "chg_ctl2=%#x\n" + "chg_status=%#x\n" + "batt_vol=%d\n" + "batt_level=%d%%\n", + power_status, + system_status, + chg_ctl1, + chg_ctl2, + chg_status, + val.intval, + level); + ret = strlen(buf) + 1; + return ret; +} + +static DEVICE_ATTR(prop, 0444, power_prop_show, NULL); + +static struct kobject *power_test_kobj; + +static int power_test_sysfs_init(void) +{ + int ret ; + power_test_kobj = kobject_create_and_add("power_test_prop", NULL); + if (power_test_kobj == NULL) { + printk(KERN_ERR + "power_test_sysfs_init:"\ + "subsystem_register failed\n"); + ret = -ENOMEM; + goto err; + } + ret = sysfs_create_file(power_test_kobj, &dev_attr_prop.attr); + if (ret) { + printk(KERN_ERR + "power_test_sysfs_init:"\ + "sysfs_create_group failed\n"); + goto err1; + } + + return 0 ; +err1: + kobject_del(power_test_kobj); +err: + return ret ; +} + + MODULE_DESCRIPTION("Power supply driver for WM831x PMICs"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b59159bf8380..bc147414a6b9 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -132,13 +132,6 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. -config REGULATOR_TPS65910 - bool "TI TPS69510x PMIC" - depends on TPS65910_CORE - help - This driver supports the voltage regulators provided by - this family of companion chips. - config REGULATOR_WM831X tristate "Wolfson Microelcronics WM831x PMIC regulators" depends on MFD_WM831X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 3932d2ec38f3..5b98d6cd9803 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -35,6 +35,10 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o +obj-$(CONFIG_RK2818_REGULATOR_LP8725) += rk2818_lp8725.o +obj-$(CONFIG_RK2818_REGULATOR_CHARGE) += charge-regulator.o +obj-$(CONFIG_RK29_PWM_REGULATOR) += rk29-pwm-regulator.o + obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o @@ -43,5 +47,6 @@ obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o +obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d3e38790906e..90cbf1fa84a7 100755 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1785,6 +1785,24 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_voltage); +int regulator_set_suspend_voltage(struct regulator *regulator, int uV) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; + + if (rdev->desc->ops->set_suspend_voltage && uV > 0) { + ret = rdev->desc->ops->set_suspend_voltage(rdev, uV); + if (ret < 0) { + printk(KERN_ERR "%s: failed to set voltage\n", + __func__); + return ret; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); + /** * regulator_set_voltage_time - get raise/fall time * @regulator: regulator source diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index a0982e809851..5ae9605aed1a 100755 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -27,6 +27,11 @@ #include #include +#include +#include +#include +#include + #define WM831X_BUCKV_MAX_SELECTOR 0x68 #define WM831X_BUCKP_MAX_SELECTOR 0x66 @@ -35,7 +40,7 @@ #define WM831X_DCDC_MODE_IDLE 2 #define WM831X_DCDC_MODE_STANDBY 3 -#define WM831X_DCDC_MAX_NAME 6 +//#define WM831X_DCDC_MAX_NAME 6 /* Register offsets in control block */ #define WM831X_DCDC_CONTROL_1 0 @@ -47,7 +52,7 @@ /* * Shared */ - +#if 0 struct wm831x_dcdc { char name[WM831X_DCDC_MAX_NAME]; struct regulator_desc desc; @@ -59,6 +64,7 @@ struct wm831x_dcdc { int on_vsel; int dvs_vsel; }; +#endif static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev) { @@ -302,6 +308,23 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) return 0; } +static int wm831x_buckv_read_voltage(struct regulator_dev *rdev) +{ + int vol_read; + int ret; + struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); + struct wm831x *wm831x = dcdc->wm831x; + int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG; + + ret = wm831x_reg_read(wm831x, on_reg); + if (ret < 0) + return ret; + ret &= WM831X_DC1_ON_VSEL_MASK; + vol_read = (ret-8)*12500 + 600000; + + return vol_read; +} + static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { @@ -393,6 +416,71 @@ static u16 wm831x_dcdc_ilim[] = { 125, 250, 375, 500, 625, 750, 875, 1000 }; +static int wm831x_buckv_set_voltage_step(struct regulator_dev * rdev, int min_uV, int max_uV) +{ + int old_vol; + int new_min_uV,new_max_uV; + int diff_value,step; + int ret=0; + + struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); + struct wm831x *wm831x = dcdc->wm831x; + struct wm831x_pdata *pdata = wm831x->dev->platform_data; + + //if(strcmp(rdev->constraints->name,"DCDC2") != 0) + if(strcmp(pdata->dcdc[1]->consumer_supplies[1].supply,"vcore") != 0) + { + ret = wm831x_buckv_set_voltage(rdev,min_uV,max_uV); + } + else + { + old_vol = wm831x_buckv_read_voltage(rdev); + + new_min_uV = old_vol; + new_max_uV = old_vol+max_uV-min_uV; + + if(old_vol > min_uV) //reduce voltage + { + diff_value = (old_vol - min_uV); + + for(step = 100000; step<=diff_value; step += 100000) + { + new_min_uV = old_vol-step; + new_max_uV = old_vol+max_uV-min_uV-step; + + ret = wm831x_buckv_set_voltage(rdev,new_min_uV,new_max_uV); + usleep_range(1000,1000); + } + + if(new_min_uV > min_uV) //0< old_vol - min_uV < 100000 ||0< new_min_uV - min_uV < 1000000 + { + ret = wm831x_buckv_set_voltage(rdev,min_uV,max_uV); + usleep_range(1000,1000); + } + } + else //rise voltage + { + diff_value = (min_uV- old_vol); + + for(step = 100000; step<=diff_value; step += 100000) + { + new_min_uV = old_vol + step; + new_max_uV = old_vol+max_uV-min_uV+step; + + ret = wm831x_buckv_set_voltage(rdev,new_min_uV,new_max_uV); + usleep_range(1000,1000); + } + if(new_min_uV < min_uV)// min_uV - old_vol < 100000 || new_min_uV - old_vol < 100000 + { + ret = wm831x_buckv_set_voltage(rdev,min_uV,max_uV); + usleep_range(1000,1000); + } + } + } + + return ret; +} + static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) { @@ -425,8 +513,18 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) return wm831x_dcdc_ilim[val & WM831X_DC1_HC_THR_MASK]; } +static int wm831x_dcdc_set_suspend_enable(struct regulator_dev *rdev) +{ + return 0; +} + +static int wm831x_dcdc_set_suspend_disable(struct regulator_dev *rdev) +{ + return 0; +} + static struct regulator_ops wm831x_buckv_ops = { - .set_voltage = wm831x_buckv_set_voltage, + .set_voltage = wm831x_buckv_set_voltage_step, .get_voltage_sel = wm831x_buckv_get_voltage_sel, .list_voltage = wm831x_buckv_list_voltage, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, @@ -440,6 +538,8 @@ static struct regulator_ops wm831x_buckv_ops = { .get_mode = wm831x_dcdc_get_mode, .set_mode = wm831x_dcdc_set_mode, .set_suspend_mode = wm831x_dcdc_set_suspend_mode, + .set_suspend_enable = wm831x_dcdc_set_suspend_enable, + .set_suspend_disable = wm831x_dcdc_set_suspend_disable, }; /* @@ -703,6 +803,8 @@ static struct regulator_ops wm831x_buckp_ops = { .get_mode = wm831x_dcdc_get_mode, .set_mode = wm831x_dcdc_set_mode, .set_suspend_mode = wm831x_dcdc_set_suspend_mode, + .set_suspend_enable = wm831x_dcdc_set_suspend_enable, + .set_suspend_disable = wm831x_dcdc_set_suspend_disable, }; static __devinit int wm831x_buckp_probe(struct platform_device *pdev) @@ -1011,6 +1113,7 @@ static struct platform_driver wm831x_epe_driver = { static int __init wm831x_dcdc_init(void) { int ret; + printk("%s \n", __FUNCTION__); ret = platform_driver_register(&wm831x_buckv_driver); if (ret != 0) pr_err("Failed to register WM831x BUCKV driver: %d\n", ret); diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 01f27c7f4236..99f214dd2286 100755 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -25,8 +25,9 @@ #include #include -#define WM831X_ISINK_MAX_NAME 7 +//#define WM831X_ISINK_MAX_NAME 7 +#if 0 struct wm831x_isink { char name[WM831X_ISINK_MAX_NAME]; struct regulator_desc desc; @@ -34,13 +35,14 @@ struct wm831x_isink { struct wm831x *wm831x; struct regulator_dev *regulator; }; +#endif static int wm831x_isink_enable(struct regulator_dev *rdev) { struct wm831x_isink *isink = rdev_get_drvdata(rdev); struct wm831x *wm831x = isink->wm831x; int ret; - + printk("%s:line=%d\n",__FUNCTION__,__LINE__); /* We have a two stage enable: first start the ISINK... */ ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, WM831X_CS1_ENA); @@ -52,7 +54,7 @@ static int wm831x_isink_enable(struct regulator_dev *rdev) WM831X_CS1_DRIVE); if (ret != 0) wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, 0); - + printk("%s:line=%d,ret=0x%x\n",__FUNCTION__,__LINE__,ret); return ret; } @@ -62,7 +64,7 @@ static int wm831x_isink_disable(struct regulator_dev *rdev) struct wm831x_isink *isink = rdev_get_drvdata(rdev); struct wm831x *wm831x = isink->wm831x; int ret; - + printk("%s:line=%d\n",__FUNCTION__,__LINE__); ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_DRIVE, 0); if (ret < 0) return ret; @@ -80,11 +82,11 @@ static int wm831x_isink_is_enabled(struct regulator_dev *rdev) struct wm831x_isink *isink = rdev_get_drvdata(rdev); struct wm831x *wm831x = isink->wm831x; int ret; - + printk("%s:line=%d\n",__FUNCTION__,__LINE__); ret = wm831x_reg_read(wm831x, isink->reg); if (ret < 0) return ret; - + if ((ret & (WM831X_CS1_ENA | WM831X_CS1_DRIVE)) == (WM831X_CS1_ENA | WM831X_CS1_DRIVE)) return 1; @@ -158,7 +160,7 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) int ret, irq; dev_dbg(&pdev->dev, "Probing ISINK%d\n", id + 1); - + printk("%s:line=%d\n",__FUNCTION__,__LINE__); if (pdata == NULL || pdata->isink[id] == NULL) return -ENODEV; @@ -198,8 +200,15 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); +<<<<<<< HEAD ret = request_threaded_irq(irq, NULL, wm831x_isink_irq, IRQF_TRIGGER_RISING, isink->name, isink); +======= + printk("%s:line=%d,irq=%d\n",__FUNCTION__,__LINE__,irq); + ret = wm831x_request_irq(wm831x, irq, wm831x_isink_irq, + IRQF_TRIGGER_RISING, isink->name, + isink); +>>>>>>> parent of 15f7fab... temp revert rk change if (ret != 0) { dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n", irq, ret); diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 2220cf8defb1..214ac7200e43 100755 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -25,7 +25,7 @@ #include #include -#define WM831X_LDO_MAX_NAME 6 +//#define WM831X_LDO_MAX_NAME 6 #define WM831X_LDO_CONTROL 0 #define WM831X_LDO_ON_CONTROL 1 @@ -34,6 +34,7 @@ #define WM831X_ALIVE_LDO_ON_CONTROL 0 #define WM831X_ALIVE_LDO_SLEEP_CONTROL 1 +#if 0 struct wm831x_ldo { char name[WM831X_LDO_MAX_NAME]; struct regulator_desc desc; @@ -41,11 +42,12 @@ struct wm831x_ldo { struct wm831x *wm831x; struct regulator_dev *regulator; }; +#endif /* * Shared */ - +extern int reboot_cmd_get(void); static int wm831x_ldo_is_enabled(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); @@ -68,7 +70,7 @@ static int wm831x_ldo_enable(struct regulator_dev *rdev) struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; int mask = 1 << rdev_get_id(rdev); - + //printk("%s,%x\n", __FUNCTION__,mask); return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, mask); } @@ -77,7 +79,7 @@ static int wm831x_ldo_disable(struct regulator_dev *rdev) struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; int mask = 1 << rdev_get_id(rdev); - + //printk("%s\n", __FUNCTION__); return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, 0); } @@ -170,7 +172,7 @@ static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev) ret = wm831x_reg_read(wm831x, reg); if (ret < 0) return ret; - + //printk("%s base=%x,ret=%x\n", __FUNCTION__,ldo->base,ret); ret &= WM831X_LDO1_ON_VSEL_MASK; return ret; @@ -210,7 +212,7 @@ static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev, int on_reg = ldo->base + WM831X_LDO_ON_CONTROL; int ret; - + printk("%s base=%x,mode=%x\n", __FUNCTION__,ldo->base,mode); switch (mode) { case REGULATOR_MODE_NORMAL: ret = wm831x_set_bits(wm831x, on_reg, @@ -290,6 +292,16 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, return REGULATOR_MODE_NORMAL; } +int wm831x_ldo_set_suspend_enable(struct regulator_dev *rdev) +{ + + return 0; +} +int wm831x_ldo_set_suspend_disable(struct regulator_dev *rdev) +{ + + return 0; +} static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, @@ -304,6 +316,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = { .is_enabled = wm831x_ldo_is_enabled, .enable = wm831x_ldo_enable, .disable = wm831x_ldo_disable, + .set_suspend_enable = wm831x_ldo_set_suspend_enable, + .set_suspend_disable = wm831x_ldo_set_suspend_disable, }; static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) @@ -316,7 +330,7 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) int ret, irq; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - + printk("Probing LDO%d\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; @@ -450,6 +464,7 @@ static int wm831x_aldo_set_voltage(struct regulator_dev *rdev, struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; + printk("%s base=%x,min_uV=%d,%d\n", __FUNCTION__,ldo->base,min_uV,max_uV); return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV, selector); } @@ -474,7 +489,7 @@ static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev) ret = wm831x_reg_read(wm831x, reg); if (ret < 0) return ret; - + printk("%s base=%x,ret=%x\n", __FUNCTION__,ldo->base,ret); ret &= WM831X_LDO7_ON_VSEL_MASK; return ret; @@ -568,6 +583,8 @@ static struct regulator_ops wm831x_aldo_ops = { .is_enabled = wm831x_ldo_is_enabled, .enable = wm831x_ldo_enable, .disable = wm831x_ldo_disable, + .set_suspend_enable = wm831x_ldo_set_suspend_enable, + .set_suspend_disable = wm831x_ldo_set_suspend_disable, }; static __devinit int wm831x_aldo_probe(struct platform_device *pdev) @@ -580,7 +597,7 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) int ret, irq; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - + printk("Probing LDO%d--\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; @@ -758,6 +775,8 @@ static struct regulator_ops wm831x_alive_ldo_ops = { .is_enabled = wm831x_ldo_is_enabled, .enable = wm831x_ldo_enable, .disable = wm831x_ldo_disable, + .set_suspend_enable = wm831x_ldo_set_suspend_enable, + .set_suspend_disable = wm831x_ldo_set_suspend_disable, }; static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) @@ -770,7 +789,7 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) int ret; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - + printk("wm831x_alive_ldo_probe Probing LDO%d\n", id + 1); if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; @@ -826,9 +845,64 @@ static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) return 0; } +static __devexit int wm831x_alive_ldo_shutdown(struct platform_device *pdev) /*ZMF*/ +{ + //struct wm831x_ldo *ldo = platform_get_drvdata(pdev); +#if 0 + //close ldo in wm831x_last_deinit() + struct regulator* ldo; + + //if (reboot_cmd_get()) + // return 0; + printk("%s\n", __FUNCTION__); + + ldo = regulator_get(NULL, "ldo1"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo2"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo3"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo4"); + //regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo5"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo6"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo7"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo8"); + //regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo9"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo10"); + regulator_disable(ldo); + regulator_put(ldo); +#endif + return 0; +} + static struct platform_driver wm831x_alive_ldo_driver = { .probe = wm831x_alive_ldo_probe, .remove = __devexit_p(wm831x_alive_ldo_remove), + .shutdown = __devexit_p(wm831x_alive_ldo_shutdown), .driver = { .name = "wm831x-alive-ldo", .owner = THIS_MODULE, @@ -838,7 +912,7 @@ static struct platform_driver wm831x_alive_ldo_driver = { static int __init wm831x_ldo_init(void) { int ret; - + printk("%s \n", __FUNCTION__); ret = platform_driver_register(&wm831x_gp_ldo_driver); if (ret != 0) pr_err("Failed to register WM831x GP LDO driver: %d\n", ret); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 27c37743e2c9..68a0c106eb6a 100755 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -153,6 +153,21 @@ config RTC_DRV_88PM860X This driver can also be built as a module. If so, the module will be called rtc-88pm860x. +config RTC_HYM8563 + tristate "RK2818 or RK29 extern HYM8563 RTC" + depends on I2C_RK2818 || I2C_RK29 + help + If you say yes here you will get support for the + HYM8563 I2C RTC chip. + This driver can also be built as a module. If so, the module + will be called rtc-HYM8563. + +config RTC_M41T66 + tristate "ST M41T66" + depends on I2C_RK2818 || I2C_RK29 + help + If you say Y here you will get support for the ST M41T66. + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help @@ -351,6 +366,16 @@ config RTC_DRV_S35390A This driver can also be built as a module. If so the module will be called rtc-s35390a. +config RTC_DRV_S35392A + tristate "Seiko Instruments S-35392A" + select BITREVERSE + help + If you say yes here you will get support for the Seiko + Instruments S-35392A. + + This driver can also be built as a module. If so the module + will be called rtc-s35392a. + config RTC_DRV_FM3130 tristate "Ramtron FM3130" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 7d2795810431..a488d45cf72f 100755 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o +obj-$(CONFIG_RTC_DRV_S35392A) += rtc-s35392a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o @@ -110,3 +111,5 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_HYM8563) += rtc-HYM8563.o +obj-$(CONFIG_RTC_M41T66) += rtc-m41t66.o diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c index e0e98dd1eac6..9b40adda0132 100644 --- a/drivers/rtc/alarm.c +++ b/drivers/rtc/alarm.c @@ -423,6 +423,7 @@ static int alarm_suspend(struct platform_device *pdev, pm_message_t state) if (rtc_current_time + 1 >= rtc_alarm_time) { pr_alarm(SUSPEND, "alarm about to go off\n"); memset(&rtc_alarm, 0, sizeof(rtc_alarm)); + rtc_time_to_tm(0, &rtc_alarm.time); rtc_alarm.enabled = 0; rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); @@ -448,6 +449,7 @@ static int alarm_resume(struct platform_device *pdev) pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev); memset(&alarm, 0, sizeof(alarm)); + rtc_time_to_tm(0, &alarm.time); alarm.enabled = 0; rtc_set_alarm(alarm_rtc_dev, &alarm); @@ -461,6 +463,18 @@ static int alarm_resume(struct platform_device *pdev) return 0; } +static void alarm_shutdown(struct platform_device *pdev) +{ + struct rtc_wkalrm alarm; + + pr_alarm(FLOW, "alarm_shutdown(%p)\n", pdev); + + memset(&alarm, 0, sizeof(alarm)); + rtc_time_to_tm(0, &alarm.time); + alarm.enabled = 0; + rtc_set_alarm(alarm_rtc_dev, &alarm); +} + static struct rtc_task alarm_rtc_task = { .func = alarm_triggered_func }; @@ -520,6 +534,7 @@ static struct class_interface rtc_alarm_interface = { static struct platform_driver alarm_driver = { .suspend = alarm_suspend, .resume = alarm_resume, + .shutdown = alarm_shutdown, .driver = { .name = "alarm" } diff --git a/drivers/rtc/rtc-HYM8563.c b/drivers/rtc/rtc-HYM8563.c index c949925e0055..ab18d469ddd8 100755 --- a/drivers/rtc/rtc-HYM8563.c +++ b/drivers/rtc/rtc-HYM8563.c @@ -401,16 +401,7 @@ static int __devinit hym8563_probe(struct i2c_client *client, const struct i2c_d return -ENOMEM; } - rtc = rtc_device_register(client->name, &client->dev, - &hym8563_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - rtc = NULL; - goto exit; - } - hym8563->client = client; - hym8563->rtc = rtc; mutex_init(&hym8563->mutex); wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563"); INIT_WORK(&hym8563->work, hym8563_work_func); @@ -447,6 +438,16 @@ static int __devinit hym8563_probe(struct i2c_client *client, const struct i2c_d goto exit; } enable_irq_wake(hym8563->irq); + + rtc = rtc_device_register(client->name, &client->dev, + &hym8563_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + rc = PTR_ERR(rtc); + rtc = NULL; + goto exit; + } + hym8563->rtc = rtc; + return 0; exit: diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c deleted file mode 100644 index 8f10a636c2ae..000000000000 --- a/drivers/rtc/rtc-tps65910.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * rtc-tps65910.c -- TPS65910 Real Time Clock interface - * - * Copyright (C) 2010 Mistral Solutions Pvt Ltd. - * Author: Umesh K - * - * Based on rtc-twl.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DBG(x...) printk(KERN_INFO x) -#else -#define DBG(x...) -#endif - -/* RTC Definitions */ -/* RTC_CTRL_REG bitfields */ -#define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 -#define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 -#define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04 -#define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08 -#define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 -#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 -#define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 -#define BIT_RTC_CTRL_REG_RTC_V_OPT_M 0x80 - -/* RTC_STATUS_REG bitfields */ -#define BIT_RTC_STATUS_REG_RUN_M 0x02 -#define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04 -#define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08 -#define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10 -#define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20 -#define BIT_RTC_STATUS_REG_ALARM_M 0x40 -#define BIT_RTC_STATUS_REG_POWER_UP_M 0x80 - -/* RTC_INTERRUPTS_REG bitfields */ -#define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03 -#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04 -#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08 - -/* DEVCTRL bitfields */ -#define BIT_RTC_PWDN 0x40 - -/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ -#define ALL_TIME_REGS 6 - -/* - * Supports 1 byte read from TPS65910 RTC register. - */ -static int tps65910_rtc_read_u8(u8 *data, u8 reg) -{ - int ret; - - ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, data, reg); - - if (ret < 0) - pr_err("tps65910_rtc: Could not read TPS65910" - "register %X - error %d\n", reg, ret); - return ret; -} - -/* - * Supports 1 byte write to TPS65910 RTC registers. - */ -static int tps65910_rtc_write_u8(u8 data, u8 reg) -{ - int ret; - - ret = tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, reg); - if (ret < 0) - pr_err("tps65910_rtc: Could not write TPS65910" - "register %X - error %d\n", reg, ret); - return ret; -} - -/* - * Cache the value for timer/alarm interrupts register; this is - * only changed by callers holding rtc ops lock (or resume). - */ -static unsigned char rtc_irq_bits; - -/* - * Enable 1/second update and/or alarm interrupts. - */ -static int set_rtc_irq_bit(unsigned char bit) -{ - unsigned char val; - int ret; - - val = rtc_irq_bits | bit; - val |= bit; - ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); - if (ret == 0) - rtc_irq_bits = val; - - return ret; -} - -/* - * Disable update and/or alarm interrupts. - */ -static int mask_rtc_irq_bit(unsigned char bit) -{ - unsigned char val; - int ret; - - val = rtc_irq_bits & ~bit; - ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); - if (ret == 0) - rtc_irq_bits = val; - - return ret; -} - -static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) -{ - int ret; - - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - - return ret; -} - -static int tps65910_rtc_update_irq_enable(struct device *dev, unsigned enabled) -{ - int ret; - - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - - return ret; -} - -#if 1 /* Debugging periodic interrupts */ -/* - * We will just handle setting the frequency and make use the framework for - * reading the periodic interupts. - * - * @freq: Current periodic IRQ freq: - * bit 0: every second - * bit 1: every minute - * bit 2: every hour - * bit 3: every day - */ - -static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) -{ - struct rtc_device *rtc = dev_get_drvdata(dev); - - if (freq < 0 || freq > 3) - return -EINVAL; - - rtc->irq_freq = freq; - /* set rtc irq freq to user defined value */ - set_rtc_irq_bit(freq); - - return 0; -} -#endif - -/* - * Gets current TPS65910 RTC time and date parameters. - * - * The RTC's time/alarm representation is not what gmtime(3) requires - * Linux to use: - * - * - Months are 1..12 vs Linux 0-11 - * - Years are 0..99 vs Linux 1900..N (we assume 21st century) - */ -static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - unsigned char rtc_data[ALL_TIME_REGS + 1]; - int ret; - u8 save_control; - - tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - return ret; - - save_control &= ~BIT_RTC_CTRL_REG_RTC_V_OPT_M; - - ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - return ret; - - ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_MINUTES); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - - tm->tm_sec = bcd2bin(rtc_data[0]); - tm->tm_min = bcd2bin(rtc_data[1]); - tm->tm_hour = bcd2bin(rtc_data[2]); - tm->tm_mday = bcd2bin(rtc_data[3]); - tm->tm_mon = bcd2bin(rtc_data[4]) - 1; - tm->tm_year = bcd2bin(rtc_data[5]) + 100; - - DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); - DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); - DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); - DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); - DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); - DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); - DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); - - return ret; -} - -static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - unsigned char save_control; - unsigned char rtc_data[ALL_TIME_REGS + 1]; - int ret; - - DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); - DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); - DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); - DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); - DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); - DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); - DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); - - rtc_data[1] = bin2bcd(tm->tm_sec); - rtc_data[2] = bin2bcd(tm->tm_min); - rtc_data[3] = bin2bcd(tm->tm_hour); - rtc_data[4] = bin2bcd(tm->tm_mday); - rtc_data[5] = bin2bcd(tm->tm_mon + 1); - rtc_data[6] = bin2bcd(tm->tm_year - 100); - - /*Dummy read*/ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - - /* Stop RTC while updating the TC registers */ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out; - - save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; - - tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); - - /* update all the time registers in one shot */ - ret = tps65910_rtc_write_u8(rtc_data[1], TPS65910_REG_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[2], TPS65910_REG_MINUTES); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[3], TPS65910_REG_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[4], TPS65910_REG_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[5], TPS65910_REG_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[6], TPS65910_REG_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - - /*Dummy read*/ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out; - /* Start back RTC */ - save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); - -out: - return ret; -} - -/* - * Gets current TPS65910 RTC alarm time. - */ -static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) -{ - unsigned char rtc_data[ALL_TIME_REGS + 1]; - int ret; - - ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_ALARM_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_ALARM_MINUTES); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_ALARM_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_ALARM_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_ALARM_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_ALARM_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - - /* some of these fields may be wildcard/"match all" */ - alm->time.tm_sec = bcd2bin(rtc_data[0]); - alm->time.tm_min = bcd2bin(rtc_data[1]); - alm->time.tm_hour = bcd2bin(rtc_data[2]); - alm->time.tm_mday = bcd2bin(rtc_data[3]); - alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1; - alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; - - /* report cached alarm enable state */ - if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) - alm->enabled = 1; - - return ret; -} - -static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) -{ - unsigned char alarm_data[ALL_TIME_REGS + 1]; - int ret; - - ret = tps65910_rtc_alarm_irq_enable(dev, 0); - if (ret) - goto out; - - alarm_data[1] = bin2bcd(alm->time.tm_sec); - alarm_data[2] = bin2bcd(alm->time.tm_min); - alarm_data[3] = bin2bcd(alm->time.tm_hour); - alarm_data[4] = bin2bcd(alm->time.tm_mday); - alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); - alarm_data[6] = bin2bcd(alm->time.tm_year - 100); - - /* update all the alarm registers in one shot */ - ret = tps65910_rtc_write_u8(alarm_data[1], TPS65910_REG_ALARM_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[2], TPS65910_REG_ALARM_MINUTES); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[3], TPS65910_REG_ALARM_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[4], TPS65910_REG_ALARM_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[5], TPS65910_REG_ALARM_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[6], TPS65910_REG_ALARM_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - - if (alm->enabled) - ret = tps65910_rtc_alarm_irq_enable(dev, 1); -out: - return ret; -} - - -struct work_struct rtc_wq; -unsigned long rtc_events; -struct rtc_device *global_rtc; - -void tps65910_rtc_work(void *data) -{ - int res; - u8 rd_reg; - unsigned long events = 0; - - DBG("Enter::%s %d\n",__FUNCTION__,__LINE__); - - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); - - if (res < 0) - goto out; - /* - * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. - * only one (ALARM or RTC) interrupt source may be enabled - * at time, we also could check our results - * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] - */ - if (rd_reg & TPS65910_RTC_ALARM_IT) { - res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_ALARM_IT, - TPS65910_REG_INT_STS); - if (res < 0) - goto out; - - /*Dummy read -- mandatory for status register*/ - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - mdelay(100); - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - - rtc_events |= RTC_IRQF | RTC_AF; - } else if (rd_reg & TPS65910_RTC_PERIOD_IT) { - res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_PERIOD_IT, - TPS65910_REG_INT_STS); - if (res < 0) - goto out; - - /*Dummy read -- mandatory for status register*/ - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - mdelay(100); - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - rd_reg &= 0xC3; - res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - rtc_events |= RTC_IRQF | RTC_UF; - } -out: - /* Notify RTC core on event */ - events = rtc_events; - rtc_update_irq(global_rtc, 1, events); -} - -static struct rtc_class_ops tps65910_rtc_ops = { - .read_time = tps65910_rtc_read_time, - .set_time = tps65910_rtc_set_time, - .read_alarm = tps65910_rtc_read_alarm, - .set_alarm = tps65910_rtc_set_alarm, - .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, - .update_irq_enable = tps65910_rtc_update_irq_enable, - .irq_set_freq = tps65910_rtc_irq_set_freq, -}; - -static int __devinit tps65910_rtc_probe(struct platform_device *pdev) -{ - struct rtc_device *rtc; - int ret = 0, stop_run = 0; - u8 rd_reg; - struct rtc_time tm_def = { // 2011.1.1 12:00:00 Saturday - .tm_wday = 6, - .tm_year = 111, - .tm_mon = 0, - .tm_mday = 1, - .tm_hour = 12, - .tm_min = 0, - .tm_sec = 0, - }; - - rtc = rtc_device_register(pdev->name, - &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); - - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - dev_err(&pdev->dev, "can't register TPS65910 RTC device,\ - err %ld\n", PTR_ERR(rtc)); - goto out0; - - } - printk(KERN_INFO "TPS65910 RTC device successfully registered\n"); - - platform_set_drvdata(pdev, rtc); - /* Take rtc out of reset */ - tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_DEVCTRL); - rd_reg &= ~BIT_RTC_PWDN; - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_DEVCTRL); - - /* Dummy read to ensure that the register gets updated. - * Please refer tps65910 TRM table:25 for details - */ - stop_run = 0; - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - if (ret < 0) { - printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); - goto out1; - } - - if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) { - dev_warn(&pdev->dev, "Power up reset detected.\n"); - // cwz:if rtc power up reset, set default time. - printk(KERN_INFO "TPS65910 RTC set to default time\n"); - tps65910_rtc_set_time(rtc, &tm_def); - } - if (!(rd_reg & BIT_RTC_STATUS_REG_RUN_M)) { - dev_warn(&pdev->dev, "RTC stop run.\n"); - stop_run = 1; - } - if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) - dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); - - /* Clear RTC Power up reset and pending alarm interrupts */ - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - if (ret < 0) - goto out1; - - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); - if (ret < 0) { - printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); - goto out1; - } - - if (rd_reg & 0x40) { - printk(KERN_INFO "pending alarm interrupt!!! clearing!!!"); - tps65910_rtc_write_u8(rd_reg, TPS65910_REG_INT_STS); - } - - global_rtc = rtc; - - /* Link RTC IRQ handler to TPS65910 Core */ - tps65910_add_irq_work(TPS65910_RTC_ALARM_IRQ, tps65910_rtc_work); - tps65910_add_irq_work(TPS65910_RTC_PERIOD_IRQ, tps65910_rtc_work); - - /* Check RTC module status, Enable if it is off */ - if (stop_run) { - dev_info(&pdev->dev, "Enabling TPS65910-RTC.\n"); - // cwz:if rtc stop, set default time, then enable rtc - printk(KERN_INFO "TPS65910 RTC set to default time\n"); - tps65910_rtc_set_time(rtc, &tm_def); - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out1; - - rd_reg |= BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out1; - } - - /* init cached IRQ enable bits */ - ret = tps65910_rtc_read_u8(&rtc_irq_bits, TPS65910_REG_RTC_INTERRUPTS); - if (ret < 0) - goto out1; - - tps65910_rtc_write_u8(0x3F, TPS65910_REG_INT_MSK); - return ret; - -out1: - rtc_device_unregister(rtc); -out0: - return ret; -} - -/* - * Disable all TPS65910 RTC module interrupts. - * Sets status flag to free. - */ -static int __devexit tps65910_rtc_remove(struct platform_device *pdev) -{ - /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - - - free_irq(irq, rtc); - - rtc_device_unregister(rtc); - platform_set_drvdata(pdev, NULL); - return 0; -} - -static void tps65910_rtc_shutdown(struct platform_device *pdev) -{ - /* mask timer interrupts, but leave alarm interrupts on to enable - * power-on when alarm is triggered - */ - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); -} - -#ifdef CONFIG_PM - -static unsigned char irqstat; - -static -int tps65910_rtc_suspend(struct platform_device *pdev, pm_message_t state) -{ - irqstat = rtc_irq_bits; - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - return 0; -} - -static int tps65910_rtc_resume(struct platform_device *pdev) -{ - set_rtc_irq_bit(irqstat); - return 0; -} - -#else -#define tps65910_rtc_suspend NULL -#define tps65910_rtc_resume NULL -#endif - - -static struct platform_driver tps65910rtc_driver = { - .probe = tps65910_rtc_probe, - .remove = __devexit_p(tps65910_rtc_remove), - .shutdown = tps65910_rtc_shutdown, - .suspend = tps65910_rtc_suspend, - .resume = tps65910_rtc_resume, - .driver = { - .owner = THIS_MODULE, - .name = "tps65910_rtc", - }, -}; -static int __init tps65910_rtc_init(void) -{ - return platform_driver_register(&tps65910rtc_driver); -} -module_init(tps65910_rtc_init); - -static void __exit tps65910_rtc_exit(void) -{ - platform_driver_unregister(&tps65910rtc_driver); -} -module_exit(tps65910_rtc_exit); - -MODULE_ALIAS("platform:tps65910_rtc"); -MODULE_AUTHOR("cwz -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rk2818_serial.h" - -#define DBG_PORT 0 -#if 0 -#define DBG(msg...) printk(msg); -#else -#define DBG(...) -#endif -/* - * We wrap our port structure around the generic uart_port. - */ -struct rk29_port { - struct uart_port uart; - char name[16]; - struct clk *clk; - unsigned int imr; -}; - -#define UART_TO_RK29(uart_port) ((struct rk29_port *) uart_port) -#define RK29_SERIAL_MAJOR TTY_MAJOR -#define RK29_SERIAL_MINOR 64 - - -static inline void rk29_uart_write(struct uart_port *port, unsigned int val, - unsigned int off) -{ - __raw_writel(val, port->membase + off); -} - -static inline unsigned int rk29_uart_read(struct uart_port *port, unsigned int off) -{ - return __raw_readl(port->membase + off); -} - -static int rk29_set_baud_rate(struct uart_port *port, unsigned int baud) -{ - unsigned int uartTemp; - - rk29_uart_write(port,rk29_uart_read(port,UART_LCR) | LCR_DLA_EN,UART_LCR); - uartTemp = port->uartclk / (16 * baud); - rk29_uart_write(port,uartTemp & 0xff,UART_DLL); - rk29_uart_write(port,(uartTemp>>8) & 0xff,UART_DLH); - rk29_uart_write(port,rk29_uart_read(port,UART_LCR) & (~LCR_DLA_EN),UART_LCR); - return baud; -} - -/* - * ÅжϷ¢ËÍ»º³åÇøÊÇ·ñΪ¿Õ - *ÏÈÒÔFIFO´ò¿ª×ö£¬ºóÃæ¿ÉÒÔ×ö³ÉFIFO¹Ø»òFIFO¿ª¡£ - */ -static u_int rk29_serial_tx_empty(struct uart_port *port) -{ - int timeout = 10000000; - while(!(rk29_uart_read(port,UART_USR)&UART_TRANSMIT_FIFO_EMPTY)) - if(timeout-- ==0) - break; - cpu_relax(); - if(rk29_uart_read(port,UART_USR)&UART_TRANSMIT_FIFO_EMPTY) - { - return (1);///1£º¿Õ - }else{ - return (0);///0:·Ç¿Õ - } -} - -/* - * Power / Clock management. - */ -static void rk29_serial_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct rk29_port *rk29_port = UART_TO_RK29(port); - - switch (state) { - case 0: - /* - * Enable the peripheral clock for this serial port. - * This is called on uart_open() or a resume event. - */ - clk_enable(rk29_port->clk); - break; - case 3: - /* - * Disable the peripheral clock for this serial port. - * This is called on uart_close() or a suspend event. - */ - clk_disable(rk29_port->clk); - break; - default: - printk(KERN_ERR "rk29_serial: unknown pm %d\n", state); - } -} - -/* - * Return string describing the specified port - */ -static const char *rk29_serial_type(struct uart_port *port) -{ - return (port->type == PORT_RK29) ? "RK29_SERIAL" : NULL; -} - -static void rk29_serial_enable_ms(struct uart_port *port) -{ - #ifdef DEBUG_LHH - printk("Enter::%s\n",__FUNCTION__); - #endif -} - -/* no modem control lines */ -static unsigned int rk29_serial_get_mctrl(struct uart_port *port) -{ - unsigned int result = 0; - unsigned int status; - - status = rk29_uart_read(port,UART_MSR); - if (status & UART_MSR_URCTS) - { - result = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; - printk("UART_GET_MSR:0x%x\n",result); - }else{ - result = TIOCM_CAR | TIOCM_DSR; - printk("UART_GET_MSR:0x%x\n",result); - } - return result; -} - -static void rk29_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - #ifdef DEBUG_LHH - printk("Enter::%s\n",__FUNCTION__); - #endif -} - -/* - * Stop transmitting. - */ -static void rk29_serial_stop_tx(struct uart_port *port) -{ - #ifdef DEBUG_LHH - printk("Enter::%s\n",__FUNCTION__); - #endif -} - -/* - * Start transmitting. - */ -static void rk29_serial_start_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - if(DBG_PORT == port->line) { - DBG("TX:"); - } - - while(!(uart_circ_empty(xmit))) - { - while (!(rk29_uart_read(port,UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL)){ - rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE|UART_IER_SEND_EMPTY_INT_ENABLE,UART_IER); - return; - } - rk29_uart_write(port,xmit->buf[xmit->tail],UART_THR); - - if(DBG_PORT == port->line) { - DBG("0x%x, ", xmit->buf[xmit->tail]); - } - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if((uart_circ_empty(xmit))) - rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if(DBG_PORT == port->line) { - DBG("\n"); - } -} - -/* - * Stop receiving - port is in process of being closed. - */ -static void rk29_serial_stop_rx(struct uart_port *port) -{ - #ifdef DEBUG_LHH - printk("Enter::%s\n",__FUNCTION__); - #endif -} - -/* - * Control the transmission of a break signal - */ -static void rk29_serial_break_ctl(struct uart_port *port, int break_state) -{ - unsigned int temp; - temp = rk29_uart_read(port,UART_LCR); - if (break_state != 0) - temp = temp & (~BREAK_CONTROL_BIT);/* start break */ - else - temp = temp | BREAK_CONTROL_BIT; /* stop break */ - rk29_uart_write(port,temp,UART_LCR); -} - - -/* - * Characters received (called from interrupt handler) - */ -static void rk29_rx_chars(struct uart_port *port) -{ - unsigned int ch, flag; - - if(DBG_PORT == port->line) { - DBG("RX:"); - } - - while((rk29_uart_read(port,UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY) - { - u32 lsr = rk29_uart_read(port, UART_LSR); - ch = rk29_uart_read(port,UART_RBR); - flag = TTY_NORMAL; - port->icount.rx++; - if (lsr & UART_BREAK_INT_BIT) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } -#if 1 - if (uart_handle_sysrq_char(port, ch)) - { - continue; - } -#endif - uart_insert_char(port, 0, 0, ch, flag); - - if(DBG_PORT == port->line) { - DBG("0x%x, ", ch); - } - } - tty_flip_buffer_push(port->state->port.tty); - - if(DBG_PORT == port->line) { - DBG("\n"); - } -} - -/* - * Interrupt handler - */ -static irqreturn_t rk29_uart_interrupt(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status, pending; - - spin_lock(&port->lock); - status = rk29_uart_read(port,UART_IIR); - pending = status & 0x0f; - if((pending == UART_IIR_RECV_AVAILABLE) || (pending == UART_IIR_CHAR_TIMEOUT)) - rk29_rx_chars(port); - if(pending == UART_IIR_THR_EMPTY) - rk29_serial_start_tx(port); - spin_unlock(&port->lock); - return IRQ_HANDLED; -} - -/* - * Disable the port - */ -static void rk29_serial_shutdown(struct uart_port *port) -{ - struct rk29_port *rk29_port = UART_TO_RK29(port); - rk29_uart_write(port,0x00,UART_IER); - rk29_uart_write(port, UART_FCR_FIFO_ENABLE | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, UART_FCR); - //rk29_uart_write(port, 0, UART_FCR); - clk_disable(rk29_port->clk); - free_irq(port->irq, port); -} -/* - * Perform initialization and enable port for reception - */ -static int rk29_serial_startup(struct uart_port *port) -{ - struct rk29_port *rk29_port = UART_TO_RK29(port); - struct tty_struct *tty = port->state->port.tty; - int retval; - DBG("%s\n",__FUNCTION__); - - if(2 == port->line) - { - rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT); - rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN); - } - else if(0 == port->line) - { - rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT); - rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN); - } - else if(3 == port->line) - { - rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT); - rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN); - } - - retval = request_irq(port->irq,rk29_uart_interrupt,IRQF_SHARED, - tty ? tty->name : "rk29_serial",port); - if(retval) - { - printk("\nrk29_serial_startup err \n"); - rk29_serial_shutdown(port); - return retval; - } - clk_enable(rk29_port->clk); -#if 0 - if(port->irq == IRQ_NR_UART0) - rk29_uart_write(port,0xf7,UART_FCR); //enable and clear fifo if busy while starting - else - rk29_uart_write(port,0xf1,UART_FCR); //enable fifo - rk29_uart_write(port,0x01,UART_SFE); - rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER); //enable uart recevice IRQ -#else - //lw modify on 110309 - /* - * Clear the FIFO buffers and disable them. - */ - rk29_uart_write(port, UART_FCR_FIFO_ENABLE, UART_FCR); - rk29_uart_write(port, UART_FCR_FIFO_ENABLE | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, UART_FCR); - rk29_uart_write(port, 0, UART_FCR); - - /* - * Clear the interrupt registers. - */ - (void) rk29_uart_read(port, UART_LSR); - (void) rk29_uart_read(port, UART_RBR); - (void) rk29_uart_read(port, UART_IIR); - (void) rk29_uart_read(port, UART_MSR); - - /* - * And clear the user registers. - */ - (void) rk29_uart_read(port, UART_USR); - -#endif - return 0; -} - -/* - * Change the port parameters - */ -static void rk29_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int mode, baud; - unsigned int umcon,fcr; - spin_lock_irqsave(&port->lock, flags); - /* Get current mode register */ - mode = rk29_uart_read(port,UART_LCR) & (BREAK_CONTROL_BIT | EVEN_PARITY_SELECT | PARITY_ENABLED - | ONE_HALF_OR_TWO_BIT | UART_DATABIT_MASK); - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - /* byte size */ - switch (termios->c_cflag & CSIZE) { - case CS5: - mode |= LCR_WLS_5; - break; - case CS6: - mode |= LCR_WLS_6; - break; - case CS7: - mode |= LCR_WLS_7; - break; - default: - mode |= LCR_WLS_8; - break; - } - - /* stop bits */ - if (termios->c_cflag & CSTOPB) - mode |= ONE_STOP_BIT; - - /* parity */ - if (termios->c_cflag & PARENB) - { - mode |= PARITY_ENABLED; - if (termios->c_cflag & PARODD) - mode |= ODD_PARITY; - else - mode |= EVEN_PARITY; - } - - int timeout = 10000000; - while(rk29_uart_read(port,UART_USR)&UART_USR_BUSY){ - if(timeout-- == 0){ - printk("rk29_serial_set_termios uart timeout,irq=%d,ret=0x%x\n",port->irq,rk29_uart_read(port,UART_USR)); - break; - } - cpu_relax(); - } - - rk29_uart_write(port,mode,UART_LCR); - baud = rk29_set_baud_rate(port, baud); - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * enable FIFO and interrupt - */ - if(termios->c_cflag & CRTSCTS) - { - /*¿ªÆôuart0Ó²¼þÁ÷¿Ø*/ - printk("start CRTSCTS control and baudrate is %d,irq=%d\n",baud,port->irq); - if(2 == port->line) - { - rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N); - rk29_mux_api_set(GPIO2A6_UART2CTSN_NAME, GPIO2L_UART2_CTS_N); - } - else if(0 == port->line) - { - rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); - rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N); - } - else if(3 == port->line) - { - rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_UART3_RTS_N); - rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_UART3_CTS_N); - } - - umcon=rk29_uart_read(port,UART_MCR); - umcon |= UART_MCR_AFCEN; - umcon |= UART_MCR_URRTS; - umcon &=~UART_SIR_ENABLE; - rk29_uart_write(port,umcon,UART_MCR); - printk("UART_GET_MCR umcon=0x%x\n",umcon); - } - mode = mode | LCR_DLA_EN; - -#if 1 - //lw modify on 110309 - fcr = UART_FCR_FIFO_ENABLE | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_10; - rk29_uart_write(port, fcr, UART_FCR); - rk29_uart_write(port,0x01,UART_SFE); - rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER); //enable uart recevice IRQ - printk("%s:fcr=0x%x,irq=%d\n",__FUNCTION__,fcr,port->irq); -#endif - - spin_unlock_irqrestore(&port->lock, flags); - -} - - -static void rk29_serial_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *resource; - resource_size_t size; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return; - size = resource->end - resource->start + 1; - - release_mem_region(port->mapbase, size); - iounmap(port->membase); - port->membase = NULL; -} - -static int rk29_serial_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *resource; - resource_size_t size; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - size = resource->end - resource->start + 1; - - if (unlikely(!request_mem_region(port->mapbase, size, "rk29_serial"))) - return -EBUSY; - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - release_mem_region(port->mapbase, size); - return -EBUSY; - } - - return 0; -} - -/* - * Configure/autoconfigure the port. - */ -static void rk29_serial_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_RK29; - rk29_serial_request_port(port); - } -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - */ -static int rk29_serial_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_RK29) - ret = -EINVAL; - if (port->irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (port->uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)port->mapbase != ser->iomem_base) - ret = -EINVAL; - if (port->iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int rk29_serial_poll_get_char(struct uart_port *port) -{ - while (!((rk29_uart_read(port, UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY)) - barrier(); - return rk29_uart_read(port, UART_RBR); -} - -static void rk29_serial_poll_put_char(struct uart_port *port, unsigned char c) -{ - while (!(rk29_uart_read(port, UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL)) - barrier(); - rk29_uart_write(port, c, UART_THR); -} -#endif /* CONFIG_CONSOLE_POLL */ - -static struct uart_ops rk29_uart_pops = { - .tx_empty = rk29_serial_tx_empty, - .set_mctrl = rk29_serial_set_mctrl, - .get_mctrl = rk29_serial_get_mctrl, - .stop_tx = rk29_serial_stop_tx, - .start_tx = rk29_serial_start_tx, - .stop_rx = rk29_serial_stop_rx, - .enable_ms = rk29_serial_enable_ms, - .break_ctl = rk29_serial_break_ctl, - .startup = rk29_serial_startup, - .shutdown = rk29_serial_shutdown, - .set_termios = rk29_serial_set_termios, - .type = rk29_serial_type, - .release_port = rk29_serial_release_port, - .request_port = rk29_serial_request_port, - .config_port = rk29_serial_config_port, - .verify_port = rk29_serial_verify_port, - .pm = rk29_serial_pm, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = rk29_serial_poll_get_char, - .poll_put_char = rk29_serial_poll_put_char, -#endif -}; - - -static struct rk29_port rk29_uart_ports[] = { - { - .uart = { - .iotype = UPIO_MEM, - .ops = &rk29_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 32, - .line = 0, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &rk29_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 32, - .line = 1, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &rk29_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 32, - .line = 2, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &rk29_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 32, - .line = 3, - }, - }, -}; - -#define UART_NR ARRAY_SIZE(rk29_uart_ports) - -static inline struct uart_port *get_port_from_line(unsigned int line) -{ - return &rk29_uart_ports[line].uart; -} - -#ifdef CONFIG_SERIAL_RK29_CONSOLE -static void rk29_console_putchar(struct uart_port *port, int ch) -{ - while (!(rk29_uart_read(port,UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL)) - cpu_relax(); - rk29_uart_write(port,ch,UART_THR); -} - -/* - * Interrupts are disabled on entering - */ -static void rk29_console_write(struct console *co, const char *s, u_int count) -{ - struct uart_port *port; - struct rk29_port *rk29_port; - - BUG_ON(co->index < 0 || co->index >= UART_NR); - - port = get_port_from_line(co->index); - rk29_port = UART_TO_RK29(port); - - spin_lock(&port->lock); - uart_console_write(port, s, count, rk29_console_putchar); - spin_unlock(&port->lock); -} - -static int __init rk29_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud, flow, bits, parity; - - if (unlikely(co->index >= UART_NR || co->index < 0)) - return -ENXIO; - - port = get_port_from_line(co->index); - - if (unlikely(!port->membase)) - return -ENXIO; - - port->cons = co; - - //rk29_init_clock(port); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - bits = 8; - parity = 'n'; - flow = 'n'; - rk29_uart_write(port,rk29_uart_read(port,UART_LCR) | LCR_WLS_8 | PARITY_DISABLED | ONE_STOP_BIT,UART_LCR); /* 8N1 */ - if (baud < 300 || baud > 115200) - baud = 115200; - rk29_set_baud_rate(port, baud); - - printk(KERN_INFO "rk29_serial: console setup on port %d\n", port->line); - - /* clear rx fifo, else will blocked on set_termios (always busy) */ - while ((rk29_uart_read(port, UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY) - rk29_uart_read(port, UART_RBR); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver rk29_uart_driver; - -static struct console rk29_console = { - .name = "ttyS", - .write = rk29_console_write, - .device = uart_console_device, - .setup = rk29_console_setup, - .flags = CON_PRINTBUFFER, - .index = 1, - .data = &rk29_uart_driver, -}; - -#define RK29_CONSOLE (&rk29_console) - -#else -#define RK29_CONSOLE NULL -#endif - -static struct uart_driver rk29_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "rk29_serial", - .dev_name = "ttyS", - .nr = UART_NR, - .cons = RK29_CONSOLE, - .major = RK29_SERIAL_MAJOR, - .minor = RK29_SERIAL_MINOR, -}; - -static int __devinit rk29_serial_probe(struct platform_device *pdev) -{ - struct rk29_port *rk29_port; - struct resource *resource; - struct uart_port *port; - //struct rk29_serial_platform_data *pdata = pdev->dev.platform_data; - - if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) - return -ENXIO; - - printk(KERN_INFO "rk29_serial: detected port %d\n", pdev->id); - - //if (pdata && pdata->io_init) - //pdata->io_init(); - - port = get_port_from_line(pdev->id); - port->dev = &pdev->dev; - rk29_port = UART_TO_RK29(port); - - rk29_port->clk = clk_get(&pdev->dev, "uart"); - if (unlikely(IS_ERR(rk29_port->clk))) - return PTR_ERR(rk29_port->clk); - port->uartclk = 24000000; ///clk_get_rate(rk29_port->clk); - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - port->mapbase = resource->start; - - port->irq = platform_get_irq(pdev, 0); - if (unlikely(port->irq < 0)) - return -ENXIO; - - platform_set_drvdata(pdev, port); - - return uart_add_one_port(&rk29_uart_driver, port); -} - -static int __devexit rk29_serial_remove(struct platform_device *pdev) -{ - struct rk29_port *rk29_port = platform_get_drvdata(pdev); - - clk_put(rk29_port->clk); - - return 0; -} - -static struct platform_driver rk29_platform_driver = { - .remove = rk29_serial_remove, - .driver = { - .name = "rk29_serial", - .owner = THIS_MODULE, - }, -}; - -static int __init rk29_serial_init(void) -{ - int ret; - ret = uart_register_driver(&rk29_uart_driver); - if (unlikely(ret)) - return ret; - - ret = platform_driver_probe(&rk29_platform_driver, rk29_serial_probe); - if (unlikely(ret)) - uart_unregister_driver(&rk29_uart_driver); - - printk(KERN_INFO "rk29_serial: driver initialized\n"); - - return ret; -} - -static void __exit rk29_serial_exit(void) -{ - #ifdef CONFIG_SERIAL_RK29_CONSOLE - unregister_console(&rk29_console); - #endif - platform_driver_unregister(&rk29_platform_driver); - uart_unregister_driver(&rk29_uart_driver); -} - -/* - * While this can be a module, if builtin it's most likely the console - * So let's leave module_exit but move module_init to an earlier place - */ -arch_initcall(rk29_serial_init); -module_exit(rk29_serial_exit); - -MODULE_AUTHOR("lhh lhh@rock-chips.com"); -MODULE_DESCRIPTION("Rockchip rk29 Serial port driver"); -MODULE_LICENSE("GPL"); - - diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 11a4b5b35963..e6578c85de82 100755 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -104,6 +104,9 @@ source "drivers/staging/iio/Kconfig" source "drivers/staging/cs5535_gpio/Kconfig" +source "drivers/staging/rk29/vivante/Kconfig" +source "drivers/staging/rk29/ipp/Kconfig" + source "drivers/staging/zram/Kconfig" source "drivers/staging/zcache/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ae62e923e1b8..d00aa99e57f4 100755 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ +obj-$(CONFIG_VIVANTE) += rk29/vivante/ +obj-$(CONFIG_RK29_IPP) += rk29/ipp/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_XVMALLOC) += zram/ obj-$(CONFIG_ZCACHE) += zcache/ diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index a64481c3e86d..4c3e8fc63099 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -20,10 +20,12 @@ #include #include #include - +#include +#include #include "timed_output.h" #include "timed_gpio.h" +#define GPIO_TYPE 0 struct timed_gpio_data { struct timed_output_dev dev; @@ -32,14 +34,40 @@ struct timed_gpio_data { unsigned gpio; int max_timeout; u8 active_low; + int adjust_time; +#if (GPIO_TYPE == 1) + struct work_struct timed_gpio_work; +#endif + struct wake_lock irq_wake; }; +#if (GPIO_TYPE == 1) +static void timed_gpio_work_handler(struct work_struct *work) +{ + struct timed_gpio_data *data = + container_of(work, struct timed_gpio_data, timed_gpio_work); + int ret = 0,i = 0; + //set gpio several times once error happened + for(i=0; i<3; i++) + { + ret = gpio_direction_output(data->gpio, data->active_low ? 1 : 0); + if(!ret) + break; + printk("%s:ret=%d,fail to set gpio and set again,i=%d\n",__FUNCTION__,ret,i); + } +} +#endif + static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer) { struct timed_gpio_data *data = container_of(timer, struct timed_gpio_data, timer); - + +#if (GPIO_TYPE == 0) gpio_direction_output(data->gpio, data->active_low ? 1 : 0); +#else + schedule_work(&data->timed_gpio_work); +#endif return HRTIMER_NORESTART; } @@ -60,24 +88,26 @@ static void gpio_enable(struct timed_output_dev *dev, int value) { struct timed_gpio_data *data = container_of(dev, struct timed_gpio_data, dev); - unsigned long flags; - - spin_lock_irqsave(&data->lock, flags); + int ret = 0,i = 0; /* cancel previous timer and set GPIO according to value */ hrtimer_cancel(&data->timer); - gpio_direction_output(data->gpio, data->active_low ? !value : !!value); - + //set gpio several times once error happened + for(i=0; i<3; i++) + { + ret = gpio_direction_output(data->gpio, data->active_low ? !value : !!value); + if(!ret) + break; + printk("%s:ret=%d,fail to set gpio and set again,i=%d\n",__FUNCTION__,ret,i); + } if (value > 0) { + value += data->adjust_time; if (value > data->max_timeout) value = data->max_timeout; - hrtimer_start(&data->timer, ktime_set(value / 1000, (value % 1000) * 1000000), HRTIMER_MODE_REL); } - - spin_unlock_irqrestore(&data->lock, flags); } static int timed_gpio_probe(struct platform_device *pdev) @@ -125,10 +155,17 @@ static int timed_gpio_probe(struct platform_device *pdev) gpio_dat->gpio = cur_gpio->gpio; gpio_dat->max_timeout = cur_gpio->max_timeout; gpio_dat->active_low = cur_gpio->active_low; + gpio_dat->adjust_time = cur_gpio->adjust_time; gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low); } - +#if (GPIO_TYPE == 1) + INIT_WORK(&gpio_dat->timed_gpio_work, timed_gpio_work_handler); +#endif platform_set_drvdata(pdev, gpio_data); + wake_lock_init(&gpio_data->irq_wake, WAKE_LOCK_SUSPEND, "timed_gpio_wake"); + + gpio_enable(&gpio_data ->dev, 100); + printk("%s\n",__FUNCTION__); return 0; } @@ -168,7 +205,7 @@ static void __exit timed_gpio_exit(void) platform_driver_unregister(&timed_gpio_driver); } -module_init(timed_gpio_init); +subsys_initcall(timed_gpio_init); module_exit(timed_gpio_exit); MODULE_AUTHOR("Mike Lockwood "); diff --git a/drivers/staging/android/timed_gpio.h b/drivers/staging/android/timed_gpio.h index a0e15f8be3f7..c8487df9a109 100644 --- a/drivers/staging/android/timed_gpio.h +++ b/drivers/staging/android/timed_gpio.h @@ -23,6 +23,7 @@ struct timed_gpio { unsigned gpio; int max_timeout; u8 active_low; + int adjust_time; }; struct timed_gpio_platform_data { diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c index 34c4be3c44cd..4f1cd0cd34ec 100644 --- a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c @@ -42,7 +42,7 @@ static gceSTATUS _lastError = gcvSTATUS_OK; static gctUINT32 _debugLevel = gcvLEVEL_ERROR; static gctUINT32 _debugZones = gcvZONE_NONE; static gctINT _indent = 0; -static spinlock_t _lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(_lock); static void OutputDebugString( diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c index f4eaae12536a..2581c269ad9d 100755 --- a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -2443,7 +2443,7 @@ gceSTATUS gckOS_CreateMutex( } /* Initialize the semaphore.. Come up in unlocked state. */ - init_MUTEX(*Mutex); + sema_init(*Mutex, 1); /* Return status. */ return gcvSTATUS_OK; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b3692e6e3c13..f94445822a1a 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1512,6 +1512,63 @@ config SERIAL_BCM63XX_CONSOLE If you have enabled the serial port on the bcm63xx CPU you can make it the console by answering Y to this option. +config SERIAL_RK29 + bool "RockChip rk29 serial port support" + depends on ARM && ARCH_RK29 + select SERIAL_CORE + +config UART0_RK29 + bool "RockChip rk29 serial port 0 support" + depends on SERIAL_RK29 + +config UART0_CTS_RTS_RK29 + bool "RockChip rk29 serial port 0 CTS/RTS support" + depends on UART0_RK29 + +config UART0_DMA_RK29 + bool "RockChip rk29 serial port 0 DMA support (EXPERIMENTAL)" + depends on UART0_RK29 + +config UART1_RK29 + bool "RockChip rk29 serial port 1 support" + depends on SERIAL_RK29 + +config UART2_RK29 + bool "RockChip rk29 serial port 2 support" + depends on SERIAL_RK29 + +config UART2_CTS_RTS_RK29 + bool "RockChip rk29 serial port 2 CTS/RTS support" + depends on UART2_RK29 + +config UART2_DMA_RK29 + bool "RockChip rk29 serial port 2 DMA support (EXPERIMENTAL)" + depends on UART2_RK29 + +config UART3_RK29 + bool "RockChip rk29 serial port 3 support" + depends on SERIAL_RK29 + +config UART3_CTS_RTS_RK29 + bool "RockChip rk29 serial port 3 CTS/RTS support" + depends on UART3_RK29 + +config UART3_DMA_RK29 + bool "RockChip rk29 serial port 3 DMA support (EXPERIMENTAL)" + depends on UART3_RK29 + +config SERIAL_RK29_CONSOLE + bool "Rockchip rk29 serial console support" + depends on SERIAL_RK29=y + select SERIAL_CORE_CONSOLE + +config SERIAL_SC8800 + tristate "SC8800 support" + depends on SPI + select SERIAL_CORE + help + SC8800 spi-serial support + config SERIAL_GRLIB_GAISLER_APBUART tristate "GRLIB APBUART serial support" depends on OF && SPARC diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index cb2628fee4c7..4c73acffb064 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -83,6 +83,8 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_RK29) += rk_serial.o +obj-$(CONFIG_SERIAL_SC8800) += sc8800.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o diff --git a/drivers/serial/rk2818_serial.h b/drivers/tty/serial/rk2818_serial.h similarity index 100% rename from drivers/serial/rk2818_serial.h rename to drivers/tty/serial/rk2818_serial.h diff --git a/drivers/serial/rk_serial.c b/drivers/tty/serial/rk_serial.c similarity index 100% rename from drivers/serial/rk_serial.c rename to drivers/tty/serial/rk_serial.c diff --git a/drivers/serial/sc8800.c b/drivers/tty/serial/sc8800.c similarity index 100% rename from drivers/serial/sc8800.c rename to drivers/tty/serial/sc8800.c diff --git a/drivers/serial/sc8800.h b/drivers/tty/serial/sc8800.h similarity index 100% rename from drivers/serial/sc8800.h rename to drivers/tty/serial/sc8800.h diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 30ddf8dc4f72..906a9666d752 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -50,4 +50,5 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ obj-$(CONFIG_USB_MUSB_HDRC) += musb/ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ obj-$(CONFIG_USB_OTG_UTILS) += otg/ +obj-$(CONFIG_DWC_OTG) += dwc_otg/ obj-$(CONFIG_USB_GADGET) += gadget/ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c old mode 100755 new mode 100644 index 4516712c6936..8706fc97e60f --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1009,6 +1009,7 @@ static int __init usb_init(void) pr_info("%s: USB support disabled\n", usbcore_name); return 0; } + retval = usb_debugfs_init(); if (retval) goto out; diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index 69bbadf59398..6540e720b47d 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -2373,8 +2373,13 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd, desc->wHubCharacteristics = 0x08; desc->bPwrOn2PwrGood = 1; desc->bHubContrCurrent = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + desc->u.hs.DeviceRemovable[0] = 0; + desc->u.hs.DeviceRemovable[1] = 0xff; +#else desc->bitmap[0] = 0; desc->bitmap[1] = 0xff; +#endif break; case GetHubStatus: DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 8eb9face9096..e5c08d1af269 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -1963,14 +1963,23 @@ void dwc_otg_pcd_remove( struct device *dev ) * @param _driver The driver being registered */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +int usb_gadget_probe_driver(struct usb_gadget_driver *_driver, + int (*bind)(struct usb_gadget *)) +#else int usb_gadget_register_driver(struct usb_gadget_driver *_driver) +#endif { int retval; DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", _driver->driver.name); if (!_driver || _driver->speed == USB_SPEED_UNKNOWN || +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + !bind || +#else !_driver->bind || +#endif !_driver->unbind || !_driver->disconnect || !_driver->setup) @@ -1994,7 +2003,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *_driver) s_pcd->gadget.dev.driver = &_driver->driver; DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", _driver->driver.name); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) + retval = bind(&s_pcd->gadget); +#else retval = _driver->bind(&s_pcd->gadget); +#endif if (retval) { DWC_ERROR("bind to driver %s --> error %d\n", @@ -2007,8 +2020,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *_driver) _driver->driver.name); return 0; } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +EXPORT_SYMBOL(usb_gadget_probe_driver); +#else EXPORT_SYMBOL(usb_gadget_register_driver); +#endif /** * This function unregisters a gadget driver diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 144a8c863b34..30ce90921f4b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -112,6 +112,7 @@ config USB_GADGET_SELECTED choice prompt "USB Peripheral Controller" depends on USB_GADGET + default USB_GADGET_DWC_OTG help A USB device uses a controller to talk to its host. Systems should have only one such upstream link. @@ -543,6 +544,19 @@ config USB_LANGWELL default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_DWC_OTG + boolean "Synopsys DWC OTG Controller" + select USB_GADGET_DUALSPEED + help + This driver provides USB Device Controller support for the + Synopsys DesignWare USB OTG Core used on the Rockchip RK28. + +config USB_DWC_OTG + tristate + depends on USB_GADGET_DWC_OTG + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_EG20T boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" depends on PCI @@ -641,9 +655,9 @@ config USB_GADGET_DUALSPEED # USB Gadget Drivers # choice - tristate "USB Gadget Drivers" + bool "USB Gadget Drivers" depends on USB_GADGET && USB_GADGET_SELECTED - default USB_ETH + default USB_G_ANDROID help A Linux "Gadget Driver" talks to the USB Peripheral Controller driver through the abstract "gadget" API. Some other operating diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index b13633bb684a..fbfdc8a4e195 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -64,8 +64,8 @@ MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; /* Default vendor and product IDs, overridden by userspace */ -#define VENDOR_ID 0x18D1 -#define PRODUCT_ID 0x0001 +#define VENDOR_ID 0x2207//0x18D1 +#define PRODUCT_ID 0x2910 struct android_usb_function { char *name; diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index fe4455e50d10..9855ad55dcab 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -72,7 +72,7 @@ static struct usb_endpoint_descriptor adb_highspeed_in_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .wMaxPacketSize = __constant_cpu_to_le16(64), }; static struct usb_endpoint_descriptor adb_highspeed_out_desc = { diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5440c6d8fc30..4d477b2b84d5 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -298,6 +298,32 @@ #include "gadget_chips.h" +#ifdef CONFIG_ARCH_RK29 +/* flush after every 4 meg of writes to avoid excessive block level caching */ +#define MAX_UNFLUSHED_BYTES (64 * 1024)// (4 * 1024 * 1024) //original value is 4MB,Modifyed by xbw at 2011-08-18 +#define MAX_UNFLUSHED_PACKETS 4//16 + +#include +#include +#include + +static int usb_msc_connected; /*usb charge status*/ + +static void set_msc_connect_flag( int connected ) +{ + printk("%s status = %d 20101216\n" , __func__, connected); + if( usb_msc_connected == connected ) + return; + usb_msc_connected = connected;//usb mass storage is ok +} + +int get_msc_connect_flag( void ) +{ + return usb_msc_connected; +} +EXPORT_SYMBOL(get_msc_connect_flag); +#endif + /*------------------------------------------------------------------------*/ #define FSG_DRIVER_DESC "Mass Storage Function" @@ -797,6 +823,13 @@ static int do_read(struct fsg_common *common) amount = min(amount, (unsigned int)PAGE_CACHE_SIZE - partial_page); + /* kever@rk + * max size for dwc_otg ctonroller is 64(max pkt sizt) * 1023(pkt) + * because of the DOEPTSIZ.PKTCNT has only 10 bits + */ + if((common->gadget->speed != USB_SPEED_HIGH)&&(amount >0x8000)) + amount = 0x8000; + /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { @@ -975,6 +1008,13 @@ static int do_write(struct fsg_common *common) amount_left_to_req -= amount; if (amount_left_to_req == 0) get_some_more = 0; + + /* kever@rk + * max size for dwc_otg ctonroller is 64(max pkt sizt) * 1023(pkt) + * because of the DOEPTSIZ.PKTCNT has only 10 bits + */ + if((common->gadget->speed != USB_SPEED_HIGH)&&(amount >0x8000)) + amount = 0x8000; /* * amount is always divisible by 512, hence by @@ -1040,6 +1080,15 @@ static int do_write(struct fsg_common *common) amount_left_to_write -= nwritten; common->residue -= nwritten; +#ifdef MAX_UNFLUSHED_PACKETS + curlun->unflushed_packet ++; + curlun->unflushed_bytes += nwritten; + if( (curlun->unflushed_packet >= MAX_UNFLUSHED_PACKETS) || (curlun->unflushed_bytes >= MAX_UNFLUSHED_BYTES)) { + fsg_lun_fsync_sub(curlun); + curlun->unflushed_packet = 0; + curlun->unflushed_bytes = 0; + } +#endif /* If an error occurred, report it and its position */ if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; @@ -1940,6 +1989,153 @@ static int check_command(struct fsg_common *common, int cmnd_size, return 0; } +#ifdef CONFIG_ARCH_RK29 +static void deferred_restart(struct work_struct *dummy) +{ + sys_sync(); + kernel_restart("loader"); +} +static DECLARE_WORK(restart_work, deferred_restart); + +typedef struct tagLoaderParam +{ + int tag; + int length; + char parameter[1]; + int crc; +} PARM_INFO; +#define PARM_TAG 0x4D524150 +#define MSC_EXT_DBG 1 +extern int GetParamterInfo(char * pbuf , int len); + +/* the buf is bh->buf,it is large enough. */ +static char * get_param_tag( char* buf , const char* tag ) +{ + PARM_INFO *pi; + int i; + char *pp = buf+256; + char *spp; + i = GetParamterInfo( pp , 1024 ); + pi = (PARM_INFO*)pp; + if( pi->tag != PARM_TAG ){ +error_out: + printk("paramter error,tag=0x%x\n" , pi->tag ); + return NULL; + } + if( pi->length+sizeof(PARM_INFO) > i ) { + GetParamterInfo( pp , pi->length+sizeof(PARM_INFO) + 511 ); + } + pp = strstr( pi->parameter , tag ); + if( !pp ) goto error_out; + pp += strlen(tag); // sizeof "MACHINE_MODEL:" + while( *pp == ' ' || *pp == '\t' ) { + if(pp - pi->parameter >= pi->length) + break; + pp++; + } + spp = pp; + while( *pp != 0x0d && *pp != 0x0a ) { + if(pp - pi->parameter >= pi->length) + break; + pp++; + } + *pp = 0; + if( spp == pp ) return NULL; + return spp; +} + +static int do_get_product_name(int ret ,char *buf) +{ + char *tag = "MACHINE_MODEL:"; + char *pname; + #if MSC_EXT_DBG + char tbuf[1300]; + if( buf == NULL ) buf = tbuf; + #endif + memset( buf , 0 , ret ); + pname = get_param_tag( buf , tag ); + if( pname ){ + strcpy( buf , pname); + } + #if MSC_EXT_DBG + printk("%s%s\n" , tag , buf ); + #endif + return ret; +} + +static int do_get_versions( int ret ,char* buf ) +{ + /* get boot version and fireware version from cmdline + * bootver=2010-07-08#4.02 firmware_ver=1.0.0 // Firmware Ver:16.01.0000 + * return format: 0x02 0x04 0x00 0x00 0x00 0x01 + * RK29: bootver=2011-07-18#2.05 firmware_ver=0.2.3 (==00.02.0003) + * for the old loader,the firmware_ver may be empty,so get the fw ver from paramter. + */ +#define ASC_BCD0( c ) (((c-'0'))&0xf) +#define ASC_BCD1( c ) (((c-'0')<<4)&0xf0) + + char *ver = buf; + char *p_l , *p_f; + char *l_tag = "bootver="; + char *fw_tag = "FIRMWARE_VER:"; + + #if MSC_EXT_DBG + char tbuf[1300]; + if( ver == NULL ) ver = tbuf; + #endif + + memset( ver , 0x00 , ret ); + p_l = strstr( saved_command_line , l_tag ); + if( !p_l ) { + return ret; + } + p_l+=strlen( l_tag ); + if( (p_l = strchr( p_l,'#')) ) { + p_l++; + if( p_l[1] == '.' ) { + ver[1] = ASC_BCD0(p_l[0]); + p_l+=2; + } else { + ver[1] = ASC_BCD1(p_l[0])|ASC_BCD0(p_l[1]); + p_l+=3; + } + ver[0] = ASC_BCD1(p_l[0])|ASC_BCD0(p_l[1]); + } + + p_f = get_param_tag( ver , fw_tag ); + if( !p_f ) return ret; + + if( p_f[1] == '.' ) { + ver[5] = ASC_BCD0(p_f[0]); + p_f+=2; + } else { + ver[5] = ASC_BCD1(p_f[0])|ASC_BCD0(p_f[1]); + p_f+=3; + } + if( p_f[1] == '.' ) { + ver[4] = ASC_BCD0(p_f[0]); + p_f+=2; + } else { + ver[4] = ASC_BCD1(p_f[0])|ASC_BCD0(p_f[1]); + p_f+=3; + } + ver[2] = ASC_BCD0(p_f[0]); + p_f++; + if( p_f[0] != ' ' ){ + ver[2] |= ASC_BCD1(p_f[0]); + p_f++; + } + // only support 2 byte version. + ver[3] = 0; + + #if MSC_EXT_DBG + printk("VERSION:%02x %02x %02x %02x %02x %02x\n" , + ver[0],ver[1],ver[2],ver[3],ver[4],ver[5]); + #endif + return ret; +} +#endif + static int do_scsi_command(struct fsg_common *common) { struct fsg_buffhd *bh; @@ -1947,6 +2143,9 @@ static int do_scsi_command(struct fsg_common *common) int reply = -EINVAL; int i; static char unknown[16]; +#ifdef CONFIG_ARCH_RK29 + struct fsg_common *fsg = common; +#endif dump_cdb(common); @@ -2137,7 +2336,11 @@ static int do_scsi_command(struct fsg_common *common) (1<<1) | (0xf<<2) | (3<<7), 1, "VERIFY"); if (reply == 0) +#ifdef CONFIG_ARCH_RK29 + reply = 0; //zyf 20100302 +#else reply = do_verify(common); +#endif break; case WRITE_6: @@ -2193,6 +2396,26 @@ unknown_cmnd: reply = -EINVAL; } break; +#ifdef CONFIG_ARCH_RK29 + case 0xff: + if( fsg->cmnd[1] != 0xe0 || + fsg->cmnd[2] != 0xff || fsg->cmnd[3] != 0xff || + fsg->cmnd[4] != 0xff ) + break; + if (fsg->cmnd_size >= 6 && fsg->cmnd[5] == 0xfe) { + schedule_work(&restart_work); + } + else if ( fsg->cmnd[5] == 0xf3 ) { + fsg->data_size_from_cmnd = fsg->data_size; + /* get product name from parameter section */ + reply = do_get_product_name( fsg->data_size,bh->buf ); + } + else if ( fsg->cmnd[5] == 0xff ){ + fsg->data_size_from_cmnd = fsg->data_size; + reply = do_get_versions( fsg->data_size,bh->buf ); + } + break; +#endif } up_read(&common->filesem); @@ -2450,6 +2673,8 @@ static void fsg_disable(struct usb_function *f) struct fsg_dev *fsg = fsg_from_func(f); fsg->common->new_fsg = NULL; raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + // yk 201009 + set_msc_connect_flag(0); } @@ -3178,3 +3403,131 @@ fsg_common_from_params(struct fsg_common *common, return fsg_common_init(common, cdev, &cfg); } +#ifdef CONFIG_USB_ANDROID_MASS_STORAGE + +#ifdef CONFIG_ARCH_RK29 +static enum power_supply_property usb_props[] = { +// POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, +}; + +static int usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: +#ifndef CONFIG_DWC_OTG_HOST_ONLY + val->intval = get_msc_connect_flag(); +#else + val->intval = 0; +#endif + break; + default: + return -EINVAL; + } + + return ret; +} + +static int usb_power_supply_register(struct device* parent) +{ + struct power_supply *ps; + int retval = 0; + + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) { + dev_err(parent, "failed to allocate power supply data\n"); + retval = -ENOMEM; + goto out; + } + ps->name = "usb"; + ps->type = POWER_SUPPLY_TYPE_USB; + ps->properties = usb_props; + ps->num_properties = ARRAY_SIZE(usb_props); + ps->get_property = usb_get_property; + ps->external_power_changed = NULL; + retval = power_supply_register(parent, ps); + if (retval) { + dev_err(parent, "failed to register battery\n"); + goto out; + } +out: + return retval; +} +#endif + +static struct fsg_config fsg_cfg; + +static int fsg_probe(struct platform_device *pdev) +{ + struct usb_mass_storage_platform_data *pdata = pdev->dev.platform_data; + int i, nluns; + + printk(KERN_INFO "fsg_probe pdev: %p, pdata: %p\n", pdev, pdata); + if (!pdata) + return -1; + + nluns = pdata->nluns; + if (nluns > FSG_MAX_LUNS) + nluns = FSG_MAX_LUNS; + fsg_cfg.nluns = nluns; + for (i = 0; i < nluns; i++) + fsg_cfg.luns[i].removable = 1; + + fsg_cfg.vendor_name = pdata->vendor; + fsg_cfg.product_name = pdata->product; + fsg_cfg.release = pdata->release; + fsg_cfg.can_stall = 0; + fsg_cfg.pdev = pdev; + +#ifdef CONFIG_ARCH_RK29 +{ + /* + * Initialize usb power supply + */ + int retval = usb_power_supply_register(&pdev->dev); + if (retval != 0) { + dev_err(&pdev->dev, "usb_power_supply_register failed\n"); + } + + return retval; +} +#else + return 0; +#endif +} + +static struct platform_driver fsg_platform_driver = { + .driver = { .name = FUNCTION_NAME, }, + .probe = fsg_probe, +}; + +int mass_storage_bind_config(struct usb_configuration *c) +{ + struct fsg_common *common = fsg_common_init(NULL, c->cdev, &fsg_cfg); + if (IS_ERR(common)) + return -1; + return fsg_add(c->cdev, c, common); +} + +static struct android_usb_function mass_storage_function = { + .name = FUNCTION_NAME, + .bind_config = mass_storage_bind_config, +}; + +static int __init init(void) +{ + int rc; + printk(KERN_INFO "f_mass_storage init\n"); + rc = platform_driver_register(&fsg_platform_driver); + if (rc != 0) + return rc; + android_register_function(&mass_storage_function); + return 0; +}module_init(init); + +#endif /* CONFIG_USB_ANDROID_MASS_STORAGE */ + diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index a872248f37df..618b3f076c1f 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -233,6 +233,10 @@ struct fsg_lun { struct file *filp; loff_t file_length; loff_t num_sectors; +#ifdef MAX_UNFLUSHED_PACKETS + unsigned int unflushed_packet; + unsigned int unflushed_bytes; +#endif unsigned int initially_ro:1; unsigned int ro:1; @@ -763,6 +767,9 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, struct rw_semaphore *filesem = dev_get_drvdata(dev); int rc = 0; +#ifdef CONFIG_ARCH_RK29 + printk("store_file: \"%s\"\n", buf); +#endif #ifndef CONFIG_USB_ANDROID_MASS_STORAGE /* disabled in android because we need to allow closing the backing file diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 60b25d8ea0e2..8cf88aa5c8f4 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -309,6 +309,7 @@ static void option_instat_callback(struct urb *urb); #define ZTE_PRODUCT_CDMA_TECH 0xfffe #define ZTE_PRODUCT_AC8710 0xfff1 #define ZTE_PRODUCT_AC2726 0xfff5 +#define ZTE_PRODUCT_AC100 0x0094 #define ZTE_PRODUCT_AC8710T 0xffff #define BENQ_VENDOR_ID 0x04a5 @@ -394,6 +395,13 @@ static void option_instat_callback(struct urb *urb); #define CINTERION_PRODUCT_EU3_P 0x0052 #define CINTERION_PRODUCT_PH8 0x0053 +/* Thinkwill products */ +#define THINKWILL_VENDOR_ID 0x19f5 +#define THINKWILL_PRODUCT_ID 0x9909 +#define THINKWILL_MI900_PRODUCT_ID 0x9013 + +#define CINTERION_VENDOR_ID 0x0681 + /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 @@ -412,6 +420,13 @@ static void option_instat_callback(struct urb *urb); #define SAMSUNG_VENDOR_ID 0x04e8 #define SAMSUNG_PRODUCT_GT_B3730 0x6889 +/* leadcore LC1808*/ +#define LEADCORE_VENDOR_ID 0x1ab7 +#define LEADCORE_PRODUCT_LC1808 0x2200 +/*展讯模组*/ +#define SC8800G_VENDOR_ID 0x067b +#define SC8800G_PRODUCT_ID 0x2303 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -448,6 +463,10 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(THINKWILL_VENDOR_ID,THINKWILL_PRODUCT_ID)}, + + { USB_DEVICE(THINKWILL_VENDOR_ID,THINKWILL_MI900_PRODUCT_ID)}, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) }, @@ -477,6 +496,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600)}, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, @@ -936,6 +956,11 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xFFED, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xFFFE, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xFFEB, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xF006, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_AC100)}, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, @@ -989,6 +1014,35 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */ { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + { USB_DEVICE(LEADCORE_VENDOR_ID, LEADCORE_PRODUCT_LC1808) }, //zzc + { USB_DEVICE(SC8800G_VENDOR_ID,SC8800G_PRODUCT_ID)}, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ + +// cmy: + { USB_DEVICE(0x0685, 0x6000) }, + { USB_DEVICE(0x1E89, 0x1E16) }, + { USB_DEVICE(0x7693, 0x0001) }, + { USB_DEVICE(0x1D09, 0x4308) }, + { USB_DEVICE(0x1234, 0x0033) }, + { USB_DEVICE(0xFEED, 0x0001) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0017) }, + { USB_DEVICE(0x1C9E, 0x9E00) }, + { USB_DEVICE(0x1C9E, 0xF000) }, + { USB_DEVICE(0x19D2, 0x1303) }, + { USB_DEVICE(0x19F5, 0x9013) }, // MW100 + { USB_DEVICE(0x21F5, 0x2008) }, + { USB_DEVICE(0x12D1, 0x1D09) }, + { USB_DEVICE(0x04CC, 0x2259) }, + { USB_DEVICE(0x04CC, 0x226E) }, + { USB_DEVICE(0x04CC, 0x225A) }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0015) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7) }, + { USB_DEVICE(ZTE_VENDOR_ID, 0xFFFF) }, + { USB_DEVICE(LEADCORE_VENDOR_ID, 0x5700) }, + { USB_DEVICE(LEADCORE_VENDOR_ID, 0x6341) }, + + { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c old mode 100755 new mode 100644 diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index 3b14863a0f24..f9a3eec2d558 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -183,6 +183,7 @@ static int rk29_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = BL_STEP; rk29_bl = backlight_device_register("rk28_bl", &pdev->dev, rk29_bl_info, &rk29_bl_ops, &props); if (!rk29_bl) { diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index d4c6eb248ff9..cea8e23f0937 100755 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -18,21 +18,46 @@ #include #include #include - +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#define BL_SET 255 +#define BL_MISC_VALUE 20 +#define BL_INIT_VALUE 102 struct wm831x_backlight_data { struct wm831x *wm831x; int isink_reg; int current_brightness; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; + struct delayed_work work; + int suspend_flag; + int shutdown_flag; +#endif }; - +#define TS_POLL_DELAY (10000*1000*1000) +int wm831x_bright = 0; +int max_tp = 0; +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct backlight_device *gwm831x_bl; +static struct wm831x_backlight_data *gwm831x_data; +#endif static int wm831x_backlight_set(struct backlight_device *bl, int brightness) { struct wm831x_backlight_data *data = bl_get_data(bl); struct wm831x *wm831x = data->wm831x; - int power_up = !data->current_brightness && brightness; - int power_down = data->current_brightness && !brightness; +// int power_up = !data->current_brightness && brightness; +// int power_down = data->current_brightness && !brightness; + int power_up; + int power_down; int ret; + int bright_tp; + bright_tp =( max_tp*brightness)/BL_SET; + power_up =!data->current_brightness && bright_tp; + power_down = data->current_brightness && !bright_tp; if (power_up) { /* Enable the ISINK */ ret = wm831x_set_bits(wm831x, data->isink_reg, @@ -63,7 +88,7 @@ static int wm831x_backlight_set(struct backlight_device *bl, int brightness) /* Set the new brightness */ ret = wm831x_set_bits(wm831x, data->isink_reg, - WM831X_CS1_ISEL_MASK, brightness); + WM831X_CS1_ISEL_MASK, bright_tp); if (ret < 0) goto err; @@ -94,7 +119,21 @@ err: static int wm831x_backlight_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; + if (brightness<=BL_MISC_VALUE) { + brightness = 8*brightness; + } + else if (brightness<=BL_INIT_VALUE) { + brightness = 31*brightness/41 + 145; + } + else { + brightness = 33*brightness/153 + 200; + } + if(gwm831x_data->suspend_flag == 1) + brightness = 0; + if (gwm831x_data->shutdown_flag == 1) + brightness = 0; + if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; @@ -104,6 +143,8 @@ static int wm831x_backlight_update_status(struct backlight_device *bl) if (bl->props.state & BL_CORE_SUSPENDED) brightness = 0; + printk("backlight brightness=%d\n", brightness); + return wm831x_backlight_set(bl, brightness); } @@ -118,6 +159,40 @@ static const struct backlight_ops wm831x_backlight_ops = { .update_status = wm831x_backlight_update_status, .get_brightness = wm831x_backlight_get_brightness, }; +#ifdef CONFIG_HAS_EARLYSUSPEND +static void wm831x_bl_work(struct work_struct *work) +{ + //struct wm831x_backlight_data *wm831x_data = container_of(work, struct wm831x_backlight_data, + //work.work); + backlight_update_status(gwm831x_bl); +} + +static void wm831x_bl_suspend(struct early_suspend *h) +{ + struct wm831x_backlight_data *wm831x_data; + wm831x_data = container_of(h, struct wm831x_backlight_data, early_suspend); + wm831x_data->suspend_flag = 1; + + schedule_delayed_work(&wm831x_data->work, msecs_to_jiffies(100)); +} + + +static void wm831x_bl_resume(struct early_suspend *h) +{ + struct wm831x_backlight_data *wm831x_data; + wm831x_data = container_of(h, struct wm831x_backlight_data, early_suspend); + wm831x_data->suspend_flag = 0; + + schedule_delayed_work(&wm831x_data->work, msecs_to_jiffies(100)); +} + +#endif + +int rk29_backlight_ctrl(int open) +{ + gwm831x_data->suspend_flag = !open; + schedule_delayed_work(&gwm831x_data->work, 0); +} static int wm831x_backlight_probe(struct platform_device *pdev) { @@ -153,7 +228,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev) return -EINVAL; } max_isel = i - 1; - + max_tp = max_isel; if (pdata->max_uA != wm831x_isinkv_values[max_isel]) dev_warn(&pdev->dev, "Maximum current is %duA not %duA as requested\n", @@ -194,7 +269,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev) data->isink_reg = isink_reg; props.type = BACKLIGHT_RAW; - props.max_brightness = max_isel; + props.max_brightness = BL_SET; bl = backlight_device_register("wm831x", &pdev->dev, data, &wm831x_backlight_ops, &props); if (IS_ERR(bl)) { @@ -203,15 +278,26 @@ static int wm831x_backlight_probe(struct platform_device *pdev) return PTR_ERR(bl); } - bl->props.brightness = max_isel; + bl->props.brightness = BL_INIT_VALUE; platform_set_drvdata(pdev, bl); +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = ~0x0; + data->early_suspend.suspend = wm831x_bl_suspend; + data->early_suspend.resume = wm831x_bl_resume; + register_early_suspend(&data->early_suspend); + INIT_DELAYED_WORK(&data->work, wm831x_bl_work); + gwm831x_bl = bl; + gwm831x_data = data; +#endif + + /* Disable the DCDC if it was started so we can bootstrap */ wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0); - - backlight_update_status(bl); + //backlight_update_status(bl); + schedule_delayed_work(&data->work, msecs_to_jiffies(100)); return 0; } @@ -222,10 +308,24 @@ static int wm831x_backlight_remove(struct platform_device *pdev) struct wm831x_backlight_data *data = bl_get_data(bl); backlight_device_unregister(bl); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif kfree(data); return 0; } +static void wm831x_backlight_shutdown(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct wm831x_backlight_data *data = bl_get_data(bl); + + printk("enter %s\n", __func__); + data->shutdown_flag = 1; + wm831x_backlight_update_status(bl); + return; +} + static struct platform_driver wm831x_backlight_driver = { .driver = { .name = "wm831x-backlight", @@ -233,6 +333,7 @@ static struct platform_driver wm831x_backlight_driver = { }, .probe = wm831x_backlight_probe, .remove = wm831x_backlight_remove, + .shutdown = wm831x_backlight_shutdown, }; static int __init wm831x_backlight_init(void) diff --git a/fs/fat/dir.c b/fs/fat/dir.c index dc563788fa89..723aa9abbf52 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -98,7 +98,7 @@ next: *bh = sb_bread(sb, phys); if (*bh == NULL) { - fat_msg(sb, KERN_ERR, "Directory bread(block %llu) failed", + fat_msg(sb, KERN_DEBUG, "Directory bread(block %llu) failed", (llu)phys); /* skip this block */ *pos = (iblock + 1) << sb->s_blocksize_bits; diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 2e81ac0df7e2..38cfeb1908a3 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -95,7 +95,7 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, err_brelse: brelse(bhs[0]); err: - fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr); + fat_msg(sb, KERN_DEBUG, "FAT read failed (blocknr %llu)", (llu)blocknr); return -EIO; } @@ -108,7 +108,7 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, fatent->fat_inode = MSDOS_SB(sb)->fat_inode; fatent->bhs[0] = sb_bread(sb, blocknr); if (!fatent->bhs[0]) { - fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", + fat_msg(sb, KERN_DEBUG, "FAT read failed (blocknr %llu)", (llu)blocknr); return -EIO; } diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 9836839e0eb4..e5d4e9bc0bae 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1282,7 +1282,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, sb_min_blocksize(sb, 512); bh = sb_bread(sb, 0); if (bh == NULL) { - fat_msg(sb, KERN_ERR, "unable to read boot sector"); + fat_msg(sb, KERN_DEBUG, "unable to read boot sector"); goto out_fail; } @@ -1348,7 +1348,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, } bh = sb_bread(sb, 0); if (bh == NULL) { - fat_msg(sb, KERN_ERR, "unable to read boot sector" + fat_msg(sb, KERN_DEBUG, "unable to read boot sector" " (logical sector size = %lu)", sb->s_blocksize); goto out_fail; diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c index d1643df2c381..9420e6ffbf92 100644 --- a/fs/yaffs2/yaffs_mtdif2.c +++ b/fs/yaffs2/yaffs_mtdif2.c @@ -149,8 +149,13 @@ int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, if (local_data) yaffs_release_temp_buffer(dev, data, __LINE__); +#ifdef CONFIG_MTD_NAND_RK29 + //dxj 20101221@ if return -EBADMSG then i think the page is badchunk so just set the eccResult=YAFFS_ECC_RESULT_NO_ERROR + if (tags && retval == -EBADMSG) { +#else if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) { +#endif tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; dev->n_ecc_unfixed++; } diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c index d5b875314005..1fbb7fc246c9 100644 --- a/fs/yaffs2/yaffs_vfs.c +++ b/fs/yaffs2/yaffs_vfs.c @@ -2217,6 +2217,9 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version, param->n_reserved_blocks = 5; param->n_caches = (options.no_cache) ? 0 : 10; param->inband_tags = options.inband_tags; +#if defined(CONFIG_ARCH_RK2818) || defined(CONFIG_ARCH_RK29) + param->inband_tags = 1; +#endif #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD param->disable_lazy_load = 1; diff --git a/include/linux/gfp.h b/include/linux/gfp.h index c2ccc3e4311b..cb4089254f01 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -86,8 +86,6 @@ struct vm_area_struct; #define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */ -#define __GFP_NO_KSWAPD ((__force gfp_t)0x400000u) - /* * This may seem redundant, but it's a way of annotating false positives vs. * allocations that simply cannot be supported (e.g. page tables). diff --git a/include/linux/i2c.h b/include/linux/i2c.h old mode 100755 new mode 100644 index a6c652ef516d..584a700b976e --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -61,6 +61,17 @@ extern int i2c_master_send(const struct i2c_client *client, const char *buf, extern int i2c_master_recv(const struct i2c_client *client, char *buf, int count); +#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29) +/* If everything went ok, return 'count' transmitted, else error code. */ +extern int i2c_master_normal_send(const struct i2c_client *client, const char *buf, int count, int scl_rate); +extern int i2c_master_normal_recv(const struct i2c_client *client, char *buf, int count, int scl_rate); +extern int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate); +extern int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate); +extern int i2c_master_reg16_send(const struct i2c_client *client, const short regs, const short *buf, int count, int scl_rate); +extern int i2c_master_reg16_recv(const struct i2c_client *client, const short regs, short *buf, int count, int scl_rate); +extern int i2c_suspended(struct i2c_adapter *adap); +#endif + /* Transfer num messages. */ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, @@ -208,6 +219,7 @@ struct i2c_client { struct i2c_driver *driver; /* and our access routines */ struct device dev; /* the device structure */ int irq; /* irq issued by device */ + int udelay; struct list_head detected; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -259,6 +271,7 @@ struct i2c_board_info { struct dev_archdata *archdata; struct device_node *of_node; int irq; + int udelay; //add by kfx }; /** @@ -517,8 +530,13 @@ struct i2c_msg { #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ +#define I2C_M_NEED_DELAY 0x0020 // add by kfx +#define I2C_M_REG8_DIRECT 0x0040 // add by kfx __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ + __u32 scl_rate; // add by kfx + int udelay; //add by kfx + __u16 read_type; }; /* To determine what functionality is present */ diff --git a/include/linux/i2c/tps65910.h b/include/linux/i2c/tps65910.h deleted file mode 100644 index 312747097637..000000000000 --- a/include/linux/i2c/tps65910.h +++ /dev/null @@ -1,275 +0,0 @@ -/* linux/i2c/tps65910.h - * - * TPS65910 Power Management Device Definitions. - * - * Based on include/linux/i2c/twl.h - * - * Copyright (C) 2010 Mistral Solutions Pvt Ltd - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __LINUX_I2C_TPS65910_H -#define __LINUX_I2C_TPS65910_H - -#define TPS65910_NUM_SLAVES 1 -/* I2C Slave Address 7-bit */ -#define TPS65910_I2C_ID0 0x2D /* general-purpose */ -#define TPS65910_I2C_ID1 0x12 /* Smart Reflex */ - -/* TPS65910 to host IRQ */ -#define TPS65910_HOST_IRQ RK29_PIN4_PD3 - -/* TPS65910 MAX GPIOs */ -#define TPS65910_GPIO_MAX 1 - -/* - * ---------------------------------------------------------------------------- - * Registers, all 8 bits - * ---------------------------------------------------------------------------- - */ -#define TPS65910_REG_SECONDS 0x00 -#define TPS65910_REG_MINUTES 0x01 -#define TPS65910_REG_HOURS 0x02 -#define TPS65910_REG_DAYS 0x03 -#define TPS65910_REG_MONTHS 0x04 -#define TPS65910_REG_YEARS 0x05 -#define TPS65910_REG_WEEKS 0x06 -#define TPS65910_REG_ALARM_SECONDS 0x08 -#define TPS65910_REG_ALARM_MINUTES 0x09 -#define TPS65910_REG_ALARM_HOURS 0x0A -#define TPS65910_REG_ALARM_DAYS 0x0B -#define TPS65910_REG_ALARM_MONTHS 0x0C -#define TPS65910_REG_ALARM_YEARS 0x0D - -#define TPS65910_REG_RTC_CTRL 0x10 -#define TPS65910_REG_RTC_STATUS 0x11 -#define TPS65910_REG_RTC_INTERRUPTS 0x12 -#define TPS65910_REG_RTC_COMP_LSB 0x13 -#define TPS65910_REG_RTC_COMP_MSB 0x14 -#define TPS65910_REG_RTC_RES_PROG 0x15 -#define TPS65910_REG_RTC_RESET_STATUS 0x16 -#define TPS65910_REG_BCK1 0x17 -#define TPS65910_REG_BCK2 0x18 -#define TPS65910_REG_BCK3 0x19 -#define TPS65910_REG_BCK4 0x1A -#define TPS65910_REG_BCK5 0x1B -#define TPS65910_REG_PUADEN 0x1C -#define TPS65910_REG_REF 0x1D -#define TPS65910_REG_VRTC 0x1E - -#define TPS65910_REG_VIO 0x20 -#define TPS65910_REG_VDD1 0x21 -#define TPS65910_REG_VDD1_OP 0x22 -#define TPS65910_REG_VDD1_SR 0x23 -#define TPS65910_REG_VDD2 0x24 -#define TPS65910_REG_VDD2_OP 0x25 -#define TPS65910_REG_VDD2_SR 0x26 -#define TPS65910_REG_VDD3 0x27 - -#define TPS65910_REG_VDIG1 0x30 -#define TPS65910_REG_VDIG2 0x31 -#define TPS65910_REG_VAUX1 0x32 -#define TPS65910_REG_VAUX2 0x33 -#define TPS65910_REG_VAUX33 0x34 -#define TPS65910_REG_VMMC 0x35 -#define TPS65910_REG_VPLL 0x36 -#define TPS65910_REG_VDAC 0x37 -#define TPS65910_REG_THERM 0x38 -#define TPS65910_REG_BBCH 0x39 - -#define TPS65910_REG_DCDCCTRL 0x3E -#define TPS65910_REG_DEVCTRL 0x3F -#define TPS65910_REG_DEVCTRL2 0x40 -#define TPS65910_REG_SLEEP_KEEP_LDO_ON 0x41 -#define TPS65910_REG_SLEEP_KEEP_RES_ON 0x42 -#define TPS65910_REG_SLEEP_SET_LDO_OFF 0x43 -#define TPS65910_REG_SLEEP_SET_RES_OFF 0x44 -#define TPS65910_REG_EN1_LDO_ASS 0x45 -#define TPS65910_REG_EN1_SMPS_ASS 0x46 -#define TPS65910_REG_EN2_LDO_ASS 0x47 -#define TPS65910_REG_EN2_SMPS_ASS 0x48 -#define TPS65910_REG_EN3_LDO_ASS 0x49 -#define TPS65910_REG_SPARE 0x4A - -#define TPS65910_REG_INT_STS 0x50 -#define TPS65910_REG_INT_MSK 0x51 -#define TPS65910_REG_INT_STS2 0x52 -#define TPS65910_REG_INT_MSK2 0x53 -#define TPS65910_REG_INT_STS3 0x54 -#define TPS65910_REG_INT_MSK3 0x55 - -#define TPS65910_REG_GPIO0 0x60 - -#define TPS65910_REG_JTAGVERNUM 0x80 - -/* TPS65910 GPIO Specific flags */ -#define TPS65910_GPIO_INT_FALLING 0 -#define TPS65910_GPIO_INT_RISING 1 - -#define TPS65910_DEBOUNCE_91_5_MS 0 -#define TPS65910_DEBOUNCE_150_MS 1 - -#define TPS65910_GPIO_PUDIS (1 << 3) -#define TPS65910_GPIO_CFG_OUTPUT (1 << 2) - - - -/* TPS65910 Interrupt events */ - -/* RTC Driver */ -#define TPS65910_RTC_ALARM_IT 0x80 -#define TPS65910_RTC_PERIOD_IT 0x40 - -/*Core Driver */ -#define TPS65910_HOT_DIE_IT 0x20 -#define TPS65910_PWRHOLD_IT 0x10 -#define TPS65910_PWRON_LP_IT 0x08 -#define TPS65910_PWRON_IT 0x04 -#define TPS65910_VMBHI_IT 0x02 -#define TPS65910_VMBGCH_IT 0x01 - -/* GPIO driver */ -#define TPS65910_GPIO_F_IT 0x02 -#define TPS65910_GPIO_R_IT 0x01 - - -#define TPS65910_VRTC_OFFMASK (1<<3) - -/* Back-up battery charger control */ -#define TPS65910_BBCHEN 0x01 - -/* Back-up battery charger voltage */ -#define TPS65910_BBSEL_3P0 0x00 -#define TPS65910_BBSEL_2P52 0x02 -#define TPS65910_BBSEL_3P15 0x04 -#define TPS65910_BBSEL_VBAT 0x06 - -/* DEVCTRL_REG flags */ -#define TPS65910_RTC_PWDNN 0x40 -#define TPS65910_CK32K_CTRL 0x20 -#define TPS65910_SR_CTL_I2C_SEL 0x10 -#define TPS65910_DEV_OFF_RST 0x08 -#define TPS65910_DEV_ON 0x04 -#define TPS65910_DEV_SLP 0x02 -#define TPS65910_DEV_OFF 0x01 - -/* DEVCTRL2_REG flags */ -#define TPS65910_DEV2_TSLOT_LENGTH 0x30 -#define TPS65910_DEV2_SLEEPSIG_POL 0x08 -#define TPS65910_DEV2_PWON_LP_OFF 0x04 -#define TPS65910_DEV2_PWON_LP_RST 0x02 -#define TPS65910_DEV2_IT_POL 0x01 - -/* TPS65910 SMPS/LDO's */ -#define TPS65910_VIO 0 -#define TPS65910_VDD1 1 -#define TPS65910_VDD2 2 -#define TPS65910_VDD3 3 -/* LDOs */ -#define TPS65910_VDIG1 4 -#define TPS65910_VDIG2 5 -#define TPS65910_VAUX33 6 -#define TPS65910_VMMC 7 -#define TPS65910_VAUX1 8 -#define TPS65910_VAUX2 9 -#define TPS65910_VDAC 10 -#define TPS65910_VPLL 11 -/* Internal LDO */ -#define TPS65910_VRTC 12 - -/* Number of step-down/up converters available */ -#define TPS65910_NUM_DCDC 4 - -/* Number of LDO voltage regulators available */ -#define TPS65910_NUM_LDO 9 - -/* Number of total regulators available */ -#define TPS65910_NUM_REGULATOR (TPS65910_NUM_DCDC + TPS65910_NUM_LDO) - - -/* Regulator Supply state */ -#define SUPPLY_STATE_FLAG 0x03 -/* OFF States */ -#define TPS65910_REG_OFF_00 0x00 -#define TPS65910_REG_OFF_10 0x02 -/* OHP - on High Power */ -#define TPS65910_REG_OHP 0x01 -/* OLP - on Low Power */ -#define TPS65910_REG_OLP 0x03 - -#define TPS65910_MAX_IRQS 10 -#define TPS65910_VMBDCH_IRQ 0 -#define TPS65910_VMBHI_IRQ 1 -#define TPS65910_PWRON_IRQ 2 -#define TPS65910_PWRON_LP_IRQ 3 -#define TPS65910_PWRHOLD_IRQ 4 -#define TPS65910_HOTDIE_IRQ 5 -#define TPS65910_RTC_ALARM_IRQ 6 -#define TPS65910_RTC_PERIOD_IRQ 7 -#define TPS65910_GPIO0_R_IRQ 8 -#define TPS65910_GPIO0_F_IRQ 9 - -/* TPS65910 has 1 GPIO */ -struct tps65910_gpio { - u8 debounce; - u8 pullup_pulldown; - u8 gpio_config; /* Input or output */ - u8 gpio_val; /* Output value */ - int (*gpio_setup)(struct tps65910_gpio *pdata); - int (*gpio_taredown)(struct tps65910_gpio *pdata); -}; - -struct tps65910_platform_data { - - unsigned irq_num; /* TPS65910 to Host IRQ Number */ - struct tps65910_gpio *gpio; - - /* plaform specific data to be initialised in board file */ - struct regulator_init_data *vio; - struct regulator_init_data *vdd1; - struct regulator_init_data *vdd2; - struct regulator_init_data *vdd3; - struct regulator_init_data *vdig1; - struct regulator_init_data *vdig2; - struct regulator_init_data *vaux33; - struct regulator_init_data *vmmc; - struct regulator_init_data *vaux1; - struct regulator_init_data *vaux2; - struct regulator_init_data *vdac; - struct regulator_init_data *vpll; - - void (*handlers[TPS65910_MAX_IRQS]) (void *data); - /* Configure TP65910 to board specific usage*/ - int (*board_tps65910_config)(struct tps65910_platform_data *pdata); -}; - -int tps65910_enable_bbch(u8 voltage); -int tps65910_disable_bbch(void); - -int tps65910_remove_irq_work(int irq); -int tps65910_add_irq_work(int irq, void (*handler)(void *data)); - -int tps65910_i2c_write_u8(u8 slave_addr, u8 val, u8 reg); -int tps65910_i2c_read_u8(u8 slave_addr, u8 *val, u8 reg); - -#endif /* __LINUX_I2C_TPS65910_H */ - diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 0d515ee1c247..4b217b9b8fc7 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -17,6 +17,8 @@ #include #include +#include +#include /* * Register values. @@ -237,6 +239,15 @@ struct regulator_dev; #define WM831X_NUM_IRQ_REGS 5 +#define WM831X_IRQ_LIST 1 +enum wm831x_parent { + WM8310 = 0x8310, + WM8311 = 0x8311, + WM8312 = 0x8312, + WM8320 = 0x8320, + WM8321 = 0x8321, + WM8325 = 0x8325, +}; enum wm831x_parent { WM8310 = 0x8310, @@ -260,7 +271,19 @@ struct wm831x { void *control_data; int irq; /* Our chip IRQ */ + int flag_suspend; + spinlock_t flag_lock; struct mutex irq_lock; + struct workqueue_struct *irq_wq; + struct delayed_work irq_work; + struct wake_lock irq_wake; + struct wake_lock handle_wake; +#if WM831X_IRQ_LIST + struct workqueue_struct *handle_wq; + struct work_struct handle_work; + spinlock_t work_lock; + struct list_head handle_queue; +#endif unsigned int irq_base; int irq_masks_cur[WM831X_NUM_IRQ_REGS]; /* Currently active value */ int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */ @@ -284,6 +307,39 @@ struct wm831x { unsigned int locked:1; }; +#define WM831X_DCDC_MAX_NAME 6 +#define WM831X_LDO_MAX_NAME 6 +#define WM831X_ISINK_MAX_NAME 7 + +struct wm831x_dcdc { + char name[WM831X_DCDC_MAX_NAME]; + struct regulator_desc desc; + int base; + struct wm831x *wm831x; + struct regulator_dev *regulator; + int dvs_gpio; + int dvs_gpio_state; + int on_vsel; + int dvs_vsel; +}; + +struct wm831x_ldo { + char name[WM831X_LDO_MAX_NAME]; + struct regulator_desc desc; + int base; + struct wm831x *wm831x; + struct regulator_dev *regulator; +}; + +struct wm831x_isink { + char name[WM831X_ISINK_MAX_NAME]; + struct regulator_desc desc; + int reg; + struct wm831x *wm831x; + struct regulator_dev *regulator; +}; + + /* Device I/O API */ int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg); int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg, @@ -298,6 +354,10 @@ int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq); void wm831x_device_exit(struct wm831x *wm831x); int wm831x_device_suspend(struct wm831x *wm831x); +int wm831x_device_resume(struct wm831x *wm831x); +int wm831x_device_shutdown(struct wm831x *wm831x); +int wm831x_read_usb(struct wm831x *wm831x); +int wm831x_device_restart(struct wm831x *wm831x); int wm831x_irq_init(struct wm831x *wm831x, int irq); void wm831x_irq_exit(struct wm831x *wm831x); diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index ff42d700293f..accc729c7970 100755 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -39,6 +39,8 @@ struct wm831x_battery_pdata { int eoc_iterm; /** End of trickle charge current, in mA */ int fast_ilim; /** Fast charge current limit, in mA */ int timeout; /** Charge cycle timeout, in minutes */ + int syslo; /** syslo threshold, in mV**/ + int sysok; /** sysok threshold, in mV**/ }; /** @@ -98,6 +100,22 @@ struct wm831x_watchdog_pdata { int update_gpio; unsigned int software:1; }; +struct wm831x_gpio_keys_button { + /* Configuration parameters */ + int code; /* input event code (KEY_*, SW_*) */ + int gpio; + int active_low; + char *desc; + int type; /* input event type (EV_KEY, EV_SW) */ + int wakeup; /* configure the button as a wake-up source */ + int debounce_interval; /* debounce ticks interval in msecs */ +}; + +struct wm831x_gpio_keys_pdata { + struct wm831x_gpio_keys_button *buttons; + int nbuttons; + unsigned int rep:1; /* enable input subsystem auto repeat */ +}; #define WM831X_MAX_STATUS 2 #define WM831X_MAX_DCDC 4 @@ -116,10 +134,21 @@ struct wm831x_pdata { int (*pre_init)(struct wm831x *wm831x); /** Called after subdevices are set up */ int (*post_init)(struct wm831x *wm831x); +<<<<<<< HEAD /** Put the /IRQ line into CMOS mode */ bool irq_cmos; +======= + /** Called before subdevices are power down */ + int (*last_deinit)(struct wm831x *wm831x); + //add by sxj + unsigned int gpio_pin_num; + struct rk2818_gpio_expander_info *settinginfo; + int settinginfolen; + int (*pin_type_init)(struct wm831x *wm831x); + //above add by sxj +>>>>>>> parent of 15f7fab... temp revert rk change int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; @@ -128,6 +157,9 @@ struct wm831x_pdata { struct wm831x_battery_pdata *battery; struct wm831x_touch_pdata *touch; struct wm831x_watchdog_pdata *watchdog; + //add by srt + struct wm831x_gpio_keys_pdata *gpio_keys; + //end by srt /** LED1 = 0 and so on */ struct wm831x_status_pdata *status[WM831X_MAX_STATUS]; diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h index f0b69cdae41c..7929fc9d6709 100644 --- a/include/linux/mfd/wm8994/core.h +++ b/include/linux/mfd/wm8994/core.h @@ -15,6 +15,7 @@ #ifndef __MFD_WM8994_CORE_H__ #define __MFD_WM8994_CORE_H__ +<<<<<<< HEAD #include enum wm8994_type { @@ -22,36 +23,16 @@ enum wm8994_type { WM8958 = 1, }; +======= +>>>>>>> parent of 15f7fab... temp revert rk change struct regulator_dev; struct regulator_bulk_data; #define WM8994_NUM_GPIO_REGS 11 -#define WM8994_NUM_LDO_REGS 2 -#define WM8994_NUM_IRQ_REGS 2 - -#define WM8994_IRQ_TEMP_SHUT 0 -#define WM8994_IRQ_MIC1_DET 1 -#define WM8994_IRQ_MIC1_SHRT 2 -#define WM8994_IRQ_MIC2_DET 3 -#define WM8994_IRQ_MIC2_SHRT 4 -#define WM8994_IRQ_FLL1_LOCK 5 -#define WM8994_IRQ_FLL2_LOCK 6 -#define WM8994_IRQ_SRC1_LOCK 7 -#define WM8994_IRQ_SRC2_LOCK 8 -#define WM8994_IRQ_AIF1DRC1_SIG_DET 9 -#define WM8994_IRQ_AIF1DRC2_SIG_DET 10 -#define WM8994_IRQ_AIF2DRC_SIG_DET 11 -#define WM8994_IRQ_FIFOS_ERR 12 -#define WM8994_IRQ_WSEQ_DONE 13 -#define WM8994_IRQ_DCS_DONE 14 -#define WM8994_IRQ_TEMP_WARN 15 - -/* GPIOs in the chip are numbered from 1-11 */ -#define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN) +#define WM8994_NUM_LDO_REGS 2 struct wm8994 { struct mutex io_lock; - struct mutex irq_lock; enum wm8994_type type; @@ -64,11 +45,6 @@ struct wm8994 { void *control_data; int gpio_base; - int irq_base; - - int irq; - u16 irq_masks_cur[WM8994_NUM_IRQ_REGS]; - u16 irq_masks_cache[WM8994_NUM_IRQ_REGS]; /* Used over suspend/resume */ bool suspended; @@ -91,26 +67,4 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, int count, const u16 *buf); - -/* Helper to save on boilerplate */ -static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq, - irq_handler_t handler, const char *name, - void *data) -{ - if (!wm8994->irq_base) - return -EINVAL; - return request_threaded_irq(wm8994->irq_base + irq, NULL, handler, - IRQF_TRIGGER_RISING, name, - data); -} -static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data) -{ - if (!wm8994->irq_base) - return; - free_irq(wm8994->irq_base + irq, data); -} - -int wm8994_irq_init(struct wm8994 *wm8994); -void wm8994_irq_exit(struct wm8994 *wm8994); - #endif diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index d12f8d635a81..3f8ab55bd6fc 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -29,6 +29,7 @@ struct wm8994_ldo_pdata { #define WM8994_CONFIGURE_GPIO 0x8000 #define WM8994_DRC_REGS 5 +<<<<<<< HEAD #define WM8994_EQ_REGS 20 #define WM8958_MBC_CUTOFF_REGS 20 #define WM8958_MBC_COEFF_REGS 48 @@ -36,6 +37,9 @@ struct wm8994_ldo_pdata { #define WM8958_VSS_HPF_REGS 2 #define WM8958_VSS_REGS 148 #define WM8958_ENH_EQ_REGS 32 +======= +#define WM8994_EQ_REGS 19 +>>>>>>> parent of 15f7fab... temp revert rk change /** * DRC configurations are specified with a label and a set of register @@ -65,6 +69,7 @@ struct wm8994_retune_mobile_cfg { u16 regs[WM8994_EQ_REGS]; }; +<<<<<<< HEAD /** * Multiband compressor configurations are specified with a label and * two sets of values to write. Configurations are expected to be @@ -112,6 +117,10 @@ struct wm8958_enh_eq_cfg { const char *name; u16 regs[WM8958_ENH_EQ_REGS]; }; +======= +#define PCM_BB 1 +#define NO_PCM_BB 0 +>>>>>>> parent of 15f7fab... temp revert rk change struct wm8994_pdata { int gpio_base; @@ -124,7 +133,6 @@ struct wm8994_pdata { struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO]; - int irq_base; /** Base IRQ number for WM8994, required for IRQs */ int num_drc_cfgs; struct wm8994_drc_cfg *drc_cfgs; @@ -165,8 +173,39 @@ struct wm8994_pdata { unsigned int jd_scthr:2; unsigned int jd_thr:2; +<<<<<<< HEAD /* WM8958 microphone bias configuration */ int micbias[2]; +======= + //for phonepad + unsigned int no_earpiece:1; // =1 don't have a earpiece, =0 has a earpiece + unsigned int sp_hp_same_channel:1; + + //BB input can be differential or single ended + unsigned int BB_input_diff:1; // =0 single ended =1 differential + unsigned int BB_class:1;//PCM_BB= 1 NO_PCM_BB=0 + + //If an external amplifier speakers wm8994 enable>0 disable=0 + unsigned int PA_control_pin; + + //wm8994 LDO1_ENA and LDO2_ENA + unsigned int Power_EN_Pin; + char PowerEN_iomux_name[50]; + int PowerEN_iomux_mode; + + //volume + int speaker_incall_vol; //max = 6, min = -21 + int speaker_incall_mic_vol; //max = 30, min = -22 + int speaker_normal_vol; //max = 6, min = -57 + int earpiece_incall_vol; //max = 6, min = -21 + int headset_incall_vol; //max = 6, min = -12 + int headset_incall_mic_vol; //max = 30, min = -22 + int headset_normal_vol; //max = 6, min = -57 + int BT_incall_vol; //max = 30, min = -16 + int BT_incall_mic_vol; //max = 6, min = -57 + int recorder_vol; //max = 60 , min = -16 + +>>>>>>> parent of 15f7fab... temp revert rk change }; #endif diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 1584b5236bbc..5a3ea9025873 100755 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -265,6 +265,12 @@ struct mmc_host { const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ +#if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + unsigned int re_initialized_flags; //in order to begin the rescan ; added by xbw@2011-04-07 + unsigned int doneflag; //added by xbw at 2011-08-27 + int (*sdmmc_host_hw_init)(void *data); +#endif + unsigned int bus_resume_flags; #define MMC_BUSRESUME_MANUAL_RESUME (1 << 0) #define MMC_BUSRESUME_NEEDS_RESUME (1 << 1) diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h old mode 100755 new mode 100644 index 9e87c1cb7270..01f597c5ee53 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -153,6 +153,9 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector); int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); +#ifdef CONFIG_ARCH_RK29 +int regulator_set_suspend_voltage(struct regulator *regulator, int uV); +#endif int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV); int regulator_get_voltage(struct regulator *regulator); @@ -243,6 +246,13 @@ static inline int regulator_set_voltage(struct regulator *regulator, return 0; } +#ifdef CONFIG_ARCH_RK29 +static inline int regulator_set_suspend_voltage(struct regulator *regulator, int uV) +{ + return 0; +} +#endif + static inline int regulator_get_voltage(struct regulator *regulator) { return 0; diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h index a096d24ada1d..492aa649629a 100755 --- a/include/linux/wakelock.h +++ b/include/linux/wakelock.h @@ -72,6 +72,7 @@ int wake_lock_active(struct wake_lock *lock); * number of jiffies until all active wake locks time out. */ long has_wake_lock(int type); +void print_active_wake_locks(int type); #else @@ -84,6 +85,7 @@ 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; } +static inline void print_active_wake_locks(int type) {} #endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index b3edb67a8311..8ba4d6237ab7 100755 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -72,14 +72,23 @@ enum { V4L2_IDENT_OV9650 = 254, V4L2_IDENT_OV9655 = 255, V4L2_IDENT_SOI968 = 256, - V4L2_IDENT_OV9640 = 257, - V4L2_IDENT_OV6650 = 258, - V4L2_IDENT_OV2640 = 259, - V4L2_IDENT_OV9740 = 260, + V4L2_IDENT_OV2655 = 257, /* ddl@rock-chips.com : ov2655 support */ + V4L2_IDENT_OV2659 = 258, + V4L2_IDENT_OV3640 = 259, + V4L2_IDENT_OV5640 = 260, + V4L2_IDENT_OV5642 = 261, + V4L2_IDENT_OV7675 = 262, + V4L2_IDENT_OV2640 = 263, + V4L2_IDENT_OV9640 = 264, + V4L2_IDENT_OV6650 = 265, + V4L2_IDENT_OV9740 = 266, /* module saa7146: reserved range 300-309 */ V4L2_IDENT_SAA7146 = 300, + /* Samsung sensors: reserved range 310-319 */ + V4L2_IDENT_S5K66A = 310, /* ddl@rock-chips.com : s5k66a support */ + /* Conexant MPEG encoder/decoders: reserved range 400-420 */ V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ V4L2_IDENT_CX23415 = 415, @@ -290,6 +299,7 @@ enum { V4L2_IDENT_MT9M001C12STM = 45005, V4L2_IDENT_MT9M111 = 45007, V4L2_IDENT_MT9M112 = 45008, + V4L2_IDENT_MT9D112 = 45009, /* ddl@rock-chips.com : MT9D112 support */ V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */ V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */ V4L2_IDENT_MT9T031 = 45020, @@ -298,6 +308,9 @@ enum { V4L2_IDENT_MT9V111 = 45031, V4L2_IDENT_MT9V112 = 45032, + V4L2_IDENT_MT9P111 = 45033, /* ddl@rock-chips.com : MT9P111 support */ + V4L2_IDENT_MT9D113 = 45034, /* ddl@rock-chips.com : MT9D113 support */ + /* HV7131R CMOS sensor: just ident 46000 */ V4L2_IDENT_HV7131R = 46000, @@ -321,6 +334,19 @@ enum { /* module upd64083: just ident 64083 */ V4L2_IDENT_UPD64083 = 64083, + + V4L2_IDENT_GT2005 = 64099, /* ddl@rock-chips.com : GT2005 support */ + V4L2_IDENT_GC0307 = 64100, /* ddl@rock-chips.com : GC0308 support */ + V4L2_IDENT_GC0308 = 64101, /* ddl@rock-chips.com : GC0308 support */ + V4L2_IDENT_GC0309 = 64102, /* ddl@rock-chips.com : GC0309 support */ + V4L2_IDENT_SIV120B = 64103, /* ddl@rock-chips.com : siv120b support */ + + V4L2_IDENT_GC2015 = 64105, /* ddl@rock-chips.com : gc2015 support */ + V4L2_IDENT_HI253 = 64106, /* ddl@rock-chips.com : hi253 support */ + V4L2_IDENT_HI704 = 64107, /* ddl@rock-chips.com : hi704 support */ + V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ + V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ + /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ }; diff --git a/kernel/power/earlysuspend.c b/kernel/power/earlysuspend.c index b15f02eba45c..e073695d44f5 100644 --- a/kernel/power/earlysuspend.c +++ b/kernel/power/earlysuspend.c @@ -20,6 +20,7 @@ #include /* sys_sync */ #include #include +#include #include "power.h" @@ -98,6 +99,8 @@ static void early_suspend(struct work_struct *work) if (pos->suspend != NULL) { if (debug_mask & DEBUG_VERBOSE) pr_info("early_suspend: calling %pf\n", pos->suspend); + if (debug_mask & DEBUG_VERBOSE) + print_symbol("early_suspend: call %s\n", (unsigned long)pos->suspend); pos->suspend(pos); } } @@ -139,6 +142,8 @@ static void late_resume(struct work_struct *work) if (pos->resume != NULL) { if (debug_mask & DEBUG_VERBOSE) pr_info("late_resume: calling %pf\n", pos->resume); + if (debug_mask & DEBUG_VERBOSE) + print_symbol("late_resume: call %s\n", (unsigned long)pos->resume); pos->resume(pos); } diff --git a/kernel/power/process.c b/kernel/power/process.c index 31338cdeafc4..dd7d22d2c0ff 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -117,6 +117,7 @@ static int try_to_freeze_tasks(bool sig_only) printk("\n"); printk(KERN_ERR "Freezing of %s aborted\n", sig_only ? "user space " : "tasks "); + print_active_wake_locks(WAKE_LOCK_SUSPEND); } else { printk("\n"); diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c index 2ee459fe4456..527d5a9addd8 100644 --- a/kernel/power/wakelock.c +++ b/kernel/power/wakelock.c @@ -202,28 +202,33 @@ static void expire_wake_lock(struct wake_lock *lock) } /* Caller must acquire the list_lock spinlock */ -static void print_active_locks(int type) +static void print_active_locks_locked(int type) { struct wake_lock *lock; - bool print_expired = true; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); list_for_each_entry(lock, &active_wake_locks[type], link) { if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) { long timeout = lock->expires - jiffies; - if (timeout > 0) - pr_info("active wake lock %s, time left %ld\n", - lock->name, timeout); - else if (print_expired) + if (timeout <= 0) pr_info("wake lock %s, expired\n", lock->name); - } else { + else + pr_info("active wake lock %s, time left %ld.%03lu\n", + lock->name, timeout / HZ, + (timeout % HZ) * MSEC_PER_SEC / HZ); + } else pr_info("active wake lock %s\n", lock->name); - if (!(debug_mask & DEBUG_EXPIRE)) - print_expired = false; - } } } +void print_active_wake_locks(int type) +{ + unsigned long irqflags; + spin_lock_irqsave(&list_lock, irqflags); + print_active_locks_locked(type); + spin_unlock_irqrestore(&list_lock, irqflags); +} + static long has_wake_lock_locked(int type) { struct wake_lock *lock, *n; @@ -250,7 +255,7 @@ long has_wake_lock(int type) spin_lock_irqsave(&list_lock, irqflags); ret = has_wake_lock_locked(type); if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND) - print_active_locks(type); + print_active_locks_locked(type); spin_unlock_irqrestore(&list_lock, irqflags); return ret; } @@ -297,7 +302,7 @@ static void expire_wake_locks(unsigned long data) pr_info("expire_wake_locks: start\n"); spin_lock_irqsave(&list_lock, irqflags); if (debug_mask & DEBUG_SUSPEND) - print_active_locks(WAKE_LOCK_SUSPEND); + print_active_locks_locked(WAKE_LOCK_SUSPEND); has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND); if (debug_mask & DEBUG_EXPIRE) pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock); @@ -337,6 +342,7 @@ void wake_lock_init(struct wake_lock *lock, int type, const char *name) if (name) lock->name = name; BUG_ON(!lock->name); + BUG_ON(lock->flags & WAKE_LOCK_INITIALIZED); if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock_init name=%s\n", lock->name); @@ -503,7 +509,7 @@ void wake_unlock(struct wake_lock *lock) } if (lock == &main_wake_lock) { if (debug_mask & DEBUG_SUSPEND) - print_active_locks(WAKE_LOCK_SUSPEND); + print_active_locks_locked(WAKE_LOCK_SUSPEND); #ifdef CONFIG_WAKELOCK_STAT update_sleep_wait_stats_locked(0); #endif diff --git a/kernel/sys.c b/kernel/sys.c index e4128b278f23..378381e9dd70 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -49,6 +49,18 @@ #include #include #include +/*************** +* DEBUG +****************/ +#define RESTART_DEBUG +#ifdef RESTART_DEBUG +#define restart_dbg(format, arg...) \ + printk("RESTART_DEBUG : " format "\n" , ## arg) +#else +#define restart_dbg(format, arg...) do {} while (0) +#endif + + #ifndef SET_UNALIGN_CTL # define SET_UNALIGN_CTL(a,b) (-EINVAL) @@ -329,6 +341,11 @@ void kernel_restart_prepare(char *cmd) */ void kernel_restart(char *cmd) { + /* + * debug trace + */ + restart_dbg("%s->%d->cmd=%s",__FUNCTION__,__LINE__,cmd); + kernel_restart_prepare(cmd); if (!cmd) printk(KERN_EMERG "Restarting system.\n"); @@ -418,6 +435,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, mutex_lock(&reboot_mutex); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: + /* + * debug trace + */ + restart_dbg("%s->%d->cmd=%x",__FUNCTION__,__LINE__,cmd); + kernel_restart(NULL); break; @@ -435,6 +457,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, panic("cannot halt"); case LINUX_REBOOT_CMD_POWER_OFF: + /* + * debug trace + */ + restart_dbg("%s->%d->cmd=%x",__FUNCTION__,__LINE__,cmd); + kernel_power_off(); do_exit(0); break; @@ -445,7 +472,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, break; } buffer[sizeof(buffer) - 1] = '\0'; - + /* + * debug trace + */ + restart_dbg("%s->%d->cmd=%x args=%s",__FUNCTION__,__LINE__,cmd,buffer); + kernel_restart(buffer); break; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a096df2..bd370c66e76a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC select SND_SOC_CS42L51 if I2C + select SND_SOC_CS42L52 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CX20442 @@ -73,6 +74,9 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C + select SND_SOC_alc5621 if I2C + select SND_SOC_alc5631 if I2C + select SND_SOC_RT5625 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C select SND_SOC_WM8915 if I2C @@ -158,6 +162,9 @@ config SND_SOC_CQ0093VC config SND_SOC_CS42L51 tristate +config SND_SOC_CS42L52 + tristate + # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate @@ -305,6 +312,15 @@ config SND_SOC_WM8804 config SND_SOC_WM8900 tristate +config SND_SOC_alc5621 + tristate + +config SND_SOC_alc5631 + tristate + +config SND_SOC_RT5625 + tristate + config SND_SOC_WM8903 tristate @@ -371,6 +387,10 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate +config SND_SOC_RK1000 + tristate + depends on RK1000_CONTROL + # Amp config SND_SOC_LM4857 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd8558406ef0..d4f5f1599532 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -57,6 +57,10 @@ snd-soc-wm8770-objs := wm8770.o snd-soc-wm8776-objs := wm8776.o snd-soc-wm8804-objs := wm8804.o snd-soc-wm8900-objs := wm8900.o +snd-soc-alc5621-objs := alc5621.o +snd-soc-alc5631-objs := rt5631.o +snd-soc-rt5625-objs := rt5625.o +snd-soc-cs42l52-objs := cs42l52.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8904-objs := wm8904.o snd-soc-wm8915-objs := wm8915.o @@ -80,6 +84,7 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o +snd-soc-rk1000-objs := rk1000_codec.o snd-soc-jz4740-codec-objs := jz4740.o # Amp @@ -149,6 +154,10 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o +obj-$(CONFIG_SND_SOC_alc5621) += snd-soc-alc5621.o +obj-$(CONFIG_SND_SOC_alc5631) += snd-soc-alc5631.o +obj-$(CONFIG_SND_SOC_RT5625) += snd-soc-rt5625.o +obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o obj-$(CONFIG_SND_SOC_WM8915) += snd-soc-wm8915.o @@ -172,6 +181,7 @@ obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o +obj-$(CONFIG_SND_SOC_RK1000) += snd-soc-rk1000.o # Amp obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 449ea09a193d..979e57fdcee5 100755 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -32,9 +32,19 @@ #include #include #include +#include +#include +#include #include "wm8900.h" + +#if 0 +#define WM8900_DBG(x...) printk(KERN_INFO x) +#else +#define WM8900_DBG(x...) +#endif + /* WM8900 register space */ #define WM8900_REG_RESET 0x0 #define WM8900_REG_ID 0x0 @@ -113,8 +123,8 @@ #define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e) #define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000) -#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0 -#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c +#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0x1c +#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0xe0 #define WM8900_REG_DACCTRL_MUTE 0x004 #define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100 @@ -136,6 +146,27 @@ #define WM8900_REG_HPCTL1_HP_SHORT2 0x04 #define WM8900_LRC_MASK 0xfc00 +#define SPK_CON RK29_PIN6_PB6 + +#define WM8900_NO_POWEROFF /* Do not close codec except suspend or poweroff */ + +#define WM8900_IS_SHUTDOWN 0 +#define WM8900_IS_STARTUP 1 + +#define WM8900_WORK_NULL 0 +#define WM8900_WORK_POWERDOWN_PLAYBACK 1 +#define WM8900_WORK_POWERDOWN_CAPTURE 2 +#define WM8900_WORK_POWERDOWN_PLAYBACK_CAPTURE 3 +#define WM8900_WORK_HW_SET 4 + +static void wm8900_work(struct work_struct *work); + +static struct workqueue_struct *wm8900_workq; +static DECLARE_DELAYED_WORK(delayed_work, wm8900_work); +static int wm8900_current_status = WM8900_IS_SHUTDOWN, wm8900_work_type = WM8900_WORK_NULL; + +static struct snd_soc_codec *wm8900_codec; +static bool isSPKon = true; struct wm8900_priv { enum snd_soc_control_type control_type; @@ -192,423 +223,126 @@ static int wm8900_volatile_register(struct snd_soc_codec *codec, unsigned int re static void wm8900_reset(struct snd_soc_codec *codec) { + WM8900_DBG("Enter:%s, %d, codec=0x%8X \n", __FUNCTION__, __LINE__,codec); + snd_soc_write(codec, WM8900_REG_RESET, 0); memcpy(codec->reg_cache, wm8900_reg_defaults, sizeof(wm8900_reg_defaults)); } -static int wm8900_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +void codec_set_spk(bool on) { - struct snd_soc_codec *codec = w->codec; - u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Clamp headphone outputs */ - hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | - WM8900_REG_HPCTL1_HP_CLAMP_OP; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - break; - - case SND_SOC_DAPM_POST_PMU: - /* Enable the input stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP; - hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | - WM8900_REG_HPCTL1_HP_SHORT2 | - WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - msleep(400); - - /* Enable the output stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; - hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Remove the shorts */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - break; - - case SND_SOC_DAPM_PRE_PMD: - /* Short the output */ - hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Disable the output stage */ - hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - - /* Clamp the outputs and power down input */ - hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | - WM8900_REG_HPCTL1_HP_CLAMP_OP; - hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); - break; - - case SND_SOC_DAPM_POST_PMD: - /* Disable everything */ - snd_soc_write(codec, WM8900_REG_HPCTL1, 0); - break; - - default: - BUG(); + isSPKon = on; + if (on) { +#ifdef SPK_CON + gpio_set_value(SPK_CON, GPIO_HIGH); +#endif + } else { +#ifdef SPK_CON + gpio_set_value(SPK_CON, GPIO_LOW); +#endif } - - return 0; } -static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0); - -static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0); - -static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0); - -static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0); - -static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); - -static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); - -static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0); - -static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); - -static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; - -static const struct soc_enum mic_bias_level = -SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); - -static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; - -static const struct soc_enum dac_mute_rate = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); - -static const char *dac_deemphasis_txt[] = { - "Disabled", "32kHz", "44.1kHz", "48kHz" -}; - -static const struct soc_enum dac_deemphasis = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); - -static const char *adc_hpf_cut_txt[] = { - "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" -}; - -static const struct soc_enum adc_hpf_cut = -SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); - -static const char *lr_txt[] = { - "Left", "Right" -}; - -static const struct soc_enum aifl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); - -static const struct soc_enum aifr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); - -static const struct soc_enum dacl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); +EXPORT_SYMBOL_GPL(codec_set_spk); -static const struct soc_enum dacr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); - -static const char *sidetone_txt[] = { - "Disabled", "Left ADC", "Right ADC" -}; +static void wm8900_powerdown(void) +{ + printk("Power down wm8900\n"); +#ifndef WM8900_NO_POWEROFF + gpio_set_value(RK29_PIN1_PD6, GPIO_LOW); +#endif -static const struct soc_enum dacl_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); - -static const struct soc_enum dacr_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); - -static const struct snd_kcontrol_new wm8900_snd_controls[] = { -SOC_ENUM("Mic Bias Level", mic_bias_level), - -SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0, - in_pga_tlv), -SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1), -SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0), - -SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0, - in_pga_tlv), -SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1), -SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0), - -SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), -SOC_ENUM("DAC Mute Rate", dac_mute_rate), -SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), -SOC_ENUM("DAC Deemphasis", dac_deemphasis), -SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, - 12, 1, 0), - -SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0), -SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut), -SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0), -SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0, - adc_svol_tlv), -SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0, - adc_svol_tlv), -SOC_ENUM("Left Digital Audio Source", aifl_src), -SOC_ENUM("Right Digital Audio Source", aifr_src), - -SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0, - dac_boost_tlv), -SOC_ENUM("Left DAC Source", dacl_src), -SOC_ENUM("Right DAC Source", dacr_src), -SOC_ENUM("Left DAC Sidetone", dacl_sidetone), -SOC_ENUM("Right DAC Sidetone", dacr_sidetone), -SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0), - -SOC_DOUBLE_R_TLV("Digital Playback Volume", - WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV, - 1, 96, 0, dac_tlv), -SOC_DOUBLE_R_TLV("Digital Capture Volume", - WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv), - -SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0, - out_mix_tlv), - -SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0, - out_mix_tlv), -SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0, - out_mix_tlv), - -SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0, - in_boost_tlv), -SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0, - in_boost_tlv), - -SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 0, 63, 0, out_pga_tlv), -SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 6, 1, 1), -SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, - 7, 1, 0), - -SOC_DOUBLE_R_TLV("LINEOUT2 Volume", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, - 0, 63, 0, out_pga_tlv), -SOC_DOUBLE_R("LINEOUT2 Switch", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1), -SOC_DOUBLE_R("LINEOUT2 ZC Switch", - WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0), -SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, - 0, 1, 1), + snd_soc_write(wm8900_codec, WM8900_REG_POWER1, 0x210D); -}; - -static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = -SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); + if (wm8900_current_status != WM8900_IS_SHUTDOWN) { +#ifdef SPK_CON + gpio_set_value(SPK_CON, GPIO_LOW); +#endif + msleep(20); + snd_soc_write(wm8900_codec, WM8900_REG_RESET, 0); + wm8900_current_status = WM8900_IS_SHUTDOWN; + } +} -static const struct snd_kcontrol_new wm8900_dapm_routput2_control = -SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0); +static void wm8900_set_hw(struct snd_soc_codec *codec) +{ + u16 reg; -static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { -SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), -SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), -SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0), -SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0), -SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0), -}; + if (wm8900_current_status & WM8900_IS_STARTUP) + return; + + printk("Power up wm8900\n"); +//CLK , PATH, VOL,POW. + + snd_soc_write(codec, WM8900_REG_HPCTL1, 0x30); + snd_soc_write(codec, WM8900_REG_POWER1, 0x0100); + snd_soc_write(codec, WM8900_REG_POWER3, 0x60); + snd_soc_write(codec, WM8900_REG_POWER1, 0x0101); + msleep(400); + snd_soc_write(codec, WM8900_REG_POWER1, 0x0109); + snd_soc_write(codec, WM8900_REG_ADDCTL, 0x02); + snd_soc_write(codec, WM8900_REG_POWER1, 0x09); + snd_soc_write(codec, WM8900_REG_POWER3, 0xEF); + snd_soc_write(codec, WM8900_REG_DACCTRL, WM8900_REG_DACCTRL_MUTE); + snd_soc_write(codec, WM8900_REG_LOUTMIXCTL1, 0x150); + snd_soc_write(codec, WM8900_REG_ROUTMIXCTL1, 0x150); + + snd_soc_write(codec, WM8900_REG_HPCTL1, 0xB0); + snd_soc_write(codec, WM8900_REG_HPCTL1, 0xF0); + snd_soc_write(codec, WM8900_REG_HPCTL1, 0xC0); + + //for recorder + snd_soc_write(codec, WM8900_REG_POWER1, 0x210D); + snd_soc_write(codec, WM8900_REG_POWER2, 0xC1AF); + + snd_soc_write(codec, WM8900_REG_LADC_DV, 0x01C0); + snd_soc_write(codec, WM8900_REG_RADC_DV, 0x01C0); + + snd_soc_write(codec, WM8900_REG_INCTL, 0x0040); + + snd_soc_write(codec, WM8900_REG_LINVOL, 0x011A); + snd_soc_write(codec, WM8900_REG_RINVOL, 0x011A); + snd_soc_write(codec, WM8900_REG_INBOOSTMIX1, 0x0042); + snd_soc_write(codec, WM8900_REG_INBOOSTMIX2, 0x0042); + snd_soc_write(codec, WM8900_REG_ADCPATH, 0x0055); -static const struct snd_kcontrol_new wm8900_routmix_controls[] = { -SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0), -SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0), -SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0), -SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0), -SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0), -}; + reg = snd_soc_read(codec, WM8900_REG_DACCTRL); -static const struct snd_kcontrol_new wm8900_linmix_controls[] = { -SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1), -SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1), -SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1), -SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), -}; + reg &= ~WM8900_REG_DACCTRL_MUTE; + snd_soc_write(codec, WM8900_REG_DACCTRL, reg); -static const struct snd_kcontrol_new wm8900_rinmix_controls[] = { -SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1), -SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1), -SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1), -SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), -}; + snd_soc_write(codec, WM8900_REG_LOUT1CTL, 0x130); + snd_soc_write(codec, WM8900_REG_ROUT1CTL, 0x130); -static const struct snd_kcontrol_new wm8900_linpga_controls[] = { -SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0), -SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0), -SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0), -}; + /* Turn up vol slowly, for HP out pop noise */ -static const struct snd_kcontrol_new wm8900_rinpga_controls[] = { -SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0), -SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0), -SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), -}; + for (reg = 0; reg <= 0x33; reg += 0x10) { + snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x100 + reg); + snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x100 + reg); + msleep(5); + } + snd_soc_write(codec, WM8900_REG_LOUT2CTL, 0x133); + snd_soc_write(codec, WM8900_REG_ROUT2CTL, 0x133); -static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; - -static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); - -static const struct snd_kcontrol_new wm8900_lineout2_lp = -SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); - -static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = { - -/* Externally visible pins */ -SND_SOC_DAPM_OUTPUT("LINEOUT1L"), -SND_SOC_DAPM_OUTPUT("LINEOUT1R"), -SND_SOC_DAPM_OUTPUT("LINEOUT2L"), -SND_SOC_DAPM_OUTPUT("LINEOUT2R"), -SND_SOC_DAPM_OUTPUT("HP_L"), -SND_SOC_DAPM_OUTPUT("HP_R"), - -SND_SOC_DAPM_INPUT("RINPUT1"), -SND_SOC_DAPM_INPUT("LINPUT1"), -SND_SOC_DAPM_INPUT("RINPUT2"), -SND_SOC_DAPM_INPUT("LINPUT2"), -SND_SOC_DAPM_INPUT("RINPUT3"), -SND_SOC_DAPM_INPUT("LINPUT3"), -SND_SOC_DAPM_INPUT("AUX"), - -SND_SOC_DAPM_VMID("VMID"), - -/* Input */ -SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0, - wm8900_linpga_controls, - ARRAY_SIZE(wm8900_linpga_controls)), -SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0, - wm8900_rinpga_controls, - ARRAY_SIZE(wm8900_rinpga_controls)), - -SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0, - wm8900_linmix_controls, - ARRAY_SIZE(wm8900_linmix_controls)), -SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0, - wm8900_rinmix_controls, - ARRAY_SIZE(wm8900_rinmix_controls)), - -SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0), - -SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0), - -/* Output */ -SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0), - -SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0, - wm8900_hp_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), - -SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0), - -SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp), -SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0), - -SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0, - wm8900_loutmix_controls, - ARRAY_SIZE(wm8900_loutmix_controls)), -SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0, - wm8900_routmix_controls, - ARRAY_SIZE(wm8900_routmix_controls)), -}; + msleep(20); -/* Target, Path, Source */ -static const struct snd_soc_dapm_route audio_map[] = { -/* Inputs */ -{"Left Input PGA", "LINPUT1 Switch", "LINPUT1"}, -{"Left Input PGA", "LINPUT2 Switch", "LINPUT2"}, -{"Left Input PGA", "LINPUT3 Switch", "LINPUT3"}, - -{"Right Input PGA", "RINPUT1 Switch", "RINPUT1"}, -{"Right Input PGA", "RINPUT2 Switch", "RINPUT2"}, -{"Right Input PGA", "RINPUT3 Switch", "RINPUT3"}, - -{"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"}, -{"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"}, -{"Left Input Mixer", "AUX Switch", "AUX"}, -{"Left Input Mixer", "Input PGA Switch", "Left Input PGA"}, - -{"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"}, -{"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"}, -{"Right Input Mixer", "AUX Switch", "AUX"}, -{"Right Input Mixer", "Input PGA Switch", "Right Input PGA"}, - -{"ADCL", NULL, "Left Input Mixer"}, -{"ADCR", NULL, "Right Input Mixer"}, - -/* Outputs */ -{"LINEOUT1L", NULL, "LINEOUT1L PGA"}, -{"LINEOUT1L PGA", NULL, "Left Output Mixer"}, -{"LINEOUT1R", NULL, "LINEOUT1R PGA"}, -{"LINEOUT1R PGA", NULL, "Right Output Mixer"}, - -{"LINEOUT2L PGA", NULL, "Left Output Mixer"}, -{"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"}, -{"LINEOUT2 LP", "Enabled", "Left Output Mixer"}, -{"LINEOUT2L", NULL, "LINEOUT2 LP"}, - -{"LINEOUT2R PGA", NULL, "Right Output Mixer"}, -{"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"}, -{"LINEOUT2 LP", "Enabled", "Right Output Mixer"}, -{"LINEOUT2R", NULL, "LINEOUT2 LP"}, - -{"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"}, -{"Left Output Mixer", "AUX Bypass Switch", "AUX"}, -{"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, -{"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, -{"Left Output Mixer", "DACL Switch", "DACL"}, - -{"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"}, -{"Right Output Mixer", "AUX Bypass Switch", "AUX"}, -{"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, -{"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, -{"Right Output Mixer", "DACR Switch", "DACR"}, - -/* Note that the headphone output stage needs to be connected - * externally to LINEOUT2 via DC blocking capacitors. Other - * configurations are not supported. - * - * Note also that left and right headphone paths are treated as a - * mono path. - */ -{"Headphone Amplifier", NULL, "LINEOUT2 LP"}, -{"Headphone Amplifier", NULL, "LINEOUT2 LP"}, -{"HP_L", NULL, "Headphone Amplifier"}, -{"HP_R", NULL, "Headphone Amplifier"}, -}; +#ifdef SPK_CON + if (isSPKon) { + gpio_set_value(SPK_CON, GPIO_HIGH); + } +#endif +#ifndef WM8900_NO_POWEROFF + msleep(350); + gpio_set_value(RK29_PIN1_PD6, GPIO_HIGH); +#endif + wm8900_current_status |= WM8900_IS_STARTUP; +} -static int wm8900_add_widgets(struct snd_soc_codec *codec) +static void wm8900_work(struct work_struct *work) { +<<<<<<< HEAD struct snd_soc_dapm_context *dapm = &codec->dapm; snd_soc_dapm_new_controls(dapm, wm8900_dapm_widgets, @@ -616,6 +350,27 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); return 0; +======= + WM8900_DBG("Enter::wm8900_work : wm8900_work_type = %d\n", wm8900_work_type); + + switch (wm8900_work_type) { + case WM8900_WORK_POWERDOWN_PLAYBACK : + break; + case WM8900_WORK_POWERDOWN_CAPTURE: + snd_soc_write(wm8900_codec, WM8900_REG_POWER1, 0x210D); + break; + case WM8900_WORK_POWERDOWN_PLAYBACK_CAPTURE: + wm8900_powerdown(); + break; + case WM8900_WORK_HW_SET: + wm8900_set_hw(wm8900_codec); + break; + default: + break; + } + + wm8900_work_type = WM8900_WORK_NULL; +>>>>>>> parent of 15f7fab... temp revert rk change } static int wm8900_hw_params(struct snd_pcm_substream *substream, @@ -626,6 +381,8 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; u16 reg; + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60; switch (params_format(params)) { @@ -646,17 +403,6 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, snd_soc_write(codec, WM8900_REG_AUDIO1, reg); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); - - if (params_rate(params) <= 24000) - reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; - else - reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; - - snd_soc_write(codec, WM8900_REG_DACCTRL, reg); - } - return 0; } @@ -680,8 +426,10 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, unsigned int K, Ndiv, Nmod, target; unsigned int div; - BUG_ON(!Fout); + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + BUG_ON(!Fout); + /* The FLL must run at 90-100MHz which is then scaled down to * the output value by FLLCLK_DIV. */ target = Fout; @@ -744,6 +492,8 @@ static int wm8900_set_fll(struct snd_soc_codec *codec, struct _fll_div fll_div; unsigned int reg; + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out) return 0; @@ -811,6 +561,9 @@ reenable: static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { + + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); } @@ -820,6 +573,8 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; + WM8900_DBG("Enter:%s, %d, div_id=%d, div=%d \n", __FUNCTION__, __LINE__, div_id, div); + switch (div_id) { case WM8900_BCLK_DIV: reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); @@ -870,6 +625,8 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; unsigned int clocking1, aif1, aif3, aif4; + WM8900_DBG("Enter:%s, %d, fmt=0x%08X \n", __FUNCTION__, __LINE__, fmt); + clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1); aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1); aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3); @@ -979,24 +736,106 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) { - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; + WM8900_DBG("Enter:%s, %d , mute = %d \n", __FUNCTION__, __LINE__, mute); - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); + return 0; +} - if (mute) - reg |= WM8900_REG_DACCTRL_MUTE; - else - reg &= ~WM8900_REG_DACCTRL_MUTE; +static int wm8900_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *codec_dai = machine->codec_dai; - snd_soc_write(codec, WM8900_REG_DACCTRL, reg); + WM8900_DBG("Enter::%s----%d substream->stream:%s \n",__FUNCTION__,__LINE__, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE"); + + cancel_delayed_work_sync(&delayed_work); + wm8900_work_type = WM8900_WORK_NULL; + + wm8900_set_hw(codec); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE || + codec_dai->capture.active) { + snd_soc_write(codec, WM8900_REG_POWER1, 0x211D); + } else if (!codec_dai->capture.active) { + snd_soc_write(codec, WM8900_REG_POWER1, 0x210D); + } + + return 0; +} + +static void wm8900_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *codec_dai = machine->codec_dai; + + WM8900_DBG("Enter::%s----%d substream->stream:%s \n",__FUNCTION__,__LINE__, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE"); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + wm8900_work_type == WM8900_WORK_NULL) { + cancel_delayed_work_sync(&delayed_work); + wm8900_work_type = WM8900_WORK_POWERDOWN_CAPTURE; + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(3000)); + } +#ifdef WM8900_NO_POWEROFF + return; /* Let codec not going to power off for pop noise */ +#endif + + if (!codec_dai->capture.active && !codec_dai->playback.active) { + + cancel_delayed_work_sync(&delayed_work); + wm8900_work_type = WM8900_WORK_NULL; + + /* If codec is already shutdown, return */ + if (wm8900_current_status == WM8900_IS_SHUTDOWN) + return; + + WM8900_DBG("Is going to power down wm8900\n"); + + wm8900_work_type = WM8900_WORK_POWERDOWN_PLAYBACK_CAPTURE; + + /* If codec is useless, queue work to close it */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(1000)); + } else { + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(3000)); + } + } +} + +static int wm8900_trigger(struct snd_pcm_substream *substream, + int status, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *codec_dai = machine->codec_dai; + + WM8900_DBG("Enter::%s----%d status = %d substream->stream:%s \n",__FUNCTION__, __LINE__, status, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE"); + + if(status == 1 || status == 0){ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + codec_dai->playback.active = status; + }else{ + codec_dai->capture.active = status; + } + } return 0; } -#define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define WM8900_RATES SNDRV_PCM_RATE_44100 #define WM8900_PCM_FORMATS \ (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ @@ -1008,6 +847,9 @@ static struct snd_soc_dai_ops wm8900_dai_ops = { .set_pll = wm8900_set_dai_pll, .set_fmt = wm8900_set_dai_fmt, .digital_mute = wm8900_digital_mute, + .startup = wm8900_startup, + .shutdown = wm8900_shutdown, + .trigger = wm8900_trigger, }; static struct snd_soc_dai_driver wm8900_dai = { @@ -1034,6 +876,11 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, { u16 reg; + WM8900_DBG("Enter:%s, %d, level=0x%08X \n", __FUNCTION__, __LINE__, level); + + codec->bias_level = level; + return 0; + switch (level) { case SND_SOC_BIAS_ON: /* Enable thermal shutdown */ @@ -1118,7 +965,12 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, WM8900_REG_POWER2_SYSCLK_ENA); break; } +<<<<<<< HEAD codec->dapm.bias_level = level; +======= + + codec->bias_level = level; +>>>>>>> parent of 15f7fab... temp revert rk change return 0; } @@ -1129,6 +981,15 @@ static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state) int fll_in = wm8900->fll_in; int ret; + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + + cancel_delayed_work_sync(&delayed_work); + wm8900_work_type = WM8900_WORK_NULL; + +#ifdef WM8900_NO_POWEROFF + wm8900_powerdown(); +#endif + /* Stop the FLL in an orderly fashion */ ret = wm8900_set_fll(codec, 0, 0, 0); if (ret != 0) { @@ -1147,17 +1008,12 @@ static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state) static int wm8900_resume(struct snd_soc_codec *codec) { struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); - u16 *cache; - int i, ret; - - cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults), - GFP_KERNEL); - wm8900_reset(codec); wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Restart the FLL? */ if (wm8900->fll_out) { + int ret; int fll_out = wm8900->fll_out; int fll_in = wm8900->fll_in; @@ -1171,20 +1027,48 @@ static int wm8900_resume(struct snd_soc_codec *codec) } } +<<<<<<< HEAD if (cache) { for (i = 0; i < WM8900_MAXREG; i++) snd_soc_write(codec, i, cache[i]); kfree(cache); } else dev_err(codec->dev, "Unable to allocate register cache\n"); +======= +#ifdef WM8900_NO_POWEROFF + if (wm8900_current_status == WM8900_IS_SHUTDOWN) { + + cancel_delayed_work_sync(&delayed_work); + wm8900_work_type = WM8900_WORK_HW_SET; + queue_delayed_work(wm8900_workq, &delayed_work, + msecs_to_jiffies(1000)); + } +#endif +>>>>>>> parent of 15f7fab... temp revert rk change return 0; } +<<<<<<< HEAD static int wm8900_probe(struct snd_soc_codec *codec) { struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); int ret = 0, reg; +======= +static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8900_priv *wm8900; + struct snd_soc_codec *codec; + unsigned int reg; + int ret; + + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + + wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); + if (wm8900 == NULL) + return -ENOMEM; +>>>>>>> parent of 15f7fab... temp revert rk change ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type); if (ret != 0) { @@ -1203,6 +1087,7 @@ static int wm8900_probe(struct snd_soc_codec *codec) /* Turn the chip on */ wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +<<<<<<< HEAD /* Latch the volume update bits */ snd_soc_write(codec, WM8900_REG_LINVOL, snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100); @@ -1231,6 +1116,9 @@ static int wm8900_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8900_snd_controls, ARRAY_SIZE(wm8900_snd_controls)); wm8900_add_widgets(codec); +======= + wm8900_dai.dev = &i2c->dev; +>>>>>>> parent of 15f7fab... temp revert rk change return 0; } @@ -1276,10 +1164,17 @@ static int __devinit wm8900_spi_probe(struct spi_device *spi) static int __devexit wm8900_spi_remove(struct spi_device *spi) { +<<<<<<< HEAD snd_soc_unregister_codec(&spi->dev); kfree(spi_get_drvdata(spi)); return 0; } +======= + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + + snd_soc_unregister_dai(&wm8900_dai); + snd_soc_unregister_codec(wm8900_codec); +>>>>>>> parent of 15f7fab... temp revert rk change static struct spi_driver wm8900_spi_driver = { .driver = { @@ -1319,6 +1214,12 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client) return 0; } +void wm8900_i2c_shutdown(struct i2c_client *client) +{ + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + wm8900_powerdown(); +} + static const struct i2c_device_id wm8900_i2c_id[] = { { "wm8900", 0 }, { } @@ -1330,8 +1231,14 @@ static struct i2c_driver wm8900_i2c_driver = { .name = "wm8900-codec", .owner = THIS_MODULE, }, +<<<<<<< HEAD .probe = wm8900_i2c_probe, .remove = __devexit_p(wm8900_i2c_remove), +======= + .probe = wm8900_i2c_probe, + .remove = __devexit_p(wm8900_i2c_remove), + .shutdown = wm8900_i2c_shutdown, +>>>>>>> parent of 15f7fab... temp revert rk change .id_table = wm8900_i2c_id, }; #endif @@ -1339,6 +1246,7 @@ static struct i2c_driver wm8900_i2c_driver = { static int __init wm8900_modinit(void) { int ret = 0; +<<<<<<< HEAD #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8900_i2c_driver); if (ret != 0) { @@ -1353,6 +1261,48 @@ static int __init wm8900_modinit(void) ret); } #endif +======= + +#ifndef WM8900_NO_POWEROFF + gpio_set_value(RK29_PIN1_PD6, GPIO_LOW); +#endif + + WM8900_DBG("Enter:%s, %d \n", __FUNCTION__, __LINE__); + + if (!wm8900_codec) { + dev_err(&pdev->dev, "I2C client not yet instantiated\n"); + return -ENODEV; + } + +#if defined(SPK_CON) + gpio_request(SPK_CON,NULL); + gpio_direction_output(SPK_CON, GPIO_LOW); +#endif + + codec = wm8900_codec; + socdev->card->codec = codec; + + /* Register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register new PCMs\n"); + goto pcm_err; + } + + wm8900_workq = create_freezeable_workqueue("wm8900"); + if (wm8900_workq == NULL) { + kfree(codec); + return -ENOMEM; + } + +#ifdef WM8900_NO_POWEROFF + wm8900_set_hw(codec); +#endif + + return ret; + +pcm_err: +>>>>>>> parent of 15f7fab... temp revert rk change return ret; } module_init(wm8900_modinit); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 039b9532b270..d6af67fb39f7 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -165,6 +165,7 @@ static unsigned int do_i2c_read(struct snd_soc_codec *codec, xfer[0].flags = 0; xfer[0].len = reglen; xfer[0].buf = reg; + xfer[0].scl_rate = 100 * 1000; /* Read data */ xfer[1].addr = client->addr; -- 2.34.1