*.lzo
*.patch
*.gcno
+Untitled Project.*
#
# Top-level generic files
/System.map
/Module.markers
/Module.symvers
+/kernel.img
#
# git files that we don't want to ignore even it they are dot-files
bool "Rockchip Soc Rk29"
select CPU_V7
select HAVE_CLK
+ select CLKDEV_LOOKUP
select COMMON_CLKDEV
select HAVE_SCHED_CLOCK
select ARCH_HAS_CPUFREQ
#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}
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);
}
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);
}
}
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)
{
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);
* 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;
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
.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
-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
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/skbuff.h>
#include <linux/spi/spi.h>
#include <linux/mmc/host.h>
#include <linux/android_pmem.h>
+#ifdef CONFIG_USB_ANDROID
#include <linux/usb/android_composite.h>
+#endif
#include <mach/hardware.h>
#include <asm/setup.h>
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)
}
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,
#include <linux/list.h>
#include <linux/module.h>
#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+#include <linux/clkdev.h>
+#else
#include <asm/clkdev.h>
+#endif
#include <mach/rk29_iomap.h>
#include <mach/cru.h>
#include <mach/pmu.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#ifdef CONFIG_USB_ANDROID
#include <linux/usb/android_composite.h>
+#endif
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <asm/pmu.h>
};
#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},
.platform_data = &rndis_pdata,
},
};
+#endif
#ifdef CONFIG_USB11_HOST
static struct resource usb11_host_resource[] = {
+++ /dev/null
-/* 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 <linux/clk.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/sysdev.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/rk29_iomap.h>
-#include <mach/iomux.h>
-#include <asm/gpio.h>
-
-
-#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<<offset;
- else
- temp &= ~(1<<offset);
-
- __raw_writel(temp,pGrfRegBase + 0x78 +(rk29_gpio->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
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);
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;
#include <linux/version.h>
#include <mach/rk29_iomap.h>
- /* 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
ldreq \rx, = RK29_UART1_PHYS
ldrne \rx, = RK29_UART1_BASE
.endm
+#endif
#define UART_SHIFT 2
#include <asm/hardware/debug-8250.S>
*/
#ifndef __ARCH_ARM_MACH_RK29_GPIO_H
#define __ARCH_ARM_MACH_RK29_GPIO_H
-#include <asm/irq.h>
+
+#include <mach/irqs.h>
typedef enum eGPIOPinLevel
{
#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)
#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)
#include <asm/errno.h>
#include <asm-generic/gpio.h> /* cansleep wrappers */
-#include <mach/irqs.h>
#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
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
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/timer.h>
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
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
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
source "drivers/spi/Kconfig"
+source "drivers/adc/Kconfig"
+
+source "drivers/headset_observe/Kconfig"
+
source "drivers/pps/Kconfig"
source "drivers/ptp/Kconfig"
source "drivers/clocksource/Kconfig"
+source "drivers/cmmb/Kconfig"
+
+source "drivers/testcode/Kconfig"
+
+source "drivers/smc/Kconfig"
+
+source "drivers/cir/Kconfig"
+
endmenu
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/
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/
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/
#include <linux/async.h>
#include <linux/suspend.h>
#include <linux/timer.h>
+#ifdef CONFIG_ARCH_RK29
+#include <linux/console.h>
+#endif
#include "../base.h"
#include "power.h"
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);
#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)
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
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
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
--- /dev/null
+/* 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 <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/rk29_iomap.h>
+#include <mach/iomux.h>
+#include <asm/gpio.h>
+#include <asm/mach/irq.h>
+
+#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
spin_lock_irqsave(&gpio_lock, flags);
+ if (value !=0 && value !=1)
+ goto fail;
if (!gpio_is_valid(gpio))
goto fail;
chip = desc->chip;
}
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
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;
{
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);
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);
}
}
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;
}
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;
}
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;
}
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;
}
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;
}
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];
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;
}
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;
}
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];
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
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
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
# 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
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
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
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
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
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
+
+++ /dev/null
-/**
- * tps65910-pwrbutton.c - TPS65910 Power Button Input Driver
- *
- * Copyright (C) 2010 Mistral Solutions Pvt Ltd <www.mistralsolutions.com>
- *
- * Based on twl4030-pwrbutton.c
- *
- * Written by Srinath.R <srinath@mistralsolutions.com>
- *
- * 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 <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c/tps65910.h>
-
-#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 <srinath@mistralsolutions.com>");
-
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
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
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
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
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/
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
/*
+<<<<<<< HEAD
* ov2640 Camera Driver
*
* Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
*
* 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 <kernel@pengutronix.de>
+>>>>>>> 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 <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
MODULE_AUTHOR("Alberto Panizzo");
MODULE_LICENSE("GPL v2");
+=======
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/circ_buf.h>
+#include <linux/miscdevice.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+#include <mach/rk29_camera.h>
+
+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) ((x<y) ? x: y)
+#define MAX(x,y) ((x>y) ? 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; i<ext_ctrl->count; 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; i<ext_ctrl->count; 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 <kernel@rock-chips>");
+MODULE_LICENSE("GPL");
+
+
+>>>>>>> parent of 15f7fab... temp revert rk change
icd->current_fmt->host_fmt->fourcc,
},
};
+<<<<<<< HEAD
ret = soc_camera_power_set(icd, icl, 1);
if (ret < 0)
/* 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) {
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,
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);
if (ret < 0)
goto einitvb;
}
+=======
+ }
+>>>>>>> parent of 15f7fab... temp revert rk change
}
file->private_data = icd;
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)
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);
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] && (i<VIDEO_MAX_FRAME)) {
+ if (icf->vb_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);
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)
{
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);
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);
{
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
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;
}
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)
{
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; i<ctrl->count; 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)
{
.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,
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)
mutex_lock(&stream->mutex);
if (uvc_queue_allocated(&stream->queue)) {
+ printk("uvc_queue_allocated failed\n");
ret = -EBUSY;
goto done;
}
}
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);
}
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);
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);
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
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
+++ /dev/null
-/*
- * tps65910-core.c -- Multifunction core driver for TPS65910x chips
- *
- * Copyright (C) 2010 Mistral solutions Pvt Ltd <www.mistralsolutions.com>
- *
- * 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 <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <linux/regulator/machine.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c/tps65910.h>
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#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 <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-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 <cwz@rock-chips.com>");
-MODULE_DESCRIPTION("I2C Core interface for TPS65910");
-MODULE_LICENSE("GPL");
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/auxadc.h>
#include <linux/mfd/wm831x/otp.h>
#include <linux/mfd/wm831x/regulator.h>
+#include <linux/mfd/wm831x/pmu.h>
+
/* 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,
* 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;
.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[] = {
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;
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;
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;
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:
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;
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
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");
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
int bytes, void *src)
{
struct i2c_client *i2c = wm831x->control_data;
+<<<<<<< HEAD
struct i2c_msg xfer[2];
int ret;
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;
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)
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 },
static const struct dev_pm_ops wm831x_pm_ops = {
.suspend = wm831x_i2c_suspend,
+ .resume = wm831x_i2c_resume,
};
static struct i2c_driver wm831x_i2c_driver = {
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
+ .shutdown = wm831x_i2c_shutdown,
.id_table = wm831x_i2c_id,
};
{
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);
#include <linux/mfd/wm831x/irq.h>
#include <linux/delay.h>
+<<<<<<< HEAD
+=======
+#include <linux/wakelock.h>
+/*
+ * 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;
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,
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)
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)
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;
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) {
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
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
dev_err(wm831x->dev,
"Failed to read IRQ status: %d\n",
*status);
- goto out;
+ goto out_lock;
}
read[offset] = 1;
/* 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);
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;
}
{
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 */
return 0;
}
+<<<<<<< HEAD
if (pdata->irq_cmos)
i = 0;
else
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;
irq_set_noprobe(cur_irq);
#endif
}
+<<<<<<< HEAD
if (irq) {
ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+=======
+#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);
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
+#include <linux/gpio.h>
#include <linux/mfd/wm831x/core.h>
/* 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++;
}
/* 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;
{
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;
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)
{
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);
}
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"
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
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;
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;
schedule();
remove_wait_queue(&wait_q, &wait);
}
+#endif
printk(KERN_DEBUG "apanic: %s partition erased\n",
CONFIG_APANIC_PLABEL);
out:
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;
}
}
}
+#ifndef CONFIG_MTD_RKNAND
if (!proc_entry_created)
mtd_panic_erase();
+#endif
return;
out_err:
printk(KERN_EMERG "Crash partition in use!\n");
goto out;
}
- console_offset = ctx->mtd->writesize;
+ console_offset = ctx->mtd->erasesize;
/*
* Write out the console
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;
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};
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)
{
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;
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
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;
} else if (disable_multi == 1) {
disable_multi = 0;
}
+ #endif
if (brq.sbc.error) {
printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT "
}
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);
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),
}
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;
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;
}
goto cmd_err;
#endif
}
+#endif
if (brq.cmd.error || brq.stop.error || brq.data.error) {
if (rq_data_dir(req) == READ) {
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);
*/
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;
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);
}
}
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 "
mmc_hostname(host), err);
err = 0;
}
+#endif
}
host->pm_flags &= ~MMC_PM_KEEP_POWER;
mmc_bus_put(host);
/* 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.
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;
}
{
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);
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;
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
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
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;
}
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;
}
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;
{
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
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;
#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;
*/
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;
+ }
}
/*
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
*/
if (oldcard)
oldcard->rca = card->rca;
+#endif
mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
}
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);
# 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
/*
* 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.
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;
rknand_parts[num_partitions - 1].size = rknand_mtd.size - rknand_parts[num_partitions - 1].offset;\r
\r
g_num_partitions = num_partitions;\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+ return mtd_device_register(&rknand_mtd, rknand_parts, num_partitions);\r
+#else\r
return add_mtd_partitions(&(rknand_mtd), rknand_parts, num_partitions);\r
+#endif\r
} \r
#endif \r
return 0;\r
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 <file:Documentation/networking/ray_cs.txt> 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
- <http://www.thekelleys.org.uk/atmel>
-
-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
#
# 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/
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.
-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 \
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) */
if (error)
return -ENODEV;
- enable_irq_wake(sdhcinfo->oob_irq);
+ set_irq_wake(sdhcinfo->oob_irq, 1);
sdhcinfo->oob_irq_registered = TRUE;
}
{
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 */
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)
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);
}
}
if (func->num == 2) {
sd_trace(("F2 found, calling bcmsdh_probe...\n"));
- ret = bcmsdh_probe(&func->dev);
+ ret = bcmsdh_probe(&sdmmc_dev);
}
return ret;
if (func->num == 2) {
sd_trace(("F2 found, calling bcmsdh_remove...\n"));
- bcmsdh_remove(&func->dev);
+ bcmsdh_remove(&sdmmc_dev);
}
}
if (!gInstance)
return -ENOMEM;
+ bzero(&sdmmc_dev, sizeof(sdmmc_dev));
error = sdio_register_driver(&bcmsdh_sdmmc_driver);
+
return error;
}
{
sd_trace(("%s Enter\n", __FUNCTION__));
+
sdio_unregister_driver(&bcmsdh_sdmmc_driver);
if (gInstance)
--- /dev/null
+/*
+ * 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 <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <sbchipc.h>
+#include <sbsdio.h>
+#include <spid.h>
+
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* ioctl/iovars */
+#include <sdio.h>
+
+#include <pcicfg.h>
+
+
+#include <bcmspibrcm.h>
+#include <bcmspi.h>
+
+#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);
+}
* 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 $
*/
/****************
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;
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)
#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);
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_ */
#include <dhd_bus.h>
#include <dhd_dbg.h>
+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) */
return ret;
}
memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+ memcpy(wlan_mac_addr, buf, ETHER_ADDR_LEN);
dhd_os_proto_unblock(dhd);
* 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 <typedefs.h>
#include <osl.h>
#include <wlioctl.h>
+#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 <linux/random.h>
#include <linux/jiffies.h>
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;
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;
}
#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)
{
}
#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__));
}
}
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))) {
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) {
/* 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];
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;
}
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);
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));
}
* 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 $
*/
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)
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
-}
* 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 <linux/platform_device.h>
+#endif
#include <typedefs.h>
#include <linuxver.h>
#include <osl.h>
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
-#include <linux/inetdevice.h>
-#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+#include <wifi_version.h>
#include <epivers.h>
#include <bcmutils.h>
#include <bcmendian.h>
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/wakelock.h>
#endif
-#ifdef CUSTOMER_HW2
-#include <linux/platform_device.h>
-#ifdef CONFIG_WIFI_CONTROL_FUNC
-#include <linux/wlan_plat.h>
-static struct wifi_platform_data *wifi_control_data = NULL;
-#endif
+#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
+//#include <linux/wlan_plat.h>
+#include <mach/board.h>
+
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)
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;
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;
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) */
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;
}
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 <linux/suspend.h>
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))
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;
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)
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;
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;
up(&dhd->sysioc_sem);
}
-
dhd_pub_t *
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) */
register_early_suspend(&dhd->early_suspend);
#endif
- register_inetaddr_notifier(&dhd_notifier);
-
return &dhd->pub;
fail:
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;
}
}
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)
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;
}
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));
/* 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 */
};
#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)
{
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
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);
}
}
-static void __exit
-dhd_module_cleanup(void)
+void
+rockchip_wifi_exit_module(void)
{
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
#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 */
goto fail_2;
}
#endif
+ bcm4329_power_save_init();
+
return error;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
fail_2:
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
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);
/* 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 */
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;
}
#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);
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);
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
#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
* 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 $
*/
#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 {
#define PM_MAX 1
#define PM_FAST 2
-#define LISTEN_INTERVAL 10
+#define LISTEN_INTERVAL 20
#define INTERFERE_NONE 0
#define NON_WLAN 1
#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
int32 lost_network_timeout;
int16 flags;
int16 rssi_margin;
- int32 repeat_scan;
- int32 max_freq_adjust;
} wl_pfn_param_t;
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
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;
* 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 $
*/
#define WL_INFORM(x)
#define WL_WSEC(x)
#define WL_SCAN(x)
-#define WL_PNO(x)
#define WL_TRACE_COEX(x)
#include <wl_iw.h>
-
+#include <linux/wakelock.h>
#ifndef IW_ENCODE_ALG_SM4
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 <bcmsdbus.h>
#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;
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,
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(
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:
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(
#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;
}
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)
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;
'G', 'O', 'O', 'G',
'T',
'1','E',
- 'R',
- '2',
- 'M',
- '2',
0x00
};
#endif
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) && \
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 {
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);
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)
{
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;
}
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", \
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;
}
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",
}
#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,
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__));
}
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)
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);
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) {
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));
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)) {
goto wl_iw_event_end;
}
}
-#endif
break;
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
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"));
#endif
#if WIRELESS_EXT > 14
+
memset(extra, 0, sizeof(extra));
if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
cmd = IWEVCUSTOM;
* 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 $
*/
#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"
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
} 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 {
};
-#define MACLIST_MODE_DISABLED 0
+#define MACLIST_MODE_DISABLED 0
#define MACLIST_MODE_DENY 1
#define MACLIST_MODE_ALLOW 2
struct mflist {
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);
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'
#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;
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 {
extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num);
-#endif
+#endif
-#endif
+#endif
#include <linux/mfd/wm831x/auxadc.h>
#include <linux/mfd/wm831x/pmu.h>
#include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/irq.h>
+
+#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)
{
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
{ 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;
{
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,
reg1 = 0;
reg2 = 0;
+ reg3 = 0;
if (!pdata->enable) {
dev_info(wm831x->dev, "Battery charger disabled\n");
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);
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 |
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);
}
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)
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;
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",
{
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
/* 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;
}
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);
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);
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",
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]);
}
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);
{
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);
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);
}
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 <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
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
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
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
}
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
#include <linux/mfd/wm831x/regulator.h>
#include <linux/mfd/wm831x/pdata.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+
#define WM831X_BUCKV_MAX_SELECTOR 0x68
#define WM831X_BUCKP_MAX_SELECTOR 0x66
#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
/*
* Shared
*/
-
+#if 0
struct wm831x_dcdc {
char name[WM831X_DCDC_MAX_NAME];
struct regulator_desc desc;
int on_vsel;
int dvs_vsel;
};
+#endif
static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
{
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)
{
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)
{
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,
.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,
};
/*
.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)
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);
#include <linux/mfd/wm831x/regulator.h>
#include <linux/mfd/wm831x/pdata.h>
-#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;
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);
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;
}
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;
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;
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;
}
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);
#include <linux/mfd/wm831x/regulator.h>
#include <linux/mfd/wm831x/pdata.h>
-#define WM831X_LDO_MAX_NAME 6
+//#define WM831X_LDO_MAX_NAME 6
#define WM831X_LDO_CONTROL 0
#define WM831X_LDO_ON_CONTROL 1
#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;
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);
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);
}
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);
}
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;
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,
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,
.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)
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;
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);
}
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;
.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)
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;
.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)
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;
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,
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);
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
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
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
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
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);
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);
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
};
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
+ .shutdown = alarm_shutdown,
.driver = {
.name = "alarm"
}
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);
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:
+++ /dev/null
-/*
- * rtc-tps65910.c -- TPS65910 Real Time Clock interface
- *
- * Copyright (C) 2010 Mistral Solutions Pvt Ltd. <www.mistralsolutions.com>
- * Author: Umesh K <umeshk@mistralsolutions.com>
- *
- * 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 <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/i2c/tps65910.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-
-#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 <cwz@rockchips.com");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * drivers/serial/rk2818_serial.h
- *
- * 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.
- */
-
-#ifndef __DRIVERS_SERIAL_RK2818_SERIAL_H
-#define __DRIVERS_SERIAL_RK2818_SERIAL_H
-
-#define UART_RBR 0x0000 /* Receive Buffer Register */
-#define UART_THR 0x0000 /* Transmit Holding Register */
-#define UART_DLL 0x0000 /* Divisor Latch (Low) */
-#define UART_DLH 0x0004 /* Divisor Latch (High) */
-#define UART_IER 0x0004 /* Interrupt Enable Register */
-#define UART_IIR 0x0008 /* Interrupt Identification Register */
-#define UART_FCR 0x0008 /* FIFO Control Register */
-#define UART_LCR 0x000C /* Line Control Register */
-#define UART_MCR 0x0010 /* Modem Control Register */
-#define UART_LSR 0x0014 /* [0x0000_0060] Line Status Register */
-#define UART_MSR 0x0018 /* Modem Status Register */
-#define UART_SCR 0x001c /* Scratchpad Register */
-#define UART_SRBR(n) (0x0030+((n) * 4)) /* Shadow Receive Buffer Register */
-#define UART_STHR(n) (0x0030+((n) * 4)) /* Shadow Transmit Holding Register */
-#define UART_FAR 0x0070 /* FIFO Access Register */
-#define UART_TFR 0x0074 /* Transmit FIFO Read */
-#define UART_RFW 0x0078 /* Receive FIFO Write */
-#define UART_USR 0x007C /* UART Status Register */
-#define UART_TFL 0x0080 /* Transmit FIFO Level */
-#define UART_RFL 0x0084 /* Receive FIFO Level */
-#define UART_SRR 0x0088 /* Software Reset Register */
-#define UART_SRTS 0x008C /* Shadow Request to Send */
-#define UART_SBCR 0x0090 /* Shadow Break Control Register */
-#define UART_SDMAM 0x0094 /* Shadow DMA Mode */
-#define UART_SFE 0x0098 /* Shadow FIFO Enable */
-#define UART_SRT 0x009C /* Shadow RCVR Trigger */
-#define UART_STET 0x00A0 /* Shadow TX Empty Trigger */
-#define UART_HTX 0x00A4 /* Halt TX */
-#define UART_DMASA 0x00A8 /* DMA Software Acknowledge */
-#define UART_CPR 0x00F4 /* Component Parameter Register */
-#define UART_UCV 0x00F8 /* [0x3330_372a] UART Component Version */
-#define UART_CTR 0x00FC /* [0x4457_0110] Component Type Register */
-
-//#define UART_FCR 0x08
-#define UART_FCR_FIFO_ENABLE (1<<0)
-#define UART_FCR_CLEAR_RCVR (1<<1) /* Clear the RCVR FIFO */
-#define UART_FCR_CLEAR_XMIT (1<<2) /* Clear the XMIT FIFO */
-#define UART_FCR_DMA_SELECT (1<<3) /* For DMA applications */
-#define UART_FCR_R_TRIG_00 0x00
-#define UART_FCR_R_TRIG_01 0x40
-#define UART_FCR_R_TRIG_10 0x80
-#define UART_FCR_R_TRIG_11 0xc0
-#define UART_FCR_T_TRIG_00 0x00
-#define UART_FCR_T_TRIG_01 0x10
-#define UART_FCR_T_TRIG_10 0x20
-#define UART_FCR_T_TRIG_11 0x30
-
-//#define UART_LCR 0x0c
-#define LCR_DLA_EN (1<<7)
-#define BREAK_CONTROL_BIT (1<<6)
-#define EVEN_PARITY_SELECT (1<<4)
-#define EVEN_PARITY (1<<4)
-#define ODD_PARITY (0)
-#define PARITY_DISABLED (0)
-#define PARITY_ENABLED (1<<3)
-#define ONE_STOP_BIT (0)
-#define ONE_HALF_OR_TWO_BIT (1<<2)
-#define LCR_WLS_5 (0x00)
-#define LCR_WLS_6 (0x01)
-#define LCR_WLS_7 (0x02)
-#define LCR_WLS_8 (0x03)
-#define UART_DATABIT_MASK (0x03)
-
-/* Detail UART_IER Register Description */
-#define UART_IER_THRE_MODE_INT_ENABLE 1<<7
-#define UART_IER_MODEM_STATUS_INT_ENABLE 1<<3
-#define UART_IER_RECV_LINE_STATUS_INT_ENABLE 1<<2
-#define UART_IER_SEND_EMPTY_INT_ENABLE 1<<1
-#define UART_IER_RECV_DATA_AVAIL_INT_ENABLE 1<<0
-
-
-/* Detail UART_IIR Register Description */
-#define UART_IIR_FIFO_DISABLE 0x00
-#define UART_IIR_FIFO_ENABLE 0x03
-#define UART_IIR_INT_ID_MASK 0x0F
-#define UART_IIR_MODEM_STATUS 0x00
-#define UART_IIR_NO_INTERRUPT_PENDING 0x01
-#define UART_IIR_THR_EMPTY 0x02
-#define UART_IIR_RECV_AVAILABLE 0x04
-#define UART_IIR_RECV_LINE_STATUS 0x06
-#define UART_IIR_BUSY_DETECT 0x07
-#define UART_IIR_CHAR_TIMEOUT 0x0C
-
-//#define UART_MCR 0x10
-/* Modem Control Register */
-#define UART_SIR_ENABLE (1 << 6)
-#define UART_MCR_AFCEN (1 << 5) /* Auto Flow Control Mode enabled */
-#define UART_MCR_URLB (1 << 4) /* Loop-back mode */
-#define UART_MCR_UROUT2 (1 << 3) /* OUT2 signal */
-#define UART_MCR_UROUT1 (1 << 2) /* OUT1 signal */
-#define UART_MCR_URRTS (1 << 1) /* Request to Send */
-#define UART_MCR_URDTR (1 << 0) /* Data Terminal Ready */
-
-//#define UART_MSR 0x18
-/* Modem Status Register */
-#define UART_MSR_URDCD (1 << 7) /* Data Carrier Detect */
-#define UART_MSR_URRI (1 << 6) /* Ring Indicator */
-#define UART_MSR_URDSR (1 << 5) /* Data Set Ready */
-#define UART_MSR_URCTS (1 << 4) /* Clear to Send */
-#define UART_MSR_URDDCD (1 << 3) /* Delta Data Carrier Detect */
-#define UART_MSR_URTERI (1 << 2) /* Trailing Edge Ring Indicator */
-#define UART_MSR_URDDST (1 << 1) /* Delta Data Set Ready */
-#define UART_MSR_URDCTS (1 << 0) /* Delta Clear to Send */
-
-/* Detail UART_USR Register Description */
-#define UART_RECEIVE_FIFO_FULL (1<<4)
-#define UART_RECEIVE_FIFO_NOT_FULL (0)
-#define UART_RECEIVE_FIFO_EMPTY (0)
-#define UART_RECEIVE_FIFO_NOT_EMPTY (1<<3)
-#define UART_TRANSMIT_FIFO_NOT_EMPTY (0)
-#define UART_TRANSMIT_FIFO_EMPTY (1<<2)
-#define UART_TRANSMIT_FIFO_FULL (0)
-#define UART_TRANSMIT_FIFO_NOT_FULL (1<<1)
-#define UART_USR_BUSY (1)
-
-/*UART_LSR Line Status Register*/
-#define UART_BREAK_INT_BIT (1<<4)/*break Interrupt bit*/
-
-#endif /* __DRIVERS_SERIAL_RK2818_SERIAL_H */
+++ /dev/null
-/*
- * drivers/serial/rk29_serial.c - driver for rk29 serial device and console
- *
- * 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.
- */
-
-
-#if defined(CONFIG_SERIAL_RK29_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/hrtimer.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <mach/iomux.h>
-#include <mach/gpio.h>
-#include <mach/board.h>
-#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");
-
-
+++ /dev/null
-/*\r
- * Driver for RK-UART controller.\r
- * Based on drivers/tty/serial/8250.c\r
- *\r
- * Copyright (C) 2011 Rochchip.\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
-\r
- * (at your option) any later version.\r
- *\r
- * Author: hhb@rock-chips.com\r
- * Date: 2011.06.18\r
- */\r
-\r
-#ifndef CONFIG_SERIAL_RK_CONSOLE\r
-#if defined(CONFIG_SERIAL_RK29_CONSOLE)\r
-#define CONFIG_SERIAL_RK_CONSOLE\r
-#endif\r
-#endif\r
-\r
-#if defined(CONFIG_SERIAL_RK_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)\r
-#define SUPPORT_SYSRQ\r
-#endif\r
-\r
-//#define DEBUG\r
-#include <linux/module.h>\r
-#include <linux/ioport.h>\r
-#include <linux/init.h>\r
-#include <linux/console.h>\r
-#include <linux/sysrq.h>\r
-#include <linux/delay.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/tty.h>\r
-#include <linux/ratelimit.h>\r
-#include <linux/tty_flip.h>\r
-#include <linux/serial_reg.h>\r
-#include <linux/serial_core.h>\r
-#include <linux/serial.h>\r
-#include <linux/serial_8250.h>\r
-#include <linux/nmi.h>\r
-#include <linux/mutex.h>\r
-#include <linux/slab.h>\r
-#include <linux/clk.h>\r
-#include <linux/timer.h>\r
-#include <linux/workqueue.h>\r
-#include <mach/rk29-dma-pl330.h>\r
-#include <linux/dma-mapping.h>\r
-\r
-#include <asm/io.h>\r
-#include <asm/irq.h>\r
-\r
-\r
-#define PORT_RK 90\r
-#define UART_USR 0x1F /* UART Status Register */\r
-#define UART_USR_BUSY (1)\r
-#define UART_IER_PTIME 0x80 /* Programmable THRE Interrupt Mode Enable */\r
-#define UART_LSR_RFE 0x80 /* receive fifo error */\r
-#define UART_SRR 0x22 /* software reset register */\r
-#define UART_RESET 0x01\r
-#define RX_TIMEOUT (3000*10) //uint ms\r
-\r
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)\r
-\r
-#define UART_NR 4 //uart port number\r
-#define POWER_MANEGEMENT 1\r
-\r
-/* configurate whether the port transmit-receive by DMA */\r
-#define OPEN_DMA 1\r
-#define CLOSE_DMA 0\r
-\r
-#ifdef CONFIG_UART0_DMA_RK29\r
-#define UART0_USE_DMA OPEN_DMA\r
-#else\r
-#define UART0_USE_DMA CLOSE_DMA\r
-#endif\r
-\r
-#ifdef CONFIG_UART2_DMA_RK29\r
-#define UART2_USE_DMA OPEN_DMA\r
-#else\r
-#define UART2_USE_DMA CLOSE_DMA\r
-#endif\r
-\r
-#ifdef CONFIG_UART3_DMA_RK29\r
-#define UART3_USE_DMA OPEN_DMA\r
-#else\r
-#define UART3_USE_DMA CLOSE_DMA\r
-#endif\r
-\r
-#define UART1_USE_DMA CLOSE_DMA\r
-\r
-#define DMA_TX_TRRIGE_LEVEL 30\r
-\r
-#define USE_TIMER 1 // use timer for dma transport\r
-#define THRE_MODE 0X00 //0yhh\r
-\r
-static struct uart_driver serial_rk_reg;\r
-\r
-/*\r
- * Debugging.\r
- */\r
-#define DBG_PORT 1 //DBG_PORT which uart is used to print log message\r
-\r
-#ifdef CONFIG_SERIAL_CORE_CONSOLE\r
-#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)\r
-#else\r
-#define uart_console(port) (0)\r
-#endif\r
-\r
-#define DEBUG 0\r
-\r
-extern void printascii(const char *);\r
-static void dbg(const char *fmt, ...)\r
-{\r
- va_list va;\r
- char buff[256];\r
-\r
- va_start(va, fmt);\r
- vsprintf(buff, fmt, va);\r
- va_end(va);\r
-\r
- printascii(buff);\r
-}\r
-\r
-#if DEBUG\r
-#define DEBUG_INTR(fmt...) if (!uart_console(&up->port)) dbg(fmt)\r
-#else\r
-#define DEBUG_INTR(fmt...) do { } while (0)\r
-#endif\r
-\r
-\r
-/* added by hhb@rock-chips.com for uart dma transfer */\r
-\r
-struct rk29_uart_dma_t {\r
- u32 use_dma; //1:used\r
- u32 rx_dma_start;\r
- enum dma_ch rx_dmach;\r
- enum dma_ch tx_dmach;\r
- u32 tx_dma_inited;\r
- u32 rx_dma_inited;\r
- spinlock_t tx_lock;\r
- spinlock_t rx_lock;\r
- char * rx_buffer;\r
- char * tx_buffer;\r
- dma_addr_t rx_phy_addr;\r
- dma_addr_t tx_phy_addr;\r
- u32 rx_buffer_size;\r
- u32 tx_buffer_size;\r
-\r
- u32 rb_cur_pos;\r
- u32 rb_pre_pos;\r
- u32 rx_size;\r
- char use_timer;\r
- char tx_dma_used;\r
- /* timer to poll activity on rx dma */\r
- struct timer_list rx_timer;\r
- int rx_timeout;\r
-\r
-};\r
-\r
-struct uart_rk_port {\r
- struct uart_port port;\r
- struct platform_device *pdev;\r
- struct clk *clk;\r
- unsigned int tx_loadsz; /* transmit fifo load size */\r
- unsigned char ier;\r
- unsigned char lcr;\r
- unsigned char mcr;\r
- unsigned char iir;\r
- unsigned char fcr;\r
- /*\r
- * Some bits in registers are cleared on a read, so they must\r
- * be saved whenever the register is read but the bits will not\r
- * be immediately processed.\r
- */\r
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS\r
- unsigned char lsr_saved_flags;\r
-#if 0\r
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA\r
- unsigned char msr_saved_flags;\r
-#endif\r
-\r
- char name[12];\r
- char fifo[32];\r
- char fifo_size;\r
- unsigned long port_activity;\r
- struct work_struct uart_work;\r
- struct work_struct uart_work_rx;\r
- struct workqueue_struct *uart_wq;\r
- struct rk29_uart_dma_t *prk29_uart_dma_t;\r
-};\r
-\r
-static void serial_rk_release_dma_tx(struct uart_port *port);\r
-static int serial_rk_start_tx_dma(struct uart_port *port);\r
-static void serial_rk_rx_timeout(unsigned long uart);\r
-static void serial_rk_release_dma_rx(struct uart_port *port);\r
-static int serial_rk_start_rx_dma(struct uart_port *port);\r
-static int serial_rk_startup(struct uart_port *port);\r
-static inline unsigned int serial_in(struct uart_rk_port *up, int offset)\r
-{\r
- offset = offset << 2;\r
- return readb(up->port.membase + offset);\r
-}\r
-\r
-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */\r
-static inline void dwapb_save_out_value(struct uart_rk_port *up, int offset,\r
- unsigned char value)\r
-{\r
- if (offset == UART_LCR)\r
- up->lcr = value;\r
-}\r
-\r
-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */\r
-static inline void dwapb_check_clear_ier(struct uart_rk_port *up, int offset)\r
-{\r
- if (offset == UART_TX || offset == UART_IER)\r
- serial_in(up, UART_IER);\r
-}\r
-\r
-static inline void serial_out(struct uart_rk_port *up, int offset, unsigned char value)\r
-{\r
- dwapb_save_out_value(up, offset, value);\r
- writeb(value, up->port.membase + (offset << 2));\r
- dwapb_check_clear_ier(up, offset);\r
-}\r
-\r
-/* Uart divisor latch read */\r
-static inline int serial_dl_read(struct uart_rk_port *up)\r
-{\r
- return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;\r
-}\r
-\r
-/* Uart divisor latch write */\r
-static int serial_dl_write(struct uart_rk_port *up, unsigned int value)\r
-{\r
- unsigned int tmout = 100;\r
- if(up->port.line != DBG_PORT)\r
- {\r
- while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){\r
- if (--tmout == 0){\r
- dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line);\r
- return -1;\r
- }\r
- }\r
-\r
- tmout = 15000;\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
- if (--tmout == 0){\r
- dbg("set serial.%d baudrate timeout\n", up->port.line);\r
- return -1;\r
- }\r
- }\r
- }\r
-\r
- serial_out(up, UART_DLL, value & 0xff);\r
- serial_out(up, UART_DLM, value >> 8 & 0xff);\r
-\r
- return 0;\r
-\r
-}\r
-\r
-static int serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
-{\r
- unsigned int tmout = 15000;\r
-\r
- if(up->port.line != DBG_PORT)\r
- {\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
-\r
- if (--tmout == 0){\r
- dbg("set serial.%d lc r = 0x%02x timeout\n", up->port.line, value);\r
- return -1;\r
- }\r
- udelay(1);\r
- }\r
- }\r
-\r
- serial_out(up, UART_LCR, value);\r
-\r
- return 0;\r
-}\r
-\r
-static inline void serial_rk_enable_ier_thri(struct uart_rk_port *up)\r
-{\r
- if (!(up->ier & UART_IER_THRI)) {\r
- up->ier |= UART_IER_THRI;\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-}\r
-\r
-\r
-static inline void serial_rk_disable_ier_thri(struct uart_rk_port *up)\r
-{\r
- if (up->ier & UART_IER_THRI) {\r
- up->ier &= ~UART_IER_THRI;\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-}\r
-#if 0\r
-static int rk29_uart_dump_register(struct uart_rk_port *up){\r
-\r
- unsigned int reg_value = 0;\r
-\r
- reg_value = serial_in(up, UART_IER);\r
- dbg("UART_IER = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, UART_IIR);\r
- dbg("UART_IIR = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, UART_LSR);\r
- dbg("UART_LSR = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, UART_MSR);\r
- dbg("UART_MSR = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, UART_MCR);\r
- dbg("UART_MCR = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, 0x21);\r
- dbg("UART_RFL = 0x%0x\n", reg_value);\r
- reg_value = serial_in(up, UART_LCR);\r
- dbg("UART_LCR = 0x%0x\n", reg_value);\r
- return 0;\r
-\r
-}\r
-#endif\r
-\r
-/*\r
- * FIFO support.\r
- */\r
-static void serial_rk_clear_fifos(struct uart_rk_port *up)\r
-{\r
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);\r
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |\r
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);\r
- serial_out(up, UART_FCR, 0);\r
-}\r
-\r
-static inline void __stop_tx(struct uart_rk_port *p)\r
-{\r
- if (p->ier & UART_IER_THRI) {\r
- p->ier &= ~UART_IER_THRI;\r
- serial_out(p, UART_IER, p->ier);\r
- }\r
-}\r
-\r
-static void serial_rk_stop_tx(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
-\r
- if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
- serial_rk_release_dma_tx(port);\r
- }\r
- __stop_tx(up);\r
-}\r
-\r
-\r
-static void serial_rk_start_tx(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
-\r
- if(0 == serial_rk_start_tx_dma(port)){\r
- serial_rk_enable_ier_thri(up);\r
- }\r
-\r
-}\r
-\r
-\r
-static void serial_rk_stop_rx(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
-\r
- if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
- serial_rk_release_dma_rx(port);\r
- }\r
- up->ier &= ~UART_IER_RLSI;\r
- up->port.read_status_mask &= ~UART_LSR_DR;\r
- serial_out(up, UART_IER, up->ier);\r
-}\r
-\r
-\r
-static void serial_rk_enable_ms(struct uart_port *port)\r
-{\r
- /* no MSR capabilities */\r
-#if 0\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- up->ier |= UART_IER_MSI;\r
- serial_out(up, UART_IER, up->ier);\r
-#endif\r
-}\r
-\r
-\r
-/*\r
- * Start transmitting by dma.\r
- */\r
-#define DMA_SERIAL_BUFFER_SIZE UART_XMIT_SIZE\r
-\r
-/* added by hhb@rock-chips.com for uart dma transfer*/\r
-static struct rk29_uart_dma_t rk29_uart_ports_dma_t[] = {\r
- {UART0_USE_DMA, 0, DMACH_UART0_RX, DMACH_UART0_TX},\r
- {UART1_USE_DMA, 0, DMACH_UART1_RX, DMACH_UART1_TX},\r
- {UART2_USE_DMA, 0, DMACH_UART2_RX, DMACH_UART2_TX},\r
- {UART3_USE_DMA, 0, DMACH_UART3_RX, DMACH_UART3_TX},\r
-};\r
-\r
-\r
-/* DMAC PL330 add by hhb@rock-chips.com */\r
-static struct rk29_dma_client rk29_uart_dma_client = {\r
- .name = "rk29xx-uart-dma",\r
-};\r
-\r
-/*TX*/\r
-\r
-static void serial_rk_release_dma_tx(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port){\r
- return;\r
- }\r
- if(prk29_uart_dma_t && prk29_uart_dma_t->tx_dma_inited) {\r
- rk29_dma_free(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client);\r
- prk29_uart_dma_t->tx_dma_inited = 0;\r
- }\r
-}\r
-\r
-/*this function will be called every time after rk29_dma_enqueue() be invoked*/\r
-static void serial_rk_dma_txcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
- struct uart_port *port = buf;\r
- struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
- struct circ_buf *xmit = &port->state->xmit;\r
-\r
- if(result != RK29_RES_OK){\r
- return;\r
- }\r
-\r
- port->icount.tx += size;\r
- xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);\r
-\r
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
- uart_write_wakeup(&up->port);\r
- spin_lock(&(up->prk29_uart_dma_t->tx_lock));\r
- up->prk29_uart_dma_t->tx_dma_used = 0;\r
- spin_unlock(&(up->prk29_uart_dma_t->tx_lock));\r
- if (!uart_circ_empty(xmit)) {\r
- serial_rk_start_tx_dma(port);\r
- }\r
-\r
- up->port_activity = jiffies;\r
-// dev_info(up->port.dev, "s:%d\n", size);\r
-}\r
-\r
-static int serial_rk_init_dma_tx(struct uart_port *port) {\r
-\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port || !prk29_uart_dma_t){\r
- dev_info(up->port.dev, "serial_rk_init_dma_tx fail\n");\r
- return -1;\r
- }\r
-\r
- if(prk29_uart_dma_t->tx_dma_inited) {\r
- return 0;\r
- }\r
-\r
- if (rk29_dma_request(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request tx fail\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->tx_dmach, serial_rk_dma_txcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn tx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_devconfig(prk29_uart_dma_t->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig tx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_config(prk29_uart_dma_t->tx_dmach, 1, 1)) {\r
- dev_info(up->port.dev, "rk29_dma_config tx fail\n");\r
- return -1;\r
- }\r
-\r
- prk29_uart_dma_t->tx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_tx sucess\n");\r
- return 0;\r
-\r
-}\r
-\r
-static int serial_rk_start_tx_dma(struct uart_port *port)\r
-{\r
-\r
- struct circ_buf *xmit = &port->state->xmit;\r
- struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
-\r
- if(0 == prk29_uart_dma_t->use_dma){\r
- return CLOSE_DMA;\r
- }\r
-\r
- if(-1 == serial_rk_init_dma_tx(port)){\r
- goto err_out;\r
- }\r
-\r
- if (1 == prk29_uart_dma_t->tx_dma_used){\r
- return 1;\r
- }\r
- if(!uart_circ_empty(xmit)){\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->tx_dmach, port,\r
- prk29_uart_dma_t->tx_phy_addr + xmit->tail,\r
- CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE))) {\r
- goto err_out;\r
- }\r
- }\r
- rk29_dma_ctrl(prk29_uart_dma_t->tx_dmach, RK29_DMAOP_START);\r
- spin_lock(&(prk29_uart_dma_t->tx_lock));\r
- up->prk29_uart_dma_t->tx_dma_used = 1;\r
- spin_unlock(&(prk29_uart_dma_t->tx_lock));\r
-\r
- return 1;\r
-err_out:\r
- dev_info(up->port.dev, "-serial_rk_start_tx_dma-error-\n");\r
- return -1;\r
-\r
-}\r
-\r
-\r
-\r
-/*RX*/\r
-static void serial_rk_dma_rxcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
-\r
-\r
-}\r
-\r
-static void serial_rk_release_dma_rx(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port){\r
- return;\r
- }\r
- if(prk29_uart_dma_t && prk29_uart_dma_t->rx_dma_inited) {\r
- del_timer(&prk29_uart_dma_t->rx_timer);\r
- rk29_dma_free(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client);\r
- prk29_uart_dma_t->rb_pre_pos = 0;\r
- prk29_uart_dma_t->rx_dma_inited = 0;\r
- prk29_uart_dma_t->rx_dma_start = 0;\r
- }\r
-}\r
-\r
-\r
-static int serial_rk_init_dma_rx(struct uart_port *port) {\r
-\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port || !prk29_uart_dma_t){\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx: port fail\n");\r
- return -1;\r
- }\r
- if(prk29_uart_dma_t->rx_dma_inited) {\r
- return 0;\r
- }\r
-\r
- if (rk29_dma_request(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request fail rx \n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->rx_dmach, serial_rk_dma_rxcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn rx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_devconfig(prk29_uart_dma_t->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig rx fail\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_config(prk29_uart_dma_t->rx_dmach, 1, 1)) {\r
- dev_info(up->port.dev, "rk29_dma_config rx fail\n");\r
- return -1;\r
- }\r
-\r
- rk29_dma_setflags(prk29_uart_dma_t->rx_dmach, RK29_DMAF_CIRCULAR);\r
-\r
- prk29_uart_dma_t->rx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx sucess\n");\r
- return 0;\r
-\r
-}\r
-\r
-static int serial_rk_start_rx_dma(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(0 == prk29_uart_dma_t->use_dma){\r
- return 0;\r
- }\r
-\r
- if(prk29_uart_dma_t->rx_dma_start == 1){\r
- return 0;\r
- }\r
-\r
- if(-1 == serial_rk_init_dma_rx(port)){\r
- dev_info(up->port.dev, "*******serial_rk_init_dma_rx*******error*******\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up, prk29_uart_dma_t->rx_phy_addr,\r
- prk29_uart_dma_t->rx_buffer_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up,\r
- prk29_uart_dma_t->rx_phy_addr+prk29_uart_dma_t->rx_buffer_size/2,\r
- prk29_uart_dma_t->rx_buffer_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
- }\r
-\r
- rk29_dma_ctrl(prk29_uart_dma_t->rx_dmach, RK29_DMAOP_START);\r
- prk29_uart_dma_t->rx_dma_start = 1;\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies +\r
- msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
- }\r
- up->port_activity = jiffies;\r
- return 1;\r
-}\r
-\r
-static void serial_rk_update_rb_addr(struct uart_rk_port *up){\r
- dma_addr_t current_pos = 0;\r
- dma_addr_t rx_current_pos = 0;\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
- rk29_dma_getposition(prk29_uart_dma_t->rx_dmach, ¤t_pos, &rx_current_pos);\r
-\r
- prk29_uart_dma_t->rb_cur_pos = (rx_current_pos - prk29_uart_dma_t->rx_phy_addr);\r
- prk29_uart_dma_t->rx_size = CIRC_CNT(prk29_uart_dma_t->rb_cur_pos,\r
- prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size);\r
-\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
-}\r
-\r
-static void serial_rk_report_dma_rx(unsigned long uart)\r
-{\r
- struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- serial_rk_update_rb_addr(up);\r
- }\r
- if(prk29_uart_dma_t->rx_size > 0) {\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
- if(prk29_uart_dma_t->rb_cur_pos > prk29_uart_dma_t->rb_pre_pos){\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
- + prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_size);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- }\r
- else if(prk29_uart_dma_t->rb_cur_pos < prk29_uart_dma_t->rb_pre_pos){\r
-\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
- + prk29_uart_dma_t->rb_pre_pos, CIRC_CNT_TO_END(prk29_uart_dma_t->rb_cur_pos,\r
- prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size));\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
-\r
- if(prk29_uart_dma_t->rb_cur_pos != 0){\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer,\r
- prk29_uart_dma_t->rb_cur_pos);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- }\r
- }\r
-\r
- prk29_uart_dma_t->rb_pre_pos = (prk29_uart_dma_t->rb_pre_pos + prk29_uart_dma_t->rx_size)\r
- & (prk29_uart_dma_t->rx_buffer_size - 1);\r
- up->port.icount.rx += prk29_uart_dma_t->rx_size;\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
- prk29_uart_dma_t->rx_timeout = 7;\r
- up->port_activity = jiffies;\r
- }\r
-\r
-\r
-#if 1\r
- if (jiffies_to_msecs(jiffies - up->port_activity) < RX_TIMEOUT) {\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
- }\r
- } else {\r
-\r
-#if 1\r
-\r
-\r
- prk29_uart_dma_t->rx_timeout = 20;\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
-#else\r
-// serial_out(up, 0x2a, 0x01);\r
- serial_rk_release_dma_rx(&up->port);\r
- serial_out(up, 0x2a, 0x01);\r
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);\r
- serial_out(up, UART_IER, up->ier);\r
-// serial_out(up, 0x22, 0x01);\r
- dev_info(up->port.dev, "*****enable recv int*****\n");\r
-\r
- //serial_rk_start_rx_dma(&up->port);\r
-#endif\r
- }\r
-\r
-\r
-#else\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
- }\r
-#endif\r
-\r
-}\r
-\r
-static void serial_rk_rx_timeout(unsigned long uart)\r
-{\r
- struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
-\r
- //serial_rk_report_dma_rx(up);\r
- queue_work(up->uart_wq, &up->uart_work);\r
-}\r
-\r
-static void serial_rk_report_revdata_workfunc(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work);\r
- serial_rk_report_dma_rx((unsigned long)up);\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
- if(up->prk29_uart_dma_t->use_timer == 1){\r
-\r
- }else{\r
- tty_insert_flip_string(up->port.state->port.tty, up->fifo, up->fifo_size);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- up->port.icount.rx += up->fifo_size;\r
- }\r
-\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
-}\r
-\r
-\r
-static void serial_rk_start_dma_rx(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work_rx);\r
- serial_rk_start_rx_dma(&up->port);\r
-}\r
-\r
-\r
-\r
-static void\r
-receive_chars(struct uart_rk_port *up, unsigned int *status)\r
-{\r
- struct tty_struct *tty = up->port.state->port.tty;\r
- unsigned char ch, lsr = *status;\r
- int max_count = 256;\r
- char flag;\r
-\r
- do {\r
- if (likely(lsr & UART_LSR_DR)){\r
- ch = serial_in(up, UART_RX);\r
- }\r
- else\r
- /*\r
- * Intel 82571 has a Serial Over Lan device that will\r
- * set UART_LSR_BI without setting UART_LSR_DR when\r
- * it receives a break. To avoid reading from the\r
- * receive buffer without UART_LSR_DR bit set, we\r
- * just force the read character to be 0\r
- */\r
- ch = 0;\r
-\r
- flag = TTY_NORMAL;\r
- up->port.icount.rx++;\r
-\r
- lsr |= up->lsr_saved_flags;\r
- up->lsr_saved_flags = 0;\r
-\r
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {\r
- /*\r
- * For statistics only\r
- */\r
- if (lsr & UART_LSR_BI) {\r
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);\r
- up->port.icount.brk++;\r
- /*\r
- * We do the SysRQ and SAK checking\r
- * here because otherwise the break\r
- * may get masked by ignore_status_mask\r
- * or read_status_mask.\r
- */\r
- if (uart_handle_break(&up->port))\r
- goto ignore_char;\r
- } else if (lsr & UART_LSR_PE)\r
- up->port.icount.parity++;\r
- else if (lsr & UART_LSR_FE)\r
- up->port.icount.frame++;\r
- if (lsr & UART_LSR_OE)\r
- up->port.icount.overrun++;\r
-\r
-\r
- /*\r
- * Mask off conditions which should be ignored.\r
- */\r
- lsr &= up->port.read_status_mask;\r
-\r
- if (lsr & UART_LSR_BI) {\r
- DEBUG_INTR("handling break....");\r
- flag = TTY_BREAK;\r
- } else if (lsr & UART_LSR_PE)\r
- flag = TTY_PARITY;\r
- else if (lsr & UART_LSR_FE)\r
- flag = TTY_FRAME;\r
- }\r
- if (uart_handle_sysrq_char(&up->port, ch))\r
- goto ignore_char;\r
-\r
- uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);\r
-\r
-ignore_char:\r
- lsr = serial_in(up, UART_LSR);\r
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));\r
- spin_unlock(&up->port.lock);\r
- tty_flip_buffer_push(tty);\r
- spin_lock(&up->port.lock);\r
- *status = lsr;\r
-}\r
-\r
-static void transmit_chars(struct uart_rk_port *up)\r
-{\r
- struct circ_buf *xmit = &up->port.state->xmit;\r
- int count;\r
-\r
- if (up->port.x_char) {\r
- serial_out(up, UART_TX, up->port.x_char);\r
- up->port.icount.tx++;\r
- up->port.x_char = 0;\r
- return;\r
- }\r
- if (uart_tx_stopped(&up->port)) {\r
- __stop_tx(up);\r
- return;\r
- }\r
- if (uart_circ_empty(xmit)) {\r
- __stop_tx(up);\r
- return;\r
- }\r
-\r
- count = up->tx_loadsz;\r
- do {\r
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);\r
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);\r
- up->port.icount.tx++;\r
- if (uart_circ_empty(xmit))\r
- break;\r
- } while (--count > 0);\r
-\r
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
- uart_write_wakeup(&up->port);\r
-\r
- DEBUG_INTR("THRE...");\r
-\r
- if (uart_circ_empty(xmit))\r
- __stop_tx(up);\r
-}\r
-\r
-static unsigned int check_modem_status(struct uart_rk_port *up)\r
-{\r
- unsigned int status = serial_in(up, UART_MSR);\r
-\r
-#if 0\r
- status |= up->msr_saved_flags;\r
- up->msr_saved_flags = 0;\r
- if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&\r
- up->port.state != NULL) {\r
- if (status & UART_MSR_TERI)\r
- up->port.icount.rng++;\r
- if (status & UART_MSR_DDSR)\r
- up->port.icount.dsr++;\r
- if (status & UART_MSR_DDCD)\r
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);\r
- if (status & UART_MSR_DCTS)\r
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);\r
-\r
- wake_up_interruptible(&up->port.state->port.delta_msr_wait);\r
- }\r
-#endif\r
-\r
- return status;\r
-}\r
-\r
-\r
-/*\r
- * This handles the interrupt from one port.\r
- */\r
-static void serial_rk_handle_port(struct uart_rk_port *up)\r
-{\r
- unsigned int status;\r
- unsigned long flags;\r
- spin_lock_irqsave(&up->port.lock, flags);\r
-\r
- /* reading UART_LSR can automatically clears PE FE OE bits, except receive fifo error bit*/\r
- status = serial_in(up, UART_LSR);\r
-\r
- DEBUG_INTR("status = %x...", status);\r
- /* DMA mode enable */\r
- if(up->prk29_uart_dma_t->use_dma == 1) {\r
-\r
- if(up->iir & UART_IIR_RLSI){\r
- if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
- up->port_activity = jiffies;\r
- up->ier &= ~UART_IER_RLSI;\r
- up->ier &= ~UART_IER_RDI;\r
- serial_out(up, UART_IER, up->ier);\r
- //receive_chars(up, &status);\r
- //mod_timer(&up->prk29_uart_dma_t->rx_timer, jiffies +\r
- //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout));\r
- if(serial_rk_start_rx_dma(&up->port) == -1){\r
- receive_chars(up, &status);\r
- }\r
- }\r
- }\r
-\r
- }else { //dma mode disable\r
-\r
- /*\r
- * when uart receive a serial of data which doesn't have stop bit and so on, that causes frame error,and\r
- * set UART_LSR_RFE to one,what is worse,we couldn't read the data in the receive fifo. So if\r
- * wo don't clear this bit and reset the receive fifo, the received data available interrupt would\r
- * occur continuously. added by hhb@rock-chips.com 2011-08-05\r
- */\r
-\r
- if (status & UART_LSR_RFE) {\r
- \r
- if(up->port.line != DBG_PORT){\r
- status = serial_in(up, UART_LSR);\r
- dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
- }\r
- \r
- \r
- // rk29_uart_dump_register(up);\r
- }\r
-\r
- if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
- receive_chars(up, &status);\r
- }\r
- check_modem_status(up);\r
- if (status & UART_LSR_THRE) {\r
- transmit_chars(up);\r
- }\r
- }\r
-\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-}\r
-\r
-/*\r
- * This is the serial driver's interrupt routine.\r
- */\r
-\r
-static irqreturn_t serial_rk_interrupt(int irq, void *dev_id)\r
-{\r
- struct uart_rk_port *up = dev_id;\r
- int handled = 0;\r
- unsigned int iir;\r
-\r
- iir = serial_in(up, UART_IIR);\r
-\r
- DEBUG_INTR("%s(%d) iir = 0x%02x\n", __func__, irq, iir);\r
-\r
- up->iir = iir;\r
-\r
- if (!(iir & UART_IIR_NO_INT)) {\r
- serial_rk_handle_port(up);\r
- handled = 1;\r
- } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {\r
-\r
- /* The DesignWare APB UART has an Busy Detect (0x07)\r
- * interrupt meaning an LCR write attempt occured while the\r
- * UART was busy. The interrupt must be cleared by reading\r
- * the UART status register (USR) and the LCR re-written. */\r
-\r
- if(!(serial_in(up, UART_USR) & UART_USR_BUSY)){\r
- serial_out(up, UART_LCR, up->lcr);\r
- }\r
- handled = 1;\r
- dbg("the serial.%d is busy\n", up->port.line);\r
- }\r
- DEBUG_INTR("end(%d).\n", handled);\r
-\r
- return IRQ_RETVAL(handled);\r
-}\r
-\r
-static unsigned int serial_rk_tx_empty(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned long flags;\r
- unsigned int lsr;\r
-\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- spin_lock_irqsave(&up->port.lock, flags);\r
- lsr = serial_in(up, UART_LSR);\r
- up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-\r
- return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;\r
-}\r
-\r
-static unsigned int serial_rk_get_mctrl(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned int status;\r
- unsigned int ret;\r
-\r
- status = check_modem_status(up);\r
-\r
- ret = 0;\r
- if (status & UART_MSR_DCD)\r
- ret |= TIOCM_CAR;\r
- if (status & UART_MSR_RI)\r
- ret |= TIOCM_RNG;\r
- if (status & UART_MSR_DSR)\r
- ret |= TIOCM_DSR;\r
- if (status & UART_MSR_CTS)\r
- ret |= TIOCM_CTS;\r
- dev_dbg(port->dev, "%s 0x%08x\n", __func__, ret);\r
- return ret;\r
-}\r
-\r
-static void serial_rk_set_mctrl(struct uart_port *port, unsigned int mctrl)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned char mcr = 0;\r
-\r
- dev_dbg(port->dev, "+%s\n", __func__);\r
- if (mctrl & TIOCM_RTS)\r
- mcr |= UART_MCR_RTS;\r
- if (mctrl & TIOCM_DTR)\r
- mcr |= UART_MCR_DTR;\r
- if (mctrl & TIOCM_OUT1)\r
- mcr |= UART_MCR_OUT1;\r
- if (mctrl & TIOCM_OUT2)\r
- mcr |= UART_MCR_OUT2;\r
- if (mctrl & TIOCM_LOOP)\r
- mcr |= UART_MCR_LOOP;\r
-\r
- mcr |= up->mcr;\r
-\r
- serial_out(up, UART_MCR, mcr);\r
- dev_dbg(port->dev, "-serial.%d %s mcr: 0x%02x\n", port->line, __func__, mcr);\r
-}\r
-\r
-static void serial_rk_break_ctl(struct uart_port *port, int break_state)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned long flags;\r
-\r
- dev_dbg(port->dev, "+%s\n", __func__);\r
- spin_lock_irqsave(&up->port.lock, flags);\r
- if (break_state == -1)\r
- up->lcr |= UART_LCR_SBC;\r
- else\r
- up->lcr &= ~UART_LCR_SBC;\r
- serial_lcr_write(up, up->lcr);\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
- dev_dbg(port->dev, "-%s lcr: 0x%02x\n", __func__, up->lcr);\r
-}\r
-\r
-/*\r
- * Wait for transmitter & holding register to empty\r
- */\r
-static void wait_for_xmitr(struct uart_rk_port *up, int bits)\r
-{\r
- unsigned int status, tmout = 10000;\r
-\r
- /* Wait up to 10ms for the character(s) to be sent. */\r
- for (;;) {\r
- status = serial_in(up, UART_LSR);\r
-\r
- up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;\r
-\r
- if ((status & bits) == bits)\r
- break;\r
- if (--tmout == 0)\r
- break;\r
- udelay(1);\r
- }\r
-}\r
-\r
-#ifdef CONFIG_CONSOLE_POLL\r
-/*\r
- * Console polling routines for writing and reading from the uart while\r
- * in an interrupt or debug context.\r
- */\r
-\r
-static int serial_rk_get_poll_char(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned char lsr = serial_in(up, UART_LSR);\r
-\r
- while (!(lsr & UART_LSR_DR))\r
- lsr = serial_in(up, UART_LSR);\r
-\r
- return serial_in(up, UART_RX);\r
-}\r
-\r
-static void serial_rk_put_poll_char(struct uart_port *port,\r
- unsigned char c)\r
-{\r
- unsigned int ier;\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
- /*\r
- * First save the IER then disable the interrupts\r
- */\r
- ier = serial_in(up, UART_IER);\r
- serial_out(up, UART_IER, 0);\r
-\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
- /*\r
- * Send the character out.\r
- * If a LF, also do CR...\r
- */\r
- serial_out(up, UART_TX, c);\r
- if (c == 10) {\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
- serial_out(up, UART_TX, 13);\r
- }\r
-\r
- /*\r
- * Finally, wait for transmitter to become empty\r
- * and restore the IER\r
- */\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
- serial_out(up, UART_IER, ier);\r
-}\r
-\r
-#endif /* CONFIG_CONSOLE_POLL */\r
-\r
-static int serial_rk_startup(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned long flags;\r
- int retval;\r
-\r
-\r
- dev_dbg(port->dev, "%s\n", __func__);\r
-\r
- /*\r
- * Allocate the IRQ\r
- */\r
- retval = request_irq(up->port.irq, serial_rk_interrupt, up->port.irqflags,\r
- up->name, up);\r
- if (retval)\r
- return retval;\r
-\r
- up->mcr = 0;\r
-\r
- clk_enable(up->clk); // enable the config uart clock\r
-\r
- /*\r
- * Clear the FIFO buffers and disable them.\r
- * (they will be reenabled in set_termios())\r
- */\r
- serial_rk_clear_fifos(up);\r
-\r
- /*\r
- * Clear the interrupt registers.\r
- */\r
- (void) serial_in(up, UART_LSR);\r
- (void) serial_in(up, UART_RX);\r
- (void) serial_in(up, UART_IIR);\r
- (void) serial_in(up, UART_MSR);\r
- (void) serial_in(up, UART_USR);\r
-\r
- /*\r
- * Now, initialize the UART\r
- */\r
- serial_lcr_write(up, UART_LCR_WLEN8 | UART_LCR_EPAR);\r
-\r
- spin_lock_irqsave(&up->port.lock, flags);\r
-\r
- /*\r
- * Most PC uarts need OUT2 raised to enable interrupts.\r
- */\r
-// up->port.mctrl |= TIOCM_OUT2;\r
-\r
- serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
-\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-\r
- /*\r
- * Clear the interrupt registers again for luck, and clear the\r
- * saved flags to avoid getting false values from polling\r
- * routines or the previous session.\r
- */\r
- (void) serial_in(up, UART_LSR);\r
- (void) serial_in(up, UART_RX);\r
- (void) serial_in(up, UART_IIR);\r
- (void) serial_in(up, UART_MSR);\r
- (void) serial_in(up, UART_USR);\r
- up->lsr_saved_flags = 0;\r
-#if 0\r
- up->msr_saved_flags = 0;\r
-#endif\r
-\r
- if (1 == up->prk29_uart_dma_t->use_dma) {\r
-\r
- if(up->port.state->xmit.buf != up->prk29_uart_dma_t->tx_buffer){\r
- free_page((unsigned long)up->port.state->xmit.buf);\r
- up->port.state->xmit.buf = up->prk29_uart_dma_t->tx_buffer;\r
- }\r
-\r
-#if 1\r
- serial_rk_start_rx_dma(&up->port);\r
-#else\r
- up->ier |= UART_IER_RDI;\r
- up->ier |= UART_IER_RLSI;\r
- serial_out(up, UART_IER, up->ier);\r
-#endif\r
- up->port_activity = jiffies;\r
-\r
- }else{\r
- up->ier = 0;\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-\r
- /*\r
- * Finally, enable interrupts. Note: Modem status interrupts\r
- * are set via set_termios(), which will be occurring imminently\r
- * anyway, so we don't enable them here.\r
- */\r
-\r
- return 0;\r
-}\r
-\r
-\r
-static void serial_rk_shutdown(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned long flags;\r
-\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- /*\r
- * Disable interrupts from this port\r
- */\r
- up->ier = 0;\r
- serial_out(up, UART_IER, 0);\r
-\r
- spin_lock_irqsave(&up->port.lock, flags);\r
-// up->port.mctrl &= ~TIOCM_OUT2;\r
- serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-\r
- /*\r
- * Disable break condition and FIFOs\r
- */\r
- serial_lcr_write(up, serial_in(up, UART_LCR) & ~UART_LCR_SBC);\r
- serial_rk_clear_fifos(up);\r
-\r
- /*\r
- * Read data port to reset things, and then free the irq\r
- */\r
- (void) serial_in(up, UART_RX);\r
-\r
- free_irq(up->port.irq, up);\r
-}\r
-\r
-static void\r
-serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,\r
- struct ktermios *old)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- unsigned char cval, fcr = 0;\r
- unsigned long flags;\r
- unsigned int baud, quot;\r
- int timeout = 1000000;\r
- dev_dbg(port->dev, "+%s\n", __func__);\r
-\r
- switch (termios->c_cflag & CSIZE) {\r
- case CS5:\r
- cval = UART_LCR_WLEN5;\r
- break;\r
- case CS6:\r
- cval = UART_LCR_WLEN6;\r
- break;\r
- case CS7:\r
- cval = UART_LCR_WLEN7;\r
- break;\r
- case CS8:\r
- default:\r
- cval = UART_LCR_WLEN8;\r
- break;\r
- }\r
-\r
- if (termios->c_cflag & CSTOPB){\r
- cval |= UART_LCR_STOP;\r
- }\r
- if (termios->c_cflag & PARENB){\r
- cval |= UART_LCR_PARITY;\r
- }\r
- if (!(termios->c_cflag & PARODD)){\r
- cval |= UART_LCR_EPAR;\r
- }\r
-#ifdef CMSPAR\r
- if (termios->c_cflag & CMSPAR)\r
- cval |= UART_LCR_SPAR;\r
-#endif\r
-\r
-\r
- /*\r
- * Ask the core to calculate the divisor for us.\r
- */\r
- baud = uart_get_baud_rate(port, termios, old,\r
- port->uartclk / 16 / 0xffff,\r
- port->uartclk / 16);\r
-\r
- quot = uart_get_divisor(port, baud);\r
-\r
- dev_info(up->port.dev, "baud:%d\n", baud);\r
-// dev_info(up->port.dev, "quot:%d\n", quot);\r
-\r
- /*\r
- * To wait long enough to avoid writting lcr when the uart is busy\r
- * because of data communication, so that we can set lcr and baud rate\r
- * successfully. added by hhb@rock-chips.com\r
- */\r
-\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
- if(--timeout == 0){\r
- if(port->line != DBG_PORT){\r
- serial_out(up, UART_SRR, UART_RESET);\r
- }\r
- dbg("rk_serial_set_termios uart.%d timeout,irq=%d,ret=0x%x AND uart is reseted\n",\r
- port->line, port->irq, serial_in(up, UART_USR));\r
- break;\r
- }\r
- cpu_relax();\r
- }\r
-\r
-\r
- printk("serial.%d timeout:%d\n", up->port.line,timeout);\r
-\r
-\r
- if (baud < 2400){\r
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
- }\r
- else{\r
- //added by hhb@rock-chips.com\r
- if(up->prk29_uart_dma_t->use_timer == 1){\r
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_01;\r
- }\r
- else{\r
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_01;\r
- }\r
- }\r
-\r
- /*\r
- * MCR-based auto flow control. When AFE is enabled, RTS will be\r
- * deasserted when the receive FIFO contains more characters than\r
- * the trigger, or the MCR RTS bit is cleared. In the case where\r
- * the remote UART is not using CTS auto flow control, we must\r
- * have sufficient FIFO entries for the latency of the remote\r
- * UART to respond. IOW, at least 32 bytes of FIFO.\r
- */\r
- up->mcr &= ~UART_MCR_AFE;\r
- if (termios->c_cflag & CRTSCTS){\r
- up->mcr |= UART_MCR_AFE;\r
- }\r
-\r
- /*\r
- * Ok, we're now changing the port state. Do it with\r
- * interrupts disabled.\r
- */\r
- spin_lock_irqsave(&up->port.lock, flags);\r
-\r
- /*\r
- * Update the per-port timeout.\r
- */\r
- uart_update_timeout(port, termios->c_cflag, baud);\r
-\r
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;\r
- if (termios->c_iflag & INPCK)\r
- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;\r
- if (termios->c_iflag & (BRKINT | PARMRK))\r
- up->port.read_status_mask |= UART_LSR_BI;\r
-\r
- /*\r
- * Characteres to ignore\r
- */\r
- up->port.ignore_status_mask = 0;\r
- if (termios->c_iflag & IGNPAR)\r
- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;\r
- if (termios->c_iflag & IGNBRK) {\r
- up->port.ignore_status_mask |= UART_LSR_BI;\r
- /*\r
- * If we're ignoring parity and break indicators,\r
- * ignore overruns too (for real raw support).\r
- */\r
- if (termios->c_iflag & IGNPAR)\r
- up->port.ignore_status_mask |= UART_LSR_OE;\r
- }\r
-\r
- /*\r
- * ignore all characters if CREAD is not set\r
- */\r
- if ((termios->c_cflag & CREAD) == 0)\r
- up->port.ignore_status_mask |= UART_LSR_DR;\r
-\r
- /*\r
- * CTS flow control flag and modem status interrupts\r
- */\r
- up->ier &= ~UART_IER_MSI;\r
-#if 0\r
- if (UART_ENABLE_MS(&up->port, termios->c_cflag))\r
- up->ier |= UART_IER_MSI;\r
-#endif\r
-\r
- up->lcr = cval; /* Save LCR */\r
- /* set DLAB */\r
- if(serial_lcr_write(up, cval | UART_LCR_DLAB)){\r
- dbg("serial.%d set DLAB fail\n", up->port.line);\r
- serial_out(up, UART_SRR, UART_RESET);\r
- goto fail;\r
- }\r
-\r
- /* set uart baud rate */\r
- if(serial_dl_write(up, quot)){\r
- dbg("serial.%d set dll fail\n", up->port.line);\r
- serial_out(up, UART_SRR, UART_RESET);\r
- goto fail;\r
- }\r
-\r
- /* reset DLAB */\r
- if(serial_lcr_write(up, cval)){\r
- dbg("serial.%d reset DLAB fail\n", up->port.line);\r
- serial_out(up, UART_SRR, UART_RESET);\r
- goto fail;\r
- }\r
- else{\r
- serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
- serial_out(up, UART_FCR, fcr); /* set fcr */\r
- up->fcr = fcr;\r
- /* enable the uart interrupt last */\r
- up->ier |= UART_IER_RDI;\r
- up->ier |= UART_IER_RLSI;\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-\r
- /* Don't rewrite B0 */\r
- if (tty_termios_baud_rate(termios))\r
- tty_termios_encode_baud_rate(termios, baud, baud);\r
- dev_dbg(port->dev, "-%s baud %d\n", __func__, baud);\r
-\r
- return;\r
-\r
-fail:\r
- spin_unlock_irqrestore(&up->port.lock, flags);\r
-\r
-}\r
-\r
-#if 0\r
-static void\r
-serial_rk_set_ldisc(struct uart_port *port, int new)\r
-{\r
- if (new == N_PPS) {\r
- port->flags |= UPF_HARDPPS_CD;\r
- serial_rk_enable_ms(port);\r
- } else\r
- port->flags &= ~UPF_HARDPPS_CD;\r
-}\r
-#endif\r
-\r
-static void\r
-serial_rk_pm(struct uart_port *port, unsigned int state,\r
- unsigned int oldstate)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
- dev_dbg(port->dev, "%s: %s\n", __func__, state ? "disable" : "enable");\r
- if (state)\r
- clk_disable(up->clk);\r
- else\r
- clk_enable(up->clk);\r
-}\r
-\r
-static void serial_rk_release_port(struct uart_port *port)\r
-{\r
- dev_dbg(port->dev, "%s\n", __func__);\r
-}\r
-\r
-static int serial_rk_request_port(struct uart_port *port)\r
-{\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- return 0;\r
-}\r
-\r
-static void serial_rk_config_port(struct uart_port *port, int flags)\r
-{\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- port->type = PORT_RK;\r
-}\r
-\r
-static int\r
-serial_rk_verify_port(struct uart_port *port, struct serial_struct *ser)\r
-{\r
- /* we don't want the core code to modify any port params */\r
- dev_dbg(port->dev, "%s\n", __func__);\r
- return -EINVAL;\r
-}\r
-\r
-static const char *\r
-serial_rk_type(struct uart_port *port)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
- dev_dbg(port->dev, "%s: %s\n", __func__, up->name);\r
- return up->name;\r
-}\r
-\r
-static struct uart_ops serial_rk_pops = {\r
- .tx_empty = serial_rk_tx_empty,\r
- .set_mctrl = serial_rk_set_mctrl,\r
- .get_mctrl = serial_rk_get_mctrl,\r
- .stop_tx = serial_rk_stop_tx,\r
- .start_tx = serial_rk_start_tx,\r
- .stop_rx = serial_rk_stop_rx,\r
- .enable_ms = serial_rk_enable_ms,\r
- .break_ctl = serial_rk_break_ctl,\r
- .startup = serial_rk_startup,\r
- .shutdown = serial_rk_shutdown,\r
- .set_termios = serial_rk_set_termios,\r
-#if 0\r
- .set_ldisc = serial_rk_set_ldisc,\r
-#endif\r
- .pm = serial_rk_pm,\r
- .type = serial_rk_type,\r
- .release_port = serial_rk_release_port,\r
- .request_port = serial_rk_request_port,\r
- .config_port = serial_rk_config_port,\r
- .verify_port = serial_rk_verify_port,\r
-#ifdef CONFIG_CONSOLE_POLL\r
- .poll_get_char = serial_rk_get_poll_char,\r
- .poll_put_char = serial_rk_put_poll_char,\r
-#endif\r
-};\r
-\r
-#ifdef CONFIG_SERIAL_RK_CONSOLE\r
-\r
-static struct uart_rk_port *serial_rk_console_ports[UART_NR];\r
-\r
-static void serial_rk_console_putchar(struct uart_port *port, int ch)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
-\r
- wait_for_xmitr(up, UART_LSR_THRE);\r
- serial_out(up, UART_TX, ch);\r
-}\r
-\r
-/*\r
- * Print a string to the serial port trying not to disturb\r
- * any possible real use of the port...\r
- *\r
- * The console_lock must be held when we get here.\r
- */\r
-static void\r
-serial_rk_console_write(struct console *co, const char *s, unsigned int count)\r
-{\r
- struct uart_rk_port *up = serial_rk_console_ports[co->index];\r
- unsigned long flags;\r
- unsigned int ier;\r
- int locked = 1;\r
-\r
- touch_nmi_watchdog();\r
-\r
- local_irq_save(flags);\r
- if (up->port.sysrq) {\r
- /* serial_rk_handle_port() already took the lock */\r
- locked = 0;\r
- } else if (oops_in_progress) {\r
- locked = spin_trylock(&up->port.lock);\r
- } else\r
- spin_lock(&up->port.lock);\r
-\r
- /*\r
- * First save the IER then disable the interrupts\r
- */\r
- ier = serial_in(up, UART_IER);\r
-\r
- serial_out(up, UART_IER, 0);\r
-\r
- uart_console_write(&up->port, s, count, serial_rk_console_putchar);\r
-\r
- /*\r
- * Finally, wait for transmitter to become empty\r
- * and restore the IER\r
- */\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
- serial_out(up, UART_IER, ier);\r
-\r
-#if 0\r
- /*\r
- * The receive handling will happen properly because the\r
- * receive ready bit will still be set; it is not cleared\r
- * on read. However, modem control will not, we must\r
- * call it if we have saved something in the saved flags\r
- * while processing with interrupts off.\r
- */\r
- if (up->msr_saved_flags)\r
- check_modem_status(up);\r
-#endif\r
-\r
- if (locked)\r
- spin_unlock(&up->port.lock);\r
- local_irq_restore(flags);\r
-}\r
-\r
-static int __init serial_rk_console_setup(struct console *co, char *options)\r
-{\r
- struct uart_rk_port *up;\r
- int baud = 115200;\r
- int bits = 8;\r
- int parity = 'n';\r
- int flow = 'n';\r
-\r
- if (unlikely(co->index >= UART_NR || co->index < 0))\r
- return -ENODEV;\r
-\r
- if (serial_rk_console_ports[co->index] == NULL)\r
- return -ENODEV;\r
- up = serial_rk_console_ports[co->index];\r
-\r
- if (options)\r
- uart_parse_options(options, &baud, &parity, &bits, &flow);\r
-\r
- return uart_set_options(&up->port, co, baud, parity, bits, flow);\r
-}\r
-\r
-static struct console serial_rk_console = {\r
- .name = "ttyS",\r
- .write = serial_rk_console_write,\r
- .device = uart_console_device,\r
- .setup = serial_rk_console_setup,\r
- .flags = CON_PRINTBUFFER | CON_ANYTIME,\r
- .index = -1,\r
- .data = &serial_rk_reg,\r
-};\r
-\r
-static void serial_rk_add_console_port(struct uart_rk_port *up)\r
-{\r
- serial_rk_console_ports[up->pdev->id] = up;\r
-}\r
-\r
-#define SERIAL_CONSOLE &serial_rk_console\r
-#else\r
-#define SERIAL_CONSOLE NULL\r
-\r
-static inline void serial_rk_add_console_port(struct uart_rk_port *up)\r
-{}\r
-\r
-#endif\r
-\r
-static struct uart_driver serial_rk_reg = {\r
- .owner = THIS_MODULE,\r
- .driver_name = "rk29_serial",\r
- .dev_name = "ttyS",\r
- .major = TTY_MAJOR,\r
- .minor = 64,\r
- .cons = SERIAL_CONSOLE,\r
- .nr = UART_NR,\r
-};\r
-\r
-static int __devinit serial_rk_probe(struct platform_device *pdev)\r
-{\r
- struct uart_rk_port *up;\r
- struct resource *mem;\r
- int irq;\r
- int ret = -ENOSPC;\r
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- if (!mem) {\r
- dev_err(&pdev->dev, "no mem resource?\n");\r
- return -ENODEV;\r
- }\r
-\r
- irq = platform_get_irq(pdev, 0);\r
- if (irq < 0) {\r
- dev_err(&pdev->dev, "no irq resource?\n");\r
- return irq;\r
- }\r
-\r
- if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,\r
- pdev->dev.driver->name)) {\r
- dev_err(&pdev->dev, "memory region already claimed\n");\r
- return -EBUSY;\r
- }\r
-\r
- up = kzalloc(sizeof(*up), GFP_KERNEL);\r
- if (up == NULL) {\r
- ret = -ENOMEM;\r
- goto do_release_region;\r
- }\r
-\r
- sprintf(up->name, "rk29_serial.%d", pdev->id);\r
- up->pdev = pdev;\r
- up->clk = clk_get(&pdev->dev, "uart");\r
- if (unlikely(IS_ERR(up->clk))) {\r
- ret = PTR_ERR(up->clk);\r
- goto do_free;\r
- }\r
- up->tx_loadsz = 30;\r
- up->prk29_uart_dma_t = &rk29_uart_ports_dma_t[pdev->id];\r
- up->port.dev = &pdev->dev;\r
- up->port.type = PORT_RK;\r
- up->port.irq = irq;\r
- up->port.iotype = UPIO_DWAPB;\r
-\r
- up->port.regshift = 2;\r
- up->port.fifosize = 32;\r
- up->port.ops = &serial_rk_pops;\r
- up->port.line = pdev->id;\r
- up->port.iobase = mem->start;\r
- up->port.membase = ioremap_nocache(mem->start, mem->end - mem->start + 1);\r
- if (!up->port.membase) {\r
- ret = -ENOMEM;\r
- goto do_put_clk;\r
- }\r
- up->port.mapbase = mem->start;\r
- up->port.irqflags = IRQF_DISABLED;\r
- up->port.uartclk = clk_get_rate(up->clk);\r
-\r
- /* set dma config */\r
- if(1 == up->prk29_uart_dma_t->use_dma) {\r
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);\r
-\r
- //timer\r
- up->prk29_uart_dma_t->use_timer = USE_TIMER;\r
- up->prk29_uart_dma_t->rx_timer.function = serial_rk_rx_timeout;\r
- up->prk29_uart_dma_t->rx_timer.data = (unsigned long)up;\r
- up->prk29_uart_dma_t->rx_timeout = 7;\r
- up->prk29_uart_dma_t->rx_timer.expires = jiffies + msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout);\r
- init_timer(&up->prk29_uart_dma_t->rx_timer);\r
- //tx buffer\r
- up->prk29_uart_dma_t->tx_buffer_size = UART_XMIT_SIZE;\r
- up->prk29_uart_dma_t->tx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->tx_buffer_size,\r
- &up->prk29_uart_dma_t->tx_phy_addr, DMA_MEMORY_MAP);\r
- if(!up->prk29_uart_dma_t->tx_buffer){\r
- dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n");\r
- }\r
- else{\r
- dev_info(up->port.dev, "dma_tx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_buffer);\r
- dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_phy_addr);\r
- }\r
- //rx buffer\r
- up->prk29_uart_dma_t->rx_buffer_size = UART_XMIT_SIZE*32;\r
- up->prk29_uart_dma_t->rx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->rx_buffer_size,\r
- &up->prk29_uart_dma_t->rx_phy_addr, DMA_MEMORY_MAP);\r
- up->prk29_uart_dma_t->rb_pre_pos = 0;\r
- if(!up->prk29_uart_dma_t->rx_buffer){\r
- dev_info(up->port.dev, "dmam_alloc_coherent dma_rx_buffer fail\n");\r
- }\r
- else {\r
- dev_info(up->port.dev, "dma_rx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->rx_buffer);\r
- dev_info(up->port.dev, "up 0x%08x\n", (unsigned)up->prk29_uart_dma_t);\r
- }\r
-\r
- // work queue\r
- INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc);\r
- INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx);\r
- up->uart_wq = create_singlethread_workqueue("uart_workqueue");\r
- up->prk29_uart_dma_t->rx_dma_start = 0;\r
- spin_lock_init(&(up->prk29_uart_dma_t->tx_lock));\r
- spin_lock_init(&(up->prk29_uart_dma_t->rx_lock));\r
- serial_rk_init_dma_rx(&up->port);\r
- serial_rk_init_dma_tx(&up->port);\r
- up->ier |= THRE_MODE; // enable THRE interrupt mode\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-\r
- serial_rk_add_console_port(up);\r
- ret = uart_add_one_port(&serial_rk_reg, &up->port);\r
- if (ret != 0)\r
- goto do_iounmap;\r
-\r
- platform_set_drvdata(pdev, up);\r
- dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase);\r
-\r
- return 0;\r
-\r
-do_iounmap:\r
- iounmap(up->port.membase);\r
- up->port.membase = NULL;\r
-do_put_clk:\r
- clk_put(up->clk);\r
-do_free:\r
- kfree(up);\r
-do_release_region:\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
- return ret;\r
-}\r
-\r
-static int __devexit serial_rk_remove(struct platform_device *pdev)\r
-{\r
- struct uart_rk_port *up = platform_get_drvdata(pdev);\r
-\r
- platform_set_drvdata(pdev, NULL);\r
- if (up) {\r
- struct resource *mem;\r
- destroy_workqueue(up->uart_wq);\r
- uart_remove_one_port(&serial_rk_reg, &up->port);\r
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- iounmap(up->port.membase);\r
- up->port.membase = NULL;\r
- clk_put(up->clk);\r
- kfree(up);\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int serial_rk_suspend(struct platform_device *dev, pm_message_t state)\r
-{\r
- struct uart_rk_port *up = platform_get_drvdata(dev);\r
-\r
- if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
- uart_suspend_port(&serial_rk_reg, &up->port);\r
- }\r
- if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
- serial_rk_pm(&up->port, 1, 0);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static int serial_rk_resume(struct platform_device *dev)\r
-{\r
- struct uart_rk_port *up = platform_get_drvdata(dev);\r
-\r
- if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
- uart_resume_port(&serial_rk_reg, &up->port);\r
- }\r
- if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
- serial_rk_pm(&up->port, 0, 1);\r
- }\r
- return 0;\r
-}\r
-\r
-static struct platform_driver serial_rk_driver = {\r
- .probe = serial_rk_probe,\r
- .remove = __devexit_p(serial_rk_remove),\r
- .suspend = serial_rk_suspend,\r
- .resume = serial_rk_resume,\r
- .driver = {\r
-#if defined(CONFIG_SERIAL_RK29)\r
- .name = "rk29_serial",\r
-#elif defined(CONFIG_SERIAL_RK2818)\r
- .name = "rk2818_serial",\r
-#else\r
- .name = "rk_serial",\r
-#endif\r
- .owner = THIS_MODULE,\r
- },\r
-};\r
-\r
-static int __init serial_rk_init(void)\r
-{\r
- int ret;\r
-\r
- ret = uart_register_driver(&serial_rk_reg);\r
- if (ret)\r
- return ret;\r
-\r
- ret = platform_driver_register(&serial_rk_driver);\r
- if (ret != 0)\r
- uart_unregister_driver(&serial_rk_reg);\r
-\r
- return ret;\r
-}\r
-\r
-static void __exit serial_rk_exit(void)\r
-{\r
- platform_driver_unregister(&serial_rk_driver);\r
- uart_unregister_driver(&serial_rk_reg);\r
-}\r
-\r
-module_init(serial_rk_init);\r
-module_exit(serial_rk_exit);\r
-\r
-MODULE_LICENSE("GPL");\r
-MODULE_DESCRIPTION("RK UART driver");\r
-\r
+++ /dev/null
-/*
- *
- * Copyright (C) 2010 liuyixing <lyx@rock-chips.com>
- *
- *
- * Example platform data:
-
- static struct plat_sc8800 sc8800_plat_data = {
- .slav_rts_pin = RK29_PIN4_PD0,
- .slav_rdy_pin = RK29_PIN4_PD0,
- .master_rts_pin = RK29_PIN4_PD0,
- .master_rdy_pin = RK29_PIN4_PD0,
- //.poll_time = 100,
- };
-
- static struct spi_board_info spi_board_info[] = {
- {
- .modalias = "sc8800",
- .platform_data = &sc8800_plat_data,
- .max_speed_hz = 12*1000*1000,
- .chip_select = 0,
- },
- };
-
- * The initial minor number is 209 in the low-density serial port:
- * mknod /dev/ttySPI0 c 204 209
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/gpio.h>
-
-#include "sc8800.h"
-
-struct sc8800_port {
- struct uart_port port;
- struct spi_device *spi;
-
- int cts; /* last CTS received for flow ctrl */
- int tx_empty; /* last TX empty bit */
-
- spinlock_t conf_lock; /* shared data */
- int conf; /* configuration for the SC88000
- * (bits 0-7, bits 8-11 are irqs) */
-
- int rx_enabled; /* if we should rx chars */
-
- int irq; /* irq assigned to the sc8800 */
-
- int minor; /* minor number */
- int loopback; /* 1 if we are in loopback mode */
-
- /* for handling irqs: need workqueue since we do spi_sync */
- struct workqueue_struct *workqueue;
- struct work_struct work;
- /* set to 1 to make the workhandler exit as soon as possible */
- int force_end_work;
- /* need to know we are suspending to avoid deadlock on workqueue */
- int suspending;
-
- /* hook for suspending SC8800 via dedicated pin */
- void (*sc8800_hw_suspend) (int suspend);
-
- /* poll time (in ms) for ctrl lines */
- int poll_time;
- /* and its timer */
- struct timer_list timer;
-
- /*signal define, always gpio*/
- int slav_rts;
- int slav_rdy;
- int master_rts;
- int master_rdy;
-};
-
-#define SC8800_MAJOR 204
-#define SC8800_MINOR 209
-#define MAX_SC8800 1
-
-#define SPI_MAX_PACKET (8192-128)
-#define FREAM_SIZE 64
-#define SPI_DMA_SIZE PAGE_SIZE
-
-void * g_dma_buffer = NULL;
-dma_addr_t g_dma_addr;
-
-#if 1
-#define sc8800_dbg(x...) printk(x)
-#else
-#define sc8800_dbg(x...)
-#endif
-
-static struct sc8800_port *sc8800s[MAX_SC8800]; /* the chips */
-static DEFINE_MUTEX(sc8800s_lock); /* race on probe */
-
-static int sc8800_get_slave_rts_status(struct sc8800_port *s)
-{
- return gpio_get_value(s->slav_rts);
-}
-
-static int sc8800_get_slave_rdy_status(struct sc8800_port *s)
-{
- return gpio_get_value(s->slav_rdy);
-}
-
-static void sc8800_set_master_rts_status(struct sc8800_port *s, int value)
-{
- gpio_set_value(s->master_rts, value);
-}
-
-static void sc8800_set_master_rdy_status(struct sc8800_port *s, int value)
-{
- gpio_set_value(s->master_rdy, value);
-}
-
-static int sc8800_send_head_data(struct sc8800_port *s, u32 data_len)
-{
- char head[64] = {0};
- struct spi_message message;
- int status;
- struct spi_transfer tran;
-
- head[0] = 0x7f;
- head[1] = 0x7e;
- head[2] = 0x55;
- head[3] = 0xaa;
- head[4] = data_len & 0xff;
- head[5] = (data_len>>8) & 0xff;
- head[6] = (data_len>>16) & 0xff;
- head[7] = (data_len>>24) & 0xff;
-
- tran.tx_buf = (void *)(head);
- tran.len = FREAM_SIZE;
-
- spi_message_init(&message);
- spi_message_add_tail(&tran, &message);
- status = spi_sync(s->spi, &message);
- if (status) {
- dev_warn(&s->spi->dev, "error while calling spi_sync\n");
- return -EIO;
- }
-
- return 0;
-}
-static int sc8800_recv_and_parse_head_data(struct sc8800_port *s, u32 *len)
-{
- struct spi_message message;
- int status;
- struct spi_transfer tran;
- char buf[64] = {0};
- u32 data_len = 0;
-
- tran.rx_buf = (void *)buf;
- tran.len = FREAM_SIZE;
-
- spi_message_init(&message);
- spi_message_add_tail(&tran, &message);
- status = spi_sync(s->spi, &message);
- if (status) {
- dev_warn(&s->spi->dev, "error while calling spi_sync\n");
- return -EIO;
- }
-
- if ((buf[0]!=0x7f) || (buf[1]!=0x7e) || (buf[2]!=0x55) || (buf[3]!=0xaa)) {
- dev_warn(&s->spi->dev, "line %d, error head data", __LINE__);
- return -EIO;
- }
-
- data_len = buf[5] + (buf[6]<<8) + (buf[7]<<16) + (buf[8]<<24);
-
- *len = data_len;
-
- sc8800_dbg("line %d, %d data need to read\n", __LINE__, *len);
-
- return 0;
-}
-
-static int sc8800_send_data(struct sc8800_port *s, char *buf, int len)
-{
-#if 1
- int status;
- struct spi_message message;
- struct spi_transfer tran;
-
- tran.tx_buf = (void *)buf;
- tran.len = len;
-
- spi_message_init(&message);
- spi_message_add_tail(&tran, &message);
- status = spi_sync(s->spi, &message);
- if (status) {
- dev_warn(&s->spi->dev, "error while calling spi_sync\n");
- return -EIO;
- }
-#else
- int status;
- struct spi_message message;
- struct spi_transfer tran;
-
- spi_message_init(&message);
-
- if (!g_dma_buffer) {
- g_dma_buffer = dma_alloc_coherent(NULL, SPI_DMA_SIZE, &g_dma_addr, GFP_KERNEL | GFP_DMA);
- if (!g_dma_buffer) {
- dev_err(&s->spi->dev, "alloc dma memory fail\n");
- }
- }
-
- if (!g_dma_buffer) { //nomal
- sc8800_dbg("send data nomal");
- tran.tx_buf = (void *)buf;
- tran.len = len;
- }
- else { //dma
- //message.is_dma_mapped = 1;
- //memcpy(g_dma_buffer, buf, );
- }
-
- spi_message_add_tail(&tran, &message);
- status = spi_sync(s->spi, &message);
- if (status) {
- dev_warn(&s->spi->dev, "error while calling spi_sync\n");
- return -EIO;
- }
-#endif
-
- return 0;
-}
-
-static int sc8800_recv_data(struct sc8800_port *s, char *buf, int len)
-{
- struct spi_message message;
- int status;
- struct spi_transfer tran;
-
- tran.rx_buf = (void *)buf;
- tran.len = len;
-
- spi_message_init(&message);
- spi_message_add_tail(&tran, &message);
- status = spi_sync(s->spi, &message);
- if (status) {
- dev_warn(&s->spi->dev, "error while calling spi_sync\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static void sc8800_work(struct work_struct *w);
-
-static void sc8800_dowork(struct sc8800_port *s)
-{
- if (!s->force_end_work && !work_pending(&s->work) &&
- !freezing(current) && !s->suspending)
- queue_work(s->workqueue, &s->work);
-}
-
-static void sc8800_timeout(unsigned long data)
-{
- struct sc8800_port *s = (struct sc8800_port *)data;
-
- if (s->port.state) {
- sc8800_dowork(s);
- mod_timer(&s->timer, jiffies + s->poll_time);
- }
-}
-
-static void sc8800_work(struct work_struct *w)
-{
- struct sc8800_port *s = container_of(w, struct sc8800_port, work);
- struct circ_buf *xmit = &s->port.state->xmit;
- u32 len,i;
- char *buf = NULL;
- unsigned char ch;
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- if (sc8800_get_slave_rts_status(s) == GPIO_HIGH) { //do wirte, master--->slave
- if (sc8800_get_slave_rdy_status(s) == GPIO_HIGH) { /*1.check slave rdy, must be high*/
- if (!(uart_circ_empty(xmit))) {
- len = uart_circ_chars_pending(xmit);
- len = (len > SPI_MAX_PACKET) ? SPI_MAX_PACKET : len;
- sc8800_dbg("send data length = %d\n", len);
-
- sc8800_set_master_rts_status(s, GPIO_LOW); /*2.set master rts low*/
- sc8800_send_head_data(s,len); /*3.send 64byte head data*/
- while (sc8800_get_slave_rdy_status(s)) { /*4.check slav rdy, wait for low */
- msleep(1);
- }
-
- /*5.long data transmit*/
- sc8800_send_data(s, xmit->buf+xmit->tail, len);
-
- while(sc8800_get_slave_rdy_status(s)==GPIO_LOW) { /*6.wait for slave rdy high*/
- msleep(1);
- }
-
- sc8800_set_master_rts_status(s, GPIO_HIGH); /*end transmit, set master rts high*/
- xmit->tail = (xmit->tail + len) & (UART_XMIT_SIZE - 1);
- s->port.icount.tx += len;
- }
- }
- else { //slave not ready, do it next time
- queue_work(s->workqueue, &s->work);
- }
- }
- else { //do read, slave--->master
- sc8800_set_master_rdy_status(s, GPIO_LOW);
- sc8800_recv_and_parse_head_data(s, &len);
-
- buf = (char *)kzalloc(len, GFP_KERNEL);
- if (!buf) {
- dev_err(&s->spi->dev, "line %d, err while malloc mem\n", __LINE__);
- sc8800_set_master_rdy_status(s, GPIO_HIGH);
- return ;
- }
- memset(buf, 0, len);
- sc8800_recv_data(s, buf, len);
-
- while (sc8800_get_slave_rts_status(s) == GPIO_LOW) {
- msleep(1);
- }
- sc8800_set_master_rdy_status(s, GPIO_HIGH);
-
- for (i=0; i<len; i++) {
- ch = buf[i];
- uart_insert_char(&s->port, 0, 0, ch, TTY_NORMAL);
- }
- tty_flip_buffer_push(s->port.state->port.tty);
- }
-}
-
-static irqreturn_t sc8800_irq(int irqno, void *dev_id)
-{
- struct sc8800_port *s = dev_id;
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- sc8800_dowork(s);
- return IRQ_HANDLED;
-}
-
-static void sc8800_enable_ms(struct uart_port *port)
-{
- struct sc8800_port *s = container_of(port,
- struct sc8800_port,
- port);
-
- if (s->poll_time > 0)
- mod_timer(&s->timer, jiffies);
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static void sc8800_start_tx(struct uart_port *port)
-{
- struct sc8800_port *s = container_of(port,
- struct sc8800_port,
- port);
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- sc8800_dowork(s);
-}
-
-static void sc8800_stop_rx(struct uart_port *port)
-{
- struct sc8800_port *s = container_of(port,
- struct sc8800_port,
- port);
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- s->rx_enabled = 0;
-
- sc8800_dowork(s);
-}
-
-static void sc8800_shutdown(struct uart_port *port)
-{
- struct sc8800_port *s = container_of(port,
- struct sc8800_port,
- port);
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- if (s->suspending)
- return;
-
- s->force_end_work = 1;
-
- if (s->poll_time > 0)
- del_timer_sync(&s->timer);
-
- if (s->workqueue) {
- flush_workqueue(s->workqueue);
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- }
- if (s->irq)
- free_irq(s->irq, s);
-
- gpio_free(s->master_rdy);
- gpio_free(s->master_rts);
- gpio_free(s->slav_rdy);
- gpio_free(s->slav_rts);
-
- /* set shutdown mode to save power */
- if (s->sc8800_hw_suspend)
- s->sc8800_hw_suspend(1);
-}
-
-static int sc8800_startup(struct uart_port *port)
-{
- struct sc8800_port *s = container_of(port,
- struct sc8800_port,
- port);
- int ret;
- char b[12];
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- s->rx_enabled = 1;
-
- if (s->suspending)
- return 0;
-
- s->force_end_work = 0;
-
- sprintf(b, "sc8800-%d", s->minor);
- s->workqueue = create_freezeable_workqueue(b);
- if (!s->workqueue) {
- dev_warn(&s->spi->dev, "cannot create workqueue\n");
- return -EBUSY;
- }
- INIT_WORK(&s->work, sc8800_work);
-
- ret = gpio_request(s->slav_rts, "slav rts");
- if (ret) {
- dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
- ret = -EBUSY;
- goto gpio_err1;
- }
- ret = gpio_request(s->slav_rdy, "slav rdy");
- if (ret) {
- dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
- ret = -EBUSY;
- goto gpio_err2;
- }
- ret = gpio_request(s->master_rts, "master rts");
- if (ret) {
- dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
- ret = -EBUSY;
- goto gpio_err3;
- }
- ret = gpio_request(s->master_rdy, "master rdy");
- if (ret) {
- dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
- ret = -EBUSY;
- goto gpio_err4;
- }
-
- gpio_direction_input(s->slav_rts);
- gpio_pull_updown(s->slav_rts, GPIOPullUp);
- gpio_direction_input(s->slav_rdy);
- gpio_pull_updown(s->slav_rdy, GPIOPullUp);
- gpio_direction_output(s->master_rts, GPIO_HIGH);
- gpio_direction_output(s->master_rdy, GPIO_HIGH);
-
- if (request_irq(s->irq, sc8800_irq,
- IRQF_TRIGGER_FALLING, "sc8800", s) < 0) {
- dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
- s->irq = 0;
- goto irq_err;
- }
-
- if (s->sc8800_hw_suspend)
- s->sc8800_hw_suspend(0);
-
- sc8800_dowork(s);
-
- sc8800_enable_ms(&s->port);
-
- return 0;
-
-irq_err:
- gpio_free(s->master_rdy);
-gpio_err4:
- gpio_free(s->master_rts);
-gpio_err3:
- gpio_free(s->slav_rdy);
-gpio_err2:
- gpio_free(s->slav_rts);
-gpio_err1:
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- return ret;
-
-}
-
-static struct uart_ops sc8800_ops = {
- .start_tx = sc8800_start_tx,
- .stop_rx = sc8800_stop_rx,
- .startup = sc8800_startup,
- .shutdown = sc8800_shutdown,
-};
-
-static struct uart_driver sc8800_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = "ttySPI",
- .dev_name = "ttySPI",
- .major = SC8800_MAJOR,
- .minor = SC8800_MINOR,
- .nr = MAX_SC8800,
-};
-static int uart_driver_registered;
-
-static int __devinit sc8800_probe(struct spi_device *spi)
-{
- int i, retval;
- struct plat_sc8800 *pdata;
-
- mutex_lock(&sc8800s_lock);
-
- if (!uart_driver_registered) {
- uart_driver_registered = 1;
- retval = uart_register_driver(&sc8800_uart_driver);
- if (retval) {
- printk(KERN_ERR "Couldn't register sc8800 uart driver\n");
- mutex_unlock(&sc8800s_lock);
- return retval;
- }
- }
-
- for (i = 0; i < MAX_SC8800; i++)
- if (!sc8800s[i])
- break;
- if (i == MAX_SC8800) {
- dev_warn(&spi->dev, "too many SC8800 chips\n");
- mutex_unlock(&sc8800s_lock);
- return -ENOMEM;
- }
-
- sc8800s[i] = kzalloc(sizeof(struct sc8800_port), GFP_KERNEL);
- if (!sc8800s[i]) {
- dev_warn(&spi->dev,
- "kmalloc for sc8800 structure %d failed!\n", i);
- mutex_unlock(&sc8800s_lock);
- return -ENOMEM;
- }
- sc8800s[i]->spi = spi;
- spin_lock_init(&sc8800s[i]->conf_lock);
- dev_set_drvdata(&spi->dev, sc8800s[i]);
- pdata = spi->dev.platform_data;
- sc8800s[i]->irq = gpio_to_irq(pdata->slav_rts_pin);
- sc8800s[i]->slav_rts = pdata->slav_rts_pin;
- sc8800s[i]->slav_rdy = pdata->slav_rdy_pin;
- sc8800s[i]->master_rts = pdata->master_rts_pin;
- sc8800s[i]->master_rdy = pdata->master_rdy_pin;
- //sc8800s[i]->sc8800_hw_suspend = pdata->sc8800_hw_suspend;
- sc8800s[i]->minor = i;
- init_timer(&sc8800s[i]->timer);
- sc8800s[i]->timer.function = sc8800_timeout;
- sc8800s[i]->timer.data = (unsigned long) sc8800s[i];
-
- dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
- sc8800s[i]->port.irq = sc8800s[i]->irq;
- sc8800s[i]->port.uartclk = 24000000;
- sc8800s[i]->port.fifosize = 64;
- sc8800s[i]->port.ops = &sc8800_ops;
- sc8800s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- sc8800s[i]->port.line = i;
- sc8800s[i]->port.dev = &spi->dev;
- retval = uart_add_one_port(&sc8800_uart_driver, &sc8800s[i]->port);
- if (retval < 0)
- dev_warn(&spi->dev,
- "uart_add_one_port failed for line %d with error %d\n",
- i, retval);
-
- /* set shutdown mode to save power. Will be woken-up on open */
- if (sc8800s[i]->sc8800_hw_suspend)
- sc8800s[i]->sc8800_hw_suspend(1);
-
- mutex_unlock(&sc8800s_lock);
- return 0;
-}
-
-static int __devexit sc8800_remove(struct spi_device *spi)
-{
- struct sc8800_port *s = dev_get_drvdata(&spi->dev);
- int i;
-
- mutex_lock(&sc8800s_lock);
-
- /* find out the index for the chip we are removing */
- for (i = 0; i < MAX_SC8800; i++)
- if (sc8800s[i] == s)
- break;
-
- dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
- uart_remove_one_port(&sc8800_uart_driver, &sc8800s[i]->port);
- kfree(sc8800s[i]);
- sc8800s[i] = NULL;
-
- /* check if this is the last chip we have */
- for (i = 0; i < MAX_SC8800; i++)
- if (sc8800s[i]) {
- mutex_unlock(&sc8800s_lock);
- return 0;
- }
- pr_debug("removing sc8800 driver\n");
- uart_unregister_driver(&sc8800_uart_driver);
-
- mutex_unlock(&sc8800s_lock);
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int sc8800_suspend(struct spi_device *spi, pm_message_t state)
-{
- struct sc8800_port *s = dev_get_drvdata(&spi->dev);
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- disable_irq(s->irq);
-
- s->suspending = 1;
- uart_suspend_port(&sc8800_uart_driver, &s->port);
-
- if (s->sc8800_hw_suspend)
- s->sc8800_hw_suspend(1);
-
- return 0;
-}
-
-static int sc8800_resume(struct spi_device *spi)
-{
- struct sc8800_port *s = dev_get_drvdata(&spi->dev);
-
- dev_dbg(&s->spi->dev, "%s\n", __func__);
-
- if (s->sc8800_hw_suspend)
- s->sc8800_hw_suspend(0);
- uart_resume_port(&sc8800_uart_driver, &s->port);
- s->suspending = 0;
-
- enable_irq(s->irq);
-
- if (s->workqueue)
- sc8800_dowork(s);
-
- return 0;
-}
-
-#else
-#define sc8800_suspend NULL
-#define sc8800_resume NULL
-#endif
-
-static struct spi_driver sc8800_driver = {
- .driver = {
- .name = "sc8800",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
-
- .probe = sc8800_probe,
- .remove = __devexit_p(sc8800_remove),
- .suspend = sc8800_suspend,
- .resume = sc8800_resume,
-};
-
-static int __init sc8800_init(void)
-{
- return spi_register_driver(&sc8800_driver);
-}
-module_init(sc8800_init);
-
-static void __exit sc8800_exit(void)
-{
- spi_unregister_driver(&sc8800_driver);
-}
-module_exit(sc8800_exit);
-
-MODULE_DESCRIPTION("SC8800 driver");
-MODULE_AUTHOR("liuyixing <lyx@rock-chips.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:SC8800");
+++ /dev/null
-#ifndef __SC8800_H__\r
-#define __SC8800_H__\r
-\r
-typedef struct _spi_packet_head {\r
- u16 tag; //HEADER_TAG(0x7e7f) \r
- u16 type; //HEADER_TYPE(0xaa55) \r
- u32 length; //the length of data after head (8192-128 bytes) \r
- u32 frame_num; //no used , always 0\r
- u32 reserved2; //reserved \r
-} SPI_PACKET_HEAD_T;\r
-\r
-\r
-/*define flatform data struct*/\r
-struct plat_sc8800 {\r
- int slav_rts_pin;\r
- int slav_rdy_pin;\r
- int master_rts_pin;\r
- int master_rdy_pin;\r
- int poll_time;\r
-};\r
-\r
-#endif\r
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"
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/
#include <linux/hrtimer.h>
#include <linux/err.h>
#include <linux/gpio.h>
-
+#include <linux/wakelock.h>
+#include <linux/delay.h>
#include "timed_output.h"
#include "timed_gpio.h"
+#define GPIO_TYPE 0
struct timed_gpio_data {
struct timed_output_dev dev;
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;
}
{
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)
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;
}
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 <lockwood@android.com>");
unsigned gpio;
int max_timeout;
u8 active_low;
+ int adjust_time;
};
struct timed_gpio_platform_data {
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(
}
/* Initialize the semaphore.. Come up in unlocked state. */
- init_MUTEX(*Mutex);
+ sema_init(*Mutex, 1);
/* Return status. */
return gcvSTATUS_OK;
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
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
--- /dev/null
+/*
+ * drivers/serial/rk2818_serial.h
+ *
+ * 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.
+ */
+
+#ifndef __DRIVERS_SERIAL_RK2818_SERIAL_H
+#define __DRIVERS_SERIAL_RK2818_SERIAL_H
+
+#define UART_RBR 0x0000 /* Receive Buffer Register */
+#define UART_THR 0x0000 /* Transmit Holding Register */
+#define UART_DLL 0x0000 /* Divisor Latch (Low) */
+#define UART_DLH 0x0004 /* Divisor Latch (High) */
+#define UART_IER 0x0004 /* Interrupt Enable Register */
+#define UART_IIR 0x0008 /* Interrupt Identification Register */
+#define UART_FCR 0x0008 /* FIFO Control Register */
+#define UART_LCR 0x000C /* Line Control Register */
+#define UART_MCR 0x0010 /* Modem Control Register */
+#define UART_LSR 0x0014 /* [0x0000_0060] Line Status Register */
+#define UART_MSR 0x0018 /* Modem Status Register */
+#define UART_SCR 0x001c /* Scratchpad Register */
+#define UART_SRBR(n) (0x0030+((n) * 4)) /* Shadow Receive Buffer Register */
+#define UART_STHR(n) (0x0030+((n) * 4)) /* Shadow Transmit Holding Register */
+#define UART_FAR 0x0070 /* FIFO Access Register */
+#define UART_TFR 0x0074 /* Transmit FIFO Read */
+#define UART_RFW 0x0078 /* Receive FIFO Write */
+#define UART_USR 0x007C /* UART Status Register */
+#define UART_TFL 0x0080 /* Transmit FIFO Level */
+#define UART_RFL 0x0084 /* Receive FIFO Level */
+#define UART_SRR 0x0088 /* Software Reset Register */
+#define UART_SRTS 0x008C /* Shadow Request to Send */
+#define UART_SBCR 0x0090 /* Shadow Break Control Register */
+#define UART_SDMAM 0x0094 /* Shadow DMA Mode */
+#define UART_SFE 0x0098 /* Shadow FIFO Enable */
+#define UART_SRT 0x009C /* Shadow RCVR Trigger */
+#define UART_STET 0x00A0 /* Shadow TX Empty Trigger */
+#define UART_HTX 0x00A4 /* Halt TX */
+#define UART_DMASA 0x00A8 /* DMA Software Acknowledge */
+#define UART_CPR 0x00F4 /* Component Parameter Register */
+#define UART_UCV 0x00F8 /* [0x3330_372a] UART Component Version */
+#define UART_CTR 0x00FC /* [0x4457_0110] Component Type Register */
+
+//#define UART_FCR 0x08
+#define UART_FCR_FIFO_ENABLE (1<<0)
+#define UART_FCR_CLEAR_RCVR (1<<1) /* Clear the RCVR FIFO */
+#define UART_FCR_CLEAR_XMIT (1<<2) /* Clear the XMIT FIFO */
+#define UART_FCR_DMA_SELECT (1<<3) /* For DMA applications */
+#define UART_FCR_R_TRIG_00 0x00
+#define UART_FCR_R_TRIG_01 0x40
+#define UART_FCR_R_TRIG_10 0x80
+#define UART_FCR_R_TRIG_11 0xc0
+#define UART_FCR_T_TRIG_00 0x00
+#define UART_FCR_T_TRIG_01 0x10
+#define UART_FCR_T_TRIG_10 0x20
+#define UART_FCR_T_TRIG_11 0x30
+
+//#define UART_LCR 0x0c
+#define LCR_DLA_EN (1<<7)
+#define BREAK_CONTROL_BIT (1<<6)
+#define EVEN_PARITY_SELECT (1<<4)
+#define EVEN_PARITY (1<<4)
+#define ODD_PARITY (0)
+#define PARITY_DISABLED (0)
+#define PARITY_ENABLED (1<<3)
+#define ONE_STOP_BIT (0)
+#define ONE_HALF_OR_TWO_BIT (1<<2)
+#define LCR_WLS_5 (0x00)
+#define LCR_WLS_6 (0x01)
+#define LCR_WLS_7 (0x02)
+#define LCR_WLS_8 (0x03)
+#define UART_DATABIT_MASK (0x03)
+
+/* Detail UART_IER Register Description */
+#define UART_IER_THRE_MODE_INT_ENABLE 1<<7
+#define UART_IER_MODEM_STATUS_INT_ENABLE 1<<3
+#define UART_IER_RECV_LINE_STATUS_INT_ENABLE 1<<2
+#define UART_IER_SEND_EMPTY_INT_ENABLE 1<<1
+#define UART_IER_RECV_DATA_AVAIL_INT_ENABLE 1<<0
+
+
+/* Detail UART_IIR Register Description */
+#define UART_IIR_FIFO_DISABLE 0x00
+#define UART_IIR_FIFO_ENABLE 0x03
+#define UART_IIR_INT_ID_MASK 0x0F
+#define UART_IIR_MODEM_STATUS 0x00
+#define UART_IIR_NO_INTERRUPT_PENDING 0x01
+#define UART_IIR_THR_EMPTY 0x02
+#define UART_IIR_RECV_AVAILABLE 0x04
+#define UART_IIR_RECV_LINE_STATUS 0x06
+#define UART_IIR_BUSY_DETECT 0x07
+#define UART_IIR_CHAR_TIMEOUT 0x0C
+
+//#define UART_MCR 0x10
+/* Modem Control Register */
+#define UART_SIR_ENABLE (1 << 6)
+#define UART_MCR_AFCEN (1 << 5) /* Auto Flow Control Mode enabled */
+#define UART_MCR_URLB (1 << 4) /* Loop-back mode */
+#define UART_MCR_UROUT2 (1 << 3) /* OUT2 signal */
+#define UART_MCR_UROUT1 (1 << 2) /* OUT1 signal */
+#define UART_MCR_URRTS (1 << 1) /* Request to Send */
+#define UART_MCR_URDTR (1 << 0) /* Data Terminal Ready */
+
+//#define UART_MSR 0x18
+/* Modem Status Register */
+#define UART_MSR_URDCD (1 << 7) /* Data Carrier Detect */
+#define UART_MSR_URRI (1 << 6) /* Ring Indicator */
+#define UART_MSR_URDSR (1 << 5) /* Data Set Ready */
+#define UART_MSR_URCTS (1 << 4) /* Clear to Send */
+#define UART_MSR_URDDCD (1 << 3) /* Delta Data Carrier Detect */
+#define UART_MSR_URTERI (1 << 2) /* Trailing Edge Ring Indicator */
+#define UART_MSR_URDDST (1 << 1) /* Delta Data Set Ready */
+#define UART_MSR_URDCTS (1 << 0) /* Delta Clear to Send */
+
+/* Detail UART_USR Register Description */
+#define UART_RECEIVE_FIFO_FULL (1<<4)
+#define UART_RECEIVE_FIFO_NOT_FULL (0)
+#define UART_RECEIVE_FIFO_EMPTY (0)
+#define UART_RECEIVE_FIFO_NOT_EMPTY (1<<3)
+#define UART_TRANSMIT_FIFO_NOT_EMPTY (0)
+#define UART_TRANSMIT_FIFO_EMPTY (1<<2)
+#define UART_TRANSMIT_FIFO_FULL (0)
+#define UART_TRANSMIT_FIFO_NOT_FULL (1<<1)
+#define UART_USR_BUSY (1)
+
+/*UART_LSR Line Status Register*/
+#define UART_BREAK_INT_BIT (1<<4)/*break Interrupt bit*/
+
+#endif /* __DRIVERS_SERIAL_RK2818_SERIAL_H */
--- /dev/null
+/*\r
+ * Driver for RK-UART controller.\r
+ * Based on drivers/tty/serial/8250.c\r
+ *\r
+ * Copyright (C) 2011 Rochchip.\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+\r
+ * (at your option) any later version.\r
+ *\r
+ * Author: hhb@rock-chips.com\r
+ * Date: 2011.06.18\r
+ */\r
+\r
+#ifndef CONFIG_SERIAL_RK_CONSOLE\r
+#if defined(CONFIG_SERIAL_RK29_CONSOLE)\r
+#define CONFIG_SERIAL_RK_CONSOLE\r
+#endif\r
+#endif\r
+\r
+#if defined(CONFIG_SERIAL_RK_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)\r
+#define SUPPORT_SYSRQ\r
+#endif\r
+\r
+//#define DEBUG\r
+#include <linux/module.h>\r
+#include <linux/ioport.h>\r
+#include <linux/init.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <linux/delay.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/tty.h>\r
+#include <linux/ratelimit.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/serial_core.h>\r
+#include <linux/serial.h>\r
+#include <linux/serial_8250.h>\r
+#include <linux/nmi.h>\r
+#include <linux/mutex.h>\r
+#include <linux/slab.h>\r
+#include <linux/clk.h>\r
+#include <linux/timer.h>\r
+#include <linux/workqueue.h>\r
+#include <mach/rk29-dma-pl330.h>\r
+#include <linux/dma-mapping.h>\r
+\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+\r
+\r
+#define PORT_RK 90\r
+#define UART_USR 0x1F /* UART Status Register */\r
+#define UART_USR_BUSY (1)\r
+#define UART_IER_PTIME 0x80 /* Programmable THRE Interrupt Mode Enable */\r
+#define UART_LSR_RFE 0x80 /* receive fifo error */\r
+#define UART_SRR 0x22 /* software reset register */\r
+#define UART_RESET 0x01\r
+#define RX_TIMEOUT (3000*10) //uint ms\r
+\r
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)\r
+\r
+#define UART_NR 4 //uart port number\r
+#define POWER_MANEGEMENT 1\r
+\r
+/* configurate whether the port transmit-receive by DMA */\r
+#define OPEN_DMA 1\r
+#define CLOSE_DMA 0\r
+\r
+#ifdef CONFIG_UART0_DMA_RK29\r
+#define UART0_USE_DMA OPEN_DMA\r
+#else\r
+#define UART0_USE_DMA CLOSE_DMA\r
+#endif\r
+\r
+#ifdef CONFIG_UART2_DMA_RK29\r
+#define UART2_USE_DMA OPEN_DMA\r
+#else\r
+#define UART2_USE_DMA CLOSE_DMA\r
+#endif\r
+\r
+#ifdef CONFIG_UART3_DMA_RK29\r
+#define UART3_USE_DMA OPEN_DMA\r
+#else\r
+#define UART3_USE_DMA CLOSE_DMA\r
+#endif\r
+\r
+#define UART1_USE_DMA CLOSE_DMA\r
+\r
+#define DMA_TX_TRRIGE_LEVEL 30\r
+\r
+#define USE_TIMER 1 // use timer for dma transport\r
+#define THRE_MODE 0X00 //0yhh\r
+\r
+static struct uart_driver serial_rk_reg;\r
+\r
+/*\r
+ * Debugging.\r
+ */\r
+#define DBG_PORT 1 //DBG_PORT which uart is used to print log message\r
+\r
+#ifdef CONFIG_SERIAL_CORE_CONSOLE\r
+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)\r
+#else\r
+#define uart_console(port) (0)\r
+#endif\r
+\r
+#define DEBUG 0\r
+\r
+extern void printascii(const char *);\r
+static void dbg(const char *fmt, ...)\r
+{\r
+ va_list va;\r
+ char buff[256];\r
+\r
+ va_start(va, fmt);\r
+ vsprintf(buff, fmt, va);\r
+ va_end(va);\r
+\r
+ printascii(buff);\r
+}\r
+\r
+#if DEBUG\r
+#define DEBUG_INTR(fmt...) if (!uart_console(&up->port)) dbg(fmt)\r
+#else\r
+#define DEBUG_INTR(fmt...) do { } while (0)\r
+#endif\r
+\r
+\r
+/* added by hhb@rock-chips.com for uart dma transfer */\r
+\r
+struct rk29_uart_dma_t {\r
+ u32 use_dma; //1:used\r
+ u32 rx_dma_start;\r
+ enum dma_ch rx_dmach;\r
+ enum dma_ch tx_dmach;\r
+ u32 tx_dma_inited;\r
+ u32 rx_dma_inited;\r
+ spinlock_t tx_lock;\r
+ spinlock_t rx_lock;\r
+ char * rx_buffer;\r
+ char * tx_buffer;\r
+ dma_addr_t rx_phy_addr;\r
+ dma_addr_t tx_phy_addr;\r
+ u32 rx_buffer_size;\r
+ u32 tx_buffer_size;\r
+\r
+ u32 rb_cur_pos;\r
+ u32 rb_pre_pos;\r
+ u32 rx_size;\r
+ char use_timer;\r
+ char tx_dma_used;\r
+ /* timer to poll activity on rx dma */\r
+ struct timer_list rx_timer;\r
+ int rx_timeout;\r
+\r
+};\r
+\r
+struct uart_rk_port {\r
+ struct uart_port port;\r
+ struct platform_device *pdev;\r
+ struct clk *clk;\r
+ unsigned int tx_loadsz; /* transmit fifo load size */\r
+ unsigned char ier;\r
+ unsigned char lcr;\r
+ unsigned char mcr;\r
+ unsigned char iir;\r
+ unsigned char fcr;\r
+ /*\r
+ * Some bits in registers are cleared on a read, so they must\r
+ * be saved whenever the register is read but the bits will not\r
+ * be immediately processed.\r
+ */\r
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS\r
+ unsigned char lsr_saved_flags;\r
+#if 0\r
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA\r
+ unsigned char msr_saved_flags;\r
+#endif\r
+\r
+ char name[12];\r
+ char fifo[32];\r
+ char fifo_size;\r
+ unsigned long port_activity;\r
+ struct work_struct uart_work;\r
+ struct work_struct uart_work_rx;\r
+ struct workqueue_struct *uart_wq;\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t;\r
+};\r
+\r
+static void serial_rk_release_dma_tx(struct uart_port *port);\r
+static int serial_rk_start_tx_dma(struct uart_port *port);\r
+static void serial_rk_rx_timeout(unsigned long uart);\r
+static void serial_rk_release_dma_rx(struct uart_port *port);\r
+static int serial_rk_start_rx_dma(struct uart_port *port);\r
+static int serial_rk_startup(struct uart_port *port);\r
+static inline unsigned int serial_in(struct uart_rk_port *up, int offset)\r
+{\r
+ offset = offset << 2;\r
+ return readb(up->port.membase + offset);\r
+}\r
+\r
+/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */\r
+static inline void dwapb_save_out_value(struct uart_rk_port *up, int offset,\r
+ unsigned char value)\r
+{\r
+ if (offset == UART_LCR)\r
+ up->lcr = value;\r
+}\r
+\r
+/* Read the IER to ensure any interrupt is cleared before returning from ISR. */\r
+static inline void dwapb_check_clear_ier(struct uart_rk_port *up, int offset)\r
+{\r
+ if (offset == UART_TX || offset == UART_IER)\r
+ serial_in(up, UART_IER);\r
+}\r
+\r
+static inline void serial_out(struct uart_rk_port *up, int offset, unsigned char value)\r
+{\r
+ dwapb_save_out_value(up, offset, value);\r
+ writeb(value, up->port.membase + (offset << 2));\r
+ dwapb_check_clear_ier(up, offset);\r
+}\r
+\r
+/* Uart divisor latch read */\r
+static inline int serial_dl_read(struct uart_rk_port *up)\r
+{\r
+ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;\r
+}\r
+\r
+/* Uart divisor latch write */\r
+static int serial_dl_write(struct uart_rk_port *up, unsigned int value)\r
+{\r
+ unsigned int tmout = 100;\r
+ if(up->port.line != DBG_PORT)\r
+ {\r
+ while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){\r
+ if (--tmout == 0){\r
+ dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line);\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ tmout = 15000;\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+ if (--tmout == 0){\r
+ dbg("set serial.%d baudrate timeout\n", up->port.line);\r
+ return -1;\r
+ }\r
+ }\r
+ }\r
+\r
+ serial_out(up, UART_DLL, value & 0xff);\r
+ serial_out(up, UART_DLM, value >> 8 & 0xff);\r
+\r
+ return 0;\r
+\r
+}\r
+\r
+static int serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
+{\r
+ unsigned int tmout = 15000;\r
+\r
+ if(up->port.line != DBG_PORT)\r
+ {\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+\r
+ if (--tmout == 0){\r
+ dbg("set serial.%d lc r = 0x%02x timeout\n", up->port.line, value);\r
+ return -1;\r
+ }\r
+ udelay(1);\r
+ }\r
+ }\r
+\r
+ serial_out(up, UART_LCR, value);\r
+\r
+ return 0;\r
+}\r
+\r
+static inline void serial_rk_enable_ier_thri(struct uart_rk_port *up)\r
+{\r
+ if (!(up->ier & UART_IER_THRI)) {\r
+ up->ier |= UART_IER_THRI;\r
+ serial_out(up, UART_IER, up->ier);\r
+ }\r
+}\r
+\r
+\r
+static inline void serial_rk_disable_ier_thri(struct uart_rk_port *up)\r
+{\r
+ if (up->ier & UART_IER_THRI) {\r
+ up->ier &= ~UART_IER_THRI;\r
+ serial_out(up, UART_IER, up->ier);\r
+ }\r
+}\r
+#if 0\r
+static int rk29_uart_dump_register(struct uart_rk_port *up){\r
+\r
+ unsigned int reg_value = 0;\r
+\r
+ reg_value = serial_in(up, UART_IER);\r
+ dbg("UART_IER = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_IIR);\r
+ dbg("UART_IIR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_LSR);\r
+ dbg("UART_LSR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_MSR);\r
+ dbg("UART_MSR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_MCR);\r
+ dbg("UART_MCR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, 0x21);\r
+ dbg("UART_RFL = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_LCR);\r
+ dbg("UART_LCR = 0x%0x\n", reg_value);\r
+ return 0;\r
+\r
+}\r
+#endif\r
+\r
+/*\r
+ * FIFO support.\r
+ */\r
+static void serial_rk_clear_fifos(struct uart_rk_port *up)\r
+{\r
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);\r
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |\r
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);\r
+ serial_out(up, UART_FCR, 0);\r
+}\r
+\r
+static inline void __stop_tx(struct uart_rk_port *p)\r
+{\r
+ if (p->ier & UART_IER_THRI) {\r
+ p->ier &= ~UART_IER_THRI;\r
+ serial_out(p, UART_IER, p->ier);\r
+ }\r
+}\r
+\r
+static void serial_rk_stop_tx(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+\r
+ if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
+ serial_rk_release_dma_tx(port);\r
+ }\r
+ __stop_tx(up);\r
+}\r
+\r
+\r
+static void serial_rk_start_tx(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+\r
+ if(0 == serial_rk_start_tx_dma(port)){\r
+ serial_rk_enable_ier_thri(up);\r
+ }\r
+\r
+}\r
+\r
+\r
+static void serial_rk_stop_rx(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+\r
+ if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
+ serial_rk_release_dma_rx(port);\r
+ }\r
+ up->ier &= ~UART_IER_RLSI;\r
+ up->port.read_status_mask &= ~UART_LSR_DR;\r
+ serial_out(up, UART_IER, up->ier);\r
+}\r
+\r
+\r
+static void serial_rk_enable_ms(struct uart_port *port)\r
+{\r
+ /* no MSR capabilities */\r
+#if 0\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ up->ier |= UART_IER_MSI;\r
+ serial_out(up, UART_IER, up->ier);\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+ * Start transmitting by dma.\r
+ */\r
+#define DMA_SERIAL_BUFFER_SIZE UART_XMIT_SIZE\r
+\r
+/* added by hhb@rock-chips.com for uart dma transfer*/\r
+static struct rk29_uart_dma_t rk29_uart_ports_dma_t[] = {\r
+ {UART0_USE_DMA, 0, DMACH_UART0_RX, DMACH_UART0_TX},\r
+ {UART1_USE_DMA, 0, DMACH_UART1_RX, DMACH_UART1_TX},\r
+ {UART2_USE_DMA, 0, DMACH_UART2_RX, DMACH_UART2_TX},\r
+ {UART3_USE_DMA, 0, DMACH_UART3_RX, DMACH_UART3_TX},\r
+};\r
+\r
+\r
+/* DMAC PL330 add by hhb@rock-chips.com */\r
+static struct rk29_dma_client rk29_uart_dma_client = {\r
+ .name = "rk29xx-uart-dma",\r
+};\r
+\r
+/*TX*/\r
+\r
+static void serial_rk_release_dma_tx(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(!port){\r
+ return;\r
+ }\r
+ if(prk29_uart_dma_t && prk29_uart_dma_t->tx_dma_inited) {\r
+ rk29_dma_free(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client);\r
+ prk29_uart_dma_t->tx_dma_inited = 0;\r
+ }\r
+}\r
+\r
+/*this function will be called every time after rk29_dma_enqueue() be invoked*/\r
+static void serial_rk_dma_txcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
+ struct uart_port *port = buf;\r
+ struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
+ struct circ_buf *xmit = &port->state->xmit;\r
+\r
+ if(result != RK29_RES_OK){\r
+ return;\r
+ }\r
+\r
+ port->icount.tx += size;\r
+ xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);\r
+\r
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
+ uart_write_wakeup(&up->port);\r
+ spin_lock(&(up->prk29_uart_dma_t->tx_lock));\r
+ up->prk29_uart_dma_t->tx_dma_used = 0;\r
+ spin_unlock(&(up->prk29_uart_dma_t->tx_lock));\r
+ if (!uart_circ_empty(xmit)) {\r
+ serial_rk_start_tx_dma(port);\r
+ }\r
+\r
+ up->port_activity = jiffies;\r
+// dev_info(up->port.dev, "s:%d\n", size);\r
+}\r
+\r
+static int serial_rk_init_dma_tx(struct uart_port *port) {\r
+\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(!port || !prk29_uart_dma_t){\r
+ dev_info(up->port.dev, "serial_rk_init_dma_tx fail\n");\r
+ return -1;\r
+ }\r
+\r
+ if(prk29_uart_dma_t->tx_dma_inited) {\r
+ return 0;\r
+ }\r
+\r
+ if (rk29_dma_request(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
+ dev_info(up->port.dev, "rk29_dma_request tx fail\n");\r
+ return -1;\r
+ }\r
+\r
+ if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->tx_dmach, serial_rk_dma_txcb)) {\r
+ dev_info(up->port.dev, "rk29_dma_set_buffdone_fn tx fail\n");\r
+ return -1;\r
+ }\r
+ if (rk29_dma_devconfig(prk29_uart_dma_t->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) {\r
+ dev_info(up->port.dev, "rk29_dma_devconfig tx fail\n");\r
+ return -1;\r
+ }\r
+ if (rk29_dma_config(prk29_uart_dma_t->tx_dmach, 1, 1)) {\r
+ dev_info(up->port.dev, "rk29_dma_config tx fail\n");\r
+ return -1;\r
+ }\r
+\r
+ prk29_uart_dma_t->tx_dma_inited = 1;\r
+ dev_info(up->port.dev, "serial_rk_init_dma_tx sucess\n");\r
+ return 0;\r
+\r
+}\r
+\r
+static int serial_rk_start_tx_dma(struct uart_port *port)\r
+{\r
+\r
+ struct circ_buf *xmit = &port->state->xmit;\r
+ struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+\r
+ if(0 == prk29_uart_dma_t->use_dma){\r
+ return CLOSE_DMA;\r
+ }\r
+\r
+ if(-1 == serial_rk_init_dma_tx(port)){\r
+ goto err_out;\r
+ }\r
+\r
+ if (1 == prk29_uart_dma_t->tx_dma_used){\r
+ return 1;\r
+ }\r
+ if(!uart_circ_empty(xmit)){\r
+ if (rk29_dma_enqueue(prk29_uart_dma_t->tx_dmach, port,\r
+ prk29_uart_dma_t->tx_phy_addr + xmit->tail,\r
+ CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE))) {\r
+ goto err_out;\r
+ }\r
+ }\r
+ rk29_dma_ctrl(prk29_uart_dma_t->tx_dmach, RK29_DMAOP_START);\r
+ spin_lock(&(prk29_uart_dma_t->tx_lock));\r
+ up->prk29_uart_dma_t->tx_dma_used = 1;\r
+ spin_unlock(&(prk29_uart_dma_t->tx_lock));\r
+\r
+ return 1;\r
+err_out:\r
+ dev_info(up->port.dev, "-serial_rk_start_tx_dma-error-\n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+\r
+/*RX*/\r
+static void serial_rk_dma_rxcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
+\r
+\r
+}\r
+\r
+static void serial_rk_release_dma_rx(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(!port){\r
+ return;\r
+ }\r
+ if(prk29_uart_dma_t && prk29_uart_dma_t->rx_dma_inited) {\r
+ del_timer(&prk29_uart_dma_t->rx_timer);\r
+ rk29_dma_free(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client);\r
+ prk29_uart_dma_t->rb_pre_pos = 0;\r
+ prk29_uart_dma_t->rx_dma_inited = 0;\r
+ prk29_uart_dma_t->rx_dma_start = 0;\r
+ }\r
+}\r
+\r
+\r
+static int serial_rk_init_dma_rx(struct uart_port *port) {\r
+\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(!port || !prk29_uart_dma_t){\r
+ dev_info(up->port.dev, "serial_rk_init_dma_rx: port fail\n");\r
+ return -1;\r
+ }\r
+ if(prk29_uart_dma_t->rx_dma_inited) {\r
+ return 0;\r
+ }\r
+\r
+ if (rk29_dma_request(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
+ dev_info(up->port.dev, "rk29_dma_request fail rx \n");\r
+ return -1;\r
+ }\r
+\r
+ if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->rx_dmach, serial_rk_dma_rxcb)) {\r
+ dev_info(up->port.dev, "rk29_dma_set_buffdone_fn rx fail\n");\r
+ return -1;\r
+ }\r
+ if (rk29_dma_devconfig(prk29_uart_dma_t->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) {\r
+ dev_info(up->port.dev, "rk29_dma_devconfig rx fail\n");\r
+ return -1;\r
+ }\r
+\r
+ if (rk29_dma_config(prk29_uart_dma_t->rx_dmach, 1, 1)) {\r
+ dev_info(up->port.dev, "rk29_dma_config rx fail\n");\r
+ return -1;\r
+ }\r
+\r
+ rk29_dma_setflags(prk29_uart_dma_t->rx_dmach, RK29_DMAF_CIRCULAR);\r
+\r
+ prk29_uart_dma_t->rx_dma_inited = 1;\r
+ dev_info(up->port.dev, "serial_rk_init_dma_rx sucess\n");\r
+ return 0;\r
+\r
+}\r
+\r
+static int serial_rk_start_rx_dma(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(0 == prk29_uart_dma_t->use_dma){\r
+ return 0;\r
+ }\r
+\r
+ if(prk29_uart_dma_t->rx_dma_start == 1){\r
+ return 0;\r
+ }\r
+\r
+ if(-1 == serial_rk_init_dma_rx(port)){\r
+ dev_info(up->port.dev, "*******serial_rk_init_dma_rx*******error*******\n");\r
+ return -1;\r
+ }\r
+\r
+ if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up, prk29_uart_dma_t->rx_phy_addr,\r
+ prk29_uart_dma_t->rx_buffer_size/2)) {\r
+ dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
+ return -1;\r
+ }\r
+\r
+ if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up,\r
+ prk29_uart_dma_t->rx_phy_addr+prk29_uart_dma_t->rx_buffer_size/2,\r
+ prk29_uart_dma_t->rx_buffer_size/2)) {\r
+ dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
+ return -1;\r
+ }\r
+\r
+ rk29_dma_ctrl(prk29_uart_dma_t->rx_dmach, RK29_DMAOP_START);\r
+ prk29_uart_dma_t->rx_dma_start = 1;\r
+ if(prk29_uart_dma_t->use_timer == 1){\r
+ mod_timer(&prk29_uart_dma_t->rx_timer, jiffies +\r
+ msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
+ }\r
+ up->port_activity = jiffies;\r
+ return 1;\r
+}\r
+\r
+static void serial_rk_update_rb_addr(struct uart_rk_port *up){\r
+ dma_addr_t current_pos = 0;\r
+ dma_addr_t rx_current_pos = 0;\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
+ rk29_dma_getposition(prk29_uart_dma_t->rx_dmach, ¤t_pos, &rx_current_pos);\r
+\r
+ prk29_uart_dma_t->rb_cur_pos = (rx_current_pos - prk29_uart_dma_t->rx_phy_addr);\r
+ prk29_uart_dma_t->rx_size = CIRC_CNT(prk29_uart_dma_t->rb_cur_pos,\r
+ prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size);\r
+\r
+ spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
+}\r
+\r
+static void serial_rk_report_dma_rx(unsigned long uart)\r
+{\r
+ struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
+ struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ if(prk29_uart_dma_t->use_timer == 1){\r
+ serial_rk_update_rb_addr(up);\r
+ }\r
+ if(prk29_uart_dma_t->rx_size > 0) {\r
+ spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
+\r
+ if(prk29_uart_dma_t->rb_cur_pos > prk29_uart_dma_t->rb_pre_pos){\r
+ tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
+ + prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_size);\r
+ tty_flip_buffer_push(up->port.state->port.tty);\r
+ }\r
+ else if(prk29_uart_dma_t->rb_cur_pos < prk29_uart_dma_t->rb_pre_pos){\r
+\r
+ tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
+ + prk29_uart_dma_t->rb_pre_pos, CIRC_CNT_TO_END(prk29_uart_dma_t->rb_cur_pos,\r
+ prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size));\r
+ tty_flip_buffer_push(up->port.state->port.tty);\r
+\r
+ if(prk29_uart_dma_t->rb_cur_pos != 0){\r
+ tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer,\r
+ prk29_uart_dma_t->rb_cur_pos);\r
+ tty_flip_buffer_push(up->port.state->port.tty);\r
+ }\r
+ }\r
+\r
+ prk29_uart_dma_t->rb_pre_pos = (prk29_uart_dma_t->rb_pre_pos + prk29_uart_dma_t->rx_size)\r
+ & (prk29_uart_dma_t->rx_buffer_size - 1);\r
+ up->port.icount.rx += prk29_uart_dma_t->rx_size;\r
+ spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
+ prk29_uart_dma_t->rx_timeout = 7;\r
+ up->port_activity = jiffies;\r
+ }\r
+\r
+\r
+#if 1\r
+ if (jiffies_to_msecs(jiffies - up->port_activity) < RX_TIMEOUT) {\r
+ if(prk29_uart_dma_t->use_timer == 1){\r
+ mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
+ }\r
+ } else {\r
+\r
+#if 1\r
+\r
+\r
+ prk29_uart_dma_t->rx_timeout = 20;\r
+ mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
+#else\r
+// serial_out(up, 0x2a, 0x01);\r
+ serial_rk_release_dma_rx(&up->port);\r
+ serial_out(up, 0x2a, 0x01);\r
+ up->ier |= (UART_IER_RDI | UART_IER_RLSI);\r
+ serial_out(up, UART_IER, up->ier);\r
+// serial_out(up, 0x22, 0x01);\r
+ dev_info(up->port.dev, "*****enable recv int*****\n");\r
+\r
+ //serial_rk_start_rx_dma(&up->port);\r
+#endif\r
+ }\r
+\r
+\r
+#else\r
+ if(prk29_uart_dma_t->use_timer == 1){\r
+ mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
+ }\r
+#endif\r
+\r
+}\r
+\r
+static void serial_rk_rx_timeout(unsigned long uart)\r
+{\r
+ struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
+\r
+ //serial_rk_report_dma_rx(up);\r
+ queue_work(up->uart_wq, &up->uart_work);\r
+}\r
+\r
+static void serial_rk_report_revdata_workfunc(struct work_struct *work)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(work, struct uart_rk_port, uart_work);\r
+ serial_rk_report_dma_rx((unsigned long)up);\r
+ spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
+\r
+ if(up->prk29_uart_dma_t->use_timer == 1){\r
+\r
+ }else{\r
+ tty_insert_flip_string(up->port.state->port.tty, up->fifo, up->fifo_size);\r
+ tty_flip_buffer_push(up->port.state->port.tty);\r
+ up->port.icount.rx += up->fifo_size;\r
+ }\r
+\r
+ spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
+\r
+}\r
+\r
+\r
+static void serial_rk_start_dma_rx(struct work_struct *work)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(work, struct uart_rk_port, uart_work_rx);\r
+ serial_rk_start_rx_dma(&up->port);\r
+}\r
+\r
+\r
+\r
+static void\r
+receive_chars(struct uart_rk_port *up, unsigned int *status)\r
+{\r
+ struct tty_struct *tty = up->port.state->port.tty;\r
+ unsigned char ch, lsr = *status;\r
+ int max_count = 256;\r
+ char flag;\r
+\r
+ do {\r
+ if (likely(lsr & UART_LSR_DR)){\r
+ ch = serial_in(up, UART_RX);\r
+ }\r
+ else\r
+ /*\r
+ * Intel 82571 has a Serial Over Lan device that will\r
+ * set UART_LSR_BI without setting UART_LSR_DR when\r
+ * it receives a break. To avoid reading from the\r
+ * receive buffer without UART_LSR_DR bit set, we\r
+ * just force the read character to be 0\r
+ */\r
+ ch = 0;\r
+\r
+ flag = TTY_NORMAL;\r
+ up->port.icount.rx++;\r
+\r
+ lsr |= up->lsr_saved_flags;\r
+ up->lsr_saved_flags = 0;\r
+\r
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {\r
+ /*\r
+ * For statistics only\r
+ */\r
+ if (lsr & UART_LSR_BI) {\r
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);\r
+ up->port.icount.brk++;\r
+ /*\r
+ * We do the SysRQ and SAK checking\r
+ * here because otherwise the break\r
+ * may get masked by ignore_status_mask\r
+ * or read_status_mask.\r
+ */\r
+ if (uart_handle_break(&up->port))\r
+ goto ignore_char;\r
+ } else if (lsr & UART_LSR_PE)\r
+ up->port.icount.parity++;\r
+ else if (lsr & UART_LSR_FE)\r
+ up->port.icount.frame++;\r
+ if (lsr & UART_LSR_OE)\r
+ up->port.icount.overrun++;\r
+\r
+\r
+ /*\r
+ * Mask off conditions which should be ignored.\r
+ */\r
+ lsr &= up->port.read_status_mask;\r
+\r
+ if (lsr & UART_LSR_BI) {\r
+ DEBUG_INTR("handling break....");\r
+ flag = TTY_BREAK;\r
+ } else if (lsr & UART_LSR_PE)\r
+ flag = TTY_PARITY;\r
+ else if (lsr & UART_LSR_FE)\r
+ flag = TTY_FRAME;\r
+ }\r
+ if (uart_handle_sysrq_char(&up->port, ch))\r
+ goto ignore_char;\r
+\r
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);\r
+\r
+ignore_char:\r
+ lsr = serial_in(up, UART_LSR);\r
+ } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));\r
+ spin_unlock(&up->port.lock);\r
+ tty_flip_buffer_push(tty);\r
+ spin_lock(&up->port.lock);\r
+ *status = lsr;\r
+}\r
+\r
+static void transmit_chars(struct uart_rk_port *up)\r
+{\r
+ struct circ_buf *xmit = &up->port.state->xmit;\r
+ int count;\r
+\r
+ if (up->port.x_char) {\r
+ serial_out(up, UART_TX, up->port.x_char);\r
+ up->port.icount.tx++;\r
+ up->port.x_char = 0;\r
+ return;\r
+ }\r
+ if (uart_tx_stopped(&up->port)) {\r
+ __stop_tx(up);\r
+ return;\r
+ }\r
+ if (uart_circ_empty(xmit)) {\r
+ __stop_tx(up);\r
+ return;\r
+ }\r
+\r
+ count = up->tx_loadsz;\r
+ do {\r
+ serial_out(up, UART_TX, xmit->buf[xmit->tail]);\r
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);\r
+ up->port.icount.tx++;\r
+ if (uart_circ_empty(xmit))\r
+ break;\r
+ } while (--count > 0);\r
+\r
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
+ uart_write_wakeup(&up->port);\r
+\r
+ DEBUG_INTR("THRE...");\r
+\r
+ if (uart_circ_empty(xmit))\r
+ __stop_tx(up);\r
+}\r
+\r
+static unsigned int check_modem_status(struct uart_rk_port *up)\r
+{\r
+ unsigned int status = serial_in(up, UART_MSR);\r
+\r
+#if 0\r
+ status |= up->msr_saved_flags;\r
+ up->msr_saved_flags = 0;\r
+ if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&\r
+ up->port.state != NULL) {\r
+ if (status & UART_MSR_TERI)\r
+ up->port.icount.rng++;\r
+ if (status & UART_MSR_DDSR)\r
+ up->port.icount.dsr++;\r
+ if (status & UART_MSR_DDCD)\r
+ uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);\r
+ if (status & UART_MSR_DCTS)\r
+ uart_handle_cts_change(&up->port, status & UART_MSR_CTS);\r
+\r
+ wake_up_interruptible(&up->port.state->port.delta_msr_wait);\r
+ }\r
+#endif\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * This handles the interrupt from one port.\r
+ */\r
+static void serial_rk_handle_port(struct uart_rk_port *up)\r
+{\r
+ unsigned int status;\r
+ unsigned long flags;\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+\r
+ /* reading UART_LSR can automatically clears PE FE OE bits, except receive fifo error bit*/\r
+ status = serial_in(up, UART_LSR);\r
+\r
+ DEBUG_INTR("status = %x...", status);\r
+ /* DMA mode enable */\r
+ if(up->prk29_uart_dma_t->use_dma == 1) {\r
+\r
+ if(up->iir & UART_IIR_RLSI){\r
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
+ up->port_activity = jiffies;\r
+ up->ier &= ~UART_IER_RLSI;\r
+ up->ier &= ~UART_IER_RDI;\r
+ serial_out(up, UART_IER, up->ier);\r
+ //receive_chars(up, &status);\r
+ //mod_timer(&up->prk29_uart_dma_t->rx_timer, jiffies +\r
+ //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout));\r
+ if(serial_rk_start_rx_dma(&up->port) == -1){\r
+ receive_chars(up, &status);\r
+ }\r
+ }\r
+ }\r
+\r
+ }else { //dma mode disable\r
+\r
+ /*\r
+ * when uart receive a serial of data which doesn't have stop bit and so on, that causes frame error,and\r
+ * set UART_LSR_RFE to one,what is worse,we couldn't read the data in the receive fifo. So if\r
+ * wo don't clear this bit and reset the receive fifo, the received data available interrupt would\r
+ * occur continuously. added by hhb@rock-chips.com 2011-08-05\r
+ */\r
+\r
+ if (status & UART_LSR_RFE) {\r
+ \r
+ if(up->port.line != DBG_PORT){\r
+ status = serial_in(up, UART_LSR);\r
+ dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
+ }\r
+ \r
+ \r
+ // rk29_uart_dump_register(up);\r
+ }\r
+\r
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
+ receive_chars(up, &status);\r
+ }\r
+ check_modem_status(up);\r
+ if (status & UART_LSR_THRE) {\r
+ transmit_chars(up);\r
+ }\r
+ }\r
+\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+}\r
+\r
+/*\r
+ * This is the serial driver's interrupt routine.\r
+ */\r
+\r
+static irqreturn_t serial_rk_interrupt(int irq, void *dev_id)\r
+{\r
+ struct uart_rk_port *up = dev_id;\r
+ int handled = 0;\r
+ unsigned int iir;\r
+\r
+ iir = serial_in(up, UART_IIR);\r
+\r
+ DEBUG_INTR("%s(%d) iir = 0x%02x\n", __func__, irq, iir);\r
+\r
+ up->iir = iir;\r
+\r
+ if (!(iir & UART_IIR_NO_INT)) {\r
+ serial_rk_handle_port(up);\r
+ handled = 1;\r
+ } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {\r
+\r
+ /* The DesignWare APB UART has an Busy Detect (0x07)\r
+ * interrupt meaning an LCR write attempt occured while the\r
+ * UART was busy. The interrupt must be cleared by reading\r
+ * the UART status register (USR) and the LCR re-written. */\r
+\r
+ if(!(serial_in(up, UART_USR) & UART_USR_BUSY)){\r
+ serial_out(up, UART_LCR, up->lcr);\r
+ }\r
+ handled = 1;\r
+ dbg("the serial.%d is busy\n", up->port.line);\r
+ }\r
+ DEBUG_INTR("end(%d).\n", handled);\r
+\r
+ return IRQ_RETVAL(handled);\r
+}\r
+\r
+static unsigned int serial_rk_tx_empty(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned long flags;\r
+ unsigned int lsr;\r
+\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+ lsr = serial_in(up, UART_LSR);\r
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
+ return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;\r
+}\r
+\r
+static unsigned int serial_rk_get_mctrl(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned int status;\r
+ unsigned int ret;\r
+\r
+ status = check_modem_status(up);\r
+\r
+ ret = 0;\r
+ if (status & UART_MSR_DCD)\r
+ ret |= TIOCM_CAR;\r
+ if (status & UART_MSR_RI)\r
+ ret |= TIOCM_RNG;\r
+ if (status & UART_MSR_DSR)\r
+ ret |= TIOCM_DSR;\r
+ if (status & UART_MSR_CTS)\r
+ ret |= TIOCM_CTS;\r
+ dev_dbg(port->dev, "%s 0x%08x\n", __func__, ret);\r
+ return ret;\r
+}\r
+\r
+static void serial_rk_set_mctrl(struct uart_port *port, unsigned int mctrl)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned char mcr = 0;\r
+\r
+ dev_dbg(port->dev, "+%s\n", __func__);\r
+ if (mctrl & TIOCM_RTS)\r
+ mcr |= UART_MCR_RTS;\r
+ if (mctrl & TIOCM_DTR)\r
+ mcr |= UART_MCR_DTR;\r
+ if (mctrl & TIOCM_OUT1)\r
+ mcr |= UART_MCR_OUT1;\r
+ if (mctrl & TIOCM_OUT2)\r
+ mcr |= UART_MCR_OUT2;\r
+ if (mctrl & TIOCM_LOOP)\r
+ mcr |= UART_MCR_LOOP;\r
+\r
+ mcr |= up->mcr;\r
+\r
+ serial_out(up, UART_MCR, mcr);\r
+ dev_dbg(port->dev, "-serial.%d %s mcr: 0x%02x\n", port->line, __func__, mcr);\r
+}\r
+\r
+static void serial_rk_break_ctl(struct uart_port *port, int break_state)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned long flags;\r
+\r
+ dev_dbg(port->dev, "+%s\n", __func__);\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+ if (break_state == -1)\r
+ up->lcr |= UART_LCR_SBC;\r
+ else\r
+ up->lcr &= ~UART_LCR_SBC;\r
+ serial_lcr_write(up, up->lcr);\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+ dev_dbg(port->dev, "-%s lcr: 0x%02x\n", __func__, up->lcr);\r
+}\r
+\r
+/*\r
+ * Wait for transmitter & holding register to empty\r
+ */\r
+static void wait_for_xmitr(struct uart_rk_port *up, int bits)\r
+{\r
+ unsigned int status, tmout = 10000;\r
+\r
+ /* Wait up to 10ms for the character(s) to be sent. */\r
+ for (;;) {\r
+ status = serial_in(up, UART_LSR);\r
+\r
+ up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;\r
+\r
+ if ((status & bits) == bits)\r
+ break;\r
+ if (--tmout == 0)\r
+ break;\r
+ udelay(1);\r
+ }\r
+}\r
+\r
+#ifdef CONFIG_CONSOLE_POLL\r
+/*\r
+ * Console polling routines for writing and reading from the uart while\r
+ * in an interrupt or debug context.\r
+ */\r
+\r
+static int serial_rk_get_poll_char(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned char lsr = serial_in(up, UART_LSR);\r
+\r
+ while (!(lsr & UART_LSR_DR))\r
+ lsr = serial_in(up, UART_LSR);\r
+\r
+ return serial_in(up, UART_RX);\r
+}\r
+\r
+static void serial_rk_put_poll_char(struct uart_port *port,\r
+ unsigned char c)\r
+{\r
+ unsigned int ier;\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+ /*\r
+ * First save the IER then disable the interrupts\r
+ */\r
+ ier = serial_in(up, UART_IER);\r
+ serial_out(up, UART_IER, 0);\r
+\r
+ wait_for_xmitr(up, BOTH_EMPTY);\r
+ /*\r
+ * Send the character out.\r
+ * If a LF, also do CR...\r
+ */\r
+ serial_out(up, UART_TX, c);\r
+ if (c == 10) {\r
+ wait_for_xmitr(up, BOTH_EMPTY);\r
+ serial_out(up, UART_TX, 13);\r
+ }\r
+\r
+ /*\r
+ * Finally, wait for transmitter to become empty\r
+ * and restore the IER\r
+ */\r
+ wait_for_xmitr(up, BOTH_EMPTY);\r
+ serial_out(up, UART_IER, ier);\r
+}\r
+\r
+#endif /* CONFIG_CONSOLE_POLL */\r
+\r
+static int serial_rk_startup(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned long flags;\r
+ int retval;\r
+\r
+\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+\r
+ /*\r
+ * Allocate the IRQ\r
+ */\r
+ retval = request_irq(up->port.irq, serial_rk_interrupt, up->port.irqflags,\r
+ up->name, up);\r
+ if (retval)\r
+ return retval;\r
+\r
+ up->mcr = 0;\r
+\r
+ clk_enable(up->clk); // enable the config uart clock\r
+\r
+ /*\r
+ * Clear the FIFO buffers and disable them.\r
+ * (they will be reenabled in set_termios())\r
+ */\r
+ serial_rk_clear_fifos(up);\r
+\r
+ /*\r
+ * Clear the interrupt registers.\r
+ */\r
+ (void) serial_in(up, UART_LSR);\r
+ (void) serial_in(up, UART_RX);\r
+ (void) serial_in(up, UART_IIR);\r
+ (void) serial_in(up, UART_MSR);\r
+ (void) serial_in(up, UART_USR);\r
+\r
+ /*\r
+ * Now, initialize the UART\r
+ */\r
+ serial_lcr_write(up, UART_LCR_WLEN8 | UART_LCR_EPAR);\r
+\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+\r
+ /*\r
+ * Most PC uarts need OUT2 raised to enable interrupts.\r
+ */\r
+// up->port.mctrl |= TIOCM_OUT2;\r
+\r
+ serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
+\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
+ /*\r
+ * Clear the interrupt registers again for luck, and clear the\r
+ * saved flags to avoid getting false values from polling\r
+ * routines or the previous session.\r
+ */\r
+ (void) serial_in(up, UART_LSR);\r
+ (void) serial_in(up, UART_RX);\r
+ (void) serial_in(up, UART_IIR);\r
+ (void) serial_in(up, UART_MSR);\r
+ (void) serial_in(up, UART_USR);\r
+ up->lsr_saved_flags = 0;\r
+#if 0\r
+ up->msr_saved_flags = 0;\r
+#endif\r
+\r
+ if (1 == up->prk29_uart_dma_t->use_dma) {\r
+\r
+ if(up->port.state->xmit.buf != up->prk29_uart_dma_t->tx_buffer){\r
+ free_page((unsigned long)up->port.state->xmit.buf);\r
+ up->port.state->xmit.buf = up->prk29_uart_dma_t->tx_buffer;\r
+ }\r
+\r
+#if 1\r
+ serial_rk_start_rx_dma(&up->port);\r
+#else\r
+ up->ier |= UART_IER_RDI;\r
+ up->ier |= UART_IER_RLSI;\r
+ serial_out(up, UART_IER, up->ier);\r
+#endif\r
+ up->port_activity = jiffies;\r
+\r
+ }else{\r
+ up->ier = 0;\r
+ serial_out(up, UART_IER, up->ier);\r
+ }\r
+\r
+ /*\r
+ * Finally, enable interrupts. Note: Modem status interrupts\r
+ * are set via set_termios(), which will be occurring imminently\r
+ * anyway, so we don't enable them here.\r
+ */\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static void serial_rk_shutdown(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned long flags;\r
+\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ /*\r
+ * Disable interrupts from this port\r
+ */\r
+ up->ier = 0;\r
+ serial_out(up, UART_IER, 0);\r
+\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+// up->port.mctrl &= ~TIOCM_OUT2;\r
+ serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
+ /*\r
+ * Disable break condition and FIFOs\r
+ */\r
+ serial_lcr_write(up, serial_in(up, UART_LCR) & ~UART_LCR_SBC);\r
+ serial_rk_clear_fifos(up);\r
+\r
+ /*\r
+ * Read data port to reset things, and then free the irq\r
+ */\r
+ (void) serial_in(up, UART_RX);\r
+\r
+ free_irq(up->port.irq, up);\r
+}\r
+\r
+static void\r
+serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,\r
+ struct ktermios *old)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+ unsigned char cval, fcr = 0;\r
+ unsigned long flags;\r
+ unsigned int baud, quot;\r
+ int timeout = 1000000;\r
+ dev_dbg(port->dev, "+%s\n", __func__);\r
+\r
+ switch (termios->c_cflag & CSIZE) {\r
+ case CS5:\r
+ cval = UART_LCR_WLEN5;\r
+ break;\r
+ case CS6:\r
+ cval = UART_LCR_WLEN6;\r
+ break;\r
+ case CS7:\r
+ cval = UART_LCR_WLEN7;\r
+ break;\r
+ case CS8:\r
+ default:\r
+ cval = UART_LCR_WLEN8;\r
+ break;\r
+ }\r
+\r
+ if (termios->c_cflag & CSTOPB){\r
+ cval |= UART_LCR_STOP;\r
+ }\r
+ if (termios->c_cflag & PARENB){\r
+ cval |= UART_LCR_PARITY;\r
+ }\r
+ if (!(termios->c_cflag & PARODD)){\r
+ cval |= UART_LCR_EPAR;\r
+ }\r
+#ifdef CMSPAR\r
+ if (termios->c_cflag & CMSPAR)\r
+ cval |= UART_LCR_SPAR;\r
+#endif\r
+\r
+\r
+ /*\r
+ * Ask the core to calculate the divisor for us.\r
+ */\r
+ baud = uart_get_baud_rate(port, termios, old,\r
+ port->uartclk / 16 / 0xffff,\r
+ port->uartclk / 16);\r
+\r
+ quot = uart_get_divisor(port, baud);\r
+\r
+ dev_info(up->port.dev, "baud:%d\n", baud);\r
+// dev_info(up->port.dev, "quot:%d\n", quot);\r
+\r
+ /*\r
+ * To wait long enough to avoid writting lcr when the uart is busy\r
+ * because of data communication, so that we can set lcr and baud rate\r
+ * successfully. added by hhb@rock-chips.com\r
+ */\r
+\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+ if(--timeout == 0){\r
+ if(port->line != DBG_PORT){\r
+ serial_out(up, UART_SRR, UART_RESET);\r
+ }\r
+ dbg("rk_serial_set_termios uart.%d timeout,irq=%d,ret=0x%x AND uart is reseted\n",\r
+ port->line, port->irq, serial_in(up, UART_USR));\r
+ break;\r
+ }\r
+ cpu_relax();\r
+ }\r
+\r
+\r
+ printk("serial.%d timeout:%d\n", up->port.line,timeout);\r
+\r
+\r
+ if (baud < 2400){\r
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
+ }\r
+ else{\r
+ //added by hhb@rock-chips.com\r
+ if(up->prk29_uart_dma_t->use_timer == 1){\r
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_01;\r
+ }\r
+ else{\r
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_01;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * MCR-based auto flow control. When AFE is enabled, RTS will be\r
+ * deasserted when the receive FIFO contains more characters than\r
+ * the trigger, or the MCR RTS bit is cleared. In the case where\r
+ * the remote UART is not using CTS auto flow control, we must\r
+ * have sufficient FIFO entries for the latency of the remote\r
+ * UART to respond. IOW, at least 32 bytes of FIFO.\r
+ */\r
+ up->mcr &= ~UART_MCR_AFE;\r
+ if (termios->c_cflag & CRTSCTS){\r
+ up->mcr |= UART_MCR_AFE;\r
+ }\r
+\r
+ /*\r
+ * Ok, we're now changing the port state. Do it with\r
+ * interrupts disabled.\r
+ */\r
+ spin_lock_irqsave(&up->port.lock, flags);\r
+\r
+ /*\r
+ * Update the per-port timeout.\r
+ */\r
+ uart_update_timeout(port, termios->c_cflag, baud);\r
+\r
+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;\r
+ if (termios->c_iflag & INPCK)\r
+ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;\r
+ if (termios->c_iflag & (BRKINT | PARMRK))\r
+ up->port.read_status_mask |= UART_LSR_BI;\r
+\r
+ /*\r
+ * Characteres to ignore\r
+ */\r
+ up->port.ignore_status_mask = 0;\r
+ if (termios->c_iflag & IGNPAR)\r
+ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;\r
+ if (termios->c_iflag & IGNBRK) {\r
+ up->port.ignore_status_mask |= UART_LSR_BI;\r
+ /*\r
+ * If we're ignoring parity and break indicators,\r
+ * ignore overruns too (for real raw support).\r
+ */\r
+ if (termios->c_iflag & IGNPAR)\r
+ up->port.ignore_status_mask |= UART_LSR_OE;\r
+ }\r
+\r
+ /*\r
+ * ignore all characters if CREAD is not set\r
+ */\r
+ if ((termios->c_cflag & CREAD) == 0)\r
+ up->port.ignore_status_mask |= UART_LSR_DR;\r
+\r
+ /*\r
+ * CTS flow control flag and modem status interrupts\r
+ */\r
+ up->ier &= ~UART_IER_MSI;\r
+#if 0\r
+ if (UART_ENABLE_MS(&up->port, termios->c_cflag))\r
+ up->ier |= UART_IER_MSI;\r
+#endif\r
+\r
+ up->lcr = cval; /* Save LCR */\r
+ /* set DLAB */\r
+ if(serial_lcr_write(up, cval | UART_LCR_DLAB)){\r
+ dbg("serial.%d set DLAB fail\n", up->port.line);\r
+ serial_out(up, UART_SRR, UART_RESET);\r
+ goto fail;\r
+ }\r
+\r
+ /* set uart baud rate */\r
+ if(serial_dl_write(up, quot)){\r
+ dbg("serial.%d set dll fail\n", up->port.line);\r
+ serial_out(up, UART_SRR, UART_RESET);\r
+ goto fail;\r
+ }\r
+\r
+ /* reset DLAB */\r
+ if(serial_lcr_write(up, cval)){\r
+ dbg("serial.%d reset DLAB fail\n", up->port.line);\r
+ serial_out(up, UART_SRR, UART_RESET);\r
+ goto fail;\r
+ }\r
+ else{\r
+ serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
+ serial_out(up, UART_FCR, fcr); /* set fcr */\r
+ up->fcr = fcr;\r
+ /* enable the uart interrupt last */\r
+ up->ier |= UART_IER_RDI;\r
+ up->ier |= UART_IER_RLSI;\r
+ serial_out(up, UART_IER, up->ier);\r
+ }\r
+\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
+ /* Don't rewrite B0 */\r
+ if (tty_termios_baud_rate(termios))\r
+ tty_termios_encode_baud_rate(termios, baud, baud);\r
+ dev_dbg(port->dev, "-%s baud %d\n", __func__, baud);\r
+\r
+ return;\r
+\r
+fail:\r
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
+}\r
+\r
+#if 0\r
+static void\r
+serial_rk_set_ldisc(struct uart_port *port, int new)\r
+{\r
+ if (new == N_PPS) {\r
+ port->flags |= UPF_HARDPPS_CD;\r
+ serial_rk_enable_ms(port);\r
+ } else\r
+ port->flags &= ~UPF_HARDPPS_CD;\r
+}\r
+#endif\r
+\r
+static void\r
+serial_rk_pm(struct uart_port *port, unsigned int state,\r
+ unsigned int oldstate)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+ dev_dbg(port->dev, "%s: %s\n", __func__, state ? "disable" : "enable");\r
+ if (state)\r
+ clk_disable(up->clk);\r
+ else\r
+ clk_enable(up->clk);\r
+}\r
+\r
+static void serial_rk_release_port(struct uart_port *port)\r
+{\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+}\r
+\r
+static int serial_rk_request_port(struct uart_port *port)\r
+{\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ return 0;\r
+}\r
+\r
+static void serial_rk_config_port(struct uart_port *port, int flags)\r
+{\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ port->type = PORT_RK;\r
+}\r
+\r
+static int\r
+serial_rk_verify_port(struct uart_port *port, struct serial_struct *ser)\r
+{\r
+ /* we don't want the core code to modify any port params */\r
+ dev_dbg(port->dev, "%s\n", __func__);\r
+ return -EINVAL;\r
+}\r
+\r
+static const char *\r
+serial_rk_type(struct uart_port *port)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+ dev_dbg(port->dev, "%s: %s\n", __func__, up->name);\r
+ return up->name;\r
+}\r
+\r
+static struct uart_ops serial_rk_pops = {\r
+ .tx_empty = serial_rk_tx_empty,\r
+ .set_mctrl = serial_rk_set_mctrl,\r
+ .get_mctrl = serial_rk_get_mctrl,\r
+ .stop_tx = serial_rk_stop_tx,\r
+ .start_tx = serial_rk_start_tx,\r
+ .stop_rx = serial_rk_stop_rx,\r
+ .enable_ms = serial_rk_enable_ms,\r
+ .break_ctl = serial_rk_break_ctl,\r
+ .startup = serial_rk_startup,\r
+ .shutdown = serial_rk_shutdown,\r
+ .set_termios = serial_rk_set_termios,\r
+#if 0\r
+ .set_ldisc = serial_rk_set_ldisc,\r
+#endif\r
+ .pm = serial_rk_pm,\r
+ .type = serial_rk_type,\r
+ .release_port = serial_rk_release_port,\r
+ .request_port = serial_rk_request_port,\r
+ .config_port = serial_rk_config_port,\r
+ .verify_port = serial_rk_verify_port,\r
+#ifdef CONFIG_CONSOLE_POLL\r
+ .poll_get_char = serial_rk_get_poll_char,\r
+ .poll_put_char = serial_rk_put_poll_char,\r
+#endif\r
+};\r
+\r
+#ifdef CONFIG_SERIAL_RK_CONSOLE\r
+\r
+static struct uart_rk_port *serial_rk_console_ports[UART_NR];\r
+\r
+static void serial_rk_console_putchar(struct uart_port *port, int ch)\r
+{\r
+ struct uart_rk_port *up =\r
+ container_of(port, struct uart_rk_port, port);\r
+\r
+ wait_for_xmitr(up, UART_LSR_THRE);\r
+ serial_out(up, UART_TX, ch);\r
+}\r
+\r
+/*\r
+ * Print a string to the serial port trying not to disturb\r
+ * any possible real use of the port...\r
+ *\r
+ * The console_lock must be held when we get here.\r
+ */\r
+static void\r
+serial_rk_console_write(struct console *co, const char *s, unsigned int count)\r
+{\r
+ struct uart_rk_port *up = serial_rk_console_ports[co->index];\r
+ unsigned long flags;\r
+ unsigned int ier;\r
+ int locked = 1;\r
+\r
+ touch_nmi_watchdog();\r
+\r
+ local_irq_save(flags);\r
+ if (up->port.sysrq) {\r
+ /* serial_rk_handle_port() already took the lock */\r
+ locked = 0;\r
+ } else if (oops_in_progress) {\r
+ locked = spin_trylock(&up->port.lock);\r
+ } else\r
+ spin_lock(&up->port.lock);\r
+\r
+ /*\r
+ * First save the IER then disable the interrupts\r
+ */\r
+ ier = serial_in(up, UART_IER);\r
+\r
+ serial_out(up, UART_IER, 0);\r
+\r
+ uart_console_write(&up->port, s, count, serial_rk_console_putchar);\r
+\r
+ /*\r
+ * Finally, wait for transmitter to become empty\r
+ * and restore the IER\r
+ */\r
+ wait_for_xmitr(up, BOTH_EMPTY);\r
+ serial_out(up, UART_IER, ier);\r
+\r
+#if 0\r
+ /*\r
+ * The receive handling will happen properly because the\r
+ * receive ready bit will still be set; it is not cleared\r
+ * on read. However, modem control will not, we must\r
+ * call it if we have saved something in the saved flags\r
+ * while processing with interrupts off.\r
+ */\r
+ if (up->msr_saved_flags)\r
+ check_modem_status(up);\r
+#endif\r
+\r
+ if (locked)\r
+ spin_unlock(&up->port.lock);\r
+ local_irq_restore(flags);\r
+}\r
+\r
+static int __init serial_rk_console_setup(struct console *co, char *options)\r
+{\r
+ struct uart_rk_port *up;\r
+ int baud = 115200;\r
+ int bits = 8;\r
+ int parity = 'n';\r
+ int flow = 'n';\r
+\r
+ if (unlikely(co->index >= UART_NR || co->index < 0))\r
+ return -ENODEV;\r
+\r
+ if (serial_rk_console_ports[co->index] == NULL)\r
+ return -ENODEV;\r
+ up = serial_rk_console_ports[co->index];\r
+\r
+ if (options)\r
+ uart_parse_options(options, &baud, &parity, &bits, &flow);\r
+\r
+ return uart_set_options(&up->port, co, baud, parity, bits, flow);\r
+}\r
+\r
+static struct console serial_rk_console = {\r
+ .name = "ttyS",\r
+ .write = serial_rk_console_write,\r
+ .device = uart_console_device,\r
+ .setup = serial_rk_console_setup,\r
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,\r
+ .index = -1,\r
+ .data = &serial_rk_reg,\r
+};\r
+\r
+static void serial_rk_add_console_port(struct uart_rk_port *up)\r
+{\r
+ serial_rk_console_ports[up->pdev->id] = up;\r
+}\r
+\r
+#define SERIAL_CONSOLE &serial_rk_console\r
+#else\r
+#define SERIAL_CONSOLE NULL\r
+\r
+static inline void serial_rk_add_console_port(struct uart_rk_port *up)\r
+{}\r
+\r
+#endif\r
+\r
+static struct uart_driver serial_rk_reg = {\r
+ .owner = THIS_MODULE,\r
+ .driver_name = "rk29_serial",\r
+ .dev_name = "ttyS",\r
+ .major = TTY_MAJOR,\r
+ .minor = 64,\r
+ .cons = SERIAL_CONSOLE,\r
+ .nr = UART_NR,\r
+};\r
+\r
+static int __devinit serial_rk_probe(struct platform_device *pdev)\r
+{\r
+ struct uart_rk_port *up;\r
+ struct resource *mem;\r
+ int irq;\r
+ int ret = -ENOSPC;\r
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ if (!mem) {\r
+ dev_err(&pdev->dev, "no mem resource?\n");\r
+ return -ENODEV;\r
+ }\r
+\r
+ irq = platform_get_irq(pdev, 0);\r
+ if (irq < 0) {\r
+ dev_err(&pdev->dev, "no irq resource?\n");\r
+ return irq;\r
+ }\r
+\r
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,\r
+ pdev->dev.driver->name)) {\r
+ dev_err(&pdev->dev, "memory region already claimed\n");\r
+ return -EBUSY;\r
+ }\r
+\r
+ up = kzalloc(sizeof(*up), GFP_KERNEL);\r
+ if (up == NULL) {\r
+ ret = -ENOMEM;\r
+ goto do_release_region;\r
+ }\r
+\r
+ sprintf(up->name, "rk29_serial.%d", pdev->id);\r
+ up->pdev = pdev;\r
+ up->clk = clk_get(&pdev->dev, "uart");\r
+ if (unlikely(IS_ERR(up->clk))) {\r
+ ret = PTR_ERR(up->clk);\r
+ goto do_free;\r
+ }\r
+ up->tx_loadsz = 30;\r
+ up->prk29_uart_dma_t = &rk29_uart_ports_dma_t[pdev->id];\r
+ up->port.dev = &pdev->dev;\r
+ up->port.type = PORT_RK;\r
+ up->port.irq = irq;\r
+ up->port.iotype = UPIO_DWAPB;\r
+\r
+ up->port.regshift = 2;\r
+ up->port.fifosize = 32;\r
+ up->port.ops = &serial_rk_pops;\r
+ up->port.line = pdev->id;\r
+ up->port.iobase = mem->start;\r
+ up->port.membase = ioremap_nocache(mem->start, mem->end - mem->start + 1);\r
+ if (!up->port.membase) {\r
+ ret = -ENOMEM;\r
+ goto do_put_clk;\r
+ }\r
+ up->port.mapbase = mem->start;\r
+ up->port.irqflags = IRQF_DISABLED;\r
+ up->port.uartclk = clk_get_rate(up->clk);\r
+\r
+ /* set dma config */\r
+ if(1 == up->prk29_uart_dma_t->use_dma) {\r
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);\r
+\r
+ //timer\r
+ up->prk29_uart_dma_t->use_timer = USE_TIMER;\r
+ up->prk29_uart_dma_t->rx_timer.function = serial_rk_rx_timeout;\r
+ up->prk29_uart_dma_t->rx_timer.data = (unsigned long)up;\r
+ up->prk29_uart_dma_t->rx_timeout = 7;\r
+ up->prk29_uart_dma_t->rx_timer.expires = jiffies + msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout);\r
+ init_timer(&up->prk29_uart_dma_t->rx_timer);\r
+ //tx buffer\r
+ up->prk29_uart_dma_t->tx_buffer_size = UART_XMIT_SIZE;\r
+ up->prk29_uart_dma_t->tx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->tx_buffer_size,\r
+ &up->prk29_uart_dma_t->tx_phy_addr, DMA_MEMORY_MAP);\r
+ if(!up->prk29_uart_dma_t->tx_buffer){\r
+ dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n");\r
+ }\r
+ else{\r
+ dev_info(up->port.dev, "dma_tx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_buffer);\r
+ dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_phy_addr);\r
+ }\r
+ //rx buffer\r
+ up->prk29_uart_dma_t->rx_buffer_size = UART_XMIT_SIZE*32;\r
+ up->prk29_uart_dma_t->rx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->rx_buffer_size,\r
+ &up->prk29_uart_dma_t->rx_phy_addr, DMA_MEMORY_MAP);\r
+ up->prk29_uart_dma_t->rb_pre_pos = 0;\r
+ if(!up->prk29_uart_dma_t->rx_buffer){\r
+ dev_info(up->port.dev, "dmam_alloc_coherent dma_rx_buffer fail\n");\r
+ }\r
+ else {\r
+ dev_info(up->port.dev, "dma_rx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->rx_buffer);\r
+ dev_info(up->port.dev, "up 0x%08x\n", (unsigned)up->prk29_uart_dma_t);\r
+ }\r
+\r
+ // work queue\r
+ INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc);\r
+ INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx);\r
+ up->uart_wq = create_singlethread_workqueue("uart_workqueue");\r
+ up->prk29_uart_dma_t->rx_dma_start = 0;\r
+ spin_lock_init(&(up->prk29_uart_dma_t->tx_lock));\r
+ spin_lock_init(&(up->prk29_uart_dma_t->rx_lock));\r
+ serial_rk_init_dma_rx(&up->port);\r
+ serial_rk_init_dma_tx(&up->port);\r
+ up->ier |= THRE_MODE; // enable THRE interrupt mode\r
+ serial_out(up, UART_IER, up->ier);\r
+ }\r
+\r
+ serial_rk_add_console_port(up);\r
+ ret = uart_add_one_port(&serial_rk_reg, &up->port);\r
+ if (ret != 0)\r
+ goto do_iounmap;\r
+\r
+ platform_set_drvdata(pdev, up);\r
+ dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase);\r
+\r
+ return 0;\r
+\r
+do_iounmap:\r
+ iounmap(up->port.membase);\r
+ up->port.membase = NULL;\r
+do_put_clk:\r
+ clk_put(up->clk);\r
+do_free:\r
+ kfree(up);\r
+do_release_region:\r
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
+ return ret;\r
+}\r
+\r
+static int __devexit serial_rk_remove(struct platform_device *pdev)\r
+{\r
+ struct uart_rk_port *up = platform_get_drvdata(pdev);\r
+\r
+ platform_set_drvdata(pdev, NULL);\r
+ if (up) {\r
+ struct resource *mem;\r
+ destroy_workqueue(up->uart_wq);\r
+ uart_remove_one_port(&serial_rk_reg, &up->port);\r
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ iounmap(up->port.membase);\r
+ up->port.membase = NULL;\r
+ clk_put(up->clk);\r
+ kfree(up);\r
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int serial_rk_suspend(struct platform_device *dev, pm_message_t state)\r
+{\r
+ struct uart_rk_port *up = platform_get_drvdata(dev);\r
+\r
+ if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
+ uart_suspend_port(&serial_rk_reg, &up->port);\r
+ }\r
+ if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
+ serial_rk_pm(&up->port, 1, 0);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int serial_rk_resume(struct platform_device *dev)\r
+{\r
+ struct uart_rk_port *up = platform_get_drvdata(dev);\r
+\r
+ if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
+ uart_resume_port(&serial_rk_reg, &up->port);\r
+ }\r
+ if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
+ serial_rk_pm(&up->port, 0, 1);\r
+ }\r
+ return 0;\r
+}\r
+\r
+static struct platform_driver serial_rk_driver = {\r
+ .probe = serial_rk_probe,\r
+ .remove = __devexit_p(serial_rk_remove),\r
+ .suspend = serial_rk_suspend,\r
+ .resume = serial_rk_resume,\r
+ .driver = {\r
+#if defined(CONFIG_SERIAL_RK29)\r
+ .name = "rk29_serial",\r
+#elif defined(CONFIG_SERIAL_RK2818)\r
+ .name = "rk2818_serial",\r
+#else\r
+ .name = "rk_serial",\r
+#endif\r
+ .owner = THIS_MODULE,\r
+ },\r
+};\r
+\r
+static int __init serial_rk_init(void)\r
+{\r
+ int ret;\r
+\r
+ ret = uart_register_driver(&serial_rk_reg);\r
+ if (ret)\r
+ return ret;\r
+\r
+ ret = platform_driver_register(&serial_rk_driver);\r
+ if (ret != 0)\r
+ uart_unregister_driver(&serial_rk_reg);\r
+\r
+ return ret;\r
+}\r
+\r
+static void __exit serial_rk_exit(void)\r
+{\r
+ platform_driver_unregister(&serial_rk_driver);\r
+ uart_unregister_driver(&serial_rk_reg);\r
+}\r
+\r
+module_init(serial_rk_init);\r
+module_exit(serial_rk_exit);\r
+\r
+MODULE_LICENSE("GPL");\r
+MODULE_DESCRIPTION("RK UART driver");\r
+\r
--- /dev/null
+/*
+ *
+ * Copyright (C) 2010 liuyixing <lyx@rock-chips.com>
+ *
+ *
+ * Example platform data:
+
+ static struct plat_sc8800 sc8800_plat_data = {
+ .slav_rts_pin = RK29_PIN4_PD0,
+ .slav_rdy_pin = RK29_PIN4_PD0,
+ .master_rts_pin = RK29_PIN4_PD0,
+ .master_rdy_pin = RK29_PIN4_PD0,
+ //.poll_time = 100,
+ };
+
+ static struct spi_board_info spi_board_info[] = {
+ {
+ .modalias = "sc8800",
+ .platform_data = &sc8800_plat_data,
+ .max_speed_hz = 12*1000*1000,
+ .chip_select = 0,
+ },
+ };
+
+ * The initial minor number is 209 in the low-density serial port:
+ * mknod /dev/ttySPI0 c 204 209
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+
+#include "sc8800.h"
+
+struct sc8800_port {
+ struct uart_port port;
+ struct spi_device *spi;
+
+ int cts; /* last CTS received for flow ctrl */
+ int tx_empty; /* last TX empty bit */
+
+ spinlock_t conf_lock; /* shared data */
+ int conf; /* configuration for the SC88000
+ * (bits 0-7, bits 8-11 are irqs) */
+
+ int rx_enabled; /* if we should rx chars */
+
+ int irq; /* irq assigned to the sc8800 */
+
+ int minor; /* minor number */
+ int loopback; /* 1 if we are in loopback mode */
+
+ /* for handling irqs: need workqueue since we do spi_sync */
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+ /* set to 1 to make the workhandler exit as soon as possible */
+ int force_end_work;
+ /* need to know we are suspending to avoid deadlock on workqueue */
+ int suspending;
+
+ /* hook for suspending SC8800 via dedicated pin */
+ void (*sc8800_hw_suspend) (int suspend);
+
+ /* poll time (in ms) for ctrl lines */
+ int poll_time;
+ /* and its timer */
+ struct timer_list timer;
+
+ /*signal define, always gpio*/
+ int slav_rts;
+ int slav_rdy;
+ int master_rts;
+ int master_rdy;
+};
+
+#define SC8800_MAJOR 204
+#define SC8800_MINOR 209
+#define MAX_SC8800 1
+
+#define SPI_MAX_PACKET (8192-128)
+#define FREAM_SIZE 64
+#define SPI_DMA_SIZE PAGE_SIZE
+
+void * g_dma_buffer = NULL;
+dma_addr_t g_dma_addr;
+
+#if 1
+#define sc8800_dbg(x...) printk(x)
+#else
+#define sc8800_dbg(x...)
+#endif
+
+static struct sc8800_port *sc8800s[MAX_SC8800]; /* the chips */
+static DEFINE_MUTEX(sc8800s_lock); /* race on probe */
+
+static int sc8800_get_slave_rts_status(struct sc8800_port *s)
+{
+ return gpio_get_value(s->slav_rts);
+}
+
+static int sc8800_get_slave_rdy_status(struct sc8800_port *s)
+{
+ return gpio_get_value(s->slav_rdy);
+}
+
+static void sc8800_set_master_rts_status(struct sc8800_port *s, int value)
+{
+ gpio_set_value(s->master_rts, value);
+}
+
+static void sc8800_set_master_rdy_status(struct sc8800_port *s, int value)
+{
+ gpio_set_value(s->master_rdy, value);
+}
+
+static int sc8800_send_head_data(struct sc8800_port *s, u32 data_len)
+{
+ char head[64] = {0};
+ struct spi_message message;
+ int status;
+ struct spi_transfer tran;
+
+ head[0] = 0x7f;
+ head[1] = 0x7e;
+ head[2] = 0x55;
+ head[3] = 0xaa;
+ head[4] = data_len & 0xff;
+ head[5] = (data_len>>8) & 0xff;
+ head[6] = (data_len>>16) & 0xff;
+ head[7] = (data_len>>24) & 0xff;
+
+ tran.tx_buf = (void *)(head);
+ tran.len = FREAM_SIZE;
+
+ spi_message_init(&message);
+ spi_message_add_tail(&tran, &message);
+ status = spi_sync(s->spi, &message);
+ if (status) {
+ dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+static int sc8800_recv_and_parse_head_data(struct sc8800_port *s, u32 *len)
+{
+ struct spi_message message;
+ int status;
+ struct spi_transfer tran;
+ char buf[64] = {0};
+ u32 data_len = 0;
+
+ tran.rx_buf = (void *)buf;
+ tran.len = FREAM_SIZE;
+
+ spi_message_init(&message);
+ spi_message_add_tail(&tran, &message);
+ status = spi_sync(s->spi, &message);
+ if (status) {
+ dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+ return -EIO;
+ }
+
+ if ((buf[0]!=0x7f) || (buf[1]!=0x7e) || (buf[2]!=0x55) || (buf[3]!=0xaa)) {
+ dev_warn(&s->spi->dev, "line %d, error head data", __LINE__);
+ return -EIO;
+ }
+
+ data_len = buf[5] + (buf[6]<<8) + (buf[7]<<16) + (buf[8]<<24);
+
+ *len = data_len;
+
+ sc8800_dbg("line %d, %d data need to read\n", __LINE__, *len);
+
+ return 0;
+}
+
+static int sc8800_send_data(struct sc8800_port *s, char *buf, int len)
+{
+#if 1
+ int status;
+ struct spi_message message;
+ struct spi_transfer tran;
+
+ tran.tx_buf = (void *)buf;
+ tran.len = len;
+
+ spi_message_init(&message);
+ spi_message_add_tail(&tran, &message);
+ status = spi_sync(s->spi, &message);
+ if (status) {
+ dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+ return -EIO;
+ }
+#else
+ int status;
+ struct spi_message message;
+ struct spi_transfer tran;
+
+ spi_message_init(&message);
+
+ if (!g_dma_buffer) {
+ g_dma_buffer = dma_alloc_coherent(NULL, SPI_DMA_SIZE, &g_dma_addr, GFP_KERNEL | GFP_DMA);
+ if (!g_dma_buffer) {
+ dev_err(&s->spi->dev, "alloc dma memory fail\n");
+ }
+ }
+
+ if (!g_dma_buffer) { //nomal
+ sc8800_dbg("send data nomal");
+ tran.tx_buf = (void *)buf;
+ tran.len = len;
+ }
+ else { //dma
+ //message.is_dma_mapped = 1;
+ //memcpy(g_dma_buffer, buf, );
+ }
+
+ spi_message_add_tail(&tran, &message);
+ status = spi_sync(s->spi, &message);
+ if (status) {
+ dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+ return -EIO;
+ }
+#endif
+
+ return 0;
+}
+
+static int sc8800_recv_data(struct sc8800_port *s, char *buf, int len)
+{
+ struct spi_message message;
+ int status;
+ struct spi_transfer tran;
+
+ tran.rx_buf = (void *)buf;
+ tran.len = len;
+
+ spi_message_init(&message);
+ spi_message_add_tail(&tran, &message);
+ status = spi_sync(s->spi, &message);
+ if (status) {
+ dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void sc8800_work(struct work_struct *w);
+
+static void sc8800_dowork(struct sc8800_port *s)
+{
+ if (!s->force_end_work && !work_pending(&s->work) &&
+ !freezing(current) && !s->suspending)
+ queue_work(s->workqueue, &s->work);
+}
+
+static void sc8800_timeout(unsigned long data)
+{
+ struct sc8800_port *s = (struct sc8800_port *)data;
+
+ if (s->port.state) {
+ sc8800_dowork(s);
+ mod_timer(&s->timer, jiffies + s->poll_time);
+ }
+}
+
+static void sc8800_work(struct work_struct *w)
+{
+ struct sc8800_port *s = container_of(w, struct sc8800_port, work);
+ struct circ_buf *xmit = &s->port.state->xmit;
+ u32 len,i;
+ char *buf = NULL;
+ unsigned char ch;
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ if (sc8800_get_slave_rts_status(s) == GPIO_HIGH) { //do wirte, master--->slave
+ if (sc8800_get_slave_rdy_status(s) == GPIO_HIGH) { /*1.check slave rdy, must be high*/
+ if (!(uart_circ_empty(xmit))) {
+ len = uart_circ_chars_pending(xmit);
+ len = (len > SPI_MAX_PACKET) ? SPI_MAX_PACKET : len;
+ sc8800_dbg("send data length = %d\n", len);
+
+ sc8800_set_master_rts_status(s, GPIO_LOW); /*2.set master rts low*/
+ sc8800_send_head_data(s,len); /*3.send 64byte head data*/
+ while (sc8800_get_slave_rdy_status(s)) { /*4.check slav rdy, wait for low */
+ msleep(1);
+ }
+
+ /*5.long data transmit*/
+ sc8800_send_data(s, xmit->buf+xmit->tail, len);
+
+ while(sc8800_get_slave_rdy_status(s)==GPIO_LOW) { /*6.wait for slave rdy high*/
+ msleep(1);
+ }
+
+ sc8800_set_master_rts_status(s, GPIO_HIGH); /*end transmit, set master rts high*/
+ xmit->tail = (xmit->tail + len) & (UART_XMIT_SIZE - 1);
+ s->port.icount.tx += len;
+ }
+ }
+ else { //slave not ready, do it next time
+ queue_work(s->workqueue, &s->work);
+ }
+ }
+ else { //do read, slave--->master
+ sc8800_set_master_rdy_status(s, GPIO_LOW);
+ sc8800_recv_and_parse_head_data(s, &len);
+
+ buf = (char *)kzalloc(len, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&s->spi->dev, "line %d, err while malloc mem\n", __LINE__);
+ sc8800_set_master_rdy_status(s, GPIO_HIGH);
+ return ;
+ }
+ memset(buf, 0, len);
+ sc8800_recv_data(s, buf, len);
+
+ while (sc8800_get_slave_rts_status(s) == GPIO_LOW) {
+ msleep(1);
+ }
+ sc8800_set_master_rdy_status(s, GPIO_HIGH);
+
+ for (i=0; i<len; i++) {
+ ch = buf[i];
+ uart_insert_char(&s->port, 0, 0, ch, TTY_NORMAL);
+ }
+ tty_flip_buffer_push(s->port.state->port.tty);
+ }
+}
+
+static irqreturn_t sc8800_irq(int irqno, void *dev_id)
+{
+ struct sc8800_port *s = dev_id;
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ sc8800_dowork(s);
+ return IRQ_HANDLED;
+}
+
+static void sc8800_enable_ms(struct uart_port *port)
+{
+ struct sc8800_port *s = container_of(port,
+ struct sc8800_port,
+ port);
+
+ if (s->poll_time > 0)
+ mod_timer(&s->timer, jiffies);
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static void sc8800_start_tx(struct uart_port *port)
+{
+ struct sc8800_port *s = container_of(port,
+ struct sc8800_port,
+ port);
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ sc8800_dowork(s);
+}
+
+static void sc8800_stop_rx(struct uart_port *port)
+{
+ struct sc8800_port *s = container_of(port,
+ struct sc8800_port,
+ port);
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ s->rx_enabled = 0;
+
+ sc8800_dowork(s);
+}
+
+static void sc8800_shutdown(struct uart_port *port)
+{
+ struct sc8800_port *s = container_of(port,
+ struct sc8800_port,
+ port);
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ if (s->suspending)
+ return;
+
+ s->force_end_work = 1;
+
+ if (s->poll_time > 0)
+ del_timer_sync(&s->timer);
+
+ if (s->workqueue) {
+ flush_workqueue(s->workqueue);
+ destroy_workqueue(s->workqueue);
+ s->workqueue = NULL;
+ }
+ if (s->irq)
+ free_irq(s->irq, s);
+
+ gpio_free(s->master_rdy);
+ gpio_free(s->master_rts);
+ gpio_free(s->slav_rdy);
+ gpio_free(s->slav_rts);
+
+ /* set shutdown mode to save power */
+ if (s->sc8800_hw_suspend)
+ s->sc8800_hw_suspend(1);
+}
+
+static int sc8800_startup(struct uart_port *port)
+{
+ struct sc8800_port *s = container_of(port,
+ struct sc8800_port,
+ port);
+ int ret;
+ char b[12];
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ s->rx_enabled = 1;
+
+ if (s->suspending)
+ return 0;
+
+ s->force_end_work = 0;
+
+ sprintf(b, "sc8800-%d", s->minor);
+ s->workqueue = create_freezeable_workqueue(b);
+ if (!s->workqueue) {
+ dev_warn(&s->spi->dev, "cannot create workqueue\n");
+ return -EBUSY;
+ }
+ INIT_WORK(&s->work, sc8800_work);
+
+ ret = gpio_request(s->slav_rts, "slav rts");
+ if (ret) {
+ dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
+ ret = -EBUSY;
+ goto gpio_err1;
+ }
+ ret = gpio_request(s->slav_rdy, "slav rdy");
+ if (ret) {
+ dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
+ ret = -EBUSY;
+ goto gpio_err2;
+ }
+ ret = gpio_request(s->master_rts, "master rts");
+ if (ret) {
+ dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
+ ret = -EBUSY;
+ goto gpio_err3;
+ }
+ ret = gpio_request(s->master_rdy, "master rdy");
+ if (ret) {
+ dev_err(&s->spi->dev, "line %d: gpio request err\n", __LINE__);
+ ret = -EBUSY;
+ goto gpio_err4;
+ }
+
+ gpio_direction_input(s->slav_rts);
+ gpio_pull_updown(s->slav_rts, GPIOPullUp);
+ gpio_direction_input(s->slav_rdy);
+ gpio_pull_updown(s->slav_rdy, GPIOPullUp);
+ gpio_direction_output(s->master_rts, GPIO_HIGH);
+ gpio_direction_output(s->master_rdy, GPIO_HIGH);
+
+ if (request_irq(s->irq, sc8800_irq,
+ IRQF_TRIGGER_FALLING, "sc8800", s) < 0) {
+ dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
+ s->irq = 0;
+ goto irq_err;
+ }
+
+ if (s->sc8800_hw_suspend)
+ s->sc8800_hw_suspend(0);
+
+ sc8800_dowork(s);
+
+ sc8800_enable_ms(&s->port);
+
+ return 0;
+
+irq_err:
+ gpio_free(s->master_rdy);
+gpio_err4:
+ gpio_free(s->master_rts);
+gpio_err3:
+ gpio_free(s->slav_rdy);
+gpio_err2:
+ gpio_free(s->slav_rts);
+gpio_err1:
+ destroy_workqueue(s->workqueue);
+ s->workqueue = NULL;
+ return ret;
+
+}
+
+static struct uart_ops sc8800_ops = {
+ .start_tx = sc8800_start_tx,
+ .stop_rx = sc8800_stop_rx,
+ .startup = sc8800_startup,
+ .shutdown = sc8800_shutdown,
+};
+
+static struct uart_driver sc8800_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttySPI",
+ .dev_name = "ttySPI",
+ .major = SC8800_MAJOR,
+ .minor = SC8800_MINOR,
+ .nr = MAX_SC8800,
+};
+static int uart_driver_registered;
+
+static int __devinit sc8800_probe(struct spi_device *spi)
+{
+ int i, retval;
+ struct plat_sc8800 *pdata;
+
+ mutex_lock(&sc8800s_lock);
+
+ if (!uart_driver_registered) {
+ uart_driver_registered = 1;
+ retval = uart_register_driver(&sc8800_uart_driver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't register sc8800 uart driver\n");
+ mutex_unlock(&sc8800s_lock);
+ return retval;
+ }
+ }
+
+ for (i = 0; i < MAX_SC8800; i++)
+ if (!sc8800s[i])
+ break;
+ if (i == MAX_SC8800) {
+ dev_warn(&spi->dev, "too many SC8800 chips\n");
+ mutex_unlock(&sc8800s_lock);
+ return -ENOMEM;
+ }
+
+ sc8800s[i] = kzalloc(sizeof(struct sc8800_port), GFP_KERNEL);
+ if (!sc8800s[i]) {
+ dev_warn(&spi->dev,
+ "kmalloc for sc8800 structure %d failed!\n", i);
+ mutex_unlock(&sc8800s_lock);
+ return -ENOMEM;
+ }
+ sc8800s[i]->spi = spi;
+ spin_lock_init(&sc8800s[i]->conf_lock);
+ dev_set_drvdata(&spi->dev, sc8800s[i]);
+ pdata = spi->dev.platform_data;
+ sc8800s[i]->irq = gpio_to_irq(pdata->slav_rts_pin);
+ sc8800s[i]->slav_rts = pdata->slav_rts_pin;
+ sc8800s[i]->slav_rdy = pdata->slav_rdy_pin;
+ sc8800s[i]->master_rts = pdata->master_rts_pin;
+ sc8800s[i]->master_rdy = pdata->master_rdy_pin;
+ //sc8800s[i]->sc8800_hw_suspend = pdata->sc8800_hw_suspend;
+ sc8800s[i]->minor = i;
+ init_timer(&sc8800s[i]->timer);
+ sc8800s[i]->timer.function = sc8800_timeout;
+ sc8800s[i]->timer.data = (unsigned long) sc8800s[i];
+
+ dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
+ sc8800s[i]->port.irq = sc8800s[i]->irq;
+ sc8800s[i]->port.uartclk = 24000000;
+ sc8800s[i]->port.fifosize = 64;
+ sc8800s[i]->port.ops = &sc8800_ops;
+ sc8800s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ sc8800s[i]->port.line = i;
+ sc8800s[i]->port.dev = &spi->dev;
+ retval = uart_add_one_port(&sc8800_uart_driver, &sc8800s[i]->port);
+ if (retval < 0)
+ dev_warn(&spi->dev,
+ "uart_add_one_port failed for line %d with error %d\n",
+ i, retval);
+
+ /* set shutdown mode to save power. Will be woken-up on open */
+ if (sc8800s[i]->sc8800_hw_suspend)
+ sc8800s[i]->sc8800_hw_suspend(1);
+
+ mutex_unlock(&sc8800s_lock);
+ return 0;
+}
+
+static int __devexit sc8800_remove(struct spi_device *spi)
+{
+ struct sc8800_port *s = dev_get_drvdata(&spi->dev);
+ int i;
+
+ mutex_lock(&sc8800s_lock);
+
+ /* find out the index for the chip we are removing */
+ for (i = 0; i < MAX_SC8800; i++)
+ if (sc8800s[i] == s)
+ break;
+
+ dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
+ uart_remove_one_port(&sc8800_uart_driver, &sc8800s[i]->port);
+ kfree(sc8800s[i]);
+ sc8800s[i] = NULL;
+
+ /* check if this is the last chip we have */
+ for (i = 0; i < MAX_SC8800; i++)
+ if (sc8800s[i]) {
+ mutex_unlock(&sc8800s_lock);
+ return 0;
+ }
+ pr_debug("removing sc8800 driver\n");
+ uart_unregister_driver(&sc8800_uart_driver);
+
+ mutex_unlock(&sc8800s_lock);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int sc8800_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct sc8800_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ disable_irq(s->irq);
+
+ s->suspending = 1;
+ uart_suspend_port(&sc8800_uart_driver, &s->port);
+
+ if (s->sc8800_hw_suspend)
+ s->sc8800_hw_suspend(1);
+
+ return 0;
+}
+
+static int sc8800_resume(struct spi_device *spi)
+{
+ struct sc8800_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+ if (s->sc8800_hw_suspend)
+ s->sc8800_hw_suspend(0);
+ uart_resume_port(&sc8800_uart_driver, &s->port);
+ s->suspending = 0;
+
+ enable_irq(s->irq);
+
+ if (s->workqueue)
+ sc8800_dowork(s);
+
+ return 0;
+}
+
+#else
+#define sc8800_suspend NULL
+#define sc8800_resume NULL
+#endif
+
+static struct spi_driver sc8800_driver = {
+ .driver = {
+ .name = "sc8800",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sc8800_probe,
+ .remove = __devexit_p(sc8800_remove),
+ .suspend = sc8800_suspend,
+ .resume = sc8800_resume,
+};
+
+static int __init sc8800_init(void)
+{
+ return spi_register_driver(&sc8800_driver);
+}
+module_init(sc8800_init);
+
+static void __exit sc8800_exit(void)
+{
+ spi_unregister_driver(&sc8800_driver);
+}
+module_exit(sc8800_exit);
+
+MODULE_DESCRIPTION("SC8800 driver");
+MODULE_AUTHOR("liuyixing <lyx@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:SC8800");
--- /dev/null
+#ifndef __SC8800_H__\r
+#define __SC8800_H__\r
+\r
+typedef struct _spi_packet_head {\r
+ u16 tag; //HEADER_TAG(0x7e7f) \r
+ u16 type; //HEADER_TYPE(0xaa55) \r
+ u32 length; //the length of data after head (8192-128 bytes) \r
+ u32 frame_num; //no used , always 0\r
+ u32 reserved2; //reserved \r
+} SPI_PACKET_HEAD_T;\r
+\r
+\r
+/*define flatform data struct*/\r
+struct plat_sc8800 {\r
+ int slav_rts_pin;\r
+ int slav_rdy_pin;\r
+ int master_rts_pin;\r
+ int master_rdy_pin;\r
+ int poll_time;\r
+};\r
+\r
+#endif\r
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/
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
+
retval = usb_debugfs_init();
if (retval)
goto out;
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 - "
* @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)
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",
_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
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.
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
# 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
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;
.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 = {
#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 <linux/power_supply.h>
+#include <linux/reboot.h>
+#include <linux/syscalls.h>
+
+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"
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) {
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
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;
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;
int reply = -EINVAL;
int i;
static char unknown[16];
+#ifdef CONFIG_ARCH_RK29
+ struct fsg_common *fsg = common;
+#endif
dump_cdb(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:
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);
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);
}
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 */
+
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;
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
#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
#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
#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,
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) },
{ 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) },
{ 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) },
{ 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 */
}
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) {
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/regulator.h>
-
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#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,
/* 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;
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;
if (bl->props.state & BL_CORE_SUSPENDED)
brightness = 0;
+ printk("backlight brightness=%d\n", brightness);
+
return wm831x_backlight_set(bl, brightness);
}
.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)
{
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",
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)) {
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;
}
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",
},
.probe = wm831x_backlight_probe,
.remove = wm831x_backlight_remove,
+ .shutdown = wm831x_backlight_shutdown,
};
static int __init wm831x_backlight_init(void)
*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;
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;
}
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;
}
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;
}
}
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;
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++;
}
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;
#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).
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,
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)
struct dev_archdata *archdata;
struct device_node *of_node;
int irq;
+ int udelay; //add by kfx
};
/**
#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 */
+++ /dev/null
-/* linux/i2c/tps65910.h
- *
- * TPS65910 Power Management Device Definitions.
- *
- * Based on include/linux/i2c/twl.h
- *
- * Copyright (C) 2010 Mistral Solutions Pvt Ltd <www.mistralsolutions.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS 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 */
-
#include <linux/completion.h>
#include <linux/interrupt.h>
+#include <linux/wakelock.h>
+#include <linux/regulator/driver.h>
/*
* Register values.
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,
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 */
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,
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);
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**/
};
/**
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
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];
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];
#ifndef __MFD_WM8994_CORE_H__
#define __MFD_WM8994_CORE_H__
+<<<<<<< HEAD
#include <linux/interrupt.h>
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;
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;
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
#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
#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
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
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;
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;
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
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)
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);
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;
* number of jiffies until all active wake locks time out.
*/
long has_wake_lock(int type);
+void print_active_wake_locks(int type);
#else
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
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,
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,
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,
/* 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! */
};
#include <linux/syscalls.h> /* sys_sync */
#include <linux/wakelock.h>
#include <linux/workqueue.h>
+#include <linux/kallsyms.h>
#include "power.h"
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);
}
}
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);
}
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");
}
/* 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;
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;
}
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);
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);
}
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
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/unistd.h>
+/***************
+* 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)
*/
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");
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;
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;
break;
}
buffer[sizeof(buffer) - 1] = '\0';
-
+ /*
+ * debug trace
+ */
+ restart_dbg("%s->%d->cmd=%x args=%s",__FUNCTION__,__LINE__,cmd,buffer);
+
kernel_restart(buffer);
break;
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
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
config SND_SOC_CS42L51
tristate
+config SND_SOC_CS42L52
+ tristate
+
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
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
config SND_SOC_WM9713
tristate
+config SND_SOC_RK1000
+ tristate
+ depends on RK1000_CONTROL
+
# Amp
config SND_SOC_LM4857
tristate
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
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
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
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
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <mach/rk29_iomap.h>
#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
#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
#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;
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,
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,
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)) {
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;
}
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;
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;
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);
}
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);
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);
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 | \
.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 = {
{
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 */
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;
}
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) {
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;
}
}
+<<<<<<< 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) {
/* 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);
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;
}
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 = {
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 },
{ }
.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
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) {
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);
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;