aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngenic <ftp.ingenic.cn/3sw/01linux/02kernel/linux-2.6.31>2020-10-30 01:37:18 +0100
committerLubomir Rintel <lkundrak@v3.sk>2020-10-30 01:46:31 +0100
commitb0bfe4f4fe557c1f16c30f35cb3fd678314e9aa7 (patch)
tree76e729bf3a9fb594fcca19f78545575d3a9b2d16
parent8155bc8f16a1f2e61f51a5bdc0918109383de34d (diff)
downloadlinux-jz47xx-b0bfe4f4fe557c1f16c30f35cb3fd678314e9aa7.tar.gz
linux-2.6.31.3-20101015.patch.bz2
* change mtd partitions * add support for oobdata 4-bit bch * add apus CIM support * fixed mono double rated bug when user application use SNDCTL_DSP_CHANNELS instead of SNDCTL_DSP_STEREO * add the bch alogrithm (4bit n8) for yaffs2 to do the oob correct * Optimize the Odd syndromes calculate for decoder * fix the second insmod g_ether.ko bug * board-lepus: add tf card insert/remove wakeup support * lcd suspend: use quick disable instead of regular disable * fix SD card suspend/resume support * fix an ov7690 bug and add apus support * add DMA burst 64-byte support in msc module * use RTC for reboot command * add Capacitive touch screen driver * use the capacitive touchscreen driver as default touchscreen driver
-rw-r--r--arch/mips/configs/apus_defconfig4
-rw-r--r--arch/mips/configs/cetus_defconfig40
-rw-r--r--arch/mips/configs/lepus_defconfig39
-rw-r--r--arch/mips/include/asm/jzmmc/jz_mmc_dma.h16
-rw-r--r--arch/mips/include/asm/jzmmc/jz_mmc_host.h38
-rw-r--r--arch/mips/include/asm/mach-jz4750/regs.h2
-rw-r--r--arch/mips/include/asm/mach-jz4750d/ops.h4
-rw-r--r--arch/mips/include/asm/mach-jz4760/board-lepus.h23
-rw-r--r--arch/mips/include/asm/mach-jz4760/dma.h8
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760aic.h681
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760bch.h125
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760cim.h83
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760dmac.h343
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760i2c.h21
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760intc.h1
-rw-r--r--arch/mips/include/asm/mach-jz4760/jz4760msc.h2
-rw-r--r--arch/mips/jz4750/board-apus.c20
-rw-r--r--arch/mips/jz4750/platform.c29
-rw-r--r--arch/mips/jz4750d/board-cetus.c169
-rw-r--r--arch/mips/jz4750d/platform.c122
-rw-r--r--arch/mips/jz4760/board-lepus.c37
-rw-r--r--arch/mips/jz4760/cpm.c27
-rw-r--r--arch/mips/jz4760/dma.c16
-rw-r--r--arch/mips/jz4760/irq.c25
-rw-r--r--arch/mips/jz4760/platform.c4
-rw-r--r--arch/mips/jz4760/pm.c175
-rw-r--r--arch/mips/jz4760/proc.c222
-rw-r--r--arch/mips/jz4760/reset.c29
-rw-r--r--drivers/i2c/busses/i2c-jz4760.c65
-rw-r--r--drivers/i2c/busses/i2c-jz47xx.c280
-rw-r--r--drivers/input/keyboard/jz_gpio_keypad.c36
-rw-r--r--drivers/input/touchscreen/Kconfig8
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ft5x0x_ts.c455
-rw-r--r--drivers/input/touchscreen/jz4760_ts.c3
-rw-r--r--drivers/misc/jz_cim/Makefile1
-rw-r--r--drivers/misc/jz_cim/camera_source/ov3640/ov3640_camera.c26
-rw-r--r--drivers/misc/jz_cim/camera_source/ov3640/ov3640_set.c338
-rw-r--r--drivers/misc/jz_cim/camera_source/ov7690/ov7690_camera.c5
-rw-r--r--drivers/misc/jz_cim/jz_cim_board_apus.c8
-rw-r--r--drivers/misc/jz_cim/jz_cim_board_f4760.c17
-rw-r--r--drivers/misc/jz_cim/jz_cim_core.c594
-rw-r--r--drivers/misc/jz_cim/jz_cim_core.h16
-rw-r--r--drivers/misc/jz_cim/jz_sensor.c3
-rw-r--r--drivers/mmc/host/jzmmc/controller/dma/jz_mmc_dma.c290
-rw-r--r--drivers/mmc/host/jzmmc/controller/gpio/jz_mmc_gpio.c99
-rw-r--r--drivers/mmc/host/jzmmc/controller/jz_mmc_controller.c2
-rw-r--r--drivers/mmc/host/jzmmc/controller/msc/jz_mmc_msc.c355
-rw-r--r--drivers/mmc/host/jzmmc/jz_mmc_main.c38
-rw-r--r--drivers/mtd/mtdblock-jz.c203
-rw-r--r--drivers/mtd/nand/jz4750_nand.c45
-rw-r--r--drivers/mtd/nand/jz4760_nand.c85
-rw-r--r--drivers/mtd/nand/nand_base.c64
-rw-r--r--drivers/usb/gadget/epautoconf.c1
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/jz4760.c17
-rw-r--r--drivers/usb/musb/musb_gadget.c5
-rw-r--r--drivers/video/jz4760_lcd.c14
-rw-r--r--drivers/video/jz4760_lcd.h249
-rw-r--r--fs/sync.c9
-rw-r--r--fs/yaffs2/Makefile2
-rw-r--r--fs/yaffs2/bch4bit_n8_decoder.c470
-rw-r--r--fs/yaffs2/bch4bit_n8_encoder.c155
-rw-r--r--fs/yaffs2/bch4bit_n8_global.c268
-rw-r--r--fs/yaffs2/utils/Makefile2
-rw-r--r--fs/yaffs2/utils/mkyaffs2image.c151
-rw-r--r--fs/yaffs2/yaffs_fs.c21
-rw-r--r--fs/yaffs2/yaffs_packedtags2.c14
-rw-r--r--include/linux/ft5x0x_ts.h23
-rw-r--r--include/mtd/mtd_bch4bit_n8.h23
-rw-r--r--sound/oss/Kconfig2
-rw-r--r--sound/oss/Makefile4
-rw-r--r--sound/oss/jz4740_i2s.c2936
-rw-r--r--sound/oss/jz4750_codec.h75
-rw-r--r--sound/oss/jz4750_dlv.h27
-rw-r--r--sound/oss/jz4760_dlv.c2193
-rw-r--r--sound/oss/jz4760_dlv.h596
-rw-r--r--sound/oss/jz4760_i2s.c180
-rw-r--r--sound/oss/jz_codec.h50
-rw-r--r--sound/oss/jz_i2s.c5008
-rw-r--r--sound/oss/jzdlv.c1384
81 files changed, 13787 insertions, 5436 deletions
diff --git a/arch/mips/configs/apus_defconfig b/arch/mips/configs/apus_defconfig
index 0cdeb1ce732..6e46ecc7c02 100644
--- a/arch/mips/configs/apus_defconfig
+++ b/arch/mips/configs/apus_defconfig
@@ -469,8 +469,8 @@ CONFIG_MTD_HW_BCH_ECC=y
# CONFIG_MTD_HW_BCH_4BIT is not set
CONFIG_MTD_HW_BCH_8BIT=y
CONFIG_MTD_NAND_DMA=y
-CONFIG_MTD_NAND_DMABUF=y
-CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY=y
+# CONFIG_MTD_NAND_DMABUF is not set
+# CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY is not set
# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
CONFIG_MTD_OOB_COPIES=3
CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
diff --git a/arch/mips/configs/cetus_defconfig b/arch/mips/configs/cetus_defconfig
index fa4d8ee8c5a..7a7546469e4 100644
--- a/arch/mips/configs/cetus_defconfig
+++ b/arch/mips/configs/cetus_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31.3
-# Fri Feb 26 12:15:30 2010
+# Tue Oct 12 17:34:28 2010
#
CONFIG_MIPS=y
@@ -19,6 +19,11 @@ CONFIG_MIPS=y
# CONFIG_JZ4750_APUS is not set
CONFIG_JZ4750D_CETUS=y
# CONFIG_JZ4750L_F4750L is not set
+# CONFIG_JZ4760_F4760 is not set
+# CONFIG_JZ4760_CYGNUS is not set
+# CONFIG_JZ4760_ALTAIR is not set
+# CONFIG_JZ4760_LEPUS is not set
+# CONFIG_JZ4810_F4810 is not set
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_AR7 is not set
# CONFIG_BASLER_EXCITE is not set
@@ -75,6 +80,7 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_SYS_HAS_EARLY_PRINTK is not set
# CONFIG_NO_IOPORT is not set
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
@@ -288,6 +294,11 @@ CONFIG_BINFMT_ELF=y
CONFIG_TRAD_SIGNALS=y
#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ_JZ is not set
+
+#
# Power management options
#
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
@@ -462,15 +473,21 @@ CONFIG_MTD_NAND_JZ4750=y
# CONFIG_MTD_NAND_CS3 is not set
# CONFIG_MTD_NAND_CS4 is not set
CONFIG_MTD_NAND_MULTI_PLANE=y
+CONFIG_MTD_NAND_BUS_WIDTH_8=y
+# CONFIG_MTD_NAND_BUS_WIDTH_16 is not set
# CONFIG_MTD_HW_HM_ECC is not set
# CONFIG_MTD_SW_HM_ECC is not set
# CONFIG_MTD_HW_RS_ECC is not set
CONFIG_MTD_HW_BCH_ECC=y
# CONFIG_MTD_HW_BCH_4BIT is not set
CONFIG_MTD_HW_BCH_8BIT=y
+# CONFIG_MTD_HW_BCH_12BIT is not set
+# CONFIG_MTD_HW_BCH_16BIT is not set
+# CONFIG_MTD_HW_BCH_20BIT is not set
+# CONFIG_MTD_HW_BCH_24BIT is not set
CONFIG_MTD_NAND_DMA=y
-CONFIG_MTD_NAND_DMABUF=y
-CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY=y
+# CONFIG_MTD_NAND_DMABUF is not set
+# CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY is not set
# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
CONFIG_MTD_OOB_COPIES=3
CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
@@ -506,6 +523,8 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_ATA_OVER_ETH is not set
# CONFIG_BLK_DEV_HD is not set
CONFIG_MISC_DEVICES=y
+# CONFIG_JZ_I2C_SIMULATE is not set
+# CONFIG_JZ_CIM is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_C2PORT is not set
@@ -678,9 +697,8 @@ CONFIG_LEGACY_PTY_COUNT=2
#
CONFIG_JZCHAR=y
# CONFIG_JZ_SIMPLE_I2C is not set
-# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_GPIO_PM_KEY is not set
# CONFIG_JZ_TPANEL_ATA2508 is not set
-# CONFIG_JZ_POWEROFF is not set
# CONFIG_JZ_OW is not set
CONFIG_JZ_TCSM=y
# CONFIG_JZ_TSSI is not set
@@ -741,6 +759,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
#
# Frame buffer hardware drivers
#
+# CONFIG_FB_JZ475X is not set
CONFIG_FB_JZSOC=y
CONFIG_FB_JZ4750_LCD=y
# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set
@@ -802,7 +821,8 @@ CONFIG_SOUND_PRIME=y
CONFIG_SOUND_JZ_I2S=y
# CONFIG_I2S_AK4642EN is not set
# CONFIG_I2S_ICODEC is not set
-CONFIG_I2S_DLV=y
+CONFIG_I2S_DLV_4750=y
+# CONFIG_I2S_DLV_4760 is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
@@ -819,6 +839,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_GADGET_MUSB_HDRC is not set
#
@@ -885,11 +906,8 @@ CONFIG_MMC_BLOCK_BOUNCE=y
#
# MMC/SD/SDIO Host Controller Drivers
#
-# CONFIG_MSC0_JZ4750 is not set
-CONFIG_MSC1_JZ4750=y
-# CONFIG_JZ4750_MSC1_BUS_1 is not set
-CONFIG_JZ4750_MSC1_BUS_4=y
-# CONFIG_JZ4750_BOOT_FROM_MSC0 is not set
+# CONFIG_JZ_MSC0 is not set
+# CONFIG_JZ_MSC1 is not set
# CONFIG_MMC_SDHCI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_NEW_LEDS is not set
diff --git a/arch/mips/configs/lepus_defconfig b/arch/mips/configs/lepus_defconfig
index 2e9ae9593a8..cf147f6789c 100644
--- a/arch/mips/configs/lepus_defconfig
+++ b/arch/mips/configs/lepus_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31.3
-# Wed Jul 21 15:48:25 2010
+# Thu Oct 14 10:19:37 2010
#
CONFIG_MIPS=y
@@ -381,7 +381,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -656,7 +666,26 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_JZ4760 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+CONFIG_TOUCHSCREEN_FT5X0X=y
# CONFIG_INPUT_MISC is not set
#
@@ -866,7 +895,7 @@ CONFIG_SOUND_PRIME=y
CONFIG_SOUND_JZ_I2S=y
# CONFIG_I2S_AK4642EN is not set
# CONFIG_I2S_ICODEC is not set
-# CONFIG_I2S_DLV is not set
+# CONFIG_I2S_DLV_4750 is not set
CONFIG_I2S_DLV_4760=y
# CONFIG_HID_SUPPORT is not set
CONFIG_USB_SUPPORT=y
@@ -1050,7 +1079,7 @@ CONFIG_JZ_MSC0=y
# CONFIG_JZ_MSC0_BUS_1 is not set
CONFIG_JZ_MSC0_BUS_4=y
# CONFIG_JZ_MSC0_BUS_8 is not set
-# CONFIG_JZ_MSC0_SDIO_SUPPORT is not set
+CONFIG_JZ_MSC0_SDIO_SUPPORT=y
CONFIG_JZ_MSC1=y
# CONFIG_JZ_MSC1_BUS_1 is not set
CONFIG_JZ_MSC1_BUS_4=y
diff --git a/arch/mips/include/asm/jzmmc/jz_mmc_dma.h b/arch/mips/include/asm/jzmmc/jz_mmc_dma.h
index 8899d9c6635..a40025d3145 100644
--- a/arch/mips/include/asm/jzmmc/jz_mmc_dma.h
+++ b/arch/mips/include/asm/jzmmc/jz_mmc_dma.h
@@ -13,13 +13,6 @@
#include <asm/jzmmc/jz_mmc_host.h>
-#define DMA_TS 32 // ONLY BYTE
-
-// No 64 byte in jz4760dmac.h
-#define DMAC_DCMD_DS_64BYTE (5 << DMAC_DCMD_DS_BIT)
-
-#define DMAC_DCMD_DS(x) (x == 32? DMAC_DCMD_DS_32BYTE:DMAC_DCMD_DS_64BYTE)
-
struct jz_mmc_dma {
int (*init) (struct jz_mmc_host *);
@@ -28,12 +21,9 @@ struct jz_mmc_dma {
int jz_mmc_dma_register(struct jz_mmc_dma *dma);
-void jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode, int ts);
+void jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode, int ds);
-void jz_mmc_send_dma(struct jz_mmc_host *host, int chan, unsigned long srcaddr,
- unsigned long taraddr, int al_count, int unal_count);
-
-void jz_mmc_receive_dma(struct jz_mmc_host *host, int chan, unsigned long srcaddr,
- unsigned long taraddr, int al_count, int unal_count);
+void jz_mmc_start_scatter_dma(int chan, struct jz_mmc_host *host,
+ struct scatterlist *sg, unsigned int sg_len, int mode);
#endif /* __JZ_MMC_DMA_H__ */
diff --git a/arch/mips/include/asm/jzmmc/jz_mmc_host.h b/arch/mips/include/asm/jzmmc/jz_mmc_host.h
index dbedcbc19b1..a64614381de 100644
--- a/arch/mips/include/asm/jzmmc/jz_mmc_host.h
+++ b/arch/mips/include/asm/jzmmc/jz_mmc_host.h
@@ -15,6 +15,11 @@
#include <asm/jzsoc.h>
#define USE_DMA
+#define USE_DMA_DESC
+#ifdef CONFIG_SOC_JZ4760
+#define USE_DMA_BUSRT_64
+#endif
+
#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
@@ -30,12 +35,14 @@
#define SZ_4K 0x00001000
+#ifndef USE_DMA_DESC
typedef struct jzsoc_dma_desc {
- volatile u32 ddadr; /* Points to the next descriptor + flags */
- volatile u32 dsadr; /* DSADR value for the current transfer */
- volatile u32 dtadr; /* DTADR value for the current transfer */
- volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + flags */
+ volatile u32 dsadr; /* DSADR value for the current transfer */
+ volatile u32 dtadr; /* DTADR value for the current transfer */
+ volatile u32 dcmd; /* DCMD value for the current transfer */
} jzsoc_dma_desc;
+#endif
struct jz_mmc_curr_req {
struct mmc_request *mrq;
@@ -47,17 +54,27 @@ struct jz_mmc_curr_req {
struct jz_mmc_host {
struct mmc_host *mmc;
spinlock_t lock;
+#ifdef USE_DMA
struct {
int len;
int dir;
int rxchannel;
int txchannel;
} dma;
+#ifdef USE_DMA_DESC
+ jz_dma_desc *dma_desc;
+ dma_addr_t dma_desc_phys_addr;
+#else
+ dma_addr_t sg_dma;
+ struct jzsoc_dma_desc *sg_cpu;
+#endif
+#else
struct {
int index;
int offset;
int len;
} pio;
+#endif
unsigned int clkrt;
unsigned int cmdat;
unsigned int imask;
@@ -73,17 +90,10 @@ struct jz_mmc_host {
struct jz_mmc_platform_data *plat;
struct jz_mmc_curr_req curr;
- dma_addr_t sg_dma;
- struct jzsoc_dma_desc *sg_cpu;
- unsigned int dma_len;
- unsigned int dma_dir;
- int dma_ts;
int msc_ack;
- int flag_cp;
- unsigned int *dma_buf;
- jz_dma_desc *ua_desc;
- dma_addr_t dma_desc_phys_addr;
- struct work_struct gpio_jiq_work;
+ struct delayed_work gpio_jiq_work;
+ atomic_t detect_refcnt;
+ int sleeping;
struct work_struct msc_jiq_work;
struct workqueue_struct *msc_work_queue;
wait_queue_head_t msc_wait_queue;
diff --git a/arch/mips/include/asm/mach-jz4750/regs.h b/arch/mips/include/asm/mach-jz4750/regs.h
index 0fcc11edc2e..e2636ac8ba3 100644
--- a/arch/mips/include/asm/mach-jz4750/regs.h
+++ b/arch/mips/include/asm/mach-jz4750/regs.h
@@ -1602,7 +1602,7 @@
#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n))
#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n))
#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n))
-#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n))
+#define REG_MSC_RDTO(n) REG32(MSC_RDTO(n))
#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n))
#define REG_MSC_NOB(n) REG16(MSC_NOB(n))
#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n))
diff --git a/arch/mips/include/asm/mach-jz4750d/ops.h b/arch/mips/include/asm/mach-jz4750d/ops.h
index 6950229b430..38efce4ea86 100644
--- a/arch/mips/include/asm/mach-jz4750d/ops.h
+++ b/arch/mips/include/asm/mach-jz4750d/ops.h
@@ -1439,9 +1439,9 @@ do { \
#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
#define __aic_flush_fifo_rx() ( REG_AIC_CR |= AIC_CR_FLUSH_RX )
-#define __aic_flush_fifo_tx() ( REG_AIC_CR |= AIC_CR_FLUSH_TX )
+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH_TX )
#define __aic_unflush_fifo_rx() ( REG_AIC_CR &= ~AIC_CR_FLUSH_RX )
-#define __aic_unflush_fifo_tx() ( REG_AIC_CR &= ~AIC_CR_FLUSH_TX )
+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH_TX )
#define __aic_enable_transmit_intr() \
( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
diff --git a/arch/mips/include/asm/mach-jz4760/board-lepus.h b/arch/mips/include/asm/mach-jz4760/board-lepus.h
index 3db15a6cc9f..ca2565605d8 100644
--- a/arch/mips/include/asm/mach-jz4760/board-lepus.h
+++ b/arch/mips/include/asm/mach-jz4760/board-lepus.h
@@ -74,6 +74,10 @@
#define DPAD_CENTER_LEVEL 1489 //1.2V
#define DPAD_RIGHT_LEVEL 868 //0.7V
+
+#define GPIO_TS_I2C_INT (32 * 1 + 20) //GPB20
+#define GPIO_TS_I2C_IRQ (IRQ_GPIO_0 + GPIO_TS_I2C_INT)
+
/*======================================================================
* Analog input for VBAT is the battery voltage divided by CFG_PBAT_DIV.
*/
@@ -245,7 +249,7 @@ do { \
#define ACTIVE_LOW_VOLUMEDOWN 1
#define ACTIVE_LOW_VOLUMEUP 1
#define ACTIVE_LOW_ADKEY 1
-#define ACTIVE_WAKE_UP 1
+#define ACTIVE_LOW_WAKE_UP 1
#define ACTIVE_LOW_MSC0_CD 1
#define ACTIVE_LOW_MSC1_CD 1
@@ -264,4 +268,21 @@ do { \
#define ACTIVE_LOW_REWIND 1
#define ACTIVE_LOW_FORWARD 1
+
+#define GPIO_SW3 (32 * 2 + 29) // SW3-GPC29
+#define GPIO_SW1 (32 * 2 + 31) // SW1-GPC31
+#define GPIO_SW6 (32 * 3 + 19) // SW6-boot_sel2-GPD19
+#define GPIO_SW4 (32 * 3 + 27) // SW4-GPD27
+#define GPIO_SW9 (32 * 0 + 30) // SW9-WAKEUP-GPA30
+#define GPIO_SW7 (32 * 3 + 18) // SW7-boot_sel1-GPD18
+#define GPIO_SW8 (32 * 3 + 17) // SW8-boot_sel0-GPD17
+
+#define ACTIVE_LOW_SW3 1
+#define ACTIVE_LOW_SW1 1
+#define ACTIVE_LOW_SW6 1
+#define ACTIVE_LOW_SW4 1
+#define ACTIVE_LOW_SW9 1
+#define ACTIVE_LOW_SW7 1
+#define ACTIVE_LOW_SW8 1
+
#endif /* __ASM_JZ4760_LEPUS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4760/dma.h b/arch/mips/include/asm/mach-jz4760/dma.h
index e341dda084c..236c90fa68d 100644
--- a/arch/mips/include/asm/mach-jz4760/dma.h
+++ b/arch/mips/include/asm/mach-jz4760/dma.h
@@ -60,11 +60,7 @@ typedef struct {
/* DMA Device ID's follow */
enum {
- DMA_ID_EXT = 0, /* External request with DREQn */
- DMA_ID_NAND, /* NAND DMA request */
- DMA_ID_BCH_ENC, /* BCH Encoding DMA request */
- DMA_ID_BCH_DEC, /* BCH Decoding DMA request */
- DMA_ID_AUTO, /* Auto-request */
+ DMA_ID_AUTO = 0, /* Auto-request */
// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */
DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */
DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */
@@ -99,7 +95,7 @@ enum {
#define DMA_MODE_MASK 0x3
struct jz_dma_chan {
- int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
unsigned int io; /* DMA channel number */
const char *dev_str; /* string describes the DMA channel */
int irq; /* DMA irq number */
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760aic.h b/arch/mips/include/asm/mach-jz4760/jz4760aic.h
index ea47d4cfe7f..059fb361076 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760aic.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760aic.h
@@ -1,360 +1,315 @@
/*
- * linux/include/asm-mips/mach-jz4760/jz4760aic.h
- *
- * JZ4760 AIC register definition.
- *
+ * chip-aic.h
+ * JZ4760 AIC register definition
* Copyright (C) 2010 Ingenic Semiconductor Co., Ltd.
+ *
+ * Author: whxu@ingenic.cn
*/
-#ifndef __JZ4760AIC_H__
-#define __JZ4760AIC_H__
-
+#ifndef __CHIP_AIC_H__
+#define __CHIP_AIC_H__
-#define AIC_BASE 0xB0020000
-#define ICDC_BASE 0xB0020000
-
-
-/*************************************************************************
- * AIC (AC97/I2S Controller)
- *************************************************************************/
-#define AIC_FR (AIC_BASE + 0x000)
-#define AIC_CR (AIC_BASE + 0x004)
-#define AIC_ACCR1 (AIC_BASE + 0x008)
-#define AIC_ACCR2 (AIC_BASE + 0x00C)
-#define AIC_I2SCR (AIC_BASE + 0x010)
-#define AIC_SR (AIC_BASE + 0x014)
-#define AIC_ACSR (AIC_BASE + 0x018)
-#define AIC_I2SSR (AIC_BASE + 0x01C)
-#define AIC_ACCAR (AIC_BASE + 0x020)
-#define AIC_ACCDR (AIC_BASE + 0x024)
-#define AIC_ACSAR (AIC_BASE + 0x028)
-#define AIC_ACSDR (AIC_BASE + 0x02C)
-#define AIC_I2SDIV (AIC_BASE + 0x030)
-#define AIC_DR (AIC_BASE + 0x034)
-#define REG_AIC_FR REG32(AIC_FR)
-#define REG_AIC_CR REG32(AIC_CR)
-#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
-#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
-#define REG_AIC_I2SCR REG32(AIC_I2SCR)
-#define REG_AIC_SR REG32(AIC_SR)
-#define REG_AIC_ACSR REG32(AIC_ACSR)
-#define REG_AIC_I2SSR REG32(AIC_I2SSR)
-#define REG_AIC_ACCAR REG32(AIC_ACCAR)
-#define REG_AIC_ACCDR REG32(AIC_ACCDR)
-#define REG_AIC_ACSAR REG32(AIC_ACSAR)
-#define REG_AIC_ACSDR REG32(AIC_ACSDR)
-#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
-#define REG_AIC_DR REG32(AIC_DR)
+/*
+ * AC97 and I2S controller module(AIC) address definition
+ */
+#define AIC_BASE 0xb0020000
-/* AIC Controller Configuration Register (AIC_FR) */
-
-#define AIC_FR_RFTH_BIT 24 /* Receive FIFO Threshold */
-#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
-#define AIC_FR_TFTH_BIT 16 /* Transmit FIFO Threshold */
-#define AIC_FR_TFTH_MASK (0x1f << AIC_FR_TFTH_BIT)
-#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */
-#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */
-#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */
-#define AIC_FR_RST (1 << 3) /* AIC registers reset */
-#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */
-#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */
-#define AIC_FR_ENB (1 << 0) /* AIC enable bit */
-
-/* AIC Controller Common Control Register (AIC_CR) */
-
-#define AIC_CR_EN2OLD (1 << 29) /* Enable old style */
-#define AIC_CR_PACK16 (1 << 28) /* Output Sample data 16bit packed mode select */
-#define AIC_CR_CHANNEL_BIT 24 /* Output Channel Number Select */
-#define AIC_CR_CHANNEL_MASK (0x7 << AIC_CR_CHANNEL_BIT)
- #define AIC_CR_CHANNEL_MONO (0x0 << AIC_CR_CHANNEL_BIT)
- #define AIC_CR_CHANNEL_STEREO (0x1 << AIC_CR_CHANNEL_BIT)
- #define AIC_CR_CHANNEL_4CHNL (0x3 << AIC_CR_CHANNEL_BIT)
- #define AIC_CR_CHANNEL_6CHNL (0x5 << AIC_CR_CHANNEL_BIT)
- #define AIC_CR_CHANNEL_8CHNL (0x7 << AIC_CR_CHANNEL_BIT)
-
-#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */
-#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT)
- #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT)
- #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT)
- #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT)
- #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT)
- #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT)
-#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */
-#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT)
- #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT)
- #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT)
- #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT)
- #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT)
- #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT)
-#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */
-#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */
-#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */
-#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */
-#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */
-#define AIC_CR_TFLUSH (1 << 8) /* Flush TFIFO */
-#define AIC_CR_RFLUSH (1 << 7) /* Flush RFIFO */
-#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */
-#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */
-#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */
-#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */
-#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */
-#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */
-#define AIC_CR_EREC (1 << 0) /* Enable Record Function */
-
-/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
-
-#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */
-#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
- #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
- #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
- #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
- #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */
- #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */
- #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */
- #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */
- #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
- #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */
- #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */
-#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */
-#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
- #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
- #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
- #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
- #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */
- #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */
- #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */
- #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */
- #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
- #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */
- #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */
-
-/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
-
-#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */
-#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */
-#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */
-#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */
-#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
- #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
- #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
- #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
- #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
-#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */
-#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
- #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
- #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
- #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
- #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
-#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */
-#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */
-#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */
-#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */
-
-/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
-
-#define AIC_I2SCR_RFIRST (1 << 17) /* Send R channel first in stereo mode */
-#define AIC_I2SCR_SWLH (1 << 16) /* Switch LR channel in 16bit-packed stereo mode */
-#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */
-#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */
-#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
- #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
- #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
- #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
- #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
- #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
-
-#define AIC_I2SCR_ESCLK (1 << 4)
-
-#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */
-
-/* AIC Controller FIFO Status Register (AIC_SR) */
-
-#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */
-#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT)
-#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */
-#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT)
-#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */
-#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */
-#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */
-#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */
-
-/* AIC Controller AC-link Status Register (AIC_ACSR) */
-
-#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */
-#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */
-#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */
-#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */
-#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */
-#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */
-
-/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
-
-#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */
-
-/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
-
-#define AIC_ACCAR_CAR_BIT 0
-#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
-
-/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
-
-#define AIC_ACCDR_CDR_BIT 0
-#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
-
-/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
-
-#define AIC_ACSAR_SAR_BIT 0
-#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
-
-/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
-
-#define AIC_ACSDR_SDR_BIT 0
-#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
-
-/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
-
-#define AIC_I2SDIV_DIV_BIT 0
-#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
- #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
- #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
- #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
- #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
- #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
- #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+/*
+ * AIC registers offset address definition
+ */
+#define AIC_FR_OFFSET (0x00)
+#define AIC_CR_OFFSET (0x04)
+#define AIC_ACCR1_OFFSET (0x08)
+#define AIC_ACCR2_OFFSET (0x0c)
+#define AIC_I2SCR_OFFSET (0x10)
+#define AIC_SR_OFFSET (0x14)
+#define AIC_ACSR_OFFSET (0x18)
+#define AIC_I2SSR_OFFSET (0x1c)
+#define AIC_ACCAR_OFFSET (0x20)
+#define AIC_ACCDR_OFFSET (0x24)
+#define AIC_ACSAR_OFFSET (0x28)
+#define AIC_ACSDR_OFFSET (0x2c)
+#define AIC_I2SDIV_OFFSET (0x30)
+#define AIC_DR_OFFSET (0x34)
+
+#define SPDIF_ENA_OFFSET (0x80)
+#define SPDIF_CTRL_OFFSET (0x84)
+#define SPDIF_STATE_OFFSET (0x88)
+#define SPDIF_CFG1_OFFSET (0x8c)
+#define SPDIF_CFG2_OFFSET (0x90)
+#define SPDIF_FIFO_OFFSET (0x94)
+
+#define ICDC_RGADW_OFFSET (0xa4)
+#define ICDC_RGDATA_OFFSET (0xa8)
-/*************************************************************************
- * ICDC (Internal CODEC)
- *************************************************************************/
+/*
+ * AIC registers address definition
+ */
+#define AIC_FR (AIC_BASE + AIC_FR_OFFSET)
+#define AIC_CR (AIC_BASE + AIC_CR_OFFSET)
+#define AIC_ACCR1 (AIC_BASE + AIC_ACCR1_OFFSET)
+#define AIC_ACCR2 (AIC_BASE + AIC_ACCR2_OFFSET)
+#define AIC_I2SCR (AIC_BASE + AIC_I2SCR_OFFSET)
+#define AIC_SR (AIC_BASE + AIC_SR_OFFSET)
+#define AIC_ACSR (AIC_BASE + AIC_ACSR_OFFSET)
+#define AIC_I2SSR (AIC_BASE + AIC_I2SSR_OFFSET)
+#define AIC_ACCAR (AIC_BASE + AIC_ACCAR_OFFSET)
+#define AIC_ACCDR (AIC_BASE + AIC_ACCDR_OFFSET)
+#define AIC_ACSAR (AIC_BASE + AIC_ACSAR_OFFSET)
+#define AIC_ACSDR (AIC_BASE + AIC_ACSDR_OFFSET)
+#define AIC_I2SDIV (AIC_BASE + AIC_I2SDIV_OFFSET)
+#define AIC_DR (AIC_BASE + AIC_DR_OFFSET)
+
+#define SPDIF_ENA (AIC_BASE + SPDIF_ENA_OFFSET)
+#define SPDIF_CTRL (AIC_BASE + SPDIF_CTRL_OFFSET)
+#define SPDIF_STATE (AIC_BASE + SPDIF_STATE_OFFSET)
+#define SPDIF_CFG1 (AIC_BASE + SPDIF_CFG1_OFFSET)
+#define SPDIF_CFG2 (AIC_BASE + SPDIF_CFG2_OFFSET)
+#define SPDIF_FIFO (AIC_BASE + SPDIF_FIFO_OFFSET)
+
+#define ICDC_RGADW (AIC_BASE + ICDC_RGADW_OFFSET)
+#define ICDC_RGDATA (AIC_BASE + ICDC_RGDATA_OFFSET)
-#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */
-#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */
-#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */
-#define REG_ICDC_CKCFG REG32(ICDC_CKCFG)
-#define REG_ICDC_RGADW REG32(ICDC_RGADW)
-#define REG_ICDC_RGDATA REG32(ICDC_RGDATA)
+/*
+ * AIC registers common define
+ */
-/* ICDC Clock Configure Register */
-#define ICDC_CKCFG_CKRDY (1 << 1)
-#define ICDC_CKCFG_SELAD (1 << 0)
+/* AIC controller configuration register(AICFR) */
+#define AIC_FR_LSMP BIT6
+#define AIC_FR_ICDC BIT5
+#define AIC_FR_AUSEL BIT4
+#define AIC_FR_RST BIT3
+#define AIC_FR_BCKD BIT2
+#define AIC_FR_SYNCD BIT1
+#define AIC_FR_ENB BIT0
+
+#define AIC_FR_RFTH_LSB 24
+#define AIC_FR_RFTH_MASK BITS_H2L(27, AIC_FR_RFTH_LSB)
+
+#define AIC_FR_TFTH_LSB 16
+#define AIC_FR_TFTH_MASK BITS_H2L(20, AIC_FR_TFTH_LSB)
+
+/* AIC controller common control register(AICCR) */
+#define AIC_CR_PACK16 BIT28
+#define AIC_CR_RDMS BIT15
+#define AIC_CR_TDMS BIT14
+#define AIC_CR_M2S BIT11
+#define AIC_CR_ENDSW BIT10
+#define AIC_CR_AVSTSU BIT9
+#define AIC_CR_TFLUSH BIT8
+#define AIC_CR_RFLUSH BIT7
+#define AIC_CR_EROR BIT6
+#define AIC_CR_ETUR BIT5
+#define AIC_CR_ERFS BIT4
+#define AIC_CR_ETFS BIT3
+#define AIC_CR_ENLBF BIT2
+#define AIC_CR_ERPL BIT1
+#define AIC_CR_EREC BIT0
+
+#define AIC_CR_CHANNEL_LSB 24
+#define AIC_CR_CHANNEL_MASK BITS_H2L(26, AIC_CR_CHANNEL_LSB)
+
+#define AIC_CR_OSS_LSB 19
+#define AIC_CR_OSS_MASK BITS_H2L(21, AIC_CR_OSS_LSB)
+ #define AIC_CR_OSS(n) (((n) > 18 ? (n)/6 : (n)/9) << AIC_CR_OSS_LSB) /* n = 8, 16, 18, 20, 24 */
+
+#define AIC_CR_ISS_LSB 16
+#define AIC_CR_ISS_MASK BITS_H2L(18, AIC_CR_ISS_LSB)
+ #define AIC_CR_ISS(n) (((n) > 18 ? (n)/6 : (n)/9) << AIC_CR_ISS_LSB) /* n = 8, 16, 18, 20, 24 */
+
+/* AIC controller AC-link control register 1(ACCR1) */
+#define AIC_ACCR1_RS_LSB 16
+#define AIC_ACCR1_RS_MASK BITS_H2L(25, AIC_ACCR1_RS_LSB)
+ #define AIC_ACCR1_RS_SLOT(n) ((1 << ((n) - 3)) << AIC_ACCR1_RS_LSB) /* n = 3 .. 12 */
+
+#define AIC_ACCR1_XS_LSB 0
+#define AIC_ACCR1_XS_MASK BITS_H2L(9, AIC_ACCR1_XS_LSB)
+ #define AIC_ACCR1_XS_SLOT(n) ((1 << ((n) - 3)) << AIC_ACCR1_XS_LSB) /* n = 3 .. 12 */
+
+/* AIC controller AC-link control register 2 (ACCR2) */
+#define AIC_ACCR2_ERSTO BIT18
+#define AIC_ACCR2_ESADR BIT17
+#define AIC_ACCR2_ECADT BIT16
+#define AIC_ACCR2_SO BIT3
+#define AIC_ACCR2_SR BIT2
+#define AIC_ACCR2_SS BIT1
+#define AIC_ACCR2_SA BIT0
+
+/* AIC controller i2s/msb-justified control register (I2SCR) */
+#define AIC_I2SCR_RFIRST BIT17
+#define AIC_I2SCR_SWLH BIT16
+#define AIC_I2SCR_STPBK BIT12
+#define AIC_I2SCR_ESCLK BIT4
+#define AIC_I2SCR_AMSL BIT0
+
+/* AIC controller FIFO status register (AICSR) */
+#define AIC_SR_ROR BIT6
+#define AIC_SR_TUR BIT5
+#define AIC_SR_RFS BIT4
+#define AIC_SR_TFS BIT3
+
+#define AIC_SR_RFL_LSB 24
+#define AIC_SR_RFL_MASK BITS_H2L(29, AIC_SR_RFL_LSB)
+
+#define AIC_SR_TFL_LSB 8
+#define AIC_SR_TFL_MASK BITS_H2L(13, AIC_SR_TFL_LSB)
+
+/* AIC controller AC-link status register (ACSR) */
+#define AIC_ACSR_SLTERR BIT21
+#define AIC_ACSR_CRDY BIT20
+#define AIC_ACSR_CLPM BIT19
+#define AIC_ACSR_RSTO BIT18
+#define AIC_ACSR_SADR BIT17
+#define AIC_ACSR_CADT BIT16
+
+/* AIC controller I2S/MSB-justified status register (I2SSR) */
+#define AIC_I2SSR_CHBSY BIT5
+#define AIC_I2SSR_TBSY BIT4
+#define AIC_I2SSR_RBSY BIT3
+#define AIC_I2SSR_BSY BIT2
+
+/* AIC controller AC97 codec command address register (ACCAR) */
+#define AIC_ACCAR_CAR_LSB 0
+#define AIC_ACCAR_CAR_MASK BITS_H2L(19, AIC_ACCAR_CAR_LSB)
+
+
+/* AIC controller AC97 codec command data register (ACCDR) */
+#define AIC_ACCDR_CDR_LSB 0
+#define AIC_ACCDR_CDR_MASK BITS_H2L(19, AIC_ACCDR_CDR_LSB)
+
+/* AC97 read and write macro based on ACCAR and ACCDR */
+#define AC97_READ_CMD BIT19
+#define AC97_WRITE_CMD (BIT19 & ~BIT19)
+
+#define AC97_INDEX_LSB 12
+#define AC97_INDEX_MASK BITS_H2L(18, AC97_INDEX_LSB)
+
+#define AC97_DATA_LSB 4
+#define AC97_DATA_MASK BITS_H2L(19, AC97_DATA_LSB)
+
+/* AIC controller AC97 codec status address register (ACSAR) */
+#define AIC_ACSAR_SAR_LSB 0
+#define AIC_ACSAR_SAR_MASK BITS_H2L(19, AIC_ACSAR_SAR_LSB)
+
+/* AIC controller AC97 codec status data register (ACSDR) */
+#define AIC_ACSDR_SDR_LSB 0
+#define AIC_ACSDR_SDR_MASK BITS_H2L(19, AIC_ACSDR_SDR_LSB)
+
+/* AIC controller I2S/MSB-justified clock divider register (I2SDIV) */
+#define AIC_I2SDIV_DIV_LSB 0
+#define AIC_I2SDIV_DIV_MASK BITS_H2L(3, AIC_I2SDIV_DIV_LSB)
+
+/* SPDIF enable register (SPDIF_ENA) */
+#define SPDIF_ENA_SPEN BIT0
-/* ICDC internal register access control Register */
-#define ICDC_RGADW_RGWR (1 << 16)
-#define ICDC_RGADW_RGADDR_BIT 8
-#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT)
-#define ICDC_RGADW_RGDIN_BIT 0
-#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT)
+/* SPDIF control register (SPDIF_CTRL) */
+#define SPDIF_CTRL_DMAEN BIT15
+#define SPDIF_CTRL_DTYPE BIT14
+#define SPDIF_CTRL_SIGN BIT13
+#define SPDIF_CTRL_INVALID BIT12
+#define SPDIF_CTRL_RST BIT11
+#define SPDIF_CTRL_SPDIFI2S BIT10
+#define SPDIF_CTRL_MTRIG BIT1
+#define SPDIF_CTRL_MFFUR BIT0
-/* ICDC internal register data output Register */
-#define ICDC_RGDATA_IRQ (1 << 8)
-#define ICDC_RGDATA_RGDOUT_BIT 0
-#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT)
+/* SPDIF state register (SPDIF_STAT) */
+#define SPDIF_STAT_BUSY BIT7
+#define SPDIF_STAT_FTRIG BIT1
+#define SPDIF_STAT_FUR BIT0
-/*************************************************************************
- * SPDIF INTERFACE in AIC Controller
- *************************************************************************/
+#define SPDIF_STAT_FLVL_LSB 8
+#define SPDIF_STAT_FLVL_MASK BITS_H2L(14, SPDIF_STAT_FLVL_LSB)
-#define SPDIF_ENA (AIC_BASE + 0x080)
-#define SPDIF_CTRL (AIC_BASE + 0x084)
-#define SPDIF_STATE (AIC_BASE + 0x088)
-#define SPDIF_CFG1 (AIC_BASE + 0x08c)
-#define SPDIF_CFG2 (AIC_BASE + 0x090)
-#define SPDIF_FIFO (AIC_BASE + 0x094)
+/* SPDIF configure 1 register (SPDIF_CFG1) */
+#define SPDIF_CFG1_INITLVL BIT17
+#define SPDIF_CFG1_ZROVLD BIT16
-#define REG_SPDIF_ENA REG32(SPDIF_ENA)
-#define REG_SPDIF_CTRL REG32(SPDIF_CTRL)
-#define REG_SPDIF_STATE REG32(SPDIF_STATE)
-#define REG_SPDIF_CFG1 REG32(SPDIF_CFG1)
-#define REG_SPDIF_CFG2 REG32(SPDIF_CFG2)
-#define REG_SPDIF_FIFO REG32(SPDIF_FIFO)
+#define SPDIF_CFG1_TRIG_LSB 12
+#define SPDIF_CFG1_TRIG_MASK BITS_H2L(13, SPDIF_CFG1_TRIG_LSB)
+#define SPDIF_CFG1_TRIG(n) (((n) > 16 ? 3 : (n)/8) << SPDIF_CFG1_TRIG_LSB) /* n = 4, 8, 16, 32 */
-/* SPDIF Enable Register (SPDIF_ENA) */
+#define SPDIF_CFG1_SRCNUM_LSB 8
+#define SPDIF_CFG1_SRCNUM_MASK BITS_H2L(11, SPDIF_CFG1_SRCNUM_LSB)
-#define SPDIF_ENA_SPEN (1 << 0) /* Enable or disable the SPDIF transmitter */
+#define SPDIF_CFG1_CH1NUM_LSB 4
+#define SPDIF_CFG1_CH1NUM_MASK BITS_H2L(7, SPDIF_CFG1_CH1NUM_LSB)
-/* SPDIF Control Register (SPDIF_CTRL) */
+#define SPDIF_CFG1_CH2NUM_LSB 0
+#define SPDIF_CFG1_CH2NUM_MASK BITS_H2L(3, SPDIF_CFG1_CH2NUM_LSB)
-#define SPDIF_CTRL_DMAEN (1 << 15)
-#define SPDIF_CTRL_DTYPE (1 << 14)
-#define SPDIF_CTRL_SIGN (1 << 13)
-#define SPDIF_CTRL_INVALID (1 << 12)
-#define SPDIF_CTRL_RST (1 << 11)
-#define SPDIF_CTRL_SPDIFI2S (1 << 10)
-#define SPDIF_CTRL_MTRIG (1 << 1)
-#define SPDIF_CTRL_MFFUR (1 << 0)
+/* SPDIF configure 2 register (SPDIF_CFG2) */
+#define SPDIF_CFG2_MAXWL BIT18
+#define SPDIF_CFG2_PRE BIT3
+#define SPDIF_CFG2_COPYN BIT2
+#define SPDIF_CFG2_AUDION BIT1
+#define SPDIF_CFG2_CONPRO BIT0
-/* SPDIF Configure 1 Register (SPDIF_CFG1) */
+#define SPDIF_CFG2_FS_LSB 26
+#define SPDIF_CFG2_FS_MASK BITS_H2L(29, SPDIF_CFG2_FS_LSB)
-#define SPDIF_CFG1_INITLVL (1 << 17)
-#define SPDIF_CFG1_ZROVLD (1 << 16)
+#define SPDIF_CFG2_ORGFRQ_LSB 22
+#define SPDIF_CFG2_ORGFRQ_MASK BITS_H2L(25, SPDIF_CFG2_ORGFRQ_LSB)
-#define SPDIF_CFG1_TRIG_BIT 12
-#define SPDIF_CFG1_TRIG_MASK (0x3 << SPDIF_CFG1_TRIG_BIT)
- #define SPDIF_CFG1_TRIG_4 (0x0 << SPDIF_CFG1_TRIG_BIT)
- #define SPDIF_CFG1_TRIG_8 (0x1 << SPDIF_CFG1_TRIG_BIT)
- #define SPDIF_CFG1_TRIG_16 (0x2 << SPDIF_CFG1_TRIG_BIT)
- #define SPDIF_CFG1_TRIG_32 (0x3 << SPDIF_CFG1_TRIG_BIT)
+#define SPDIF_CFG2_SAMWL_LSB 19
+#define SPDIF_CFG2_SAMWL_MASK BITS_H2L(21, SPDIF_CFG2_SAMWL_LSB)
-#define SPDIF_CFG1_SRCNUM_BIT 8
-#define SPDIF_CFG1_SRCNUM_MASK (0xf << SPDIF_CFG1_SRCNUM_BIT)
+#define SPDIF_CFG2_CLKACU_LSB 16
+#define SPDIF_CFG2_CLKACU_MASK BITS_H2L(17, SPDIF_CFG2_CLKACU_LSB)
-#define SPDIF_CFG1_CH1NUM_BIT 4
-#define SPDIF_CFG1_CH1NUM_MASK (0xf << SPDIF_CFG1_CH1NUM_BIT)
+#define SPDIF_CFG2_CATCODE_LSB 8
+#define SPDIF_CFG2_CATCODE_MASK BITS_H2L(15, SPDIF_CFG2_CATCODE_LSB)
-#define SPDIF_CFG1_CH2NUM_BIT 0
-#define SPDIF_CFG1_CH2NUM_MASK (0xf << SPDIF_CFG1_CH2NUM_BIT)
+#define SPDIF_CFG2_CHMD_LSB 6
+#define SPDIF_CFG2_CHMD_MASK BITS_H2L(7, SPDIF_CFG2_CHMD_LSB)
-/* SPDIF Configure 2 Register (SPDIF_CFG2) */
+/* ICDC internal register access control register(RGADW) */
+#define ICDC_RGADW_RGWR BIT16
-#define SPDIF_CFG2_FS_BIT 26
-#define SPDIF_CFG2_FS_MASK (0xf << SPDIF_CFG2_FS_BIT)
- #define SPDIF_CFG2_FS_44K (0x0 << SPDIF_CFG2_FS_BIT) /* 44.1kHz */
- #define SPDIF_CFG2_FS_48K (0x2 << SPDIF_CFG2_FS_BIT)
- #define SPDIF_CFG2_FS_32K (0x3 << SPDIF_CFG2_FS_BIT)
- #define SPDIF_CFG2_FS_96K (0xa << SPDIF_CFG2_FS_BIT)
- #define SPDIF_CFG2_FS_192K (0xe << SPDIF_CFG2_FS_BIT)
+#define ICDC_RGADW_RGADDR_LSB 8
+#define ICDC_RGADW_RGADDR_MASK BITS_H2L(14, ICDC_RGADW_RGADDR_LSB)
-#define SPDIF_CFG2_ORGFRQ_BIT 22
-#define SPDIF_CFG2_ORGFRQ_MASK (0xf << SPDIF_CFG2_ORGFRQ_BIT)
- #define SPDIF_CFG2_ORGFRQ_44K (0xf << SPDIF_CFG2_ORGFRQ_BIT) /* 44.1kHz */
- #define SPDIF_CFG2_ORGFRQ_48K (0xd << SPDIF_CFG2_ORGFRQ_BIT)
- #define SPDIF_CFG2_ORGFRQ_32K (0xc << SPDIF_CFG2_ORGFRQ_BIT)
- #define SPDIF_CFG2_ORGFRQ_96K (0x5 << SPDIF_CFG2_ORGFRQ_BIT)
- #define SPDIF_CFG2_ORGFRQ_192K (0x1 << SPDIF_CFG2_ORGFRQ_BIT)
+#define ICDC_RGADW_RGDIN_LSB 0
+#define ICDC_RGADW_RGDIN_MASK BITS_H2L(7, ICDC_RGADW_RGDIN_LSB)
-#define SPDIF_CFG2_SAMWL_BIT 19
-#define SPDIF_CFG2_SAMWL_MASK (0x7 << SPDIF_CFG2_SAMWL_BIT)
+/* ICDC internal register data output register (RGDATA)*/
+#define ICDC_RGDATA_IRQ BIT8
-#define SPDIF_CFG2_MAXWL (1 << 18)
+#define ICDC_RGDATA_RGDOUT_LSB 0
+#define ICDC_RGDATA_RGDOUT_MASK BITS_H2L(7, ICDC_RGDATA_RGDOUT_LSB)
-#define SPDIF_CFG2_CLKACU_BIT 16
-#define SPDIF_CFG2_CLKACU_MASK (0x3 << SPDIF_CFG2_CLKACU_BIT)
- #define SPDIF_CFG2_CLKACU_LVL2 (0x0 << SPDIF_CFG2_CLKACU_BIT)
- #define SPDIF_CFG2_CLKACU_LVL1 (0x1 << SPDIF_CFG2_CLKACU_BIT)
- #define SPDIF_CFG2_CLKACU_LVL3 (0x2 << SPDIF_CFG2_CLKACU_BIT)
- #define SPDIF_CFG2_CLKACU_NOTMAT (0x3 << SPDIF_CFG2_CLKACU_BIT)
-#define SPDIF_CFG2_CATCODE_BIT 8
-#define SPDIF_CFG2_CATCODE_MASK (0xff << SPDIF_CFG2_CATCODE_BIT)
+#ifndef __MIPS_ASSEMBLER
-#define SPDIF_CFG2_CHMD_BIT 6
-#define SPDIF_CFG2_CHMD_MASK (0x3 << SPDIF_CFG2_CHMD_BIT)
- #define SPDIF_CFG2_CHMD_MOD0 (0x0 << SPDIF_CFG2_CHMD_BIT)
-#define SPDIF_CFG2_PRE (1 << 3)
-#define SPDIF_CFG2_COPYN (1 << 2)
-#define SPDIF_CFG2_AUDION (1 << 1)
-#define SPDIF_CFG2_CONPRO (1 << 0)
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+#define REG_SPDIF_ENA REG32(SPDIF_ENA)
+#define REG_SPDIF_CTRL REG32(SPDIF_CTRL)
+#define REG_SPDIF_STATE REG32(SPDIF_STATE)
+#define REG_SPDIF_CFG1 REG32(SPDIF_CFG1)
+#define REG_SPDIF_CFG2 REG32(SPDIF_CFG2)
+#define REG_SPDIF_FIFO REG32(SPDIF_FIFO)
-#ifndef __MIPS_ASSEMBLER
+#define REG_ICDC_RGADW REG32(ICDC_RGADW)
+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA)
-/***************************************************************************
- * AIC (AC'97 & I2S Controller)
- ***************************************************************************/
#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
@@ -378,25 +333,25 @@ do { \
#define __aic_set_transmit_trigger(n) \
do { \
REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
- REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_LSB); \
} while(0)
#define __aic_set_receive_trigger(n) \
do { \
REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
- REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_LSB); \
} while(0)
-#define __aic_enable_oldstyle() ( REG_AIC_CR |= AIC_CR_EN2OLD )
-#define __aic_enable_newstyle() ( REG_AIC_CR &= ~AIC_CR_EN2OLD )
+#define __aic_enable_oldstyle()
+#define __aic_enable_newstyle()
#define __aic_enable_pack16() ( REG_AIC_CR |= AIC_CR_PACK16 )
-#define __aic_enable_unpack16() ( REG_AIC_CR &= ~AIC_CR_PACK16)
+#define __aic_enable_unpack16() ( REG_AIC_CR &= ~AIC_CR_PACK16)
/* n = AIC_CR_CHANNEL_MONO,AIC_CR_CHANNEL_STEREO ... */
#define __aic_out_channel_select(n) \
do { \
REG_AIC_CR &= ~AIC_CR_CHANNEL_MASK; \
- REG_AIC_CR |= ((n) << AIC_CR_CHANNEL_BIT ); \
+ REG_AIC_CR |= ((n) << AIC_CR_CHANNEL_LSB ); \
} while(0)
#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
@@ -432,19 +387,19 @@ do { \
#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU )
#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU )
-#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
-#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
-#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
-#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
-#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
-#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT(3)
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT(4)
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT(6)
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT(7)
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT(8)
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT(9)
-#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
-#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
-#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
-#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
-#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
-#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT(3)
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT(4)
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT(6)
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT(7)
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT(8)
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT(9)
#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
#define __ac97_set_xs_mono() \
@@ -458,7 +413,7 @@ do { \
REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
} while(0)
-/* In fact, only stereo is support now. */
+/* In fact, only stereo is support now. */
#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
#define __ac97_set_rs_mono() \
do { \
@@ -511,9 +466,9 @@ do { \
#define __i2s_out_channel_select(n) __aic_out_channel_select(n)
#define __i2s_set_oss_sample_size(n) \
- ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT )
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS(n))
#define __i2s_set_iss_sample_size(n) \
- ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT )
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS(n))
#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
@@ -526,9 +481,9 @@ do { \
#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
#define __aic_get_transmit_resident() \
- ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_LSB )
#define __aic_get_receive_count() \
- ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_LSB )
#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
@@ -540,33 +495,26 @@ do { \
#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
-#define CODEC_READ_CMD (1 << 19)
-#define CODEC_WRITE_CMD (0 << 19)
-#define CODEC_REG_INDEX_BIT 12
-#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
-#define CODEC_REG_DATA_BIT 4
-#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
-
#define __ac97_out_rcmd_addr(reg) \
do { \
- REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+ REG_AIC_ACCAR = AC97_READ_CMD | ((reg) << AC97_INDEX_LSB); \
} while (0)
#define __ac97_out_wcmd_addr(reg) \
do { \
- REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+ REG_AIC_ACCAR = AC97_WRITE_CMD | ((reg) << AC97_INDEX_LSB); \
} while (0)
#define __ac97_out_data(value) \
do { \
- REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+ REG_AIC_ACCDR = ((value) << AC97_DATA_LSB); \
} while (0)
#define __ac97_in_data() \
- ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> AC97_DATA_LSB )
#define __ac97_in_status_addr() \
- ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+ ( (REG_AIC_ACSAR & AC97_INDEX_MASK) >> AC97_INDEX_LSB )
#define __i2s_set_sample_rate(i2sclk, sync) \
( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
@@ -574,7 +522,7 @@ do { \
#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
#define __aic_read_rfifo() ( REG_AIC_DR )
-#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC )
//
@@ -700,49 +648,49 @@ do { \
#define __spdif_set_transmit_trigger(n) \
do { \
REG_SPDIF_CFG1 &= ~SPDIF_CFG1_TRIG_MASK; \
- REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_TRIG_BIT ); \
+ REG_SPDIF_CFG1 |= SPDIF_CFG1_TRIG(n); \
} while(0)
/* 1 ~ 15 */
#define __spdif_set_srcnum(n) \
do { \
REG_SPDIF_CFG1 &= ~SPDIF_CFG1_SRCNUM_MASK; \
- REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_SRCNUM_BIT); \
+ REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_SRCNUM_LSB); \
} while(0)
/* 1 ~ 15 */
#define __spdif_set_ch1num(n) \
do { \
REG_SPDIF_CFG1 &= ~SPDIF_CFG1_CH1NUM_MASK; \
- REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_CH1NUM_BIT); \
+ REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_CH1NUM_LSB); \
} while(0)
/* 1 ~ 15 */
#define __spdif_set_ch2num(n) \
do { \
REG_SPDIF_CFG1 &= ~SPDIF_CFG1_CH2NUM_MASK; \
- REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_CH2NUM_BIT); \
+ REG_SPDIF_CFG1 |= ((n) << SPDIF_CFG1_CH2NUM_LSB); \
} while(0)
/* 0x0, 0x2, 0x3, 0xa, 0xe */
#define __spdif_set_fs(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_FS_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_FS_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_FS_LSB); \
} while(0)
/* 0xd, 0xc, 0x5, 0x1 */
#define __spdif_set_orgfrq(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_ORGFRQ_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_ORGFRQ_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_ORGFRQ_LSB); \
} while(0)
/* 0x1, 0x6, 0x2, 0x4, 0x5 */
#define __spdif_set_samwl(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_SAMWL_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_SAMWL_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_SAMWL_LSB); \
} while(0)
#define __spdif_enable_samwl_24() ( REG_SPDIF_CFG2 |= SPDIF_CFG2_MAXWL )
@@ -752,21 +700,21 @@ do { \
#define __spdif_set_clkacu(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_CLKACU_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CLKACU_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CLKACU_LSB); \
} while(0)
/* see IEC60958-3 */
#define __spdif_set_catcode(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_CATCODE_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CATCODE_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CATCODE_LSB); \
} while(0)
/* n = 0x0, */
#define __spdif_set_chmode(n) \
do { \
REG_SPDIF_CFG2 &= ~SPDIF_CFG2_CHMD_MASK; \
- REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CHMD_BIT); \
+ REG_SPDIF_CFG2 |= ((n) << SPDIF_CFG2_CHMD_LSB); \
} while(0)
#define __spdif_enable_pre() ( REG_SPDIF_CFG2 |= SPDIF_CFG2_PRE )
@@ -797,13 +745,13 @@ do { \
#define __icdc_set_addr(n) \
do { \
REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \
- REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_LSB; \
} while(0)
#define __icdc_set_cmd(n) \
do { \
REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \
- REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_LSB; \
} while(0)
#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ )
@@ -813,5 +761,4 @@ do { \
#endif /* __MIPS_ASSEMBLER */
-#endif /* __JZ4760AIC_H__ */
-
+#endif /* __CHIP_AIC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760bch.h b/arch/mips/include/asm/mach-jz4760/jz4760bch.h
index 3657069b0be..d188ae4ccdf 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760bch.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760bch.h
@@ -43,9 +43,9 @@
#define BCH_ERR10 (BCH_BASE + 0x64) /* BCH Error Report 10 register */
#define BCH_ERR11 (BCH_BASE + 0x68) /* BCH Error Report 11 register */
#define BCH_INTS (BCH_BASE + 0x6C) /* BCH Interrupt Status register */
-#define BCH_INTES (BCH_BASE + 0x70) /* BCH Interrupt Enable register */
-#define BCH_INTEC (BCH_BASE + 0x74) /* BCH Interrupt Set register */
-#define BCH_INTE (BCH_BASE + 0x78) /* BCH Interrupt Clear register */
+#define BCH_INTE (BCH_BASE + 0x70) /* BCH Interrupt Enable register */
+#define BCH_INTES (BCH_BASE + 0x74) /* BCH Interrupt Set register */
+#define BCH_INTEC (BCH_BASE + 0x78) /* BCH Interrupt Clear register */
#define REG_BCH_CR REG32(BCH_CR)
#define REG_BCH_CRS REG32(BCH_CRS)
@@ -115,72 +115,84 @@
#define BCH_ERR_INDEX_ODD_MASK (0x1fff << BCH_ERR_INDEX_ODD_BIT)
#define BCH_ERR_INDEX_EVEN_BIT 16
#define BCH_ERR_INDEX_EVEN_MASK (0x1fff << BCH_ERR_INDEX_EVEN_BIT)
-#define BCH_ERR_INDEX_MASK 0x1fff
+#define BCH_ERR_INDEX_MASK 0x1fff
#ifndef __MIPS_ASSEMBLER
/*************************************************************************
* BCH
*************************************************************************/
-#define __ecc_encoding_4bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_4 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_4 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_4 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_4 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_4bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_4 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_4 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_4 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_4 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_encoding_8bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_8 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_8 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_8 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_8 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_8bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_8 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_8 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_8 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_8 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_encoding_12bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_12 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_12 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_12bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_12 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_12 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_12bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_12 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_12 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_12bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_12 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_12 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_encoding_16bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_16 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_16 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_16bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_16 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_16 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_16bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_16 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_16 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_16bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_16 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_16 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_encoding_20bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_20 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_20 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_20bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_20 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_20 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_20bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_20 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_20 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_20bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_20 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_20 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_encoding_24bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_24 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_24 | BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_encoding_24bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_24 | BCH_CR_ENCE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_24 | BCH_CR_ENCE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
-#define __ecc_decoding_24bit() \
-do { \
- REG_BCH_CRS = BCH_CR_BSEL_24 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE; \
- REG_BCH_CRC = ~(BCH_CR_BSEL_24 | BCH_CR_DECE | BCH_CR_BRST | BCH_CR_BCHE); \
+#define __ecc_decoding_24bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BSEL_24 | BCH_CR_DECE | BCH_CR_BCHE; \
+ REG_BCH_CRC = ~(BCH_CR_BSEL_24 | BCH_CR_DECE | BCH_CR_BCHE); \
+ REG_BCH_CRS = BCH_CR_BRST; \
} while(0)
#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE )
#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE )
@@ -190,17 +202,14 @@ do { \
#define __ecc_cnt_dec(n) \
do { \
- REG_BCH_CNT &= ~BCH_CNT_DEC_MASK; \
- REG_BCH_CNT |= (n) << BCH_CNT_DEC_BIT; \
+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \
} while(0)
+
#define __ecc_cnt_enc(n) \
do { \
- REG_BCH_CNT &= ~BCH_CNT_ENC_MASK; \
- REG_BCH_CNT |= (n) << BCH_CNT_ENC_BIT; \
+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \
} while(0)
-
-
#endif /* __MIPS_ASSEMBLER */
#endif /* __JZ4760BCH_H__ */
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760cim.h b/arch/mips/include/asm/mach-jz4760/jz4760cim.h
index 14c56f1471a..38b49d48098 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760cim.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760cim.h
@@ -26,10 +26,18 @@
#define CIM_CMD (CIM_BASE + 0x002C)
#define CIM_SIZE (CIM_BASE + 0x0030)
#define CIM_OFFSET (CIM_BASE + 0x0034)
+#define CIM_YFA (CIM_BASE + 0x0038)
+#define CIM_YCMD (CIM_BASE + 0x003C)
+#define CIM_CBFA (CIM_BASE + 0x0040)
+#define CIM_CBCMD (CIM_BASE + 0x0044)
+#define CIM_CRFA (CIM_BASE + 0x0048)
+#define CIM_CRCMD (CIM_BASE + 0x004C)
+#define CIM_CTRL2 (CIM_BASE + 0x0050)
#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
#define REG_CIM_CFG REG32(CIM_CFG)
#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_CTRL2 REG32(CIM_CTRL2)
#define REG_CIM_STATE REG32(CIM_STATE)
#define REG_CIM_IID REG32(CIM_IID)
#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
@@ -39,7 +47,16 @@
#define REG_CIM_CMD REG32(CIM_CMD)
#define REG_CIM_SIZE REG32(CIM_SIZE)
#define REG_CIM_OFFSET REG32(CIM_OFFSET)
-
+#define REG_CIM_YFA REG32(CIM_YFA)
+#define REG_CIM_YCMD REG32(CIM_YCMD)
+#define REG_CIM_CBFA REG32(CIM_CBFA)
+#define REG_CIM_CBCMD REG32(CIM_CBCMD)
+#define REG_CIM_CRFA REG32(CIM_CRFA)
+#define REG_CIM_CRCMD REG32(CIM_CRCMD)
+
+#define CIM_CFG_RXF_TRIG_BIT 24
+#define CIM_CFG_RXF_TRIG_MASK (0x3f << CIM_CFG_RT_TRIG_MASK)
+#define CIM_CFG_SEP (1 << 20)
#define CIM_CFG_ORDER_BIT 18
#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT)
#define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* Y0CbY1Cr; YCbCr */
@@ -60,6 +77,7 @@
#define CIM_CFG_DMA_BURST_INCR4 (0 << CIM_CFG_DMA_BURST_TYPE_BIT)
#define CIM_CFG_DMA_BURST_INCR8 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested */
#define CIM_CFG_DMA_BURST_INCR16 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/
+ #define CIM_CFG_DMA_BURST_INCR32 (3 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/
#define CIM_CFG_DUMMY_ZERO (1 << 9)
#define CIM_CFG_EXT_VSYNC (1 << 8) /* Only for ITU656 Progressive mode */
#define CIM_CFG_PACK_BIT 4
@@ -103,7 +121,7 @@
#define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
#define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
-#define CIM_CTRL_DMA_EEOF (1 << 15) /* Enable EEOF interrupt */
+#define CIM_CTRL_DMA_EEOFM (1 << 15) /* Enable EEOF interrupt */
#define CIM_CTRL_WIN_EN (1 << 14)
#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */
#define CIM_CTRL_DMA_SOFM (1 << 12)
@@ -119,7 +137,27 @@
#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */
#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */
+
+/* cim control2 */
+#define CIM_CTRL2_OPG_BIT 4
+#define CIM_CTRL2_OPG_MASK (0x3 << CIM_CTRL2_OPG_BIT)
+#define CIM_CTRL2_OPE (1 << 2)
+#define CIM_CTRL2_EME (1 << 1)
+#define CIM_CTRL2_APM (1 << 0)
+
/* CIM State Register (CIM_STATE) */
+#define CIM_STATE_CR_RF_OF (1 << 27)
+#define CIM_STATE_CR_RF_TRIG (1 << 26)
+#define CIM_STATE_CR_RF_EMPTY (1 << 25)
+
+#define CIM_STATE_CB_RF_OF (1 << 19)
+#define CIM_STATE_CB_RF_TRIG (1 << 18)
+#define CIM_STATE_CB_RF_EMPTY (1 << 17)
+
+#define CIM_STATE_Y_RF_OF (1 << 11)
+#define CIM_STATE_Y_RF_TRIG (1 << 10)
+#define CIM_STATE_Y_RF_EMPTY (1 << 9)
+
#define CIM_STATE_DMA_EEOF (1 << 7) /* DMA Line EEOf irq */
#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */
#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */
@@ -151,7 +189,6 @@
#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */
#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/
-
#ifndef __MIPS_ASSEMBLER
/***************************************************************************
@@ -161,6 +198,9 @@
#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+#define __cim_enable_sep() (REG_CIM_CFG |= CIM_CFG_SEP)
+#define __cim_disable_sep() (REG_CIM_CFG &= ~CIM_CFG_SEP)
+
/* n = 0, 1, 2, 3 */
#define __cim_set_input_data_stream_order(n) \
do { \
@@ -302,11 +342,19 @@ do { \
( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
/* n=4,8,12,16,20,24,28,32 */
-#define __cim_set_rxfifo_trigger(n) \
-do { \
- REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
- REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
-} while (0)
+#define __cim_set_rxfifo_trigger(n) \
+ do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+ } while (0)
+
+
+#define __cim_set_eeof_line(n) \
+ do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_EEOF_LINE_MASK; \
+ REG_CIM_CTRL |= ( ((n) << CIM_CTRL_EEOF_LINE_BIT) & CIM_CTRL_EEOF_LINE_MASK ); \
+ } while (0)
+
#define __cim_enable_fast_mode() ( REG_CIM_CTRL |= CIM_CTRL_FAST_MODE )
#define __cim_disable_fast_mode() ( REG_CIM_CTRL &= ~CIM_CTRL_FAST_MODE )
#define __cim_use_normal_mode() __cim_disable_fast_mode()
@@ -315,6 +363,25 @@ do { \
#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+/* cim control2 */
+#define __cim_enable_priority_control() ( REG_CIM_CTRL2 |= CIM_CTRL2_APM)
+#define __cim_disable_priority_control() ( REG_CIM_CTRL2 &= ~CIM_CTRL2_APM)
+#define __cim_enable_auto_priority() ( REG_CIM_CTRL2 |= CIM_CTRL2_OPE)
+#define __cim_disable_auto_priority() ( REG_CIM_CTRL2 &= ~CIM_CTRL2_OPE)
+#define __cim_enable_emergency() ( REG_CIM_CTRL2 |= CIM_CTRL2_EME)
+#define __cim_disable_emergency() ( REG_CIM_CTRL2 &= ~CIM_CTRL2_EME);
+/* 0, 1, 2, 3
+ * 0: highest priority
+ * 3: lowest priority
+ * 1 maybe best for SEP=1
+ * 3 maybe best for SEP=0
+ */
+#define __cim_set_opg(n) \
+ do { \
+ REG_CIM_CTRL2 &= ~CIM_CTRL2_OPG_MASK; \
+ REG_CIM_CTRL2 |= ((n) << CIM_CTRL2_OPG_BIT) & CIM_CTRL2_OPG_MASK; \
+ } while (0)
+
#define __cim_clear_state() ( REG_CIM_STATE = 0 )
#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760dmac.h b/arch/mips/include/asm/mach-jz4760/jz4760dmac.h
index 7fd23dc644d..9ae143867c3 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760dmac.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760dmac.h
@@ -31,7 +31,7 @@
#define DMAC_DCCSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x10 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA control/status */
#define DMAC_DCMD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x14 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA command */
#define DMAC_DDA(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x18 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA descriptor address */
-#define DMAC_DSD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0xc0 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x04)) /* DMA Stride Address */
+#define DMAC_DSD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x1c + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x04)) /* DMA Stride Address */
#define DMAC_DMACR(m) (DMAC_BASE + 0x0300 + 0x100 * (m)) /* DMA control register */
#define DMAC_DMAIPR(m) (DMAC_BASE + 0x0304 + 0x100 * (m)) /* DMA interrupt pending */
@@ -56,102 +56,105 @@
// DMA request source register
#define DMAC_DRSR_RS_BIT 0
#define DMAC_DRSR_RS_MASK (0x3f << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_EXT (0 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_NAND (1 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_BCH_ENC (2 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_BCH_DEC (3 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_TSSIIN (9 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_SSI0OUT (22 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_SSI0IN (23 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_MSC0OUT (26 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_MSC0IN (27 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_MSC1OUT (30 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_MSC1IN (31 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_SSI1OUT (32 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_SSI1IN (33 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_PMOUT (34 << DMAC_DRSR_RS_BIT)
- #define DMAC_DRSR_RS_PMIN (35 << DMAC_DRSR_RS_BIT)
+/* 0~7 is reserved */
+#define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_TSSIIN (9 << DMAC_DRSR_RS_BIT)
+/* 10 ~ 11 is reserved */
+#define DMAC_DRSR_RS_EXTERN (12 << DMAC_DRSR_RS_BIT)
+/* 13 is reserved */
+#define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_SSI0OUT (22 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_SSI0IN (23 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC0OUT (26 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC0IN (27 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC1OUT (30 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC1IN (31 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_SSI1OUT (32 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_SSI1IN (33 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_PMOUT (34 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_PMIN (35 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC2OUT (36 << DMAC_DRSR_RS_BIT)
+#define DMAC_DRSR_RS_MSC2IN (37 << DMAC_DRSR_RS_BIT)
+/* others are reserved */
// DMA channel control/status register
#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */
#define DMAC_DCCSR_DES8 (1 << 30) /* Descriptor 8 Word */
#define DMAC_DCCSR_DES4 (0 << 30) /* Descriptor 4 Word */
+/* [29:24] reserved */
#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */
#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT)
-#define DMAC_DCCSR_BERR (1 << 7) /* BCH error within this transfer, Only for channel 0 */
-#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */
+/* [15:5] reserved */
#define DMAC_DCCSR_AR (1 << 4) /* address error */
#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */
#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */
#define DMAC_DCCSR_CT (1 << 1) /* count terminated */
#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */
-// DMA channel command register
+// DMA channel command register
#define DMAC_DCMD_EACKS_LOW (1 << 31) /* External DACK Output Level Select, active low */
#define DMAC_DCMD_EACKS_HIGH (0 << 31) /* External DACK Output Level Select, active high */
#define DMAC_DCMD_EACKM_WRITE (1 << 30) /* External DACK Output Mode Select, output in write cycle */
#define DMAC_DCMD_EACKM_READ (0 << 30) /* External DACK Output Mode Select, output in read cycle */
#define DMAC_DCMD_ERDM_BIT 28 /* External DREQ Detection Mode Select */
#define DMAC_DCMD_ERDM_MASK (0x03 << DMAC_DCMD_ERDM_BIT)
- #define DMAC_DCMD_ERDM_LOW (0 << DMAC_DCMD_ERDM_BIT)
- #define DMAC_DCMD_ERDM_FALL (1 << DMAC_DCMD_ERDM_BIT)
- #define DMAC_DCMD_ERDM_HIGH (2 << DMAC_DCMD_ERDM_BIT)
- #define DMAC_DCMD_ERDM_RISE (3 << DMAC_DCMD_ERDM_BIT)
-#define DMAC_DCMD_BLAST (1 << 25) /* BCH last */
+#define DMAC_DCMD_ERDM_LOW (0 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_ERDM_FALL (1 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_ERDM_HIGH (2 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_ERDM_RISE (3 << DMAC_DCMD_ERDM_BIT)
+/* [27:24] reserved */
#define DMAC_DCMD_SAI (1 << 23) /* source address increment */
#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */
#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */
#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
- #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
#define DMAC_DCMD_SWDH_BIT 14 /* source port width */
#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
- #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
- #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
- #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */
#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
- #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
- #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
- #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+/* bit11 reserved */
#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */
#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT)
- #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
- #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
- #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
- #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
- #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
-#define DMAC_DCMD_STDE (1 << 5) /* Stride Disable/Enable */
-#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */
-#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */
-#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */
+#define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_DS_64BYTE (5 << DMAC_DCMD_DS_BIT)
+/* [7:3] reserved */
+#define DMAC_DCMD_STDE (1 << 2) /* Stride Disable/Enable */
#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */
#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */
@@ -160,6 +163,7 @@
#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT)
#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */
#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT)
+/* [3:0] reserved */
// DMA stride address register
#define DMAC_DSD_TSD_BIT 16 /* target stride address */
@@ -173,14 +177,17 @@
#define DMAC_DMACR_FTSSI (1 << 29) /* TSSI Fast DMA mode */
#define DMAC_DMACR_FUART (1 << 28) /* UART Fast DMA mode */
#define DMAC_DMACR_FAIC (1 << 27) /* AIC Fast DMA mode */
+/* [26:10] reserved */
#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */
#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
- #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
- #define DMAC_DMACR_PR_120345 (1 << DMAC_DMACR_PR_BIT)
- #define DMAC_DMACR_PR_230145 (2 << DMAC_DMACR_PR_BIT)
- #define DMAC_DMACR_PR_340125 (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_PR_120345 (1 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_PR_230145 (2 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_PR_340125 (3 << DMAC_DMACR_PR_BIT)
+/* [7:4] resered */
#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */
#define DMAC_DMACR_AR (1 << 2) /* address error flag */
+/* bit1 reserved */
#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */
// DMA doorbell register
@@ -217,55 +224,55 @@
/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
-#define __dmac_enable_module(m) \
+#define __dmac_enable_module(m) \
( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 )
-#define __dmac_disable_module(m) \
+#define __dmac_disable_module(m) \
( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE )
/* p=0,1,2,3 */
-#define __dmac_set_priority(m,p) \
-do { \
- REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \
- REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \
-} while (0)
+#define __dmac_set_priority(m,p) \
+ do { \
+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \
+ } while (0)
#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT )
#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR )
-#define __dmac_channel_enable_clk(n) \
+#define __dmac_channel_enable_clk(n) \
REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM);
-#define __dmac_enable_descriptor(n) \
- ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
-#define __dmac_disable_descriptor(n) \
- ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
-
-#define __dmac_enable_channel(n) \
-do { \
- REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \
-} while (0)
-#define __dmac_disable_channel(n) \
-do { \
- REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \
-} while (0)
-#define __dmac_channel_enabled(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
-
-#define __dmac_channel_enable_irq(n) \
- ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
-#define __dmac_channel_disable_irq(n) \
- ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
-
-#define __dmac_channel_transmit_halt_detected(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
-#define __dmac_channel_transmit_end_detected(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
-#define __dmac_channel_address_error_detected(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
-#define __dmac_channel_count_terminated_detected(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
-#define __dmac_channel_descriptor_invalid_detected(n) \
- ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
+#define __dmac_enable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
+#define __dmac_disable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
+
+#define __dmac_enable_channel(n) \
+ do { \
+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \
+ } while (0)
+#define __dmac_disable_channel(n) \
+ do { \
+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \
+ } while (0)
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
+#define __dmac_channel_count_terminated_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
+#define __dmac_channel_descriptor_invalid_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
#define __dmac_channel_clear_transmit_halt(n) \
do { \
@@ -273,8 +280,8 @@ do { \
REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \
REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \
} while (0)
-#define __dmac_channel_clear_transmit_end(n) \
- ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
#define __dmac_channel_clear_address_error(n) \
do { \
REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \
@@ -284,73 +291,73 @@ do { \
REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \
REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \
} while (0)
-#define __dmac_channel_clear_count_terminated(n) \
- ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
-#define __dmac_channel_clear_descriptor_invalid(n) \
- ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
-
-#define __dmac_channel_set_transfer_unit_32bit(n) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
-} while (0)
-
-#define __dmac_channel_set_transfer_unit_16bit(n) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
-} while (0)
-
-#define __dmac_channel_set_transfer_unit_8bit(n) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
-} while (0)
-
-#define __dmac_channel_set_transfer_unit_16byte(n) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
-} while (0)
-
-#define __dmac_channel_set_transfer_unit_32byte(n) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
-} while (0)
+#define __dmac_channel_clear_count_terminated(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
+#define __dmac_channel_clear_descriptor_invalid(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
+ } while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
+ } while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
+ } while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
+ } while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
+ } while (0)
/* w=8,16,32 */
-#define __dmac_channel_set_dest_port_width(n,w) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
-} while (0)
+#define __dmac_channel_set_dest_port_width(n,w) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
+ } while (0)
/* w=8,16,32 */
-#define __dmac_channel_set_src_port_width(n,w) \
-do { \
- REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
- REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
-} while (0)
+#define __dmac_channel_set_src_port_width(n,w) \
+ do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
+ } while (0)
/* v=0-15 */
#define __dmac_channel_set_rdil(n,v) \
-do { \
+ do { \
REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \
REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \
-} while (0)
+ } while (0)
-#define __dmac_channel_dest_addr_fixed(n) \
- ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
-#define __dmac_channel_dest_addr_increment(n) \
- ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
-#define __dmac_channel_src_addr_fixed(n) \
- ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
-#define __dmac_channel_src_addr_increment(n) \
- ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
-#define __dmac_channel_set_doorbell(n) \
+#define __dmac_channel_set_doorbell(n) \
( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760i2c.h b/arch/mips/include/asm/mach-jz4760/jz4760i2c.h
index a69e37b6dd1..584da4c794e 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760i2c.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760i2c.h
@@ -80,7 +80,7 @@
/* I2C Control Register (I2C_CTRL) */
#define I2C_CTRL_SLVDIS (1 << 6) /* after reset slave is disabled*/
-#define I2C_CTRL_REST (1 << 5)
+#define I2C_CTRL_REST (1 << 5)
#define I2C_CTRL_MATP (1 << 4) /* 1: 10bit address 0: 7bit addressing*/
#define I2C_CTRL_SATP (1 << 3) /* standard mode 100kbps */
#define I2C_CTRL_SPDF (2 << 1) /* fast mode 400kbps */
@@ -105,7 +105,7 @@
#define I2C_INTST_ISTP (1 << 9)
#define I2C_INTST_IACT (1 << 8)
#define I2C_INTST_RXDN (1 << 7)
-#define I2C_INTST_TXABT (1 << 6)
+#define I2C_INTST_TXABT (1 << 6)
#define I2C_INTST_RDREQ (1 << 5)
#define I2C_INTST_TXEMP (1 << 4)
#define I2C_INTST_TXOF (1 << 3)
@@ -143,7 +143,7 @@
/* I2C Enable (I2C_ENB) */
-#define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */
+#define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */
/* I2C Status Register (I2C_STA) */
@@ -179,10 +179,21 @@
#define I2C_ENSTA_SLVRDLST (1 << 2)
#define I2C_ENSTA_SLVDISB (1 << 1)
#define I2C_ENSTA_I2CEN (1 << 0) /* when read as 1, i2c is deemed to be in an enabled state
- when read as 0, i2c is deemed completely inactive. The cpu can
- safely read this bit anytime .When this bit is read as 0 ,the cpu can
+ when read as 0, i2c is deemed completely inactive. The cpu can
+ safely read this bit anytime .When this bit is read as 0 ,the cpu can
safely read SLVRDLST and SLVDISB */
+/* I2C standard mode high count register(I2CSHCNT) */
+#define I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+
+/* I2C standard mode low count register(I2CSLCNT) */
+#define I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
+
+/* I2C fast mode high count register(I2CFHCNT) */
+#define I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+
+/* I2C fast mode low count register(I2CFLCNT) */
+#define I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
#ifndef __MIPS_ASSEMBLER
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760intc.h b/arch/mips/include/asm/mach-jz4760/jz4760intc.h
index 44e6a5570af..09eced164d6 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760intc.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760intc.h
@@ -23,6 +23,7 @@
#define INTC_IMSR(n) (INTC_BASE + 0x08 + (n) * 0x20)
#define INTC_ICMSR(n) INTC_IMSR(n)
#define INTC_IMCR(n) (INTC_BASE + 0x0c + (n) * 0x20)
+#define INTC_ICMCR(n) INTC_IMCR(n)
#define INTC_IPR(n) (INTC_BASE + 0x10 + (n) * 0x20)
//#define INTC_ISSR (INTC_BASE + 0x18) /* Interrupt Controller Source Set Register */
//#define INTC_ISCR (INTC_BASE + 0x1c) /* Interrupt Controller Source Clear Register */
diff --git a/arch/mips/include/asm/mach-jz4760/jz4760msc.h b/arch/mips/include/asm/mach-jz4760/jz4760msc.h
index 176ecaf3af9..71b9f15d098 100644
--- a/arch/mips/include/asm/mach-jz4760/jz4760msc.h
+++ b/arch/mips/include/asm/mach-jz4760/jz4760msc.h
@@ -42,7 +42,7 @@
#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n))
#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n))
#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n))
-#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n))
+#define REG_MSC_RDTO(n) REG32(MSC_RDTO(n))
#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n))
#define REG_MSC_NOB(n) REG16(MSC_NOB(n))
#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n))
diff --git a/arch/mips/jz4750/board-apus.c b/arch/mips/jz4750/board-apus.c
index 632802ff05c..884c8152102 100644
--- a/arch/mips/jz4750/board-apus.c
+++ b/arch/mips/jz4750/board-apus.c
@@ -24,7 +24,7 @@
#include <asm/reboot.h>
#include <asm/jzsoc.h>
-
+#include <linux/i2c.h>
#include <asm/jzmmc/jz_mmc_platform_data.h>
void __init board_msc_init(void);
@@ -200,6 +200,24 @@ struct jz_mmc_platform_data apus_tf_data = {
#endif
};
+static struct i2c_board_info lepus_i2c0_devs[] __initdata = {
+ {
+ I2C_BOARD_INFO("cm3511", 0x30),
+ },
+ {
+ I2C_BOARD_INFO("ov3640", 0x3c),
+ },
+ {
+ I2C_BOARD_INFO("ov7690", 0x21),
+ },
+ {
+ },
+};
+
+void __init board_i2c_init(void) {
+ i2c_register_board_info(0, lepus_i2c0_devs, ARRAY_SIZE(lepus_i2c0_devs));
+}
+
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
diff --git a/arch/mips/jz4750/platform.c b/arch/mips/jz4750/platform.c
index 0d5ac617b1e..acf09c8406f 100644
--- a/arch/mips/jz4750/platform.c
+++ b/arch/mips/jz4750/platform.c
@@ -15,7 +15,7 @@
#include <linux/resource.h>
#include <asm/jzsoc.h>
-
+#include <../sound/oss/jz_audio.h>
#include <asm/jzmmc/jz_mmc_platform_data.h>
@@ -247,7 +247,29 @@ static struct platform_device jz_i2c_device = {
.resource = jz_i2c_resources,
};
-
+//////////////////////////////////////////////////////////
+#define SND(num, desc) { .name = desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+ SND(0, "HANDSET"),
+ SND(1, "SPEAKER"),
+ SND(2, "HEADSET"),
+
+};
+#undef SND
+
+static struct jz_snd_endpoints vogue_snd_endpoints = {
+ .endpoints = snd_endpoints_list,
+ .num = ARRAY_SIZE(snd_endpoints_list),
+};
+
+static struct platform_device vogue_snd_device = {
+ .name = "mixer",
+ .id = -1,
+ .dev = {
+ .platform_data = &vogue_snd_endpoints,
+ },
+};
+///////////////////////////////////////////////////////////
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
@@ -256,10 +278,13 @@ static struct platform_device *jz_platform_devices[] __initdata = {
&jz_usb_gdt_device,
// &jz_mmc_device,
&jz_i2c_device,
+ &vogue_snd_device,
};
+extern void __init board_i2c_init(void);
static int __init jz_platform_init(void)
{
+ board_i2c_init();
board_msc_init();
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
diff --git a/arch/mips/jz4750d/board-cetus.c b/arch/mips/jz4750d/board-cetus.c
index 0febbd3f0e3..d154cc61fb1 100644
--- a/arch/mips/jz4750d/board-cetus.c
+++ b/arch/mips/jz4750d/board-cetus.c
@@ -24,6 +24,11 @@
#include <asm/reboot.h>
#include <asm/jzsoc.h>
+#include <asm/jzmmc/jz_mmc_platform_data.h>
+
+void __init board_msc_init(void);
+
+extern int jz_add_msc_devices(unsigned int controller, struct jz_mmc_platform_data *plat);
extern void (*jz_timer_callback)(void);
@@ -47,6 +52,159 @@ static void cetus_timer_callback(void)
}
}
+static void cetus_sd_gpio_init(struct device *dev)
+{
+ __gpio_as_msc0_4bit();
+ __gpio_as_output(GPIO_SD0_VCC_EN_N);
+ __gpio_as_input(GPIO_SD0_CD_N);
+}
+
+static void cetus_sd_power_on(struct device *dev)
+{
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N);
+}
+
+static void cetus_sd_power_off(struct device *dev)
+{
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N);
+}
+
+static void cetus_sd_cpm_start(struct device *dev)
+{
+ __cpm_start_msc(0);
+}
+
+static unsigned int cetus_sd_status(struct device *dev)
+{
+ unsigned int status;
+
+ status = (unsigned int) __gpio_get_pin(GPIO_SD0_CD_N);
+ return (!status);
+}
+
+#if 0
+static void cetus_sd_plug_change(int state)
+{
+ if(state == CARD_INSERTED)
+ __gpio_as_irq_high_level(MSC0_HOTPLUG_PIN); /* wait remove */
+ else
+ __gpio_as_irq_low_level(MSC0_HOTPLUG_PIN); /* wait insert */
+}
+#else
+static void cetus_sd_plug_change(int state)
+{
+ if(state == CARD_INSERTED)
+ __gpio_as_irq_rise_edge(MSC0_HOTPLUG_PIN);
+ else
+ __gpio_as_irq_fall_edge(MSC0_HOTPLUG_PIN);
+}
+#endif
+
+static unsigned int cetus_sd_get_wp(struct device *dev)
+{
+ unsigned int status;
+
+ status = (unsigned int) __gpio_get_pin(GPIO_SD0_WP);
+ return (status);
+}
+
+struct jz_mmc_platform_data cetus_sd_data = {
+#ifndef CONFIG_JZ_MSC0_SDIO_SUPPORT
+ .support_sdio = 0,
+#else
+ .support_sdio = 1,
+#endif
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .status_irq = MSC0_HOTPLUG_IRQ,
+ .detect_pin = GPIO_SD0_CD_N,
+ .init = cetus_sd_gpio_init,
+ .power_on = cetus_sd_power_on,
+ .power_off = cetus_sd_power_off,
+ .cpm_start = cetus_sd_cpm_start,
+ .status = cetus_sd_status,
+ .plug_change = cetus_sd_plug_change,
+ .write_protect = cetus_sd_get_wp,
+ .max_bus_width = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA,
+#ifdef CONFIG_JZ_MSC0_BUS_1
+ .bus_width = 1,
+#elif defined CONFIG_JZ_MSC0_BUS_4
+ .bus_width = 4,
+#else
+ .bus_width = 8,
+#endif
+};
+
+static void cetus_tf_gpio_init(struct device *dev)
+{
+ __gpio_as_msc1_4bit();
+ __gpio_as_output(GPIO_SD1_VCC_EN_N);
+ __gpio_as_input(GPIO_SD1_CD_N);
+}
+
+static void cetus_tf_power_on(struct device *dev)
+{
+ __msc1_enable_power();
+}
+
+static void cetus_tf_power_off(struct device *dev)
+{
+ __msc1_disable_power();
+}
+
+static void cetus_tf_cpm_start(struct device *dev)
+{
+ __cpm_start_msc(1);
+}
+
+static unsigned int cetus_tf_status(struct device *dev)
+{
+ unsigned int status;
+
+ status = (unsigned int) __gpio_get_pin(GPIO_SD1_CD_N);
+ return (!status);
+}
+
+#if 0
+static void cetus_tf_plug_change(int state)
+{
+ if(state == CARD_INSERTED)
+ __gpio_as_irq_low_level(MSC1_HOTPLUG_PIN);
+ else
+ __gpio_as_irq_high_level(MSC1_HOTPLUG_PIN);
+}
+#else
+static void cetus_tf_plug_change(int state)
+{
+ if(state == CARD_INSERTED)
+ __gpio_as_irq_fall_edge(MSC1_HOTPLUG_PIN);
+ else
+ __gpio_as_irq_rise_edge(MSC1_HOTPLUG_PIN);
+}
+#endif
+
+struct jz_mmc_platform_data cetus_tf_data = {
+#ifndef CONFIG_JZ_MSC1_SDIO_SUPPORT
+ .support_sdio = 0,
+#else
+ .support_sdio = 1,
+#endif
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .status_irq = MSC1_HOTPLUG_IRQ,
+ .detect_pin = GPIO_SD1_CD_N,
+ .init = cetus_tf_gpio_init,
+ .power_on = cetus_tf_power_on,
+ .power_off = cetus_tf_power_off,
+ .cpm_start = cetus_tf_cpm_start,
+ .status = cetus_tf_status,
+ .plug_change = cetus_tf_plug_change,
+ .max_bus_width = MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA,
+#ifdef CONFIG_JZ_MSC1_BUS_1
+ .bus_width = 1,
+#else
+ .bus_width = 4,
+#endif
+};
+
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
@@ -61,6 +219,17 @@ static void __init board_gpio_setup(void)
*/
}
+void __init board_msc_init(void)
+{
+#ifdef CONFIG_JZ_MSC0
+ jz_add_msc_devices(0, &cetus_sd_data);
+#endif
+
+#ifdef CONFIG_JZ_MSC1
+ jz_add_msc_devices(1, &cetus_tf_data);
+#endif
+}
+
void __init jz_board_setup(void)
{
printk("JZ4750D CETUS board setup\n");
diff --git a/arch/mips/jz4750d/platform.c b/arch/mips/jz4750d/platform.c
index a725c18a727..cf119330c0d 100644
--- a/arch/mips/jz4750d/platform.c
+++ b/arch/mips/jz4750d/platform.c
@@ -15,6 +15,14 @@
#include <linux/resource.h>
#include <asm/jzsoc.h>
+#include <../sound/oss/jz_audio.h>
+
+#include <asm/jzmmc/jz_mmc_platform_data.h>
+
+extern void __init board_msc_init(void);
+
+int __init jz_add_msc_devices(unsigned int controller, struct jz_mmc_platform_data *plat);
+
#if 0
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
@@ -99,6 +107,8 @@ static struct platform_device jz_usb_gdt_device = {
};
/** MMC/SD controller **/
+#if 0
+/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC_BASE),
@@ -125,6 +135,92 @@ static struct platform_device jz_mmc_device = {
.resource = jz_mmc_resources,
};
+#else
+/** MMC/SD controller MSC0**/
+static struct resource jz_msc0_resources[] = {
+ {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_MSC0,
+ .end = IRQ_MSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = DMA_ID_MSC0_RX,
+ .end = DMA_ID_MSC0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static u64 jz_msc0_dmamask = ~(u32)0;
+
+static struct platform_device jz_msc0_device = {
+ .name = "jz-msc0",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_msc0_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_msc0_resources),
+ .resource = jz_msc0_resources,
+};
+
+/** MMC/SD controller MSC1**/
+static struct resource jz_msc1_resources[] = {
+ {
+ .start = CPHYSADDR(MSC_BASE) + 0x1000,
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_MSC1,
+ .end = IRQ_MSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = DMA_ID_MSC1_RX,
+ .end = DMA_ID_MSC1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+
+};
+
+static u64 jz_msc1_dmamask = ~(u32)0;
+
+static struct platform_device jz_msc1_device = {
+ .name = "jz-msc1",
+ .id = 1,
+ .dev = {
+ .dma_mask = &jz_msc1_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_msc1_resources),
+ .resource = jz_msc1_resources,
+};
+
+static struct platform_device *jz_msc_devices[] __initdata = {
+ &jz_msc0_device,
+ &jz_msc1_device,
+};
+
+int __init jz_add_msc_devices(unsigned int controller, struct jz_mmc_platform_data *plat)
+{
+ struct platform_device *pdev;
+
+ if (controller < 0 || controller > 1)
+ return -EINVAL;
+
+ pdev = jz_msc_devices[controller];
+
+ pdev->dev.platform_data = plat;
+
+ return platform_device_register(pdev);
+}
+#endif
+
/** I2C controller **/
static struct resource jz_i2c_resources[] = {
[0] = {
@@ -153,19 +249,43 @@ static struct platform_device jz_i2c_device = {
.resource = jz_i2c_resources,
};
+//////////////////////////////////////////////////////////
+#define SND(num, desc) { .name = desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+ SND(0, "HANDSET"),
+ SND(1, "SPEAKER"),
+ SND(2, "HEADSET"),
+
+};
+#undef SND
+
+static struct jz_snd_endpoints vogue_snd_endpoints = {
+ .endpoints = snd_endpoints_list,
+ .num = ARRAY_SIZE(snd_endpoints_list),
+};
+static struct platform_device vogue_snd_device = {
+ .name = "mixer",
+ .id = -1,
+ .dev = {
+ .platform_data = &vogue_snd_endpoints,
+ },
+};
+///////////////////////////////////////////////////////////
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
// &jz_usb_ohci_device,
&jz_lcd_device,
&jz_usb_gdt_device,
- &jz_mmc_device,
+ //&jz_mmc_device,
&jz_i2c_device,
+ &vogue_snd_device,
};
static int __init jz_platform_init(void)
{
+ board_msc_init();
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
diff --git a/arch/mips/jz4760/board-lepus.c b/arch/mips/jz4760/board-lepus.c
index 0bc9dcad97a..d3b43c8d0a3 100644
--- a/arch/mips/jz4760/board-lepus.c
+++ b/arch/mips/jz4760/board-lepus.c
@@ -25,7 +25,7 @@
#include <asm/jzsoc.h>
#include <linux/i2c.h>
#include <asm/jzmmc/jz_mmc_platform_data.h>
-
+#include <linux/ft5x0x_ts.h>
extern void (*jz_timer_callback)(void);
extern int __init jz_add_msc_devices(unsigned int controller, struct jz_mmc_platform_data *plat);
@@ -70,20 +70,16 @@ struct wakeup_key_s {
/* add wakeup keys here */
static struct wakeup_key_s wakeup_key[] = {
{
- .gpio = GPIO_HOME,
- .active_low = ACTIVE_LOW_HOME,
- },
- {
- .gpio = GPIO_BACK,
- .active_low = ACTIVE_LOW_BACK,
+ .gpio = GPIO_POWER_ON,
+ .active_low = ACTIVE_LOW_WAKE_UP,
},
{
- .gpio = GPIO_ENDCALL,
- .active_low = ACTIVE_LOW_ENDCALL,
+ .gpio = MSC0_HOTPLUG_PIN,
+ .active_low = ACTIVE_LOW_MSC0_CD,
},
{
- .gpio = GPIO_ADKEY_INT,
- .active_low = ACTIVE_LOW_ADKEY,
+ .gpio = MSC1_HOTPLUG_PIN,
+ .active_low = ACTIVE_LOW_MSC1_CD,
},
};
@@ -93,22 +89,11 @@ static void wakeup_key_setup(void)
int num = sizeof(wakeup_key) / sizeof(wakeup_key[0]);
for(i = 0; i < num; i++) {
-#if 0
if(wakeup_key[i].active_low)
__gpio_as_irq_fall_edge(wakeup_key[i].gpio);
else
__gpio_as_irq_rise_edge(wakeup_key[i].gpio);
-#endif
-#if 1
- /* Because GPIO_VOLUMUP, GPIO_VOLUMDOWN and GPIO_MENU are boot_sel pins, and
- resuming from sleep is implemented by reseting, the values of boot_sel pins
- will be read at this time to determine boot method. So system couldn't be
- waken by these keys. */
- __gpio_as_input(GPIO_MENU);
- __gpio_as_input(GPIO_VOLUMEDOWN);
- __gpio_as_input(GPIO_VOLUMEUP);
-#endif
__gpio_ack_irq(wakeup_key[i].gpio);
__gpio_unmask_irq(wakeup_key[i].gpio);
__intc_unmask_irq(IRQ_GPIO0 - (wakeup_key[i].gpio/32)); /* unmask IRQ_GPIOn */
@@ -430,6 +415,9 @@ static void __init board_gpio_setup(void)
*/
}
+static struct ft5x0x_ts_platform_data ft5x0x_ts_pdata = {
+ .intr = GPIO_TS_I2C_INT,
+};
static struct i2c_board_info lepus_i2c0_devs[] __initdata = {
{
I2C_BOARD_INFO("cm3511", 0x30),
@@ -441,6 +429,11 @@ static struct i2c_board_info lepus_i2c0_devs[] __initdata = {
I2C_BOARD_INFO("ov7690", 0x21),
},
{
+ I2C_BOARD_INFO(FT5X0X_NAME, 0x38),
+ .irq = GPIO_TS_I2C_IRQ,
+ .platform_data = &ft5x0x_ts_pdata,
+ },
+ {
},
};
diff --git a/arch/mips/jz4760/cpm.c b/arch/mips/jz4760/cpm.c
index 25046480d5f..901041e6fdc 100644
--- a/arch/mips/jz4760/cpm.c
+++ b/arch/mips/jz4760/cpm.c
@@ -80,6 +80,11 @@ unsigned int cpm_get_pllout1(void)
unsigned int m, n, od, no, val, div;
pll_ctrl = INREG32(CPM_CPPCR1);
+
+ if ( !(pll_ctrl & CPPCR1_PLL1ON)) { /* pll1 off */
+ return 0;
+ }
+
if (pll_ctrl & CPPCR1_P1SCS) {
val = get_bf_value(pll_ctrl, CPPCR1_P1SDIV_LSB, CPPCR1_P1SDIV_MASK);
div = val + 1;
@@ -405,6 +410,8 @@ static unsigned int __check_div(unsigned int div, unsigned int lsb, unsigned int
* Set the clock, assigned by the clock_name, and the return value unit is Hz,
* which means the actual clock
*/
+#define ceil(v,div) ({ unsigned int val = 0; if(v % div ) val = v /div + 1; else val = v /div; val;})
+#define nearbyint(v,div) ({unsigned int val = 0; if((v % div) * 2 >= div) val = v / div + 1;else val = v / div; val;})
unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
{
unsigned int actual_clock = 0;
@@ -420,11 +427,11 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
case CGU_MSCCLK:
if (clock_hz == exclk) {
/* Select external clock as input*/
- SETREG32(CPM_MSCCDR, MSCCDR_MCS);
+ CLRREG32(CPM_MSCCDR, MSCCDR_MCS);
} else {
- div = pllclk / clock_hz - 1;
+ div = ceil(pllclk , clock_hz) - 1;
div = __check_div(div, MSCCDR_MSCDIV_LSB, MSCCDR_MSCDIV_MASK);
- OUTREG32(CPM_MSCCDR, div);
+ OUTREG32(CPM_MSCCDR, MSCCDR_MCS | div);
}
break;
@@ -434,7 +441,7 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
/* Select external clock as input */
SETREG32(CPM_LPCDR, LPCDR_LSCS | LPCDR_LTCS);
} else {
- div = pllclk1 / clock_hz - 1;
+ div = nearbyint(pllclk1 , clock_hz) - 1;
div = __check_div(div, LPCDR_PIXDIV_LSB, LPCDR_PIXDIV_MASK);
/* Select pll1 clock as input */
OUTREG32(CPM_LPCDR, LPCDR_LTCS | LPCDR_LPCS | div);
@@ -442,7 +449,7 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
break;
case CGU_LPCLK:
- div = pllclk / clock_hz - 1;
+ div = nearbyint(pllclk , clock_hz) - 1;
div = __check_div(div, LPCDR_PIXDIV_LSB, LPCDR_PIXDIV_MASK);
/* Select pll0 clock as input */
OUTREG32(CPM_LPCDR, div);
@@ -456,7 +463,7 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
SETREG32(CPM_CPCCR, CPCCR_ECS);
OUTREG32(CPM_I2SCDR, 0);
} else {
- div = pllclk / clock_hz - 1;
+ div = nearbyint(pllclk , clock_hz) - 1;
div = __check_div(div, I2SCDR_I2SDIV_LSB, I2SCDR_I2SDIV_MASK);
OUTREG32(CPM_I2SCDR, I2SCDR_I2CS | div);
}
@@ -470,7 +477,7 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
SETREG32(CPM_CPCCR, CPCCR_ECS);
OUTREG32(CPM_USBCDR, 0);
} else {
- div = pllclk / clock_hz - 1;
+ div = nearbyint(pllclk , clock_hz) - 1;
div = __check_div(div, USBCDR_OTGDIV_LSB, USBCDR_OTGDIV_MASK);
OUTREG32(CPM_USBCDR, USBCDR_UCS | div);
}
@@ -481,13 +488,13 @@ unsigned int cpm_set_clock(cgu_clock clock_name, unsigned int clock_hz)
break;
case CGU_CIMCLK:
- div = pllclk / clock_hz - 1;
- div = __check_div(div, CIMCDR_CIMDIV_LSB, CIMCDR_CIMDIV_MASK);
+ div = ceil(pllclk , clock_hz) - 1;
+ div = __check_div(div, CIMCDR_CIMDIV_LSB, CIMCDR_CIMDIV_MASK);
OUTREG32(CPM_CIMCDR, div);
break;
case CGU_UHCCLK:
- div = pllclk / clock_hz - 1;
+ div = nearbyint(pllclk , clock_hz) - 1;
div = __check_div(div, UHCCDR_UHCDIV_LSB, UHCCDR_UHCDIV_MASK);
OUTREG32(CPM_UHCCDR, div);
break;
diff --git a/arch/mips/jz4760/dma.c b/arch/mips/jz4760/dma.c
index 97d35e44107..c411363c60b 100644
--- a/arch/mips/jz4760/dma.c
+++ b/arch/mips/jz4760/dma.c
@@ -3,7 +3,7 @@
*
* Support functions for the JZ4760 internal DMA channels.
* No-descriptor transfer only.
- * Descriptor transfer should also call jz_request_dma() to get a free
+ * Descriptor transfer should also call jz_request_dma() to get a free
* channel and call jz_free_dma() to free the channel. And driver should
* build the DMA descriptor and setup the DMA channel by itself.
*
@@ -47,7 +47,7 @@
*/
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
- { dev_id: DMA_ID_BCH_ENC, }, /* DMAC0 channel 0, reserved for BCH */
+ { dev_id: -1, }, /* DMAC0 channel 0, reserved for BCH */
{ dev_id: -1, }, /* DMAC0 channel 1 */
{ dev_id: -1, }, /* DMAC0 channel 2 */
{ dev_id: -1, }, /* DMAC0 channel 3 */
@@ -70,10 +70,6 @@ static const struct {
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[DMA_ID_MAX] = {
- {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
- {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
- {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
- {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
{CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
@@ -86,7 +82,7 @@ static const struct {
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
-
+
/*spdif used */
//{CPHYSADDR(SPDIF_FIFO), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
/*aic unpack used*/
@@ -535,7 +531,7 @@ void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fm
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
-
+
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
@@ -569,7 +565,7 @@ void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_f
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
-
+
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
@@ -788,7 +784,7 @@ void dma_desc_test(void)
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
-
+
desc++;
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
diff --git a/arch/mips/jz4760/irq.c b/arch/mips/jz4760/irq.c
index be5847fc580..68db2a6a612 100644
--- a/arch/mips/jz4760/irq.c
+++ b/arch/mips/jz4760/irq.c
@@ -458,7 +458,7 @@ asmlinkage void plat_irq_dispatch(void)
if (!(intc_ipr0 || intc_ipr1)) return;
-
+#if 0
if (intc_ipr0) {
irq = ffs(intc_ipr0) - 1;
intc_ipr0 &= ~(1<<irq);
@@ -467,6 +467,29 @@ asmlinkage void plat_irq_dispatch(void)
intc_ipr1 &= ~(1<<irq);
irq += 32;
}
+#endif
+#if 1
+ if (!(intc_ipr0 & 3)) {
+ if (intc_ipr0) {
+ irq = fls(intc_ipr0) - 1;
+ intc_ipr0 &= ~(1<<irq);
+ } else {
+ irq = fls(intc_ipr1) - 1;
+ intc_ipr1 &= ~(1<<irq);
+ irq += 32;
+ }
+ } else {
+ if (intc_ipr0 & 2) {
+
+ irq = 1;
+ intc_ipr0 &= ~(1<<irq);
+ } else {
+
+ irq = 0;
+ intc_ipr0 &= ~(1<<irq);
+ }
+ }
+#endif
if ((irq >= IRQ_GPIO5) && (irq <= IRQ_GPIO0)) {
group = IRQ_GPIO0 - irq;
diff --git a/arch/mips/jz4760/platform.c b/arch/mips/jz4760/platform.c
index befea50f656..80f045e2d8f 100644
--- a/arch/mips/jz4760/platform.c
+++ b/arch/mips/jz4760/platform.c
@@ -294,8 +294,8 @@ static struct platform_device jz_i2c1_device = {
};
static struct platform_device rtc_device = {
- .name = "jz_rtc",
- .id = 0,
+ .name = "jz4760-rtc",
+ .id = -1,
};
/* All */
diff --git a/arch/mips/jz4760/pm.c b/arch/mips/jz4760/pm.c
index 030efe9e7e5..34334f9b382 100644
--- a/arch/mips/jz4760/pm.c
+++ b/arch/mips/jz4760/pm.c
@@ -1,14 +1,14 @@
/*
* linux/arch/mips/jz4760/pm.c
- *
+ *
* JZ4760 Power Management Routines
- *
+ *
* Copyright (C) 2006 - 2010 Ingenic Semiconductor Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
- *
+ *
* This program is distributed in the hope 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
@@ -17,7 +17,7 @@
* 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>
@@ -25,14 +25,29 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/suspend.h>
-#include <linux/proc_fs.h>
+#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <asm/cacheops.h>
#include <asm/jzsoc.h>
+#define CONFIG_PM_POWERDOWN_P0 y
+#define JZ_PM_SIMULATE_BATTERY y
+
+#ifdef JZ_PM_SIMULATE_BATTERY
+#define CONFIG_BATTERY_JZ
+#define JZ_PM_BATTERY_SIMED
+#endif
+
+#if defined(CONFIG_RTC_JZ4760) && defined(CONFIG_BATTERY_JZ)
+//extern unsigned long jz_read_bat(void);
+//extern int g_jz_battery_min_voltage;
+static unsigned int usr_alarm_data = 0;
+static int alarm_state = 0;
+#endif
+
#undef DEBUG
-//#define DEBUG
+//#define DEBUG
#ifdef DEBUG
#define dprintk(x...) printk(x)
#else
@@ -50,20 +65,19 @@ extern void wm8310_power_off(void);
#endif
int jz_pm_do_hibernate(void)
{
+ printk("Put CPU into hibernate mode.\n");
#if defined(CONFIG_INPUT_WM831X_ON)
printk("The power will be off.\n");
wm8310_power_off();
while(1);
#else
- printk("Put CPU into hibernate mode.\n");
-
/* Mask all interrupts */
OUTREG32(INTC_ICMSR(0), 0xffffffff);
OUTREG32(INTC_ICMSR(1), 0x7ff);
- /*
- * RTC Wakeup or 1Hz interrupt can be enabled or disabled
+ /*
+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
*/
@@ -79,6 +93,9 @@ int jz_pm_do_hibernate(void)
/* clear wakeup status register */
rtc_write_reg(RTC_HWRSR, 0x0);
+ /* set wake up valid level as low and disable rtc alarm wake up.*/
+ rtc_write_reg(RTC_HWCR,0x8);
+
/* Put CPU to hibernate mode */
rtc_write_reg(RTC_HCR, HCR_PD);
@@ -91,9 +108,66 @@ int jz_pm_do_hibernate(void)
return 0;
}
+
+#if defined(CONFIG_RTC_JZ4760) && defined(CONFIG_BATTERY_JZ)
+static int alarm_remain = 0;
+//#define ALARM_TIME (3 * 60)
+#define ALARM_TIME (10 * 60)
+static inline void jz_save_alarm(void) {
+ uint32_t rtc_rtcsr = 0,rtc_rtcsar = 0;
+
+ rtc_rtcsar = rtc_read_reg(RTC_RTCSAR); /* second alarm register */
+ rtc_rtcsr = rtc_read_reg(RTC_RTCSR); /* second register */
+
+ alarm_remain = rtc_rtcsar - rtc_rtcsr;
+}
+
+static inline void jz_restore_alarm(void) {
+ if (alarm_remain > 0) {
+ rtc_write_reg(RTC_RTCSAR, rtc_read_reg(RTC_RTCSR) + alarm_remain);
+ rtc_set_reg(RTC_RTCCR,0x3<<2); /* alarm enable, alarm interrupt enable */
+ }
+}
+
+static void jz_set_alarm(void)
+{
+ uint32_t rtc_rtcsr = 0,rtc_rtcsar = 0;
+
+ rtc_rtcsar = rtc_read_reg(RTC_RTCSAR); /* second alarm register */
+ rtc_rtcsr = rtc_read_reg(RTC_RTCSR); /* second register */
+#if 0
+ if(rtc_rtcsar <= rtc_rtcsr) {
+#endif
+ printk("1\n");
+ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + ALARM_TIME);
+ rtc_set_reg(RTC_RTCCR,0x3<<2); /* alarm enable, alarm interrupt enable */
+// alarm_state = 1; /* alarm on */
+#if 0
+ } else if(rtc_rtcsar > rtc_rtcsr + ALARM_TIME) {
+ printk("2\n");
+ usr_alarm_data = rtc_rtcsar;
+ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + ALARM_TIME);
+ rtc_set_reg(RTC_RTCCR,0x3<<2);
+ alarm_state = 1;
+ } else { /* ??? I have some questions here, when the cpu is sleeping, the time freezes, doesn't it?
+ consider sleep->wakeup->sleep --- by Lutts */
+ printk("3\n");
+ usr_alarm_data = 0;
+ rtc_set_reg(RTC_RTCCR,0x3<<2);
+ alarm_state = 0;
+ }
+#endif
+
+ rtc_rtcsar = rtc_read_reg(RTC_RTCSAR); /* second alarm register */
+ rtc_rtcsr = rtc_read_reg(RTC_RTCSR); /* second register */
+
+ printk("rtc_rtcsar = %u rtc_rtcsr = %u alarm_state = %d\n", rtc_rtcsar, rtc_rtcsr, alarm_state);
+}
+#undef ALARM_TIME
+#endif
+
static int jz_pm_do_sleep(void)
-{
- unsigned long delta;
+{
unsigned long nfcsr = REG_NEMC_NFCSR;
unsigned long opcr = INREG32(CPM_OPCR);
unsigned long icmr0 = INREG32(INTC_ICMR(0));
@@ -103,12 +177,14 @@ static int jz_pm_do_sleep(void)
unsigned long sleep_gpio_save[7*(GPIO_PORT_NUM-1)];
unsigned long cpuflags;
+ jz_save_alarm();
+
+#if defined(CONFIG_RTC_JZ4760) && defined(CONFIG_BATTERY_JZ)
+ __jz_pm_do_sleep_start:
+#endif
/* set SLEEP mode */
CMSREG32(CPM_LCR, LCR_LPM_SLEEP, LCR_LPM_MASK);
- /* Preserve current time */
- delta = xtime.tv_sec - rtc_read_reg(RTC_RTCSR);
-
/* Save CPU irqs */
local_irq_save(cpuflags);
@@ -127,20 +203,26 @@ static int jz_pm_do_sleep(void)
/* stop uhc */
SETREG32(CPM_OPCR, OPCR_UHCPHY_DISABLE);
-
+
/* stop otg and gps */
CLRREG32(CPM_OPCR, OPCR_OTGPHY_ENABLE | OPCR_GPSEN);
/*power down gps and ahb1*/
- SETREG32(CPM_LCR, LCR_PDAHB1 | LCR_PDGPS);
+ //SETREG32(CPM_LCR, LCR_PDAHB1 | LCR_PDGPS);
+
+ //while(!(REG_CPM_LCR && LCR_PDAHB1S)) ;
+ //while(!(REG_CPM_LCR && LCR_PDGPSS)) ;
/* Mask all interrupts except rtc*/
OUTREG32(INTC_ICMSR(0), 0xffffffff);
- OUTREG32(INTC_ICMSR(1), 0x7fe);
+ OUTREG32(INTC_ICMSR(1), 0x7ff);
-#if defined(CONFIG_RTC_DRV_JZ4760)
- /* unmask rtc interrupts */
+#if defined(CONFIG_RTC_JZ4760)
OUTREG32(INTC_ICMCR(1), 0x1);
+ jz_set_alarm();
+ __intc_ack_irq(IRQ_RTC);
+ __intc_unmask_irq(IRQ_RTC);
+ rtc_clr_reg(RTC_RTCCR,RTCCR_AF);
#else
/* mask rtc interrupts */
OUTREG32(INTC_ICMSR(1), 0x1);
@@ -149,6 +231,9 @@ static int jz_pm_do_sleep(void)
/* Sleep on-board modules */
jz_board_do_sleep(sleep_gpio_save);
+ printk("control = 0x%08x icmr0 = 0x%08x icmr1 = 0x%08x\n",
+ INREG32(RTC_RTCCR), INREG32(INTC_ICMR(0)), INREG32(INTC_ICMR(1)));
+
#if 0
/* WAKEUP key */
__gpio_as_irq_fall_edge(GPIO_POWER_ON);
@@ -177,6 +262,8 @@ static int jz_pm_do_sleep(void)
#endif
#if defined(CONFIG_PM_POWERDOWN_P0)
+ printk("Shutdown P0\n");
+
/* power down the p0 */
SETREG32(CPM_OPCR, OPCR_PD);
@@ -188,6 +275,8 @@ static int jz_pm_do_sleep(void)
udelay(1);
OUTREG32(CPM_CPSPR, virt_to_phys(jz_cpu_resume));
+ rtc_clr_reg(RTC_RTCCR,RTCCR_AF);
+
/* *** go zzz *** */
jz_cpu_sleep();
#else
@@ -214,7 +303,7 @@ static int jz_pm_do_sleep(void)
/*Restore pmembs0*/
REG_EMC_PMEMBS0 = pmembs0;
- /* Restore interrupts */
+ /* Restore interrupts FIXME:*/
OUTREG32(INTC_ICMR(0), icmr0);
OUTREG32(INTC_ICMR(1), icmr1);
@@ -230,8 +319,24 @@ static int jz_pm_do_sleep(void)
/* Restore CPU interrupt flags */
local_irq_restore(cpuflags);
- /* Restore current time */
- xtime.tv_sec = rtc_read_reg(RTC_RTCSR) + delta;
+ CLRREG32(CPM_RSR, RSR_PR | RSR_WR | RSR_P0R);
+
+ printk("===>Leave CPU Sleep\n");
+#if defined(CONFIG_RTC_JZ4760) && defined(CONFIG_BATTERY_JZ)
+ if((INREG32(RTC_RTCCR) & RTCCR_AF)) {
+ rtc_clr_reg(RTC_RTCCR,RTCCR_AF | RTCCR_AE | RTCCR_AIE);
+ if(!usr_alarm_data) /* restore usrs alarm state */
+ rtc_write_reg(RTC_RTCSAR,usr_alarm_data);
+#if 0
+ if(g_jz_battery_min_voltage > jz_read_bat()) /* Just for example, add your Battery check here */
+ pm_power_off();
+ else
+#endif
+ goto __jz_pm_do_sleep_start;
+ }
+#endif
+
+ jz_restore_alarm();
return 0;
}
@@ -275,34 +380,16 @@ void jz_flush_cache_all(void)
: "r"(addr));
}
-/* Put CPU to HIBERNATE mode
- *----------------------------------------------------------------------------
- * Power Management sleep sysctl interface
- *
- * Write "mem" to /sys/power/state invokes this function
- * which initiates a poweroff.
- */
void jz_pm_hibernate(void)
{
jz_pm_do_hibernate();
}
-/* Put CPU to SLEEP mode
- *----------------------------------------------------------------------------
- * Power Management sleep sysctl interface
- *
- * Write "disk" to /sys/power/state invokes this function
- * which initiates a sleep.
- */
-
-int jz_pm_sleep(void)
+int jz_pm_sleep(void)
{
return jz_pm_do_sleep();
}
-/*
- * valid states, only support mem(sleep) and disk(hibernate)
- */
static int jz4760_pm_valid(suspend_state_t state)
{
return state == PM_SUSPEND_MEM;
@@ -333,3 +420,7 @@ int __init jz_pm_init(void)
return 0;
}
+#ifdef JZ_PM_BATTERY_SIMED
+#undef CONFIG_BATTERY_JZ
+#endif
+
diff --git a/arch/mips/jz4760/proc.c b/arch/mips/jz4760/proc.c
index 8578410b3b9..34c56f12b22 100644
--- a/arch/mips/jz4760/proc.c
+++ b/arch/mips/jz4760/proc.c
@@ -595,7 +595,7 @@ static int mmc_read_proc (char *page, char **start, off_t off,
/***********************************************************************
* IPU memory management (used by mplayer and other apps)
*
- * We reserved 4MB memory for IPU
+ * We reserved 16MB memory for IPU
* The memory base address is jz_ipu_framebuf
*/
@@ -609,7 +609,7 @@ static int mmc_read_proc (char *page, char **start, off_t off,
//#define DEBUG_IMEM 1
-#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
+#define IMEM_MAX_ORDER 12 /* max 2^12 * 4096 = 16MB */
static unsigned int jz_imem_base; /* physical base address of ipu memory */
@@ -626,6 +626,12 @@ typedef struct imem_list {
static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
+#define IMEM1_MAX_ORDER 11 /* max 2^11 * 4096 = 8MB */
+static unsigned int jz_imem1_base; /* physical base address of ipu memory */
+static unsigned int allocated_phys_addr1 = 0;
+static struct imem_list *imem1_list_head = NULL; /* up sorted by phys_start */
+
+
#ifdef DEBUG_IMEM
static void dump_imem_list(void)
{
@@ -637,10 +643,17 @@ static void dump_imem_list(void)
printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
imem = imem->next;
}
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem1_list_head);
+ imem = imem1_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
}
#endif
-/* allocate 2^order pages inside the 4MB memory */
+/* allocate 2^order pages inside the 16MB memory */
static int imem_alloc(unsigned int order)
{
int alloc_ok = 0;
@@ -713,6 +726,79 @@ static int imem_alloc(unsigned int order)
return 0;
}
+/* allocate 2^order pages inside the 8MB memory */
+static int imem1_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr1 = 0;
+
+ start = jz_imem1_base;
+ end = start + (1 << IMEM1_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem1_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr1 = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem1_list_head)
+ imem1_list_head = imemn;
+ else {
+ imem = imemp = imem1_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem1_list_head) {
+ imem1_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
static void imem_free(unsigned int phys_addr)
{
struct imem_list *imem, *imemp;
@@ -735,6 +821,24 @@ static void imem_free(unsigned int phys_addr)
imem = imem->next;
}
+ imem = imemp = imem1_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem1_list_head) {
+ imem1_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
@@ -754,6 +858,16 @@ static void imem_free_all(void)
allocated_phys_addr = 0;
+ imem = imem1_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem1_list_head = NULL;
+
+ allocated_phys_addr1 = 0;
+
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
@@ -829,6 +943,77 @@ static int imem_write_proc(struct file *file, const char *buffer, unsigned long
return count;
}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem1_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem1_base;
+ end_addr = start_addr + (1 << IMEM1_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem1_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem1_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr1; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem1_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ ipu_del_wired_entry();
+ } else if ((val >= 0) && (val <= IMEM1_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem1_alloc(val);
+ } else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
#endif /* #ifndef CONFIG_ANDROID_PMEM */
static int fpu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
@@ -914,7 +1099,7 @@ static int __init jz_proc_init(void)
#ifndef CONFIG_ANDROID_PMEM
/*
- * Reserve a 4MB memory for IPU on JZ4760.
+ * Reserve a 16MB memory for IPU on JZ4760.
*/
jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
if (jz_imem_base) {
@@ -939,6 +1124,35 @@ static int __init jz_proc_init(void)
printk("Total %dMB memory at 0x%x was reserved for IPU\n",
(unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
}
+ else
+ printk("NOT enough memory for imem\n");
+
+ jz_imem1_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM1_MAX_ORDER);
+ if (jz_imem1_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem1", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem1_read_proc;
+ res->write_proc = imem1_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem1_base;
+ for (i = 0; i < (1 << IMEM1_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem1_base = virt_to_phys((void *)jz_imem1_base);
+
+ printk("Total %dMB memory1 at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM1_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem1_base);
+ }
+ else
+ printk("NOT enough memory for imem1\n");
+
#endif /* #ifdef CONFIG_ANDROID_PMEM */
/* fpu */
diff --git a/arch/mips/jz4760/reset.c b/arch/mips/jz4760/reset.c
index 034e2563b61..b2bc72e7cac 100644
--- a/arch/mips/jz4760/reset.c
+++ b/arch/mips/jz4760/reset.c
@@ -21,12 +21,37 @@
void jz_restart(char *command)
{
- printk("Restarting after 4 ms\n");
+#if 1
+ printk("Restarting after 4ms\n");
+
REG_WDT_WCSR = WCSR_PRESCALE4 | WCSR_CLKIN_EXT;
REG_WDT_WCNT = 0;
- REG_WDT_WDR = JZ_EXTAL/1000; /* reset after 4ms */
+ REG_WDT_WDR = JZ_EXTAL / 1000; /* reset after 4ms */
REG_TCU_TSCR = TSCR_WDT; /* enable wdt clock */
REG_WDT_WCER = WCER_TCEN; /* wdt start */
+#else
+ printk("Restarting after 1s\n");
+ /* clear wakeup status register */
+ rtc_write_reg(RTC_HWRSR, 0x0);
+
+ /* Scratch pad register to be reserved */
+ rtc_write_reg(RTC_HSPR, HSPR_RTCV);
+
+ /* RTC Alarm Wakeup Enable */
+ rtc_set_reg(RTC_HWCR, HWCR_EALM);
+
+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */
+ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(60));
+
+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
+ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(100));
+
+ rtc_write_reg(RTC_RTCSAR, rtc_read_reg(RTC_RTCSR) + 1);
+ rtc_set_reg(RTC_RTCCR, RTCCR_AIE | RTCCR_AE | RTCCR_RTCE); /* alarm enable, alarm interrupt enable */
+
+ /* Put CPU to hibernate mode */
+ rtc_write_reg(RTC_HCR, HCR_PD);
+#endif
while (1);
}
diff --git a/drivers/i2c/busses/i2c-jz4760.c b/drivers/i2c/busses/i2c-jz4760.c
index 7d71799aa16..a7ae6e3b8fb 100644
--- a/drivers/i2c/busses/i2c-jz4760.c
+++ b/drivers/i2c/busses/i2c-jz4760.c
@@ -90,8 +90,8 @@ void i2c_jz_setclk(struct i2c_client *client,unsigned long i2cclk)
jz4760_i2c_speed[client_cnt].speed = 400;
}
- printk("Device 0x%2x with i2c speed:%dK\n",jz4760_i2c_speed[client_cnt].slave_addr,
- jz4760_i2c_speed[client_cnt].speed );
+ //printk("Device 0x%2x with i2c speed:%dK\n",jz4760_i2c_speed[client_cnt].slave_addr,
+ // jz4760_i2c_speed[client_cnt].speed );
client_cnt++;
}
@@ -240,46 +240,46 @@ Set_fclk_err:
static int i2c_set_clk(int i2c_clk, int I2C_ID)
{
- int dev_clk = cpm_get_clock(CGU_PCLK);
- int count = 0;
+ int dev_clk_khz = cpm_get_clock(CGU_PCLK) / 1000;
+ int cnt_high = 0; /* HIGH period count of the SCL clock */
+ int cnt_low = 0; /* LOW period count of the SCL clock */
+ int cnt_period = 0; /* period count of the SCL clock */
- if (i2c_clk < 0 || i2c_clk > 400)
+ if (i2c_clk <= 0 || i2c_clk > 400)
goto Set_clk_err;
- count = dev_clk/(i2c_clk*1000) - 23;
- if (count < 0)
- goto Set_clk_err;
+ cnt_period = dev_clk_khz / i2c_clk;
+ if (i2c_clk <= 100) {
+ /* i2c standard mode, the min LOW and HIGH period are 4700 ns and 4000 ns */
+ cnt_high = (cnt_period * 4000) / (4700 + 4000);
+ } else {
+ /* i2c fast mode, the min LOW and HIGH period are 1300 ns and 600 ns */
+ cnt_high = (cnt_period * 600) / (1300 + 600);
+ }
+
+ cnt_low = cnt_period - cnt_high;
if (i2c_clk <= 100) {
REG_I2C_CTRL(I2C_ID) = 0x43 | i2c_ctrl_rest[I2C_ID]; /* standard speed mode*/
- if (count%2 == 0) {
- REG_I2C_SHCNT(I2C_ID) = count/2 + 6 - 5;
- REG_I2C_SLCNT(I2C_ID) = count/2 + 8 + 5;
- } else {
- REG_I2C_SHCNT(I2C_ID) = count/2 + 6 -5;
- REG_I2C_SLCNT(I2C_ID) = count/2 + 8 +5 + 1;
- }
+ REG_I2C_SHCNT(I2C_ID) = I2CSHCNT_ADJUST(cnt_high);
+ REG_I2C_SLCNT(I2C_ID) = I2CSLCNT_ADJUST(cnt_low);
} else {
REG_I2C_CTRL(I2C_ID) = 0x45 | i2c_ctrl_rest[I2C_ID]; /* high speed mode*/
- if (count%2 == 0) {
- REG_I2C_FHCNT(I2C_ID) = count/2 + 6;
- REG_I2C_FLCNT(I2C_ID) = count/2 + 8;
- } else {
- REG_I2C_FHCNT(I2C_ID) = count/2 + 6;
- REG_I2C_FLCNT(I2C_ID) = count/2 + 8 + 1;
- }
+ REG_I2C_FHCNT(I2C_ID) = I2CFLCNT_ADJUST(cnt_high);
+ REG_I2C_FLCNT(I2C_ID) = I2CFLCNT_ADJUST(cnt_low);
}
- /* printk("i2c controler %d speed:%d\n",I2C_ID,i2c_speed[I2C_ID]); */
+
return 0;
Set_clk_err:
- printk("i2c set sclk faild,i2c_clk=%d,dev_clk=%d.\n",i2c_clk,dev_clk);
+ printk("i2c set sclk faild,i2c_clk=%d KHz,dev_clk=%dKHz.\n", i2c_clk, dev_clk_khz);
return -1;
}
static void i2c_set_target(unsigned char address,int I2C_ID)
{
+
while (!__i2c_txfifo_is_empty(I2C_ID) || __i2c_master_active(I2C_ID));
REG_I2C_TAR(I2C_ID) = address; /* slave id needed write only once */
}
@@ -293,13 +293,13 @@ static void i2c_init_as_master(int I2C_ID,unsigned char device)
for (i = 0; i < I2C_CLIENT_NUM; i++) {
if(device == jz4760_i2c_speed[i].slave_addr) {
i2c_set_clk(jz4760_i2c_speed[i].speed,I2C_ID);
- printk("----------------------Device 0x%2x with i2c speed:%dK\n",jz4760_i2c_speed[i].slave_addr,
- jz4760_i2c_speed[i].speed );
+ /* printk("-----Device 0x%2x with i2c speed:%dK\n",jz4760_i2c_speed[i].slave_addr,
+ jz4760_i2c_speed[i].speed ); */
break;
}
}
if (i == I2C_CLIENT_NUM) {
- printk("+++++++++++++++++++++++++++++++i2c speed 100K.\n");
+ /* printk("+++++++++++++++++++++++++++++++i2c speed 100K.\n"); */
i2c_set_clk(100,I2C_ID);
}
REG_I2C_INTM(I2C_ID) = 0x0; /*mask all interrupt*/
@@ -310,7 +310,7 @@ static void i2c_init_as_master(int I2C_ID,unsigned char device)
static int xfer_read(unsigned char device, unsigned char *buf,
int length, struct jz_i2c *i2c)
{
- int timeout,r_i = 0;
+ int timeout,timeout_1,r_i = 0;
int I2C_ID = i2c->id;
#if defined(CONFIG_TOUCHSCREEN_JZ_MT4D)
@@ -335,8 +335,10 @@ static int xfer_read(unsigned char device, unsigned char *buf,
goto R_timeout;
}
- while (r_cnt[I2C_ID]) {
- while (!(REG_I2C_STA(I2C_ID) & I2C_STA_RFNE)) {
+ timeout = TIMEOUT;
+ while (r_cnt[I2C_ID] && --timeout) {
+ timeout_1 = TIMEOUT;
+ while ((!(REG_I2C_STA(I2C_ID) & I2C_STA_RFNE)) && (--timeout_1)) {
if ((cmd_flag[I2C_ID] == -1) ||
(REG_I2C_INTST(I2C_ID) & I2C_INTST_TXABT) ||
REG_I2C_TXABRT(I2C_ID)) {
@@ -391,7 +393,8 @@ static int xfer_write(unsigned char device, unsigned char *buf,
cmd_flag[I2C_ID] = 0;
REG_I2C_INTM(I2C_ID) = 0x10;
- while (cmd_flag[I2C_ID] != 2){
+ timeout = TIMEOUT;
+ while ((cmd_flag[I2C_ID] != 2) && (timeout--)) {
if (cmd_flag[I2C_ID] == -1){
w_i = 1;
goto W_dev_err;
diff --git a/drivers/i2c/busses/i2c-jz47xx.c b/drivers/i2c/busses/i2c-jz47xx.c
index 4c936a13300..aa148f9d75e 100644
--- a/drivers/i2c/busses/i2c-jz47xx.c
+++ b/drivers/i2c/busses/i2c-jz47xx.c
@@ -1,15 +1,19 @@
+
/*
- * i2c_jz47xx.c for the INGENIC I2C bus access.
+ * I2C adapter for the INGENIC I2C bus access.
*
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
* Author: <cwjia@ingenic.cn>
- * The first Modified :<zhzhao@ingenic.cn>
- * Date:20091027
+ * Date:20091027 modified by <zhzhao@ingenic.cn>
+ * Date:20091105 modified by <hlguo@ingenic.cn>
+ * Date:20091120 modified by <hlguo@ingenic.cn>
+
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -35,7 +39,15 @@
#define I2C_WRITE 0
#define TIMEOUT 1000
-unsigned long sub_addr = 0;
+
+#define __reg_printk() printk("%s:%d:REG_I2C_CR=%x ,REG_I2C_SR = %x , REG_I2C_GR = %x\n",\
+ __FUNCTION__,__LINE__,REG_I2C_CR,REG_I2C_SR,REG_I2C_GR);
+
+/* The value of the most significant byte of sub_addr
+ * indicate the length of sub address:
+ * zero:1 byte, non-zero:2 bytes
+ */
+unsigned long sub_addr;
struct jz_i2c {
spinlock_t lock;
@@ -50,22 +62,52 @@ struct jz_i2c {
/*
* I2C bus protocol basic routines
*/
+
+static int check_i2c_is_busy(void)
+{
+ int timeout = TIMEOUT;
+ while (__i2c_is_busy() && --timeout){
+ udelay(10);
+ }
+ if (!timeout){
+ printk("i2c is busy---\n");
+ return -ETIMEDOUT;
+ }
+ else
+ return 0;
+}
+
+static void delay_i2c_clock(int count)
+{
+ volatile int i, j;
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < 2000; j++) {
+ ;
+ }
+ }
+}
+
static int i2c_put_data(unsigned char data)
{
- unsigned int timeout = TIMEOUT*10;
+ if (__i2c_check_drf()){
+ printk("WARNING: need clear DRF first\n");
+ __i2c_clear_drf();
+ delay_i2c_clock(1);
+ }
__i2c_write(data);
__i2c_set_drf();
- while (__i2c_check_drf() != 0 && timeout)
- timeout--;
- while (!__i2c_transmit_ended());
-
- timeout = TIMEOUT*10;
- while (!__i2c_received_ack() && timeout)
- timeout--;
- if (timeout){
+
+ do {
+ delay_i2c_clock(1);
+ } while (__i2c_check_drf() != 0);
+
+ /* wait for the i2c controller set the ack BIT*/
+ delay_i2c_clock(1);
+
+ if (__i2c_received_ack())
return 0;
- }
- else{
+ else {
+ printk("%s ERROR, get an NACK\n", __FUNCTION__);
return -ETIMEDOUT;
}
}
@@ -73,170 +115,116 @@ static int i2c_put_data(unsigned char data)
static int i2c_get_data(unsigned char *data, int ack)
{
- int timeout = TIMEOUT*10;
- if (!ack)
- __i2c_send_nack();
- else
- __i2c_send_ack();
+ while (__i2c_check_drf() == 0)
+ delay_i2c_clock(1);
- while (__i2c_check_drf() == 0 && timeout)
- timeout--;
- if (timeout) {
- if (!ack)
- __i2c_send_stop();
- *data = __i2c_read();
- __i2c_clear_drf();
- return 0;
- } else{
+ *data = __i2c_read();
- return -ETIMEDOUT;
+ /* wait for the i2c controller from TRANSFERRING to IDLE*/
+ delay_i2c_clock(1);
+
+ __i2c_clear_drf();
+
+ if (!ack) {
+ __i2c_send_nack();
+ __i2c_send_stop();
}
+
+ return 0;
}
/*
* I2C interface
*/
-void i2c_jz_setclk(unsigned int i2cclk)
+void i2c_jz_setclk(struct i2c_client *client,unsigned long i2cclk)
{
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
}
-
static int xfer_read(unsigned char device, unsigned char *buf, int length)
{
- int cnt = length;
- int timeout = 5;
+ int cnt = 0;
- /*eeprom device address transfer*/
- if(EEPROM_DEVICE_NUMBER == (device & 0xf0)){
- device = device | ((sub_addr & 0x0700) >> 8);
- sub_addr = sub_addr & 0xff;
+ if (length == 1)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+#if defined(CONFIG_TOUCHSCREEN_JZ_MT4D)
+ if ((device == 0x40) && __gpio_get_pin(GPIO_ATTN)) {
+ return -EBUSY;
}
-
-L_try_again:
-
- if (timeout < 0)
- goto L_timeout;
-
- __i2c_send_nack(); /* Master does not send ACK, slave sends it */
-
- __i2c_send_start();
-
-
- if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
- goto device_werr;
-
- if (i2c_put_data(sub_addr) < 0)
- goto address_err;
-
+#endif
__i2c_send_start();
+ __i2c_write((device << 1) | I2C_READ);
+ __i2c_set_drf();
- if (i2c_put_data((device << 1) | I2C_READ ) < 0)
- goto device_rerr;
-
-
- __i2c_send_ack(); /* Master sends ACK for continue reading */
-
-
- while (cnt) {
+ /* wait for i2c controller from IDLE to TRANSFERRING*/
+ delay_i2c_clock(1);
- if (cnt == 1) {
+ while (!__i2c_transmit_ended())
+ delay_i2c_clock(1);
+ if (!__i2c_received_ack())
+ goto xfer_read_err;
- if (i2c_get_data(buf, 0) < 0)
- break;
- } else {
+ do {
+ i2c_get_data(buf, (length - cnt) != 2);
- if (i2c_get_data(buf, 1) < 0){
- break;
- }
- }
- cnt--;
+ cnt++;
buf++;
- }
- __i2c_send_stop();
+ } while (cnt < length);
- return length - cnt;
- device_rerr:
- device_werr:
- address_err:
+ if (length == 1)
+ __i2c_send_stop();
- timeout --;
- __i2c_send_stop();
- goto L_try_again;
+ do {
+ __i2c_clear_drf();
+ /* wait for i2c controller from TRANSFERRING to IDLE*/
+ delay_i2c_clock(8);
+ } while (__i2c_check_drf());
-L_timeout:
+ return 0;
+
+xfer_read_err:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
+
return -ENODEV;
}
-
static int xfer_write(unsigned char device, unsigned char *buf, int length)
{
- int cnt = length;
- int cnt_in_pg;
- int timeout = 5;
- unsigned char *tmpbuf;
-
- /*eeprom device address transfer*/
- if(EEPROM_DEVICE_NUMBER == (device & 0xf0)){
- device = device | ((sub_addr & 0x0700) >> 8);
- sub_addr = sub_addr & 0xff;
- }
- __i2c_send_nack(); /* Master does not send ACK, slave sends it */
-
- W_try_again:
- if (timeout < 0)
- goto W_timeout;
+ int cnt = 0, ret = 0;
- cnt = length;
- tmpbuf = (unsigned char *)buf;
-
- start_write_page:
- cnt_in_pg = 0;
__i2c_send_start();
- if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
- goto device_err;
-
- if (i2c_put_data(sub_addr) < 0)
- goto address_err;
-
-
-
- while (cnt) {
- if (++cnt_in_pg > 8) {
- __i2c_send_stop();
- mdelay(1);
- sub_addr += 8;
- mdelay(2);// add 20091027
- goto start_write_page;
-
- }
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) {
+ ret = -ENODEV;
+ goto xfer_write_err;
+ }
+ while (cnt < length) {
+ ret = i2c_put_data(*buf);
+ if (ret < 0)
+ goto xfer_write_err;
- if (i2c_put_data(*tmpbuf) < 0)
- break;
- cnt--;
- tmpbuf++;
+ cnt++;
+ buf++;
}
- __i2c_send_stop();
- return length - cnt;
- device_err:
- address_err:
- timeout--;
- __i2c_send_stop();
- goto W_try_again;
-W_timeout:
- printk( "Write I2C device 0x%2x failed.\n", device);
+xfer_write_err:
__i2c_send_stop();
- return -ENODEV;
+ while (!__i2c_transmit_ended())
+ delay_i2c_clock(1);
+
+ if (ret == -ENODEV)
+ printk("Write I2C device 0x%2x failed\n", device);
+
+ return ret;
}
static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
{
int ret, i;
-
+
dev_dbg(&adap->dev, "jz47xx_xfer: processing %d messages:\n", num);
for (i = 0; i < num; i++) {
dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
@@ -245,11 +233,9 @@ static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
if (pmsg->len && pmsg->buf) { /* sanity check */
if (pmsg->flags & I2C_M_RD){
-
- ret = xfer_read(pmsg->addr, pmsg->buf, pmsg->len);
- }else{
-
- ret = xfer_write(pmsg->addr, pmsg->buf, pmsg->len);
+ ret = xfer_read(pmsg->addr, pmsg->buf, pmsg->len);
+ } else {
+ ret = xfer_write(pmsg->addr, pmsg->buf, pmsg->len);
}
if (ret)
return ret;
@@ -258,6 +244,7 @@ static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
dev_dbg(&adap->dev, "transfer complete\n");
pmsg++; /* next message */
}
+
return i;
}
@@ -273,14 +260,15 @@ static const struct i2c_algorithm i2c_jz_algorithm = {
static int i2c_jz_probe(struct platform_device *dev)
{
-
struct jz_i2c *i2c;
struct i2c_jz_platform_data *plat = dev->dev.platform_data;
int ret;
- __gpio_as_i2c(); // open i2c 20091027
- __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
- __i2c_enable();
+ __gpio_as_i2c();
+ __i2c_set_clk(jz_clocks.extalclk, 100000); /* default 100 KHz */
+ udelay(10);
+ __i2c_enable();
+ __reg_printk();
i2c = kzalloc(sizeof(struct jz_i2c), GFP_KERNEL);
if (!i2c) {
printk("There is no enough memory\n");
@@ -352,6 +340,6 @@ static void __exit i2c_adap_jz_exit(void)
}
MODULE_LICENSE("GPL");
-
-module_init(i2c_adap_jz_init);
+subsys_initcall(i2c_adap_jz_init);
+//arch_initcall(i2c_adap_jz_init);
module_exit(i2c_adap_jz_exit);
diff --git a/drivers/input/keyboard/jz_gpio_keypad.c b/drivers/input/keyboard/jz_gpio_keypad.c
index febfe5bd223..10e223dc9e8 100644
--- a/drivers/input/keyboard/jz_gpio_keypad.c
+++ b/drivers/input/keyboard/jz_gpio_keypad.c
@@ -52,10 +52,14 @@
/* Timer interval */
#define SCAN_INTERVAL 5
#define KEY_NUM ARRAY_SIZE(board_buttons)
+
+//#define KEY_FOR_MPLAYER
+#define KEY_FOR_CUR_TEST
/*
* GPIO Buttons,
* .code conforms with android/build/target/board/<boardname>/<boardname>-keypad.kl
*/
+#ifdef KEY_FOR_MPLAYER
static struct gpio_keys_button board_buttons[] = {
{
.gpio = GPIO_MP_VOLUMEUP,
@@ -100,6 +104,36 @@ static struct gpio_keys_button board_buttons[] = {
.active_low = ACTIVE_LOW_FORWARD,
},
};
+#endif /* KEY_FOR_MPLAYER */
+
+#ifdef KEY_FOR_CUR_TEST
+static struct gpio_keys_button board_buttons[] = {
+ {
+ .gpio = GPIO_SW3,
+ .code = KEY_F1,
+ .desc = "mp4 test",
+ .active_low = ACTIVE_LOW_SW3,
+ },
+ {
+ .gpio = GPIO_SW1,
+ .code = KEY_F2,
+ .desc = "gcc test",
+ .active_low = ACTIVE_LOW_SW1,
+ },
+ {
+ .gpio = GPIO_SW7,
+ .code = KEY_F3,
+ .desc = "suspend",
+ .active_low = ACTIVE_LOW_SW7,
+ },
+ {
+ .gpio = GPIO_SW8,
+ .code = KEY_F4,
+ .desc = "hibernation",
+ .active_low = ACTIVE_LOW_SW8,
+ },
+};
+#endif /* KEY_FOR_CUR_TEST */
static struct timer_list kbd_timer[KEY_NUM];
static int current_key[KEY_NUM];
@@ -154,7 +188,6 @@ static void button_timer_callback(unsigned long data)
state = __gpio_get_pin(gpio);
if (active_low ^ state) {
- printk("===>%d pressed!\n", gpio);
/* button pressed */
button_pressed[i] = 1;
input_report_key(input, code, 1);
@@ -164,7 +197,6 @@ static void button_timer_callback(unsigned long data)
dprintk("gpio %d down, code:%d \n",
gpio, code);
} else {
- printk("===>%d pressed!\n", gpio);
/* button released */
if (1 == button_pressed[i]) {
input_report_key(input, code, 0);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index dbb109f1a72..a2f99312b36 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -43,7 +43,7 @@ config TOUCHSCREEN_JZ
config JZ_ADKEY
bool "JZ ADKEY"
- depends on TOUCHSCREEN_JZ
+ depends on TOUCHSCREEN_JZ || TOUCHSCREEN_JZ4760
help
The AD value of the key is get by JZ SAR A/D controller when any ad key
is pressed down.
@@ -524,4 +524,10 @@ config TOUCHSCREEN_W90X900
To compile this driver as a module, choose M here: the
module will be called w90p910_ts.
+config TOUCHSCREEN_FT5X0X
+ tristate "FocalTech FT5X0X TouchScreen driver"
+ depends on I2C
+ help
+ lepus FocalTech FT5X0X TouchSreen Driver implemented by Ingenic.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 5770fc9222a..c9806d37582 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
+obj-$(CONFIG_TOUCHSCREEN_FT5X0X) += ft5x0x_ts.o
diff --git a/drivers/input/touchscreen/ft5x0x_ts.c b/drivers/input/touchscreen/ft5x0x_ts.c
new file mode 100644
index 00000000000..46c44e9339b
--- /dev/null
+++ b/drivers/input/touchscreen/ft5x0x_ts.c
@@ -0,0 +1,455 @@
+/*
+ * drivers/input/touchscreen/ft5x0x_ts.c
+ *
+ * FocalTech ft5x0x TouchScreen driver.
+ *
+ * Copyright (c) 2010 Ingenic Semiconductor 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.
+ *
+ *
+ * note: only support mulititouch liaoqizhen 2010-09-01
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/ft5x0x_ts.h>
+#include <asm/jzsoc.h>
+
+static struct i2c_client *this_client;
+static struct ft5x0x_ts_platform_data *pdata;
+
+//#define CONFIG_FT5X0X_MULTITOUCH 1U
+#define GPIO_FT5X0X_WAKE (32 * 5 + 10) //GPF10
+struct ts_event {
+ u16 x1;
+ u16 y1;
+ u16 x2;
+ u16 y2;
+ u16 pressure;
+ u8 touch_point;
+};
+
+struct ft5x0x_ts_data {
+ struct input_dev *input_dev;
+ struct ts_event event;
+ struct work_struct pen_event_work;
+ struct workqueue_struct *ts_workqueue;
+};
+
+static int ft5x0x_i2c_rxdata(char *rxdata, int length)
+{
+ int ret;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = rxdata,
+ },
+ {
+ .addr = this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxdata,
+ },
+ };
+
+ //msleep(1);
+ ret = i2c_transfer(this_client->adapter, msgs, 2);
+ if (ret < 0)
+ pr_err("msg %s i2c read error: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int ft5x0x_i2c_txdata(char *txdata, int length)
+{
+ int ret;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = length,
+ .buf = txdata,
+ },
+ };
+
+ msleep(1);
+ ret = i2c_transfer(this_client->adapter, msg, 1);
+ if (ret < 0)
+ pr_err("%s i2c write error: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int ft5x0x_set_reg(u8 addr, u8 para)
+{
+ u8 buf[3];
+ int ret = -1;
+
+ buf[0] = addr;
+ buf[1] = para;
+ ret = ft5x0x_i2c_txdata(buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! %#x ret: %d", buf[0], ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ft5x0x_ts_release(void)
+{
+
+ struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
+#ifdef CONFIG_FT5X0X_MULTITOUCH
+ int i = 0;
+ //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ for(i=0; i<2; ++i)
+ {
+ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_X, 0);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_Y, 0);
+ input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(data->input_dev);
+ }
+#else
+ input_report_abs(data->input_dev, ABS_PRESSURE, 0);
+ input_report_key(data->input_dev, BTN_TOUCH, 0);
+#endif
+ input_sync(data->input_dev);
+}
+
+static int ft5x0x_read_data(void)
+{
+ struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
+ struct ts_event *event = &data->event;
+ u8 buf[14] = {0};
+ int ret = -1;
+// int i = 0;
+
+#ifdef CONFIG_FT5X0X_MULTITOUCH
+ ret = ft5x0x_i2c_rxdata(buf, 13);
+#else
+ ret = ft5x0x_i2c_rxdata(buf, 7);
+#endif
+ if (ret < 0) {
+ printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ //printk("\n====ft5x0x_read_data==========\n");
+ //for(i=0;i<14;i++)
+ // printk(" %2x ", buf[i]);
+ //printk("\n====ft5x0x_read_data==========\n");
+
+ memset(event, 0, sizeof(struct ts_event));
+ event->touch_point = buf[2] & 0x03;
+
+ if (event->touch_point == 0) {
+// printk("==ft5x0x_ts_release=\n");
+ ft5x0x_ts_release();
+ return 1;
+ }
+
+#ifdef CONFIG_FT5X0X_MULTITOUCH
+ switch (event->touch_point) {
+ case 2:
+ event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
+ event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
+ case 1:
+ event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
+ event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
+ break;
+ default:
+ return -1;
+ }
+#else
+ if (event->touch_point == 1) {
+ event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
+ event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
+ }
+#endif
+ event->pressure = 200;
+
+ dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
+ event->x1, event->y1, event->x2, event->y2);
+
+ return 0;
+}
+
+static void ft5x0x_report_value(void)
+{
+ struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
+ struct ts_event *event = &data->event;
+
+#ifdef CONFIG_FT5X0X_MULTITOUCH
+ switch(event->touch_point) {
+ case 2:
+ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
+ input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(data->input_dev);
+ case 1:
+ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
+ input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(data->input_dev);
+ default:
+ break;
+ }
+#else /* CONFIG_FT5X0X_MULTITOUCH*/
+ if (event->touch_point == 1) {
+ input_report_abs(data->input_dev, ABS_X, event->x1);
+ input_report_abs(data->input_dev, ABS_Y, event->y1);
+ input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
+ }
+ input_report_key(data->input_dev, BTN_TOUCH, 1);
+#endif /* CONFIG_FT5X0X_MULTITOUCH*/
+ input_sync(data->input_dev);
+
+ dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
+ event->x1, event->y1, event->x2, event->y2);
+} /*end ft5x0x_report_value*/
+
+static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
+{
+ int ret = -1;
+
+ ret = ft5x0x_read_data();
+ if (ret == 0) {
+ ft5x0x_report_value();
+ }
+
+ msleep(1);
+ enable_irq(this_client->irq);
+}
+
+static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
+{
+ struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
+ disable_irq_nosync(this_client->irq);
+ if (!work_pending(&ft5x0x_ts->pen_event_work)) {
+ queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
+ }
+ return IRQ_HANDLED;
+}
+
+static int ft5x0x_init(void)
+{
+//#if DEBUG
+ printk("==ft5x0x_init==\n");
+//#endif
+ __gpio_as_output(GPIO_FT5X0X_WAKE);
+ __gpio_set_pin(GPIO_FT5X0X_WAKE);
+ mdelay(200);
+ __gpio_clear_pin(GPIO_FT5X0X_WAKE);
+ mdelay(200);
+ __gpio_set_pin(GPIO_FT5X0X_WAKE);
+
+ //ft5x0x_set_reg(FT5X0X_REG_STATE, STATE_WORK);
+ ft5x0x_set_reg(FT5X0X_REG_PMODE, PMODE_ACTIVE);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ft5x0x_ts_suspend(struct i2c_client *client, pm_message_t state)
+{
+ disable_irq_nosync(this_client->irq);
+ ft5x0x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
+
+ printk("==ft5x0x_ts_suspend=\n");
+ //__gpio_as_output(GPIO_FT5X0X_WAKE);
+ //__gpio_clear_pin(GPIO_FT5X0X_WAKE);
+
+ return 0;
+}
+
+static int ft5x0x_ts_resume(struct i2c_client *client)
+{
+ // __gpio_clear_pin(GPIO_FT5X0X_WAKE);
+ // msleep(10);
+ // __gpio_set_pin(GPIO_FT5X0X_WAKE);
+ printk("==ft5x0x_ts_resume=\n");
+ ft5x0x_init();
+ enable_irq(this_client->irq);
+
+ return 0;
+}
+#else
+#define ft5x0x_ts_suspend NULL
+#define ft5x0x_ts_resume NULL
+#endif //CONFIG_PM
+
+static int
+ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct ft5x0x_ts_data *ft5x0x_ts;
+ struct input_dev *input_dev;
+ int err = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err = -ENODEV;
+ goto exit_check_functionality_failed;
+ }
+
+ ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);
+ if (!ft5x0x_ts) {
+ err = -ENOMEM;
+ goto exit_alloc_data_failed;
+ }
+
+ this_client = client;
+ i2c_set_clientdata(client, ft5x0x_ts);
+ i2c_jz_setclk(client, 200*1000);
+
+ INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);
+ ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
+ if (!ft5x0x_ts->ts_workqueue) {
+ err = -ESRCH;
+ goto exit_create_singlethread;
+ }
+
+ pdata = client->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&client->dev, "%s: platform data is null\n", __func__);
+ goto exit_platform_data_null;
+ }
+
+ err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_DISABLED, "ft5x0x_ts", ft5x0x_ts);
+ if (err < 0) {
+ dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
+ goto exit_irq_request_failed;
+ }
+
+ __gpio_as_irq_fall_edge(pdata->intr);
+ disable_irq(this_client->irq);
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ err = -ENOMEM;
+ dev_err(&client->dev, "failed to allocate input device\n");
+ goto exit_input_dev_alloc_failed;
+ }
+
+ ft5x0x_ts->input_dev = input_dev;
+
+#ifdef CONFIG_FT5X0X_MULTITOUCH
+ set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
+ set_bit(ABS_MT_POSITION_X, input_dev->absbit);
+ set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
+ set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);
+
+ input_set_abs_params(input_dev,
+ ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
+#else
+ set_bit(ABS_X, input_dev->absbit);
+ set_bit(ABS_Y, input_dev->absbit);
+ set_bit(ABS_PRESSURE, input_dev->absbit);
+ set_bit(BTN_TOUCH, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);
+#endif
+
+ set_bit(EV_ABS, input_dev->evbit);
+ set_bit(EV_KEY, input_dev->evbit);
+
+ input_dev->name = FT5X0X_NAME; //dev_name(&client->dev)
+ err = input_register_device(input_dev);
+ if (err) {
+ dev_err(&client->dev,
+ "ft5x0x_ts_probe: failed to register input device: %s\n",
+ dev_name(&client->dev));
+ goto exit_input_register_device_failed;
+ }
+
+ // __gpio_as_output(GPIO_FT5X0X_WAKE);
+ // __gpio_set_pin(GPIO_FT5X0X_WAKE);
+ ft5x0x_init();
+ //msleep(50);
+ enable_irq(this_client->irq);
+
+ return 0;
+
+exit_input_register_device_failed:
+ input_free_device(input_dev);
+exit_input_dev_alloc_failed:
+ free_irq(client->irq, ft5x0x_ts);
+exit_irq_request_failed:
+exit_platform_data_null:
+ cancel_work_sync(&ft5x0x_ts->pen_event_work);
+ destroy_workqueue(ft5x0x_ts->ts_workqueue);
+exit_create_singlethread:
+ i2c_set_clientdata(client, NULL);
+ kfree(ft5x0x_ts);
+exit_alloc_data_failed:
+exit_check_functionality_failed:
+ return err;
+}
+
+static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
+{
+ struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);
+ free_irq(client->irq, ft5x0x_ts);
+ input_unregister_device(ft5x0x_ts->input_dev);
+ kfree(ft5x0x_ts);
+ cancel_work_sync(&ft5x0x_ts->pen_event_work);
+ destroy_workqueue(ft5x0x_ts->ts_workqueue);
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static const struct i2c_device_id ft5x0x_ts_id[] = {
+ { FT5X0X_NAME, 0 },
+};
+MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
+
+static struct i2c_driver ft5x0x_ts_driver = {
+ .probe = ft5x0x_ts_probe,
+ .remove = __devexit_p(ft5x0x_ts_remove),
+ .suspend = ft5x0x_ts_suspend,
+ .resume = ft5x0x_ts_resume,
+ .id_table = ft5x0x_ts_id,
+ .driver = {
+ .name = FT5X0X_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ft5x0x_ts_init(void)
+{
+ return i2c_add_driver(&ft5x0x_ts_driver);
+}
+
+static void __exit ft5x0x_ts_exit(void)
+{
+ i2c_del_driver(&ft5x0x_ts_driver);
+}
+
+module_init(ft5x0x_ts_init);
+module_exit(ft5x0x_ts_exit);
+
+MODULE_AUTHOR("<hsgou@ingenic.cn>");
+MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/jz4760_ts.c b/drivers/input/touchscreen/jz4760_ts.c
index 8f791a1065d..25e9cd275f9 100644
--- a/drivers/input/touchscreen/jz4760_ts.c
+++ b/drivers/input/touchscreen/jz4760_ts.c
@@ -45,7 +45,7 @@
#define TS_SCAN_INTERVAL 0
/* from qwerty.kl of android */
-#define DPAD_CENTER 232
+#define DPAD_CENTER 28
#define DPAD_DOWN 108
#define DPAD_UP 103
#define DPAD_LEFT 105
@@ -390,7 +390,6 @@ static irqreturn_t key_interrupt(int irq, void * dev_id)
{
struct jz_ts_t *ts = dev_id;
- dprintk("key_interrup entered.\n");
__gpio_as_input(GPIO_ADKEY_INT);
diff --git a/drivers/misc/jz_cim/Makefile b/drivers/misc/jz_cim/Makefile
index 998d04c1341..aaf359091fb 100644
--- a/drivers/misc/jz_cim/Makefile
+++ b/drivers/misc/jz_cim/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_JZ4750_AQUILA) += jz_cim_board_aquila.o
obj-$(CONFIG_JZ4760_ALTAIR) += jz_cim_board_altair.o
obj-$(CONFIG_JZ4760_PT701) += jz_cim_board_pt701.o
obj-$(CONFIG_JZ4760_LEPUS) += jz_cim_board_lepus.o
+obj-$(CONFIG_JZ4760_F4760) += jz_cim_board_f4760.o
obj-$(CONFIG_OV7690) += camera_source/ov7690/
obj-$(CONFIG_OV3640) += camera_source/ov3640/
diff --git a/drivers/misc/jz_cim/camera_source/ov3640/ov3640_camera.c b/drivers/misc/jz_cim/camera_source/ov3640/ov3640_camera.c
index df6a2d5087f..6fb474f6037 100644
--- a/drivers/misc/jz_cim/camera_source/ov3640/ov3640_camera.c
+++ b/drivers/misc/jz_cim/camera_source/ov3640/ov3640_camera.c
@@ -25,11 +25,13 @@ struct camera_sensor_desc ov3640_sensor_desc;
/* gpio init */
#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_FUWA1) || defined(CONFIG_JZ4750_AQUILA)/* board APUS */
-#define GPIO_CAMERA_RST (32*4+8)
+#define GPIO_CAMERA_RST (32*4+8) /* MCLK as reset */
#elif defined(CONFIG_JZ4760_ALTAIR)
#define GPIO_CAMERA_RST (32*4+13) /*GPE13*/
#elif defined(CONFIG_JZ4760_LEPUS)
#define GPIO_CAMERA_RST (32*1 + 26) /* GPB26 */
+#elif defined(CONFIG_JZ4760_F4760) /* JZ4760 FPGA */
+#define GPIO_CAMERA_RST (32*1+9) /* CIM_MCLK as reset */
#else
#error "ov3640/ov3640_camera.c , please define camera for your board."
#endif
@@ -494,6 +496,7 @@ int ov3640_sensor_probe(void)
int retval = 0;
ov3640_power_up();
ov3640_reset();
+ mdelay(10);
retval=sensor_read_reg16(ov3640_sensor_desc.client,0x300a);
ov3640_power_down();
@@ -516,7 +519,8 @@ static int ov3640_probe(struct i2c_client *client, const struct i2c_device_id *i
{
printk("=====>enter ov3640 probe\n");
ov3640_sensor_desc.client = client;
- sensor_set_i2c_speed(client,400000);//set ov3640 i2c speed : 400khz
+ sensor_set_i2c_speed(client,400000);// set ov3640 i2c speed : 400khz
+ //sensor_set_i2c_speed(client,5000);// F4760: set ov3640 i2c speed : 5khz
camera_sensor_register(&ov3640_sensor_desc);
return 0;
@@ -534,7 +538,7 @@ struct camera_sensor_ops ov3640_sensor_ops = {
struct resolution_info ov3640_resolution_table[] = {
- {2048,1536,16,PIXEL_FORMAT_YUV422I},
+ // {2048,1536,16,PIXEL_FORMAT_YUV422I},
{1600,1200,16,PIXEL_FORMAT_YUV422I},
{1280,1024,16,PIXEL_FORMAT_YUV422I},
{1024,768,16,PIXEL_FORMAT_YUV422I},
@@ -559,11 +563,27 @@ struct camera_sensor_desc ov3640_sensor_desc = {
.resolution_table = ov3640_resolution_table,
.resolution_table_nr=ARRAY_SIZE(ov3640_resolution_table),
+#if 0
.capture_parm = {2048, 1536, 16,PIXEL_FORMAT_YUV422I},
.max_capture_parm = {2048, 1536, 16,PIXEL_FORMAT_YUV422I},
.preview_parm = {1024,768, 16,PIXEL_FORMAT_YUV422I},
.max_preview_parm = {1024,768, 16,PIXEL_FORMAT_YUV422I},
+#else
+#if 0
+ .capture_parm = {1600, 1200, 16,PIXEL_FORMAT_YUV422I},
+ .max_capture_parm = {1600, 1200, 16,PIXEL_FORMAT_YUV422I},
+
+ .preview_parm = {1024, 768, 16,PIXEL_FORMAT_YUV422I},
+ .max_preview_parm = {1024 , 768, 16,PIXEL_FORMAT_YUV422I},
+#else
+ .capture_parm = {800, 600, 16,PIXEL_FORMAT_YUV422I},
+ .max_capture_parm = {800, 600, 16,PIXEL_FORMAT_YUV422I},
+
+ .preview_parm = {640, 480, 16,PIXEL_FORMAT_YUV422I},
+ .max_preview_parm = {640 , 480, 16,PIXEL_FORMAT_YUV422I},
+#endif
+#endif
.cfg_info = {
.configure_register= 0x0
diff --git a/drivers/misc/jz_cim/camera_source/ov3640/ov3640_set.c b/drivers/misc/jz_cim/camera_source/ov3640/ov3640_set.c
index c860e9569cc..3a490921db7 100644
--- a/drivers/misc/jz_cim/camera_source/ov3640/ov3640_set.c
+++ b/drivers/misc/jz_cim/camera_source/ov3640/ov3640_set.c
@@ -214,7 +214,7 @@ void init_set(struct i2c_client *client)
sensor_write_reg16(client,0x304c,0x85);
sensor_write_reg16(client,0x300e,0x39);
sensor_write_reg16(client,0x300f,0xa1);//12.5fps -> 25fps
- sensor_write_reg16(client,0x3011,0x00);
+ sensor_write_reg16(client,0x3011,0x00); /* default 0x00, change ov3640 PCLK DIV here --- by Lutts*/
sensor_write_reg16(client,0x3010,0x81);
sensor_write_reg16(client,0x302e,0xA0);
sensor_write_reg16(client,0x302d,0x00);
@@ -259,13 +259,15 @@ void capture_reg_set(struct i2c_client *client)
sensor_write_reg16(client,0x3010,0x20);
sensor_write_reg16(client,0x304c,0x81);
sensor_write_reg16(client,0x3366,0x10);
- sensor_write_reg16(client,0x3011,0x00);
+ sensor_write_reg16(client,0x3011,0x00); /* default 0x00, change ov3640 PCLK DIV here --- by lutts */
sensor_write_reg16(client,0x3f00,0x02);//disable overlay
}
-void preview_set(struct i2c_client *client)
-{
+void preview_set(struct i2c_client *client)
+{
+ unsigned char value;
+
if(mode == CAMERA_MODE_PREVIEW) // 0 for preview
return;
@@ -304,7 +306,7 @@ void preview_set(struct i2c_client *client)
sensor_write_reg16(client,0x300e,0x39);
sensor_write_reg16(client,0x300f,0xa1);//12.5fps -> 25fps
sensor_write_reg16(client,0x3010,0x81);
- sensor_write_reg16(client,0x3011,0x00);
+ sensor_write_reg16(client,0x3011,0x00); /* default: 0x00, change ov3640 PCLK here --- by Lutts */
sensor_write_reg16(client,0x302e,0xa0);
sensor_write_reg16(client,0x302d,0x00);
sensor_write_reg16(client,0x3071,0x82);
@@ -313,18 +315,64 @@ void preview_set(struct i2c_client *client)
sensor_write_reg16(client,0x3100,0x02);
sensor_write_reg16(client,0x3301,0xde);
sensor_write_reg16(client,0x3304,0xfc);
- sensor_write_reg16(client,0x3400,0x00);
- sensor_write_reg16(client,0x3404,0x00);
+
+ /* reg 0x3404 */
+#define YUV422_YUYV 0x00
+#define YUV422_YVYU 0X01
+#define YUV422_UYVY 0x02
+#define YUV422_VYUY 0x03
+
+#define YUV444_YUV 0x0E
+#define YUV444_YVU 0x0F
+#define YUV444_UYV 0x1C
+#define YUV444_VYU 0x1D
+#define YUV444_UVY 0x1E
+#define YUV444_VUY 0x1F
+ sensor_write_reg16(client,0x3400,0x00); /* source */
+ //sensor_write_reg16(client,0x3404,0x00); /* fmt control */
+ sensor_write_reg16(client,0x3404,YUV422_YUYV);
+ //sensor_write_reg16(client,0x3404, YUV422_YVYU);
+ //sensor_write_reg16(client,0x3404, YUV422_UYVY);
+ //sensor_write_reg16(client,0x3404, YUV422_VYUY);
+
+ //sensor_write_reg16(client,0x3404, YUV444_YUV);
+ //sensor_write_reg16(client,0x3404, YUV444_YVU);
+ //sensor_write_reg16(client,0x3404, YUV444_UVY);
+ //sensor_write_reg16(client,0x3404, YUV444_VUY);
+
sensor_write_reg16(client,0x3600,0xc0);
sensor_write_reg16(client,0x3013,0xf7);
+
+
+ /* slcao */
+ /* HSYNC mode */
+#if 0
+ value = sensor_read_reg16(client, 0x3646);
+ value |= 0x40;
+
+ /* test pattern(color bar) */
+ value = sensor_read_reg16(client, 0x307b);
+ value &= ~0x3;
+ sensor_write_reg16(client, 0x307b, value | 0x2);
+
+ value = sensor_read_reg16(client, 0x306c);
+ sensor_write_reg16(client, 0x306c, value & ~0x10);
+
+ value = sensor_read_reg16(client, 0x307d);
+ sensor_write_reg16(client,0x307d,value | 0x80);
+
+ //value = sensor_read_reg16(client, 0x3080);
+ //sensor_write_reg16(client,0x3080,value | 0x80);
+#endif
+
/************************************************************/
ov3640_stop_focus(client);
mode = CAMERA_MODE_PREVIEW;
-}
+}
void size_switch(struct i2c_client *client,int width,int height,int setmode)
{
@@ -398,7 +446,7 @@ void size_switch(struct i2c_client *client,int width,int height,int setmode)
sensor_write_reg16(client,0x3302, 0xef);
sensor_write_reg16(client,0x335f, 0x34);
sensor_write_reg16(client,0x3360, 0x0c);
- sensor_write_reg16(client,0x3361, 0x04);
+ sensor_write_reg16(client,0x3361, 0x04);
}
sensor_write_reg16(client,0x3362, (unsigned char)((((width+8)>>8) & 0x0F) + (((height+4)>>4)&0x70)) );
@@ -419,33 +467,33 @@ void size_switch(struct i2c_client *client,int width,int height,int setmode)
void capture_set(struct i2c_client *client)
{
uint8_t reg0x3001;
- uint8_t reg0x3002,reg0x3003,reg0x3013;
- uint8_t reg0x3028,reg0x3029;
- uint8_t reg0x302a,reg0x302b;
+ uint8_t reg0x3002,reg0x3003,reg0x3013;
+ uint8_t reg0x3028,reg0x3029;
+ uint8_t reg0x302a,reg0x302b;
uint8_t reg0x302d,reg0x302e;
- uint16_t shutter;
- uint16_t extra_lines, Preview_Exposure;
- uint16_t Preview_Gain16;
- uint16_t Preview_dummy_pixel;
+ uint16_t shutter;
+ uint16_t extra_lines, Preview_Exposure;
+ uint16_t Preview_Gain16;
+ uint16_t Preview_dummy_pixel;
uint16_t Capture_max_gain16, Capture_banding_Filter;
- uint16_t Preview_line_width,Capture_line_width,Capture_maximum_shutter;
- uint16_t Capture_Exposure;
-
- uint8_t Mclk =24; //MHz
- uint8_t Preview_PCLK_frequency, Capture_PCLK_frequency;
- uint32_t Gain_Exposure,Capture_Gain16;
- uint8_t Gain;
-
- uint8_t capture_max_gain = 31;// parm,from 4* gain to 2* gain
- uint8_t Default_Reg0x3028 = 0x09;
- uint8_t Default_Reg0x3029 = 0x47;
- uint8_t Cap_Default_Reg0x302a = 0x06;
- uint8_t Cap_Default_Reg0x302b = 0x20;
- uint16_t capture_Dummy_pixel = 0;
- uint16_t capture_dummy_lines = 0;
+ uint16_t Preview_line_width,Capture_line_width,Capture_maximum_shutter;
+ uint16_t Capture_Exposure;
+
+ uint8_t Mclk =24; //MHz
+ uint8_t Preview_PCLK_frequency, Capture_PCLK_frequency;
+ uint32_t Gain_Exposure,Capture_Gain16;
+ uint8_t Gain;
+
+ uint8_t capture_max_gain = 31;// parm,from 4* gain to 2* gain
+ uint8_t Default_Reg0x3028 = 0x09;
+ uint8_t Default_Reg0x3029 = 0x47;
+ uint8_t Cap_Default_Reg0x302a = 0x06;
+ uint8_t Cap_Default_Reg0x302b = 0x20;
+ uint16_t capture_Dummy_pixel = 0;
+ uint16_t capture_dummy_lines = 0;
//uint16_t Default_XGA_Line_Width = 1188;
- uint16_t Default_QXGA_Line_Width = 2376;
- uint16_t Default_QXGA_maximum_shutter = 1563;
+ uint16_t Default_QXGA_Line_Width = 2376;
+ uint16_t Default_QXGA_maximum_shutter = 1563;
if(mode == CAMERA_MODE_CAPTURE) // 1 for capture
return;
@@ -456,43 +504,43 @@ void capture_set(struct i2c_client *client)
- // 1. Stop Preview
- //Stop AE/AG
+ // 1. Stop Preview
+ //Stop AE/AG
reg0x3013 = sensor_read_reg16(client,0x3013);
reg0x3013 = reg0x3013 & 0xf8;
sensor_write_reg16(client,0x3013,reg0x3013);
- //Read back preview shutter
+ //Read back preview shutter
reg0x3002 = sensor_read_reg16(client,0x3002);
reg0x3003 = sensor_read_reg16(client,0x3003);
- shutter = (reg0x3002 << 8) + reg0x3003;
+ shutter = (reg0x3002 << 8) + reg0x3003;
- //Read back extra line
+ //Read back extra line
reg0x302d = sensor_read_reg16(client,0x302d);
reg0x302e = sensor_read_reg16(client,0x302e);
- extra_lines = reg0x302e + (reg0x302d << 8);
- Preview_Exposure = shutter + extra_lines;
+ extra_lines = reg0x302e + (reg0x302d << 8);
+ Preview_Exposure = shutter + extra_lines;
- //Read Back Gain for preview
+ //Read Back Gain for preview
reg0x3001 = sensor_read_reg16(client,0x3001);
- Preview_Gain16 = (((reg0x3001 & 0xf0)>>4) + 1) * (16 + (reg0x3001 & 0x0f));
+ Preview_Gain16 = (((reg0x3001 & 0xf0)>>4) + 1) * (16 + (reg0x3001 & 0x0f));
- //Read back dummy pixels
+ //Read back dummy pixels
reg0x3028 = sensor_read_reg16(client,0x3028);
reg0x3029 = sensor_read_reg16(client,0x3029);
- Preview_dummy_pixel = (((reg0x3028 - Default_Reg0x3028) & 0xf0)<<8) + reg0x3029-Default_Reg0x3029;
+ Preview_dummy_pixel = (((reg0x3028 - Default_Reg0x3028) & 0xf0)<<8) + reg0x3029-Default_Reg0x3029;
- Preview_PCLK_frequency = (64 - 50) * 1 * Mclk / 1.5 / 2 / 2;
+ Preview_PCLK_frequency = (64 - 50) * 1 * Mclk / 1.5 / 2 / 2;
Capture_PCLK_frequency = (64 - 57) * 1 * Mclk / 1.5 / 2 / 3; // 7.5fps 56MHz
- // 2.Calculate Capture Exposure
+ // 2.Calculate Capture Exposure
Capture_max_gain16 = capture_max_gain;
- //In common, Preview_dummy_pixel,Preview_dummy_line,Capture_dummy_pixel and
- //Capture_dummy_line can be set to zero.
+ //In common, Preview_dummy_pixel,Preview_dummy_line,Capture_dummy_pixel and
+ //Capture_dummy_line can be set to zero.
Preview_line_width = Default_QXGA_Line_Width + Preview_dummy_pixel ;
- Capture_line_width = Default_QXGA_Line_Width + capture_Dummy_pixel;
+ Capture_line_width = Default_QXGA_Line_Width + capture_Dummy_pixel;
if(extra_lines>5000)
{
Capture_Exposure = 16*11/10*Preview_Exposure * Capture_PCLK_frequency/Preview_PCLK_frequency *Preview_line_width/Capture_line_width;
@@ -504,137 +552,137 @@ void capture_set(struct i2c_client *client)
else if(extra_lines>100)
{
Capture_Exposure = 16*20/10*Preview_Exposure * Capture_PCLK_frequency/Preview_PCLK_frequency *Preview_line_width/Capture_line_width;
- }
+ }
else
{
Capture_Exposure = 16*22/10*Preview_Exposure * Capture_PCLK_frequency/Preview_PCLK_frequency *Preview_line_width/Capture_line_width;
}
if(Capture_Exposure == 0)
- {
+ {
Capture_Exposure =1 ;
}
- //Calculate banding filter value
- //If (50Hz) {Capture_banding_Filter = Capture_PCLK_Frequency/ 100/ (2*capture_line_width);
- //else {(60Hz)Capture_banding_Filter = Capture_PCLK_frequency /120 /(2*capture_line_width);
- Capture_banding_Filter = (uint16_t)((float)Capture_PCLK_frequency * 1000000 / 100/ (2*Capture_line_width)+0.5);
+ //Calculate banding filter value
+ //If (50Hz) {Capture_banding_Filter = Capture_PCLK_Frequency/ 100/ (2*capture_line_width);
+ //else {(60Hz)Capture_banding_Filter = Capture_PCLK_frequency /120 /(2*capture_line_width);
+ Capture_banding_Filter = (uint16_t)((float)Capture_PCLK_frequency * 1000000 / 100/ (2*Capture_line_width)+0.5);
- Capture_maximum_shutter = (Default_QXGA_maximum_shutter + capture_dummy_lines)/Capture_banding_Filter;
- Capture_maximum_shutter = Capture_maximum_shutter * Capture_banding_Filter;
+ Capture_maximum_shutter = (Default_QXGA_maximum_shutter + capture_dummy_lines)/Capture_banding_Filter;
+ Capture_maximum_shutter = Capture_maximum_shutter * Capture_banding_Filter;
- //redistribute gain and exposure
- Gain_Exposure = Preview_Gain16 * Capture_Exposure/16;
+ //redistribute gain and exposure
+ Gain_Exposure = Preview_Gain16 * Capture_Exposure/16;
if( Gain_Exposure ==0)
- {
- Gain_Exposure =1;
+ {
+ Gain_Exposure =1;
}
- if (Gain_Exposure < (Capture_banding_Filter * 16))
- {
- // Exposure < 1/100
- Capture_Exposure = Gain_Exposure /16;
- Capture_Gain16 = (Gain_Exposure*2 + 1)/Capture_Exposure/2;
- }
- else
-
- {
- if (Gain_Exposure > Capture_maximum_shutter * 16)
- {
- // Exposure > Capture_Maximum_Shutter
- Capture_Exposure = Capture_maximum_shutter;
- Capture_Gain16 = (Gain_Exposure*2 + 1)/Capture_maximum_shutter/2;
-
- if (Capture_Gain16 > Capture_max_gain16)
- {
- // gain reach maximum, insert extra line
- Capture_Exposure = Gain_Exposure*11/10/Capture_max_gain16;
- // For 50Hz, Exposure = n/100; For 60Hz, Exposure = n/120
- Capture_Exposure = Capture_Exposure/Capture_banding_Filter;
- Capture_Exposure =Capture_Exposure * Capture_banding_Filter;
- Capture_Gain16 = (Gain_Exposure *2+1)/ Capture_Exposure/2;
- }
- }
- else
- {
- // 1/100(120) < Exposure < Capture_Maximum_Shutter, Exposure = n/100(120)
- Capture_Exposure = Gain_Exposure/16/Capture_banding_Filter;
- Capture_Exposure = Capture_Exposure * Capture_banding_Filter;
- Capture_Gain16 = (Gain_Exposure*2 +1) / Capture_Exposure/2;
- }
- }
-
- // 3.Switch to QXGA
- /*// Write registers, change to QXGA resolution.*/
+ if (Gain_Exposure < (Capture_banding_Filter * 16))
+ {
+ // Exposure < 1/100
+ Capture_Exposure = Gain_Exposure /16;
+ Capture_Gain16 = (Gain_Exposure*2 + 1)/Capture_Exposure/2;
+ }
+ else
+
+ {
+ if (Gain_Exposure > Capture_maximum_shutter * 16)
+ {
+ // Exposure > Capture_Maximum_Shutter
+ Capture_Exposure = Capture_maximum_shutter;
+ Capture_Gain16 = (Gain_Exposure*2 + 1)/Capture_maximum_shutter/2;
+
+ if (Capture_Gain16 > Capture_max_gain16)
+ {
+ // gain reach maximum, insert extra line
+ Capture_Exposure = Gain_Exposure*11/10/Capture_max_gain16;
+ // For 50Hz, Exposure = n/100; For 60Hz, Exposure = n/120
+ Capture_Exposure = Capture_Exposure/Capture_banding_Filter;
+ Capture_Exposure =Capture_Exposure * Capture_banding_Filter;
+ Capture_Gain16 = (Gain_Exposure *2+1)/ Capture_Exposure/2;
+ }
+ }
+ else
+ {
+ // 1/100(120) < Exposure < Capture_Maximum_Shutter, Exposure = n/100(120)
+ Capture_Exposure = Gain_Exposure/16/Capture_banding_Filter;
+ Capture_Exposure = Capture_Exposure * Capture_banding_Filter;
+ Capture_Gain16 = (Gain_Exposure*2 +1) / Capture_Exposure/2;
+ }
+ }
+
+ // 3.Switch to QXGA
+ /*// Write registers, change to QXGA resolution.*/
/***********************************************************************/
capture_reg_set(client);
- // 4.Write Registers
- //write dummy pixels
+ // 4.Write Registers
+ //write dummy pixels
reg0x3029 = sensor_read_reg16(client,0x3029);
- reg0x3029 = reg0x3029 + (capture_Dummy_pixel & 0x00ff);
+ reg0x3029 = reg0x3029 + (capture_Dummy_pixel & 0x00ff);
reg0x3028 = sensor_read_reg16(client,0x3028);
- reg0x3028 = (reg0x3028 & 0x0f) | ((capture_Dummy_pixel & 0x0f00)>>4);
+ reg0x3028 = (reg0x3028 & 0x0f) | ((capture_Dummy_pixel & 0x0f00)>>4);
sensor_write_reg16(client,0x3028, reg0x3028);
sensor_write_reg16(client,0x3029, reg0x3029);
- //Write Dummy Lines
- reg0x302b = (capture_dummy_lines & 0x00ff ) + Cap_Default_Reg0x302b;
- reg0x302a =( capture_dummy_lines >>8 ) + Cap_Default_Reg0x302a;
+ //Write Dummy Lines
+ reg0x302b = (capture_dummy_lines & 0x00ff ) + Cap_Default_Reg0x302b;
+ reg0x302a =( capture_dummy_lines >>8 ) + Cap_Default_Reg0x302a;
sensor_write_reg16(client,0x302a, reg0x302a);
sensor_write_reg16(client,0x302b, reg0x302b);
- //Write Exposure
- if (Capture_Exposure > Capture_maximum_shutter)
- {
- shutter = Capture_maximum_shutter;
+ //Write Exposure
+ if (Capture_Exposure > Capture_maximum_shutter)
+ {
+ shutter = Capture_maximum_shutter;
extra_lines = Capture_Exposure - Capture_maximum_shutter;
}
- else
- {
- shutter = Capture_Exposure;
- extra_lines = 0;
- }
-
- reg0x3003 = shutter & 0x00ff;
- reg0x3002 = (shutter>>8) & 0x00ff;
+ else
+ {
+ shutter = Capture_Exposure;
+ extra_lines = 0;
+ }
+
+ reg0x3003 = shutter & 0x00ff;
+ reg0x3002 = (shutter>>8) & 0x00ff;
sensor_write_reg16(client,0x3003, reg0x3003);
sensor_write_reg16(client,0x3002, reg0x3002);
- // Write extra line
- reg0x302e= extra_lines & 0x00ff;
- reg0x302d= extra_lines >> 8;
+ // Write extra line
+ reg0x302e= extra_lines & 0x00ff;
+ reg0x302d= extra_lines >> 8;
sensor_write_reg16(client,0x302d, reg0x302d);
sensor_write_reg16(client,0x302e, reg0x302e);
- // Write Gain
- Gain = 0;
- if (Capture_Gain16 > 31)
- {
- Capture_Gain16 = Capture_Gain16 /2;
- Gain = 0x10;
- }
- if (Capture_Gain16 > 31)
- {
- Capture_Gain16 = Capture_Gain16 /2;
- Gain = Gain| 0x20;
- }
- if (Capture_Gain16 > 31)
- {
- Capture_Gain16 = Capture_Gain16 /2;
- Gain = Gain | 0x40;
- }
- if (Capture_Gain16 > 31)
- {
- Capture_Gain16 = Capture_Gain16 /2;
- Gain = Gain | 0x80;
- }
- if (Capture_Gain16 > 16)
- {
- Gain = Gain | ((uint32_t)Capture_Gain16 -16);
- }
+ // Write Gain
+ Gain = 0;
+ if (Capture_Gain16 > 31)
+ {
+ Capture_Gain16 = Capture_Gain16 /2;
+ Gain = 0x10;
+ }
+ if (Capture_Gain16 > 31)
+ {
+ Capture_Gain16 = Capture_Gain16 /2;
+ Gain = Gain| 0x20;
+ }
+ if (Capture_Gain16 > 31)
+ {
+ Capture_Gain16 = Capture_Gain16 /2;
+ Gain = Gain | 0x40;
+ }
+ if (Capture_Gain16 > 31)
+ {
+ Capture_Gain16 = Capture_Gain16 /2;
+ Gain = Gain | 0x80;
+ }
+ if (Capture_Gain16 > 16)
+ {
+ Gain = Gain | ((uint32_t)Capture_Gain16 -16);
+ }
sensor_write_reg16(client,0x3001, Gain+0x05);
// mdelay(500);
diff --git a/drivers/misc/jz_cim/camera_source/ov7690/ov7690_camera.c b/drivers/misc/jz_cim/camera_source/ov7690/ov7690_camera.c
index 6828be308a1..cf66aa156b8 100644
--- a/drivers/misc/jz_cim/camera_source/ov7690/ov7690_camera.c
+++ b/drivers/misc/jz_cim/camera_source/ov7690/ov7690_camera.c
@@ -23,9 +23,12 @@
#elif defined(CONFIG_JZ4760_ALTAIR)
#define OV7690_RESET_PIN
#define OV7690_PD_PIN (1*32+9) //GPB9
-#elif define(CONFIG_JZ4760_LEPUS)
+#elif defined(CONFIG_JZ4760_LEPUS)
#define OV7690_RESET_PIN (32 * 1 + 26) /* GPB26 */
#define OV7690_PD_PIN (32 * 1 + 27) /* GPB27 */
+#elif defined(CONFIG_JZ4750_APUS)
+#define OV7690_RESET_PIN (32 * 4 + 16) /* GPe16 */
+#define OV7690_PD_PIN (32 * 4 + 17) /* GPe17 */
#endif
diff --git a/drivers/misc/jz_cim/jz_cim_board_apus.c b/drivers/misc/jz_cim/jz_cim_board_apus.c
index 850894b25af..a3d8114ede3 100644
--- a/drivers/misc/jz_cim/jz_cim_board_apus.c
+++ b/drivers/misc/jz_cim/jz_cim_board_apus.c
@@ -1,16 +1,16 @@
-#include <asm/jzsoc.h>
+#include <asm/jzsoc.h>
-#define GPIO_CAMERA_RST (32*4+8) /*GPE8 mclk*/
+//#define GPIO_CAMERA_RST (32*4+8) /*GPE8 mclk*/
void cim_power_off(void)
{
- __camera_power_off();
+ __cpm_stop_cim();
}
void cim_power_on(void)
{
- __camera_power_on();
+ __cpm_start_cim();
}
diff --git a/drivers/misc/jz_cim/jz_cim_board_f4760.c b/drivers/misc/jz_cim/jz_cim_board_f4760.c
new file mode 100644
index 00000000000..74d3a9af2fd
--- /dev/null
+++ b/drivers/misc/jz_cim/jz_cim_board_f4760.c
@@ -0,0 +1,17 @@
+#include <asm/jzsoc.h>
+
+void cim_power_off(void)
+{
+ cpm_stop_clock(CGM_CIM);
+}
+
+void cim_power_on(void)
+{
+ cpm_stop_clock(CGM_CIM);
+ cpm_set_clock(CGU_CIMCLK,24000000);
+ cpm_start_clock(CGM_CIM);
+}
+
+
+
+
diff --git a/drivers/misc/jz_cim/jz_cim_core.c b/drivers/misc/jz_cim/jz_cim_core.c
index 443215aa896..3f7ed7cd8cf 100644
--- a/drivers/misc/jz_cim/jz_cim_core.c
+++ b/drivers/misc/jz_cim/jz_cim_core.c
@@ -42,10 +42,25 @@
#include "jz_cim_core.h"
#include "jz_sensor.h"
-MODULE_AUTHOR("sonil<ztyan@ingenic.cn>");
+MODULE_AUTHOR("Lutts Cao<slcao@ingenic.cn>");
MODULE_DESCRIPTION("Ingenic Camera interface driver");
MODULE_LICENSE("GPL");
+//#define CONFIG_TEST_JZ4760E y
+
+//#define CIM_INTR_SOF_EN
+#define CIM_INTR_EOF_EN
+//#define CIM_INTR_EEOF_EN
+//#define CIM_INTR_STOP_EN
+//#define CIM_INTR_TRIG_EN
+#define CIM_INTR_OF_EN
+
+//#define CIM_SAFE_DISABLE
+
+#if defined(CONFIG_SOC_JZ4750)
+#undef CIM_INTR_EEOF_EN
+#endif
+
#define CIM_DEBUG
#define CIM_I_DEBUG
@@ -53,7 +68,11 @@ MODULE_LICENSE("GPL");
#undef CIM_DEBUG
#ifdef CIM_DEBUG
+#if defined(CONFIG_TEST_JZ4760E)
+#define dprintk(x...) do{printk("CIM(test jz4760e)---\t");printk(x);}while(0)
+#else
#define dprintk(x...) do{printk("CIM---\t");printk(x);}while(0)
+#endif
#else
#define dprintk(x...)
#endif
@@ -77,9 +96,19 @@ enum {TRUE=1,FALSE=0};
struct cim_desc {
u32 nextdesc; // Physical address of next desc
- u32 framebuf; // Physical address of frame buffer
+#if defined(CONFIG_TEST_JZ4760E)
u32 frameid; // Frame ID
- u32 dmacmd; // DMA command
+ u32 framebuf; // Physical address of frame buffer, when SEP=1, it's y framebuffer
+#else
+ u32 framebuf; // Physical address of frame buffer, when SEP=1, it's y framebuffer
+ u32 frameid; // Frame ID
+#endif
+ u32 dmacmd; // DMA command, when SEP=1, it's y cmd
+ /* only used when SEP = 1 */
+ u32 cb_frame;
+ u32 cb_len;
+ u32 cr_frame;
+ u32 cr_len;
};
/*
@@ -115,6 +144,18 @@ static struct cim_device *jz_cim;
static int snapshot_flag __read_mostly = 0;
+static unsigned int dmacmd_intr_flag = 0
+#ifdef CIM_INTR_SOF_EN
+ | CIM_CMD_SOFINT
+#endif
+#ifdef CIM_INTR_EOF_EN
+ | CIM_CMD_EOFINT
+#endif
+#ifdef CIM_INTR_EEOF_EN
+ | CIM_CMD_EEOFINT
+#endif
+ ;
+
//-------------------------------------------------------------------------------------------
static spinlock_t fresh_lock = SPIN_LOCK_UNLOCKED;
@@ -122,8 +163,8 @@ static int fresh_id __read_mostly = -1;
static int fresh_buf __read_mostly;
static int wait_count __read_mostly;
-static struct cim_desc frame_desc[SWAP_NR] __attribute__ ((aligned (16)));
-static struct cim_desc capture_desc __attribute__ ((aligned (16)));
+static struct cim_desc frame_desc[SWAP_NR] __attribute__ ((aligned (sizeof(struct cim_desc))));
+static struct cim_desc capture_desc __attribute__ ((aligned (sizeof(struct cim_desc))));
/*====================================================================================
* sensor muti-support
@@ -145,7 +186,7 @@ static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t
static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int cim_mmap(struct file *file, struct vm_area_struct *vma);
-static void cim_framebuffer_destroy(void);
+static void cim_fb_free(void);
static int cim_set_function(int function,void *cookie);
static int cim_set_preview_resolution(struct resolution_info param);
@@ -163,12 +204,14 @@ int camera_sensor_register(struct camera_sensor_desc *desc)
desc->max_capture_size=
desc->max_capture_parm.width
*desc->max_capture_parm.height
- *desc->max_capture_parm.bpp >> 3;
+ * 3; /* in order to support seperate YCbCr */
+ //*desc->max_capture_parm.bpp >> 3;
desc->max_preview_size=
desc->max_preview_parm.width
*desc->max_preview_parm.height
- *desc->max_preview_parm.bpp >> 3;
+ * 3; /* in order to support seperate YCbCr */
+ //*desc->max_preview_parm.bpp >> 3;
mutex_lock(&sensor_lock);
list_add_tail(&desc->list,&sensor_list);
@@ -183,6 +226,8 @@ void cim_scan_sensor(void)
struct camera_sensor_desc *si;
struct list_head *tmp;
+ dprintk("Enter %s\n", __FUNCTION__);
+
mutex_lock(&sensor_lock);
list_for_each_entry(si, &sensor_list, list)
{
@@ -197,6 +242,7 @@ void cim_scan_sensor(void)
}
mutex_unlock(&sensor_lock);
+ dprintk("Leave %s\n", __FUNCTION__);
}
void sensors_make_default(void)
@@ -225,6 +271,9 @@ static void cim_print_regs(void)
{
printk("REG_CIM_CFG \t= \t0x%08x\n", REG_CIM_CFG);
printk("REG_CIM_CTRL \t= \t0x%08x\n", REG_CIM_CTRL);
+#ifdef CONFIG_TEST_JZ4760E
+ printk("REG_CIM_CTRL2 \t= \t0x%08x\n", REG_CIM_CTRL2);
+#endif
printk("REG_CIM_STATE \t= \t0x%08x\n", REG_CIM_STATE);
printk("REG_CIM_IID \t= \t0x%08x\n", REG_CIM_IID);
printk("REG_CIM_DA \t= \t0x%08x\n", REG_CIM_DA);
@@ -233,26 +282,43 @@ static void cim_print_regs(void)
printk("REG_CIM_CMD \t= \t0x%08x\n", REG_CIM_CMD);
printk("REG_CIM_SIZE \t= \t0x%08x\n", REG_CIM_SIZE);
printk("REG_CIM_OFFSET \t= \t0x%08x\n", REG_CIM_OFFSET);
+#ifdef CONFIG_TEST_JZ4760E
+ printk("REG_CIM_YFA \t= \t%#08x\n", REG_CIM_YFA);
+ printk("REG_CIM_YCMD \t= \t%#08x\n", REG_CIM_YCMD);
+ printk("REG_CIM_CBFA \t= \t%#08x\n", REG_CIM_CBFA);
+ printk("REG_CIM_CBCMD \t= \t%#08x\n", REG_CIM_CBCMD);
+ printk("REG_CIM_CRFA \t= \t%#08x\n", REG_CIM_CRFA);
+ printk("REG_CIM_CRCMD \t= \t%#08x\n", REG_CIM_CRCMD);
+#endif
}
-#if 0
+#if 1
static void cim_print_buffers(void)
{
int i;
- printk("cim_tran_buf_id%x\n",cim_tran_buf_id);
- printk("data_ready_buf_id=0x%x\n",data_ready_buf_id);
+ //printk("cim_tran_buf_id%x\n",cim_tran_buf_id);
+ //printk("data_ready_buf_id=0x%x\n",data_ready_buf_id);
- for(i=0;i<3;i++)
+ for(i = 0; i < SWAP_NR; i++)
{
- printk("cim_framebuf_desc[%d]=0x%x\n",i,cim_frame_desc[i].framebuf);
- printk("cim_frameid _desc[%d]=0x%x\n",i,cim_frame_desc[i].frameid);
- printk("cim_dmacmd _desc[%d]=0x%x\n",i,cim_frame_desc[i].dmacmd);
- printk("cim_nextdesc_desc[%d]=0x%x\n\n",i,cim_frame_desc[i].nextdesc);
+ printk("=============%p=============\n", &frame_desc[i]);
+ printk("cim_nextdesc_desc[%d]=0x%x\n",i,frame_desc[i].nextdesc);
+ printk("cim_framebuf_desc[%d]=0x%x\n",i,frame_desc[i].framebuf);
+ printk("cim_frameid _desc[%d]=0x%x\n",i,frame_desc[i].frameid);
+ printk("cim_dmacmd _desc[%d]=0x%x\n",i,frame_desc[i].dmacmd);
+ //if (!jz_cim->cim_cfg.packed)
+ {
+ printk("cim_cb_frame_desc[%d]=0x%x\n",i,frame_desc[i].cb_frame);
+ printk("cim_cb_len_desc[%d]=0x%x\n",i,frame_desc[i].cb_len);
+ printk("cim_cr_frame_desc[%d]=0x%x\n",i,frame_desc[i].cr_frame);
+ printk("cim_cr_len_desc[%d]=0x%x\n",i,frame_desc[i].cr_len);
+ }
+ printk("========================================\n");
}
- printk("preview_working_buf=0x%x\n",preview_working_buf);
- printk("recorder_prepare_buf=0x%x\n",recorder_prepare_buf);
- printk("recorder_working_buf=0x%x\n\n",recorder_working_buf);
+ //printk("preview_working_buf=0x%x\n",preview_working_buf);
+ //printk("recorder_prepare_buf=0x%x\n",recorder_prepare_buf);
+ //printk("recorder_working_buf=0x%x\n\n",recorder_working_buf);
}
#endif
@@ -262,17 +328,35 @@ static void cim_print_buffers(void)
static int cim_init_capture_desc(void)
{
- int capture_frmsize = ((cur_desc->capture_parm.width * cur_desc->capture_parm.height
- * cur_desc->capture_parm.bpp) >> 3);
+ int imgsize = cur_desc->capture_parm.width * cur_desc->capture_parm.height;
+ int capture_frmsize = ((imgsize * cur_desc->capture_parm.bpp) >> 3);
dprintk("cap_size=0x%x\n",capture_frmsize);
- capture_desc.framebuf = jz_cim->capture_binfo.base_paddr;;
capture_desc.nextdesc = virt_to_phys(&capture_desc);
capture_desc.frameid = 0xff;
+ capture_desc.framebuf = jz_cim->capture_binfo.base_paddr;
+ printk("=======>cap fb = %#010x\n", capture_desc.framebuf);
//capture_desc.dmacmd = (capture_frmsize>>2) | CIM_CMD_EOFINT | CIM_CMD_STOP;
- capture_desc.dmacmd = (capture_frmsize>>2) | CIM_CMD_EOFINT;
-#ifdef CONFIG_SOC_JZ4760
+ if (jz_cim->cim_cfg.packed)
+ capture_desc.dmacmd = (capture_frmsize>>2) | dmacmd_intr_flag;
+ else {
+ printk("=======>%s:%d we are test sep!!!\n", __FUNCTION__, __LINE__);
+ capture_desc.dmacmd = (imgsize>>2) | dmacmd_intr_flag;
+ /* FIXME: test YCbCr444 or YCbCr422 bellow */
+ if (jz_cim->cim_cfg.fmt_422) {
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize;
+ capture_desc.cb_len = (imgsize / 2) >> 2;
+ capture_desc.cr_frame = jz_cim->capture_binfo.base_paddr + imgsize + imgsize / 2;
+ capture_desc.cb_len = (imgsize / 2) >> 2;
+ } else {
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize;
+ capture_desc.cb_len = imgsize >> 2;
+ capture_desc.cr_frame = jz_cim->capture_binfo.base_paddr + imgsize + imgsize;
+ capture_desc.cb_len = imgsize >> 2;
+ }
+ }
+#if !defined(CONFIG_SOC_JZ4750)
capture_desc.dmacmd |= CIM_CMD_OFRCV ;
#endif
if(cur_desc->wait_frames == 0)
@@ -286,25 +370,46 @@ static int cim_init_preview_desc(void)
{
int i;
+ int imgsize = cur_desc->preview_parm.width * cur_desc->preview_parm.height;
+ int preview_frmsize = ((imgsize * cur_desc->preview_parm.bpp) >> 3);
+ unsigned int base_paddr = 0;
dprintk("=================preview: width = %d height = %d bpp = %d\n",
- cur_desc->preview_parm.width , cur_desc->preview_parm.height, cur_desc->preview_parm.bpp);
- int preview_frmsize = ((cur_desc->preview_parm.width * cur_desc->preview_parm.height
- * cur_desc->preview_parm.bpp) >> 3);
-
+ cur_desc->preview_parm.width , cur_desc->preview_parm.height, cur_desc->preview_parm.bpp);
dprintk("pre_size=0x%x",preview_frmsize);
//--------------------------------------------------------------------------------------------
for (i= 0; i< SWAP_NR; i++)
{
- frame_desc[i].framebuf = jz_cim->preview_binfo.base_paddr + jz_cim->ginfo.max_preview_size * i;
+ base_paddr = jz_cim->preview_binfo.base_paddr + jz_cim->ginfo.max_preview_size * i;
+
+ frame_desc[i].nextdesc = virt_to_phys(&frame_desc[i+1]);
frame_desc[i].frameid = i;
- frame_desc[i].dmacmd = (preview_frmsize>>2) | CIM_CMD_EOFINT ;
-#ifdef CONFIG_SOC_JZ4760
+ frame_desc[i].framebuf = base_paddr;
+ if (jz_cim->cim_cfg.packed)
+ frame_desc[i].dmacmd = (preview_frmsize>>2) | dmacmd_intr_flag;
+ else {
+ printk("=======>%s:%d we are test sep!!!\n", __FUNCTION__, __LINE__);
+ frame_desc[i].dmacmd = (imgsize>>2) | dmacmd_intr_flag;
+
+ /* FIXME: test YCbCr444 and YCbCr422 here */
+ if (jz_cim->cim_cfg.fmt_422) {
+ frame_desc[i].cb_frame = base_paddr + imgsize;
+ frame_desc[i].cb_len = (imgsize / 2) >> 2;
+ frame_desc[i].cr_frame = base_paddr + imgsize + imgsize / 2;
+ frame_desc[i].cr_len = (imgsize / 2) >> 2;
+ } else {
+ printk(">>>>>>>>>>>>>>in %s, we are test YUV444, img_size = %d\n", __FUNCTION__, imgsize);
+ frame_desc[i].cb_frame = base_paddr + imgsize;
+ frame_desc[i].cb_len = imgsize >> 2;
+ frame_desc[i].cr_frame = base_paddr + imgsize * 2;
+ frame_desc[i].cr_len = imgsize >> 2;
+ }
+ }
+#if !defined(CONFIG_SOC_JZ4750)
frame_desc[i].dmacmd |= CIM_CMD_OFRCV ;
#endif
- frame_desc[i].nextdesc = virt_to_phys(&frame_desc[i+1]);
}
frame_desc[SWAP_BUF-1].nextdesc = virt_to_phys(&frame_desc[0]);
@@ -322,25 +427,6 @@ static int cim_init_preview_desc(void)
return 0;
}
-static void cim_framebuffer_destroy(void)
-{
- if(jz_cim->mem_base != 0)
- {
- int page_order;
- __cim_disable();
-
- if(jz_cim->mem_size == 0)
- {
- dprintk("Original memory is NULL\n");
- return;
- }
- page_order = get_order(jz_cim->mem_size);
- free_pages((unsigned long)jz_cim->mem_base, page_order);
- jz_cim->mem_base = 0;
- dprintk("cim_fb_destory!\n");
- }
-}
-
static unsigned int cim_init_fb_info(int swap_nr)
{
unsigned int max_p_size=0,max_c_size=0;
@@ -372,34 +458,38 @@ static unsigned int cim_init_fb_info(int swap_nr)
static int cim_fb_alloc(void)
{
- unsigned int mem_size = 0;
+ unsigned int mem_size = 0, preview_mem_size = 0, capture_mem_size = 0;
int order = 0;
- if (jz_cim->mem_base == 0 )
+ if (jz_cim->mem_base == NULL )
{
dprintk("get new page!\n");
- mem_size=cim_init_fb_info(SWAP_NR);
+
+ (void)cim_init_fb_info(SWAP_NR);
+ preview_mem_size = jz_cim->ginfo.max_preview_size * SWAP_NR;
+ capture_mem_size = jz_cim->ginfo.max_capture_size;
+ mem_size = (preview_mem_size > capture_mem_size) ? preview_mem_size : capture_mem_size;
order = get_order(mem_size);
- dprintk("mem_size=%dK\n",mem_size>>10);
- dprintk("order=%d\n",order);
+ dprintk("mem_size=%dK\n", mem_size>>10);
+ dprintk("order=%d\n", order);
-#if 1
jz_cim->mem_base = (unsigned char *)__get_free_pages(GFP_KERNEL, order);
if (jz_cim->mem_base == NULL)
{
- printk("GET FREE PAGES FAILED!\n");
+ printk("Preview: GET FREE PAGES FAILED!\n");
return -ENOMEM;
}
jz_cim->preview_binfo.base_vaddr = (unsigned int)jz_cim->mem_base;
jz_cim->preview_binfo.base_paddr = virt_to_phys(jz_cim->mem_base);
- jz_cim->capture_binfo.base_vaddr = (unsigned int)jz_cim->mem_base + jz_cim->preview_binfo.buffer_size;
- jz_cim->capture_binfo.base_paddr = virt_to_phys(jz_cim->mem_base + jz_cim->preview_binfo.buffer_size);
+ jz_cim->capture_binfo.base_vaddr = (unsigned int)jz_cim->mem_base;
+ jz_cim->capture_binfo.base_paddr = virt_to_phys(jz_cim->mem_base);
+
+ memset(jz_cim->mem_base, 0, mem_size);
-#endif
jz_cim->mem_size = mem_size;
jz_cim->ginfo.mmap_size = mem_size;
}
@@ -407,6 +497,24 @@ static int cim_fb_alloc(void)
return 0;
}
+static void cim_fb_free(void)
+{
+ if(jz_cim->mem_base != 0)
+ {
+ int page_order;
+ __cim_disable();
+
+ if(jz_cim->mem_size == 0)
+ {
+ dprintk("Original memory is NULL\n");
+ return;
+ }
+ page_order = get_order(jz_cim->mem_size);
+ free_pages((unsigned long)jz_cim->mem_base, page_order);
+ jz_cim->mem_base = NULL;
+ dprintk("cim_fb_destory!\n");
+ }
+}
/*==========================================================================
* CIM Module operations
@@ -420,15 +528,104 @@ static void cim_config(cim_config_t *c)
REG_CIM_SIZE = c->size;
REG_CIM_OFFSET = c->offs;
+#if defined(CONFIG_TEST_JZ4760E)
+ __cim_input_data_format_select_YUV422();
+ //__cim_input_data_format_select_YUV444();
+ __cim_set_input_data_stream_order(0); /* YCbCr or Y0CbY1Cr */
+ //__cim_set_input_data_stream_order(1); /* YCrCb or Y0CrY1Cb */
+ //__cim_set_input_data_stream_order(2); /* CbCrY or CbY0CrY1 */
+ //__cim_set_input_data_stream_order(3); /* CrCbY or CrY0CbY1 */
+
+ //__cim_set_data_packing_mode(0); /* 0x11 22 33 44 or 0x Y0 Cb Y1 Cr */
+ //__cim_set_data_packing_mode(1); /* 0x 22 33 44 11 or 0x Cb Y1 Cr Y0 */
+ //__cim_set_data_packing_mode(2); /* 0x 33 44 11 22 or 0x Y1 Cr Y0 Cb */
+ //__cim_set_data_packing_mode(3); /* 0x 44 11 22 33 or 0x Cr Y0 Cb Y1 */
+ __cim_set_data_packing_mode(4); /* 0x 44 33 22 11 or 0x Cr Y1 Cb Y0 */
+ //__cim_set_data_packing_mode(5); /* 0x 33 22 11 44 or 0x Y1 Cb Y0 Cr */
+ //__cim_set_data_packing_mode(6); /* 0x 22 11 44 33 or 0x Cb Y0 Cr Y1 */
+ //__cim_set_data_packing_mode(7); /* 0x 11 44 33 22 or 0x Y0 Cr Y1 Cb */
+
+ __cim_enable_bypass_func();
+ //__cim_disable_bypass_func();
+
+ __cim_enable_auto_priority();
+ //__cim_disable_auto_priority();
+
+ __cim_enable_emergency();
+ //__cim_disable_emergency();
+
+ /* 0, 1, 2, 3
+ * 0: highest priority
+ * 3: lowest priority
+ * 1 maybe best for SEP=1
+ * 3 maybe best for SEP=0
+ */
+ //__cim_set_opg(0);
+ __cim_set_opg(1);
+ //__cim_set_opg(2);
+ //__cim_set_opg(3);
+
+ __cim_enable_priority_control();
+ //__cim_disable_priority_control();
+
+
+ if (c->packed) {
+ __cim_disable_sep();
+ } else {
+ __cim_enable_sep();
+ }
+#endif
+
if(cur_desc->no_dma) //just for fake sensor test
return;
- // Enable sof, eof and stop interrupts
__cim_enable_dma();
+#ifdef CIM_SAFE_DISABLE
+ //__cim_enable_vdd_intr();
+#else
+ __cim_disable_vdd_intr();
+#endif
+
+#ifdef CIM_INTR_SOF_EN
+ __cim_enable_sof_intr();
+#else
+ __cim_disable_sof_intr();
+#endif
+
+#ifdef CIM_INTR_EOF_EN
__cim_enable_eof_intr();
+#else
+ __cim_disable_eof_intr();
+#endif
+
+#ifdef CIM_INTR_STOP_EN
+ __cim_enable_stop_intr();
+#else
+ __cim_disable_stop_intr();
+#endif
+#ifdef CIM_INTR_TRIG_EN
+ __cim_enable_trig_intr();
+#else
+ __cim_disable_trig_intr();
+#endif
+
+#ifdef CIM_INTR_OF_EN
__cim_enable_rxfifo_overflow_intr();
+#else
+ __cim_disable_rxfifo_overflow_intr();
+#endif
+
+#ifdef CIM_INTR_EEOF_EN
+ __cim_set_eeof_line(100);
+ __cim_enable_eeof_intr();
+#else
+#if !defined(CONFIG_SOC_JZ4750)
+ __cim_set_eeof_line(0);
+ __cim_disable_eeof_intr();
+#endif
+#endif
}
static void cim_init_config(struct camera_sensor_desc *desc)
@@ -440,7 +637,10 @@ static void cim_init_config(struct camera_sensor_desc *desc)
jz_cim->cim_cfg.cfg = cur_desc->cfg_info.configure_register;
jz_cim->cim_cfg.cfg &=~CIM_CFG_DMA_BURST_TYPE_MASK;
-#if defined(CONFIG_SOC_JZ4760)
+#if defined(CONFIG_TEST_JZ4760E)
+ jz_cim->cim_cfg.cfg |= CIM_CFG_DMA_BURST_INCR32 | (0<<CIM_CFG_RXF_TRIG_BIT);// (n+1)*burst = 2*16 = 32 <64
+ jz_cim->cim_cfg.ctrl = CIM_CTRL_DMA_SYNC | CIM_CTRL_FRC_1;
+#elif defined(CONFIG_SOC_JZ4760)
jz_cim->cim_cfg.cfg |= CIM_CFG_DMA_BURST_INCR16;
jz_cim->cim_cfg.ctrl = CIM_CTRL_DMA_SYNC | CIM_CTRL_FRC_1 | (1<<CIM_CTRL_RXF_TRIG_BIT);// (n+1)*burst = 2*16 = 32 <64
#else
@@ -448,6 +648,10 @@ static void cim_init_config(struct camera_sensor_desc *desc)
jz_cim->cim_cfg.ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_8 | CIM_CTRL_FAST_MODE; // 16 < 32
#endif
+ jz_cim->cim_cfg.packed = jz_cim->ginfo.packed;
+ /* Just for test */
+ jz_cim->cim_cfg.fmt_422 = jz_cim->ginfo.fmt_422;
+
return;
}
@@ -456,6 +660,7 @@ static int cim_device_init(void)
{
cim_init_config(cur_desc);
cim_config(&jz_cim->cim_cfg);
+ cim_print_regs();
return 0;
}
@@ -604,9 +809,13 @@ static int cim_snapshot(void)
cim_init_capture_desc();
+ dprintk("1: SNAPSHOT WRITE DMA PADDR:%#010x\n",capture_desc.framebuf);
+
cim_set_function(1,NULL);
cim_set_capture_resoultion(cur_desc->capture_parm,1);
+ dprintk("2: SNAPSHOT WRITE DMA PADDR:%#010x\n",capture_desc.framebuf);
+
//OUTPUT_TIME();
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
if(unlikely(cur_desc->no_dma)) //just for fake sensor test
@@ -620,8 +829,8 @@ static int cim_snapshot(void)
else
{
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
- dprintk("SNAPSHOT START!");
- dprintk("SNAPSHOT WRITE DMA PADDR:%u\n",capture_desc.framebuf);
+ dprintk("SNAPSHOT START!\n");
+ dprintk("SNAPSHOT WRITE DMA PADDR:%#010x\n",capture_desc.framebuf);
__cim_enable();
@@ -642,8 +851,43 @@ static int cim_snapshot(void)
static irqreturn_t cim_irq_handler(int irq, void *dev_id)
{
u32 state = REG_CIM_STATE;
+ u32 state_back = state;
unsigned long flags;
+ iprintk(">>>>>>>>>>>>>>>>>>>state = %#0x\n", state);
+
+ if ( (state & CIM_STATE_DMA_SOF) ||
+ (state & CIM_STATE_DMA_STOP) ||
+ (state & CIM_STATE_VDD) ||
+ (state & CIM_STATE_RXF_TRIG)) {
+ if (state & CIM_STATE_DMA_SOF) {
+ state &= ~CIM_STATE_DMA_SOF;
+ iprintk("sof intrrupt occured\n");
+ }
+
+ if (state & CIM_STATE_DMA_STOP) {
+ state &= ~CIM_STATE_DMA_STOP;
+ iprintk("stop intrrupt occured\n");
+ }
+
+ if (state & CIM_STATE_VDD) {
+ state &= ~CIM_STATE_VDD;
+ iprintk("cim disable done!\n");
+ }
+
+ if (state & CIM_STATE_RXF_TRIG) {
+ state &= ~CIM_STATE_RXF_TRIG;
+ iprintk("rx trig reached!\n");
+ }
+ }
+
+#if !defined(CONFIG_SOC_JZ4750)
+ if (state & CIM_STATE_DMA_EEOF) {
+ state &= ~CIM_STATE_DMA_EEOF;
+ iprintk("eeof intrrupt occured!\n");
+ }
+#endif
+
if (state & CIM_STATE_DMA_EOF)
{
if(likely(snapshot_flag != 1))
@@ -651,6 +895,8 @@ static irqreturn_t cim_irq_handler(int irq, void *dev_id)
spin_lock_irqsave(fresh_lock,flags);
jz_cim->preview_timeout_state = 1;
+ iprintk("__cim_get_iid() = %d\n", __cim_get_iid());
+ //cim_print_regs();
fresh_id = __cim_get_iid() - 1;
if(fresh_id == -1)
fresh_id = SWAP_BUF-1;
@@ -690,8 +936,30 @@ static irqreturn_t cim_irq_handler(int irq, void *dev_id)
}
}
- if (state & CIM_STATE_RXF_OF)
+ state = state_back;
+ if ( (state & CIM_STATE_RXF_OF)
+#if defined(CONFIG_TEST_JZ4760E)
+ || (state & CIM_STATE_Y_RF_OF) ||
+ (state & CIM_STATE_CB_RF_OF) ||
+ (state & CIM_STATE_CR_RF_OF)
+#endif
+ )
{
+ if (state & CIM_STATE_RXF_OF)
+ printk("OverFlow interrupt!\n");
+
+#if defined(CONFIG_TEST_JZ4760E)
+ if (state & CIM_STATE_Y_RF_OF)
+ printk("Y overflow interrupt!!!\n");
+
+ if (state & CIM_STATE_CB_RF_OF)
+ printk("Cb overflow interrupt!!!\n");
+
+ if (state & CIM_STATE_CR_RF_OF)
+ printk("Cr overflow interrupt!!!\n");
+#endif
+
+ cim_print_regs();
REG_CIM_STATE &= ~CIM_STATE_VDD;
__cim_disable();
@@ -700,7 +968,6 @@ static irqreturn_t cim_irq_handler(int irq, void *dev_id)
__cim_clear_state(); // clear state register
__cim_enable();
- dprintk("OverFlow interrupt!\n");
return IRQ_HANDLED;
}
@@ -719,13 +986,25 @@ static struct file_operations cim_fops =
};
+static atomic_t jzcim_opened = ATOMIC_INIT(1); /* initially not opened */
+
static int cim_open(struct inode *inode, struct file *filp)
{
- return 0;
+ if (jz_cim->ginfo.sensor_count <= 0)
+ return -ENODEV;
+
+ if (! atomic_dec_and_test (&jzcim_opened)) {
+ atomic_inc(&jzcim_opened);
+ return -EBUSY; /* already open */
+ }
+
+ return cim_fb_alloc();
}
static int cim_release(struct inode *inode, struct file *filp)
{
+ cim_fb_free();
+ atomic_inc(&jzcim_opened); /* release the device */
return 0;
}
@@ -739,7 +1018,7 @@ unsigned int get_phy_addr(unsigned int vaddr)
pmd_t *pmdir;
pte_t *pte;
- dprintk("current task(%d)'s pgd is 0x%x\n",current->pid,current->mm->pgd);
+ dprintk("current task(%d)'s pgd is %p\n",current->pid,current->mm->pgd);
pgdir=pgd_offset(current->mm,vaddr);
if(pgd_none(*pgdir)||pgd_bad(*pgdir))
@@ -772,7 +1051,7 @@ unsigned int get_phy_addr(unsigned int vaddr)
static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
- dprintk("user buf paddr = 0x%x\n",get_phy_addr(buf));
+ dprintk("user buf paddr = 0x%x\n",get_phy_addr((unsigned int)buf));
return -1;
}
@@ -790,18 +1069,35 @@ static unsigned int cim_get_preview_buf(int is_pbuf)
if(unlikely(fresh_id == -1))
{
iprintk("w");
+ //cim_print_regs();
interruptible_sleep_on_timeout(&jz_cim->preview_wait_queue,10*HZ);
//cim_print_regs();
}
- if(unlikely(jz_cim->preview_timeout_state != 1))
+ if(unlikely(jz_cim->preview_timeout_state != 1)) {
+ printk("========>preview timeout!!!\n");
+ //cim_print_regs();
return (unsigned int)(~0);
+ }
+
+ //cim_print_regs();
/******/spin_lock_irqsave(fresh_lock,flags);/*********************************************************/
+ iprintk("===>fresh_buf = %d fresh_id = %d\n", fresh_buf, fresh_id);
tmp_addr=frame_desc[fresh_id].framebuf;
frame_desc[fresh_id].framebuf=frame_desc[SWAP_BUF+fresh_buf].framebuf;
frame_desc[SWAP_BUF+fresh_buf].framebuf=tmp_addr;
+ if (!jz_cim->cim_cfg.packed) {
+ iprintk("=======>%s:%d we are test sep!!!\n", __FUNCTION__, __LINE__);
+ tmp_addr = frame_desc[fresh_id].cb_frame;
+ frame_desc[fresh_id].cb_frame = frame_desc[SWAP_BUF+fresh_buf].cb_frame;
+ frame_desc[SWAP_BUF+fresh_buf].cb_frame=tmp_addr;
+
+ tmp_addr = frame_desc[fresh_id].cr_frame;
+ frame_desc[fresh_id].cr_frame = frame_desc[SWAP_BUF+fresh_buf].cr_frame;
+ frame_desc[SWAP_BUF+fresh_buf].cr_frame=tmp_addr;
+ }
dma_cache_wback((unsigned long)(&frame_desc[fresh_id]), sizeof(struct cim_desc));
jz_cim->preview_timeout_state = 0;
@@ -879,21 +1175,36 @@ static int cim_get_sensor_info(void __user *arg,struct sensor_info *info)
return -ENODEV;
}
+#if !defined(CONFIG_SOC_JZ4750)
static int cim_enable_image_mode(int image_w,int image_h,int width,int height)
{
- int voffset,hoffset;
+ int voffset,hoffset, half_words_per_line = 0;
+
+ voffset = (height - image_h) / 2;
+ voffset &= ~0x1; /* must be even */
+
+ /* hoffset / 2 * 4 = (width - image_w) / 2 * (bpp / 8)
+ * ---> hoffset = (width - image_w) / 2 * (bpp / 8) / 4 * 2
+ */
+ if (jz_cim->cim_cfg.fmt_422) {
+ hoffset = (width - image_w) / 2;
+ hoffset &= ~0x1; /* must be even */
- voffset = (((height - image_h) / 2) >> 1) << 1;
- hoffset = (((width - image_w) / 2) >> 1) << 1;
+ half_words_per_line = image_w;
+ } else {
+ hoffset = (width - image_w) / 2;
+ hoffset = hoffset * 3 / 4 * 2;
+
+ half_words_per_line = image_w * 3 / 2; /* image_w must be even */
+ }
__cim_set_line(image_h);
- __cim_set_pixel(image_w);
+ __cim_set_pixel(half_words_per_line);
__cim_set_v_offset(voffset);
__cim_set_h_offset(hoffset);
__cim_enable_size_func();
- //REG_CIM_CTRL |= CIM_CTRL_WIN_EN;
dprintk("enable image mode (real size %d x %d) - %d x %d\n",width,height,image_w,image_h);
return 0;
@@ -907,22 +1218,35 @@ static int cim_disable_image_mode(void)
dprintk("disable image mode\n");
return 0;
}
+#else /* !CONFIG_SOC_JZ4750 */
+#define cim_enable_image_mode(iw, ih, w, h) do { } while(0)
+#define cim_disable_image_mode() do { } while(0)
+#endif
+
+static void param_normalization(struct resolution_info *param) {
+ if(param->bpp != 8 || param->bpp != 16 || param->bpp != 24 || param->bpp != 32 ) {
+ if (jz_cim->cim_cfg.fmt_422)
+ param->bpp = 16;
+ else /* yuv444 */
+ param->bpp = 24;
+ }
+ if(param->format == (unsigned int)(-1))
+ param->format= cur_desc->preview_parm.format;
+}
static int cim_set_preview_resolution(struct resolution_info param)
{
- int i, max_preview_index, framesize, wpf; /* words per frame */
+ int i, max_preview_index, imgsize, framesize;
dprintk("SET PREVIEW RESOULTION %d\tX\t%d\t%d\n",param.width,param.height,param.bpp);
if(cur_desc == NULL)
return -ENODEV;
- if(param.bpp != 8 || param.bpp != 16 || param.bpp != 32 )
- param.bpp = cur_desc->preview_parm.bpp;
- if(param.format == (unsigned int)(-1))
- param.format= cur_desc->preview_parm.format;
+ param_normalization(&param);
- framesize = (param.width * param.height * param.bpp + 7) >> 3;
+ imgsize = param.width * param.height;
+ framesize = (imgsize * param.bpp + 7) >> 3;
if (framesize > cur_desc->max_preview_size){
dprintk("ERROR! Preview size is too large!\n");
return -EINVAL;
@@ -1001,37 +1325,57 @@ static int cim_set_preview_resolution(struct resolution_info param)
CAMERA_MODE_PREVIEW);
}
//---------------------------------------------------------------------------
- wpf = (framesize +3) >> 2 ;
-
for (i = 0; i < SWAP_NR - 1; i++) {
- frame_desc[i].dmacmd &= ~CIM_CMD_LEN_MASK;
- frame_desc[i].dmacmd |= wpf;
+ if (jz_cim->cim_cfg.packed) {
+ frame_desc[i].dmacmd &= ~CIM_CMD_LEN_MASK;
+ frame_desc[i].dmacmd |= (framesize + 3) >> 2;
+ dprintk("framesize = %d\n", framesize);
+ } else {
+ dprintk("=======>%s:%d we are test sep!!!\n", __FUNCTION__, __LINE__);
+ frame_desc[i].dmacmd &= ~CIM_CMD_LEN_MASK;
+ frame_desc[i].dmacmd |= (imgsize + 3) >> 2;
+
+ /* FIXME: test YCbCr444 or YCbCr422 here */
+ if (jz_cim->cim_cfg.fmt_422) {
+ frame_desc[i].cb_frame = frame_desc[i].framebuf + imgsize;
+ frame_desc[i].cb_len = ( (imgsize + 1) / 2 + 3) >> 2;
+ frame_desc[i].cr_frame = frame_desc[i].cb_frame + imgsize / 2;
+ frame_desc[i].cr_len = ( (imgsize + 1) / 2 + 3) >> 2;
+ } else {
+ printk("we are testing yuv444\n");
+ frame_desc[i].cb_frame = frame_desc[i].framebuf + imgsize;
+ frame_desc[i].cb_len = imgsize >> 2;
+ frame_desc[i].cr_frame = frame_desc[i].cb_frame + imgsize;
+ frame_desc[i].cr_len = imgsize >> 2;
+ }
+ }
dma_cache_wback((unsigned long)(&frame_desc[i]), sizeof(struct cim_desc));
}
+
+ cim_print_buffers();
+ cim_print_regs();
+ printk("=========================\n");
return 0;
}
static int cim_set_capture_resoultion(struct resolution_info param,int state)
{
- int i,framesize, wpf,max_capture_index; // words per frame
+ int i,imgsize, framesize, max_capture_index; // words per frame
dprintk("SET CAPTURE RESOULTION %d\tX\t%d\t%d\n",param.width,param.height,param.bpp);
if(cur_desc == NULL)
return -ENODEV;
- if(param.bpp != 8 || param.bpp != 16 || param.bpp != 32 )
- param.bpp = cur_desc->capture_parm.bpp;
- if(param.format == (unsigned int)(-1))
- param.format= cur_desc->capture_parm.format;
+ param_normalization(&param);
- framesize = (param.width * param.height * param.bpp + 7) >> 3;
+ imgsize = param.width * param.height;
+ framesize = (imgsize * param.bpp + 7) >> 3;
if (framesize > cur_desc->max_capture_size){
dprintk("ERROR! Capture size is too large!\n");
return -EINVAL;
}
-
cur_desc->capture_parm.width = param.width;
cur_desc->capture_parm.height = param.height;
cur_desc->capture_parm.bpp = param.bpp;
@@ -1068,8 +1412,6 @@ static int cim_set_capture_resoultion(struct resolution_info param,int state)
}
}
- //if(jz_cim->cim_started == TRUE)
- //if(jz_cim->cim_transfer_started == 1)
if(i >= cur_desc->resolution_table_nr)
{
dprintk("size not found! use image mode!\n");
@@ -1110,9 +1452,26 @@ static int cim_set_capture_resoultion(struct resolution_info param,int state)
}
//---------------------------------------------------------------------------------------------
- wpf = (framesize + 3) >> 2 ;
- capture_desc.dmacmd &= ~CIM_CMD_LEN_MASK;
- capture_desc.dmacmd |= wpf;
+ if (jz_cim->cim_cfg.packed) {
+ capture_desc.dmacmd &= ~CIM_CMD_LEN_MASK;
+ capture_desc.dmacmd |= (framesize + 3) >>2;
+ } else {
+ dprintk("=======>%s:%d we are test sep!!!\n", __FUNCTION__, __LINE__);
+ capture_desc.dmacmd &= ~CIM_CMD_LEN_MASK;
+ capture_desc.dmacmd |= (imgsize + 3) >> 2;
+ /* FIXME: test YCbCr444 or YCbCr422 */
+ if (jz_cim->cim_cfg.fmt_422) {
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize;
+ capture_desc.cb_len = ((imgsize + 1) / 2 + 3) >> 2;
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize + imgsize / 2;
+ capture_desc.cr_len = ((imgsize + 1) / 2 + 3) >> 2;
+ } else {
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize;
+ capture_desc.cb_len = (imgsize + 3) >> 2;
+ capture_desc.cb_frame = jz_cim->capture_binfo.base_paddr + imgsize + imgsize;
+ capture_desc.cr_len = (imgsize + 3) >> 2;
+ }
+ }
dma_cache_wback((unsigned long)(&capture_desc), sizeof(struct cim_desc));
dprintk("SET CAPTURE RESOULTION %d\tX\t%d\t%d\n -- OK!",param.width,param.height,param.bpp);
@@ -1300,9 +1659,10 @@ static int cim_select_sensor(unsigned int sensor_id)
return 0;
}
+#if 0
static int cim_set_buffer(void __user *argp, struct camera_buffer_info *binfo)
{
- unsigned int mb;
+ unsigned int mb, cap_mb;
struct camera_buffer_info tmp;
if (copy_from_user(&tmp, argp, sizeof(struct camera_buffer_info)))
@@ -1315,9 +1675,10 @@ static int cim_set_buffer(void __user *argp, struct camera_buffer_info *binfo)
}
memcpy(binfo, &tmp, sizeof(struct camera_buffer_info));
- mb = (unsigned int)jz_cim->mem_base;
+ mb = (unsigned int)jz_cim->preview_mem_base;
+ cap_mb = (unsigned int)jz_cim->cap_mem_base;
if ((jz_cim->preview_binfo.base_vaddr != mb)
- && (jz_cim->capture_binfo.base_vaddr != (mb + jz_cim->preview_binfo.buffer_size)))
+ && (jz_cim->capture_binfo.base_vaddr != cap_mb))
{
cim_framebuffer_destroy();
dprintk("CIM FRAME BUFFER DESTORY\n");
@@ -1325,6 +1686,7 @@ static int cim_set_buffer(void __user *argp, struct camera_buffer_info *binfo)
return 0;
}
+#endif
/**************************
* IOCTL Handlers *
@@ -1347,6 +1709,16 @@ static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, u
cim_stop();
return 0;
}
+ case IOCTL_CIM_CHANGE_PACK_MODE:
+ jz_cim->cim_cfg.packed = *((unsigned int *)argp);
+ jz_cim->ginfo.packed = jz_cim->cim_cfg.packed;
+ printk("=============>set packed to %d\n", jz_cim->ginfo.packed);
+ return 0;
+ case IOCTL_CIM_CHANGE_FMT:
+ jz_cim->cim_cfg.fmt_422 = *((unsigned int *)argp);
+ jz_cim->ginfo.fmt_422 = jz_cim->cim_cfg.fmt_422;
+ printk("=============>set fmt_422 to %d\n", jz_cim->ginfo.fmt_422);
+ return 0;
case IOCTL_CIM_START_PREVIEW:
{
dprintk("IOCTL_CIM_START_PREVIEW\n");
@@ -1394,6 +1766,7 @@ static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, u
{
return copy_to_user(argp, &jz_cim->preview_binfo, sizeof(struct camera_buffer_info)) ? -EFAULT : 0;
}
+#if 0
case IOCTL_CIM_SET_PREVIEW_MEM:
{
dprintk("IOCTL_SET_PREVIEW_MEM\n");
@@ -1404,6 +1777,7 @@ static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, u
dprintk("IOCTL_SET_CAPTURE_MEM\n");
return cim_set_buffer(argp,&jz_cim->capture_binfo);
}
+#endif
case IOCTL_CIM_GET_PREVIEW_OFFSET:
{
unsigned int offset;
@@ -1522,13 +1896,13 @@ static int cim_mmap(struct file *file, struct vm_area_struct *vma)
buf_offsize_app_drv =(unsigned int )(jz_cim->mem_base)-(unsigned int )(vma->vm_start);
-#if 1
+#if 0
dprintk("vma->vm_start: 0x%x\n",vma->vm_start);
dprintk("vma->vm_end: 0x%x\n",vma->vm_end);
dprintk("vma->vm_pgoff: 0x%x\n",vma->vm_pgoff);
- dprintk("jz_cim->mem_base(V): 0x%x\n",jz_cim->mem_base);
- dprintk("jz_cim->mem_base(P): 0x%x\n",virt_to_phys(jz_cim->mem_base));
- dprintk("jz_cim->mem_size: %dbytes\n",jz_cim->mem_size);
+ dprintk("jz_cim->mem_base(V): 0x%x\n",mem_base);
+ dprintk("jz_cim->mem_base(P): 0x%x\n",virt_to_phys(mem_base));
+ dprintk("jz_cim->mem_size: %dbytes\n",mem_size);
dprintk("buf_offsize_app_drv = jz_cim->mem_base-vma->vm_start\n");
dprintk("buf_offsize_app_drv = 0x%x\n",buf_offsize_app_drv);
dprintk("get_phy_addr test addr = 0x%x\n",get_phy_addr(vma->vm_start));
@@ -1557,6 +1931,12 @@ static int __init cim_init(void)
return -ENOMEM;
}
+#if !defined(CONFIG_SOC_JZ4750)
+ jz_cim->ginfo.window_support = 1;
+#else
+ jz_cim->ginfo.window_support = 0;
+#endif
+
cim_power_on();
cim_scan_sensor();
@@ -1572,7 +1952,7 @@ static int __init cim_init(void)
init_waitqueue_head(&jz_cim->capture_wait_queue);
init_waitqueue_head(&jz_cim->preview_wait_queue);
- cim_fb_alloc();
+ //cim_fb_alloc();
if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, CIM_NAME, jz_cim))) {
dprintk(KERN_ERR "request_irq return error, ret=%d\n", ret);
@@ -1591,7 +1971,7 @@ static int __init cim_init(void)
static void __exit cim_exit(void)
{
- cim_framebuffer_destroy();
+ //cim_fb_free();
kfree(jz_cim);
misc_deregister(&cim_dev);
}
diff --git a/drivers/misc/jz_cim/jz_cim_core.h b/drivers/misc/jz_cim/jz_cim_core.h
index a6e0d46f585..441bb6a5b78 100644
--- a/drivers/misc/jz_cim/jz_cim_core.h
+++ b/drivers/misc/jz_cim/jz_cim_core.h
@@ -40,8 +40,8 @@ extern void cim_power_off(void);
#define IOCTL_CIM_GET_SUPPORT_SIZE 0xf0c
#define IOCTL_CIM_SET_PARAM 0xf0d
-#define IOCTL_CIM_SET_PREVIEW_MEM 0xf0e // alloc mem for buffers by app
-#define IOCTL_CIM_SET_CAPTURE_MEM 0xf0f // alloc mem for buffers by app
+//#define IOCTL_CIM_SET_PREVIEW_MEM 0xf0e // alloc mem for buffers by app
+//#define IOCTL_CIM_SET_CAPTURE_MEM 0xf0f // alloc mem for buffers by app
#define IOCTL_CIM_TAKE_SNAPSHOT 0xf10
@@ -50,6 +50,9 @@ extern void cim_power_off(void);
#define IOCTL_CIM_AF_INIT 0xf13
#define IOCTL_CIM_STOP_FOCUS 0xf14
+#define IOCTL_CIM_CHANGE_PACK_MODE 0xf15
+#define IOCTL_CIM_CHANGE_FMT 0xf16
+
//-----------------------------------------------------------------------------------------------------------------------
//camera param cmd
#define CPCMD_SET_PREVIEW_RESOLUTION 0x01
@@ -187,6 +190,8 @@ struct camera_param
int mode_arg;
};
+#define CIM_FB_PACKED 1
+#define CIM_FB_PLANAR 0
struct global_info
{
@@ -195,6 +200,10 @@ struct global_info
unsigned int max_preview_size;
unsigned int preview_buf_nr;
unsigned int max_capture_size;
+ unsigned int packed:1, /* framebuffer type: 1 -- packed, 0 -- planar */
+ fmt_422:1,
+ window_support:1,
+ reserved:29;
};
struct sensor_info
@@ -249,6 +258,9 @@ typedef struct{
unsigned int ctrl;
unsigned int size;
unsigned int offs;
+ unsigned int packed:1,
+ fmt_422:1,
+ reserved:30;
} cim_config_t;
typedef enum{CAMERA_MODE_CAPTURE,CAMERA_MODE_PREVIEW} camera_mode_t;
diff --git a/drivers/misc/jz_cim/jz_sensor.c b/drivers/misc/jz_cim/jz_sensor.c
index 507d2586cc9..f7faa8a3bac 100644
--- a/drivers/misc/jz_cim/jz_sensor.c
+++ b/drivers/misc/jz_cim/jz_sensor.c
@@ -11,6 +11,7 @@
* option) any later version.
*/
+#include <asm/jzsoc.h>
#include <linux/i2c.h>
#include "jz_sensor.h"
@@ -20,7 +21,7 @@ static inline int sensor_i2c_master_send(struct i2c_client *client,const char *b
void sensor_set_i2c_speed(struct i2c_client *client,unsigned long speed)
{
-#if defined(CONFIG_SOC_JZ4760)
+#if defined(CONFIG_SOC_JZ4760) || defined(CONFIG_JZ4760_F4760)
i2c_jz_setclk(client,speed);
#endif
//printk("set sensor i2c write read speed = %d hz\n",speed);
diff --git a/drivers/mmc/host/jzmmc/controller/dma/jz_mmc_dma.c b/drivers/mmc/host/jzmmc/controller/dma/jz_mmc_dma.c
index 3edd61df5f8..e343d024604 100644
--- a/drivers/mmc/host/jzmmc/controller/dma/jz_mmc_dma.c
+++ b/drivers/mmc/host/jzmmc/controller/dma/jz_mmc_dma.c
@@ -11,117 +11,210 @@
#include <asm/jzsoc.h>
#include <asm/jzmmc/jz_mmc_dma.h>
+#include <linux/scatterlist.h>
-void jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode, int ts)
-{
- unsigned long flags;
+#ifdef USE_DMA_DESC
+static inline int best_burst_size(unsigned int dma_len) {
+#ifdef USE_DMA_BUSRT_64
+ if (dma_len % 64 == 0)
+ return 64;
+#endif
- flags = claim_dma_lock();
- disable_dma(chan);
- clear_dma_ff(chan);
- jz_set_dma_block_size(chan, ts);
- set_dma_mode(chan, mode);
- set_dma_addr(chan, phyaddr);
- set_dma_count(chan, count + (ts - 1));
- enable_dma(chan);
- release_dma_lock(flags);
+ if (dma_len % 32 == 0)
+ return 32;
+
+ if (dma_len % 16 == 0)
+ return 16;
+
+#ifdef USE_DMA_BUSRT_64
+ if (dma_len > 64)
+ return 64;
+#endif
+
+ if (dma_len > 32)
+ return 32;
+
+ if (dma_len > 16)
+ return 16;
+
+ return 4;
}
-void jz_mmc_send_dma(struct jz_mmc_host *host, int chan, unsigned long srcaddr,
- unsigned long taraddr, int al_count, int unal_count)
-{
- unsigned long flags;
+static void sg_to_desc(struct scatterlist *sgentry, struct jz_mmc_host *host, int *desc_pos /* IN OUT */, int mode) {
jz_dma_desc *desc;
+ int pos = *desc_pos;
+ unsigned int ds = 32; /* ehh, 32byte is the best */
unsigned int next;
+ dma_addr_t dma_addr;
+ unsigned int dma_len;
+ unsigned int head_unalign_size = 0; /* ds = 4byte */
+ unsigned int aligned_size = 0;
+ unsigned int tail_unalign_size = 0; /* ds = 4byte */
+
+ dma_addr = sg_dma_address(sgentry);
+ dma_len = sg_dma_len(sgentry);
+
+ BUG_ON(dma_len % 4); /* we do NOT support transfer size < 4byte */
+
+ ds = best_burst_size(dma_len);
+ head_unalign_size = dma_addr & (ds - 1);
+ tail_unalign_size = (dma_addr + dma_len) & (ds - 1);
+ aligned_size = dma_len - head_unalign_size - tail_unalign_size;
+
+ BUG_ON(head_unalign_size % 4);
+ BUG_ON(tail_unalign_size % 4);
+
+ if (head_unalign_size) {
+ desc = host->dma_desc + pos;
+ next = (host->dma_desc_phys_addr + (pos + 1) * (sizeof(jz_dma_desc))) >> 4;
+ desc->dcmd = DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN |
+#ifndef CONFIG_SOC_JZ4760
+ DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE |
+#endif
+ DMAC_DCMD_LINK;
+ if (DMA_MODE_WRITE == mode) {
+ desc->dcmd |= DMAC_DCMD_SAI;
+ desc->dsadr = (unsigned int)dma_addr; /* DMA source address */
+ desc->dtadr = CPHYSADDR(MSC_TXFIFO(host->pdev_id)); /* DMA target address */
+ } else {
+ desc->dcmd |= DMAC_DCMD_DAI;
+ desc->dsadr = CPHYSADDR(MSC_RXFIFO(host->pdev_id));
+ desc->dtadr = (unsigned int)dma_addr;
+ }
+ desc->ddadr = (next << 24) | (head_unalign_size >> 2) ;
+
+ pos ++;
+ }
- flags = claim_dma_lock();
-
- memset(host->ua_desc, 0, 4096);
+ if (aligned_size) {
+ desc = host->dma_desc + pos;
+ next = (host->dma_desc_phys_addr + (pos + 1) * (sizeof(jz_dma_desc))) >> 4;
- next = (host->dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
- desc = host->ua_desc;
- desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS(DMA_TS) |
- DMAC_DCMD_LINK;
- desc->dsadr = srcaddr; /* DMA source address */
- desc->dtadr = taraddr; /* DMA target address */
- desc->ddadr = (next << 24) | al_count;
- desc++;
- desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT |
- DMAC_DCMD_TIE;
- desc->dsadr = srcaddr + (al_count * DMA_TS); /* DMA source address */
- desc->dtadr = taraddr; /* DMA target address */
- desc->ddadr = unal_count; /* counter */
-
- dma_cache_wback_inv((unsigned long)desc, 2 * (sizeof(jz_dma_desc)));
+ desc->dcmd = DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_RDIL_IGN |
+#ifndef CONFIG_SOC_JZ4760
+ DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE |
+#endif
+ DMAC_DCMD_LINK;
+ switch (ds) {
+#ifdef USE_DMA_BUSRT_64
+ case 64:
+ desc->dcmd |= DMAC_DCMD_DS_64BYTE;
+ break;
+#endif
- /* Setup DMA descriptor address */
- REG_DMAC_DDA(chan) = host->dma_desc_phys_addr;
+ case 32:
+ desc->dcmd |= DMAC_DCMD_DS_32BYTE;
+ break;
+
+ case 16:
+ desc->dcmd |= DMAC_DCMD_DS_16BYTE;
+ break;
+
+ case 4:
+ desc->dcmd |= DMAC_DCMD_DS_32BIT;
+ break;
+
+ default:
+ ;
+ }
+
+ if (DMA_MODE_WRITE == mode) {
+ desc->dcmd |= DMAC_DCMD_SAI;
+ desc->dsadr = (unsigned int)(dma_addr + head_unalign_size); /* DMA source address */
+ desc->dtadr = CPHYSADDR(MSC_TXFIFO(host->pdev_id)); /* DMA target address */
+ } else {
+ desc->dcmd |= DMAC_DCMD_DAI;
+ desc->dsadr = CPHYSADDR(MSC_RXFIFO(host->pdev_id));
+ desc->dtadr = (unsigned int)(dma_addr + head_unalign_size);;
+ }
+ desc->ddadr = (next << 24) | (aligned_size / ds) ;
+
+ pos ++;
+ }
- /* Setup request source */
- if(host->pdev_id == 0)
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC0OUT;
- else if(host->pdev_id == 1)
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC1OUT;
- else
-#ifdef DMAC_DRSR_RS_MSC2OUT
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC2OUT;
-#else
- ;
-#endif
- /* Setup DMA channel control/status register */
- REG_DMAC_DCCSR(chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+ if (tail_unalign_size) {
+ desc = host->dma_desc + pos;
+ next = (host->dma_desc_phys_addr + (pos + 1) * (sizeof(jz_dma_desc))) >> 4;
- /* Enable DMA */
- REG_DMAC_DMACR(chan / HALF_DMA_NUM) = DMAC_DMACR_DMAE;
+ desc->dcmd = DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN |
+#ifndef CONFIG_SOC_JZ4760
+ DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE |
+#endif
+ DMAC_DCMD_LINK;
+ if (DMA_MODE_WRITE == mode) {
+ desc->dcmd |= DMAC_DCMD_SAI;
+ desc->dsadr = (unsigned int)(dma_addr + head_unalign_size + aligned_size); /* DMA source address */
+ desc->dtadr = CPHYSADDR(MSC_TXFIFO(host->pdev_id)); /* DMA target address */
+ } else {
+ desc->dcmd |= DMAC_DCMD_DAI;
+ desc->dsadr = CPHYSADDR(MSC_RXFIFO(host->pdev_id));
+ desc->dtadr = (unsigned int)(dma_addr + head_unalign_size + aligned_size);;
+ }
+ desc->ddadr = (next << 24) | (tail_unalign_size >> 2) ;
+
+ pos ++;
- /* DMA doorbell set -- start DMA now ... */
- REG_DMAC_DMADBSR(chan / HALF_DMA_NUM) = 1 << chan;
+ }
- release_dma_lock(flags);
+ *desc_pos = pos;
}
-void jz_mmc_receive_dma(struct jz_mmc_host *host, int chan, unsigned long srcaddr,
- unsigned long taraddr, int al_count, int unal_count)
-{
- unsigned long flags;
+void jz_mmc_start_scatter_dma(int chan, struct jz_mmc_host *host,
+ struct scatterlist *sg, unsigned int sg_len, int mode) {
+ int i = 0;
+ int desc_pos = 0;
+ struct mmc_data *data = host->curr.data;
+ struct scatterlist *sgentry;
jz_dma_desc *desc;
unsigned int next;
+ unsigned long flags;
+
+ memset(host->dma_desc, 0, PAGE_SIZE);
+ desc = host->dma_desc;
+ next = (host->dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
+
+ desc_pos = 0;
flags = claim_dma_lock();
+ for_each_sg(data->sg, sgentry, host->dma.len, i) {
+ sg_to_desc(sgentry, host, &desc_pos, mode);
+ }
- memset(host->ua_desc, 0, 4096);
+ desc = host->dma_desc + (desc_pos - 1);
+ desc->dcmd |= DMAC_DCMD_TIE;
+ desc->dcmd &= ~DMAC_DCMD_LINK;
+ desc->ddadr &= ~0xff000000;
- next = (host->dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
- desc = host->ua_desc;
- desc->dcmd = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS(DMA_TS) |
- DMAC_DCMD_LINK;
- desc->dsadr = srcaddr; /* DMA source address */
- desc->dtadr = taraddr; /* DMA target address */
- desc->ddadr = (next << 24) | al_count;
- desc++;
- desc->dcmd = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT |
- DMAC_DCMD_TIE;
- desc->dsadr = srcaddr; /* DMA source address */
- desc->dtadr = taraddr + (al_count * DMA_TS); /* DMA target address */
- desc->ddadr = unal_count; /* counter */
-
- dma_cache_wback((unsigned long)desc, 2 * (sizeof(jz_dma_desc)));
+ dma_cache_wback_inv((unsigned long)desc, desc_pos * (sizeof(jz_dma_desc)));
/* Setup DMA descriptor address */
REG_DMAC_DDA(chan) = host->dma_desc_phys_addr;
/* Setup request source */
- if(host->pdev_id == 0)
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC0IN;
- else if(host->pdev_id == 1)
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC1IN;
- else
+ if (DMA_MODE_WRITE == mode) {
+ if(host->pdev_id == 0)
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC0OUT;
+ else if(host->pdev_id == 1)
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC1OUT;
+ else
+#ifdef DMAC_DRSR_RS_MSC2OUT
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC2OUT;
+#else
+ ;
+#endif
+ } else {
+ if(host->pdev_id == 0)
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC0IN;
+ else if(host->pdev_id == 1)
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC1IN;
+ else
#ifdef DMAC_DRSR_RS_MSC2IN
- REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC2IN;
+ REG_DMAC_DRSR(chan) = DMAC_DRSR_RS_MSC2IN;
#else
- ;
+ ;
#endif
+ }
/* Setup DMA channel control/status register */
REG_DMAC_DCCSR(chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
@@ -130,10 +223,29 @@ void jz_mmc_receive_dma(struct jz_mmc_host *host, int chan, unsigned long srcadd
REG_DMAC_DMACR(chan / HALF_DMA_NUM) = DMAC_DMACR_DMAE;
/* DMA doorbell set -- start DMA now ... */
- REG_DMAC_DMADBSR(chan / HALF_DMA_NUM) = 1 << chan;
+ REG_DMAC_DMADBSR(chan / HALF_DMA_NUM) = 1 << (chan - (chan / HALF_DMA_NUM) * HALF_DMA_NUM) ;
release_dma_lock(flags);
+
}
+#else
+void jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode, int ds)
+{
+ unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ jz_set_dma_src_width(chan, 32);
+ jz_set_dma_dest_width(chan, 32);
+ jz_set_dma_block_size(chan, ds);
+ set_dma_mode(chan, mode);
+ set_dma_addr(chan, phyaddr);
+ set_dma_count(chan, (count + ds - 1));
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+#endif
static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid)
{
@@ -204,14 +316,10 @@ static int jz_mmc_init_dma(struct jz_mmc_host *host)
else
REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC;
- host->dma_buf = (unsigned int *)__get_free_page(GFP_KERNEL);
-
- /* setup descriptor */
- host->ua_desc = (jz_dma_desc *)__get_free_page(GFP_KERNEL);
- host->dma_desc_phys_addr = CPHYSADDR((unsigned long)host->ua_desc);
-
- memset(host->ua_desc, 0, 4096);
- dma_cache_wback_inv((unsigned long)host->ua_desc, 4096);
+#ifdef USE_DMA_DESC
+ host->dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); /* 4096 / 4 = 1024 descriptor max */
+ host->dma_desc_phys_addr = CPHYSADDR((unsigned long)host->dma_desc);
+#endif
return 0;
@@ -223,8 +331,6 @@ err1:
static void jz_mmc_deinit_dma(struct jz_mmc_host *host)
{
- free_page((unsigned long)host->ua_desc);
- free_page((unsigned long)host->dma_buf);
jz_free_dma(host->dma.rxchannel);
jz_free_dma(host->dma.txchannel);
}
diff --git a/drivers/mmc/host/jzmmc/controller/gpio/jz_mmc_gpio.c b/drivers/mmc/host/jzmmc/controller/gpio/jz_mmc_gpio.c
index 6abab079abd..f7a2c5077a2 100644
--- a/drivers/mmc/host/jzmmc/controller/gpio/jz_mmc_gpio.c
+++ b/drivers/mmc/host/jzmmc/controller/gpio/jz_mmc_gpio.c
@@ -12,45 +12,14 @@
#define TRY_TIME 10
#define RETRY_TIME 50
-//#define CARD_REINSERT_DURATTION (5 * HZ)
-//static unsigned long msmsdcc_irqtime = 0;
-#if 0
-static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
-{
- struct jz_mmc_host *host = (struct jz_mmc_host *) devid;
-
- printk("jz-mmc: card detect interrupt raised!!! check status......\n");
-
- if (!host->plat->status) {
- mmc_detect_change(host->mmc, 50);
- return IRQ_HANDLED;
- }
-
- if (host->plat->status(mmc_dev(host->mmc))) { /* card detected */
- host->eject = 0;
- host->plat->plug_change(CARD_INSERTED);
- } else {
- host->eject = 1;
- host->plat->plug_change(CARD_REMOVED);
- }
-
- if (host->eject ^ host->oldstat) {
- mmc_detect_change(host->mmc, 50);
- }
-
- host->oldstat = host->eject;
-
- return IRQ_HANDLED;
-}
-#else
static void jiq_de_quiver(struct work_struct *ptr){
struct jz_mmc_host *host = container_of(ptr, struct jz_mmc_host, gpio_jiq_work);
unsigned int time_to_try, i, tmp, counter = 0, result = 1;
- unsigned long duration;
- if (!host->plat->status) {
+ if (unlikely(!host->plat->status)) { /* NEVER */
mmc_detect_change(host->mmc, 0);
+ atomic_inc(&host->detect_refcnt);
return;
}
@@ -88,37 +57,60 @@ static void jiq_de_quiver(struct work_struct *ptr){
}
stable:
- if (host->eject ^ host->oldstat) {
- /* Delay the process for Card re-insert */
- //duration = jiffies - msmsdcc_irqtime;
+ /* oldstat: 1 -- eject, 0 -- inserted */
+ /* eject: 1 -- eject, 0 -- inserted */
+
+ if ( (0 == host->oldstat) && (0 == host->eject) && host->sleeping) {
+ mmc_resume_host(host->mmc);
+ }
+
+ if ( (0== host->oldstat) && (1 == host->eject) ) {
+ if (host->sleeping) {
+ mmc_resume_host(host->mmc);
+ } else {
+ mmc_detect_change(host->mmc, 50);
+ }
- //if ((!(host->eject)) && (duration < CARD_REINSERT_DURATTION)) {
- // duration = CARD_REINSERT_DURATTION - duration;
- //} else {
- // duration = 0;
- //}
+ wake_up_interruptible(&host->msc_wait_queue);
+ }
+ if ( (1 == host->oldstat) && (0 == host->eject) ) {
mmc_detect_change(host->mmc, 50);
- //msmsdcc_irqtime = jiffies;
- if (host->eject)
- wake_up_interruptible(&host->msc_wait_queue);
}
+ host->sleeping = 0;
host->oldstat = host->eject;
+
+ atomic_inc(&host->detect_refcnt);
}
-static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
-{
- struct jz_mmc_host *host = (struct jz_mmc_host *) devid;
+int jz_mmc_detect(struct jz_mmc_host *host, int from_resuming) {
+ int ret = 0;
- printk("jz-msc%d: detect card......\n", host->pdev_id);
disable_irq_nosync(host->plat->status_irq);
- schedule_work( &(((struct jz_mmc_host *) devid)->gpio_jiq_work) );
+ if (!atomic_dec_and_test(&host->detect_refcnt)) {
+ atomic_inc(&host->detect_refcnt);
+ return 0;
+ }
+
+ printk("jz-msc%d: detect card......\n", host->pdev_id);
+
+ if (from_resuming)
+ schedule_timeout(HZ / 2); /* 500ms, wait for MMC Block module resuming*/
+
+ ret = schedule_delayed_work( &(host->gpio_jiq_work), HZ / 100); /* 10ms, a little time */
+
+ return ret;
+}
+
+static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
+{
+ printk("enter jz_mmc_detect_irq ......\n");
+ jz_mmc_detect((struct jz_mmc_host *) devid, 0);
return IRQ_HANDLED;
}
-#endif
static int jz_mmc_gpio_init(struct jz_mmc_host *host, struct platform_device *pdev)
{
@@ -141,9 +133,10 @@ static int jz_mmc_gpio_init(struct jz_mmc_host *host, struct platform_device *pd
device_init_wakeup(&pdev->dev, 1);
-#if 1
- INIT_WORK(&(host->gpio_jiq_work), jiq_de_quiver);
-#endif
+ INIT_DELAYED_WORK(&(host->gpio_jiq_work), jiq_de_quiver);
+
+ atomic_set(&host->detect_refcnt, 1);
+ host->sleeping = 0;
// Check if there were any card present
if (host->plat->status) {
diff --git a/drivers/mmc/host/jzmmc/controller/jz_mmc_controller.c b/drivers/mmc/host/jzmmc/controller/jz_mmc_controller.c
index 8db9ee999a9..cb79f8954ee 100644
--- a/drivers/mmc/host/jzmmc/controller/jz_mmc_controller.c
+++ b/drivers/mmc/host/jzmmc/controller/jz_mmc_controller.c
@@ -118,7 +118,7 @@ int controller_register(struct jz_mmc_controller *controller, struct jz_mmc_host
host->plat->driver_data = &(controller->functions);
- struct jz_mmc_functions *functions = host->plat->driver_data;
+ // struct jz_mmc_functions *functions = host->plat->driver_data;
// printk("%s: host->plat->driver_data->set_clock = %x\n", __FUNCTION__, functions->set_clock);
diff --git a/drivers/mmc/host/jzmmc/controller/msc/jz_mmc_msc.c b/drivers/mmc/host/jzmmc/controller/msc/jz_mmc_msc.c
index fbdfd3862cd..1e94aea4ebe 100644
--- a/drivers/mmc/host/jzmmc/controller/msc/jz_mmc_msc.c
+++ b/drivers/mmc/host/jzmmc/controller/msc/jz_mmc_msc.c
@@ -21,26 +21,118 @@
#define MSC_STAT_ERR_BITS 0x3f
-#if 0
-#define TRACE_CMD_NUM MMC_SWITCH
+#if 1
+
+static int jzmmc_trace_level = 0;
+static int jzmmc_trace_cmd_code = -1;
+static int jzmmc_trace_data_len = -1;
+module_param(jzmmc_trace_level, int, 0644);
+module_param(jzmmc_trace_cmd_code, int, 0644);
+module_param(jzmmc_trace_data_len, int, 0644);
+
#define TRACE_CMD_REQ() \
({ \
- if ( (TRACE_CMD_NUM == -1) || (TRACE_CMD_NUM == cmd->opcode) ) \
- printk("execute_cmd: opcode = %d cmdat = %#0x arg = %#0x data_flags = %#0x\n", \
- cmd->opcode, cmdat, cmdarg, \
- host->curr.data ? host->curr.data->flags : 0); \
+ if (jzmmc_trace_level & 0x1) \
+ if ( (jzmmc_trace_cmd_code == -1) || (jzmmc_trace_cmd_code == cmd->opcode) ) \
+ printk("%s: execute_cmd: opcode = %d cmdat = %#0x arg = %#0x data_flags = %#0x\n", \
+ mmc_hostname(host->mmc), cmd->opcode, cmdat, cmdarg, \
+ host->curr.data ? host->curr.data->flags : 0); \
})
#define TRACE_CMD_RES() \
({ \
- if ( (TRACE_CMD_NUM == -1) || (TRACE_CMD_NUM == cmd->opcode) ) \
- printk("cmd done: r_type = %d resp[0] = %#0x err = %d state = %#0x\n", \
- host->curr.r_type, cmd->resp[0], cmd->error, \
- REG_MSC_STAT(host->pdev_id)); \
+ if (jzmmc_trace_level & 0x1) \
+ if ( (jzmmc_trace_cmd_code == -1) || (jzmmc_trace_cmd_code == cmd->opcode) ) \
+ printk("%s: cmd done: r_type = %d resp[0] = %#0x err = %d state = %#0x\n", \
+ mmc_hostname(host->mmc), host->curr.r_type, cmd->resp[0], cmd->error, \
+ REG_MSC_STAT(host->pdev_id)); \
+ })
+
+#define TRACE_DATA_REQ() \
+ ({ \
+ if ( (jzmmc_trace_level & 0x2) && host->curr.data ) { \
+ if ((jzmmc_trace_data_len == -1) || \
+ (jzmmc_trace_data_len == host->curr.data->blksz * host->curr.data->blocks) ) \
+ printk("%s: blksz %d blocks %d flags %08x " \
+ "tsac %d ms nsac %d\n", \
+ mmc_hostname(host->mmc), host->curr.data->blksz, \
+ host->curr.data->blocks, host->curr.data->flags, \
+ host->curr.data->timeout_ns / 1000000, \
+ host->curr.data->timeout_clks); \
+ } \
+ })
+
+#define TRACE_DATA_DONE() \
+ ({ \
+ if (jzmmc_trace_level & 0x2) \
+ if ((jzmmc_trace_data_len == -1) || \
+ (jzmmc_trace_data_len == data->blksz * data->blocks) ) \
+ printk("%s: stat = 0x%08x error = %d bytes_xfered = %d stop = %p\n", \
+ mmc_hostname(host->mmc), stat, data->error, \
+ data->bytes_xfered, host->curr.mrq->stop); \
})
#else
#define TRACE_CMD_REQ() do { } while(0)
#define TRACE_CMD_RES() do { } while(0)
+#define TRACE_DATA_REQ() do { } while(0)
+#define TRACE_DATA_DONE() do { } while(0)
+#endif
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+static void jz_mmc_dump_register(int msc_id) {
+ printk("***** mmc%d registers *****\n",msc_id);
+ printk("\tREG_MSC_STRPCL(%d) = 0x%08x\n", msc_id, REG_MSC_STRPCL(msc_id));
+ printk("\tREG_MSC_STAT(%d) = 0x%08x\n", msc_id, REG_MSC_STAT(msc_id));
+ printk("\tREG_MSC_CLKRT(%d) = 0x%08x\n", msc_id, REG_MSC_CLKRT(msc_id));
+ printk("\tREG_MSC_CMDAT(%d) = 0x%08x\n", msc_id, REG_MSC_CMDAT(msc_id));
+ printk("\tREG_MSC_RESTO(%d) = 0x%08x\n", msc_id, REG_MSC_RESTO(msc_id));
+ printk("\tREG_MSC_RDTO(%d) = 0x%08x\n", msc_id, REG_MSC_RDTO(msc_id));
+ printk("\tREG_MSC_BLKLEN(%d) = 0x%08x\n", msc_id, REG_MSC_BLKLEN(msc_id));
+ printk("\tREG_MSC_NOB(%d) = 0x%08x\n", msc_id, REG_MSC_NOB(msc_id));
+ printk("\tREG_MSC_SNOB(%d) = 0x%08x\n", msc_id, REG_MSC_SNOB(msc_id));
+ printk("\tREG_MSC_IMASK(%d) = 0x%08x\n", msc_id, REG_MSC_IMASK(msc_id));
+ printk("\tREG_MSC_IREG(%d) = 0x%08x\n", msc_id, REG_MSC_IREG(msc_id));
+ printk("\tREG_MSC_CMD(%d) = 0x%08x\n", msc_id, REG_MSC_CMD(msc_id));
+ printk("\tREG_MSC_ARG(%d) = 0x%08x\n", msc_id, REG_MSC_ARG(msc_id));
+ printk("\tREG_MSC_RES(%d) = 0x%08x\n", msc_id, REG_MSC_RES(msc_id));
+ printk("\tREG_MSC_RXFIFO(%d) = 0x%08x\n", msc_id, REG_MSC_RXFIFO(msc_id));
+ printk("\tREG_MSC_TXFIFO(%d) = 0x%08x\n", msc_id, REG_MSC_TXFIFO(msc_id));
+ printk("\tREG_MSC_LPM(%d) = 0x%08x\n", msc_id, REG_MSC_LPM(msc_id));
+}
+
+static struct timer_list debug_timer;
+#define DEBUG_INTERVAL HZ/2
+
+static void debug_func(unsigned long arg) {
+ int msc_id = (int)arg;
+ jz_mmc_dump_register(msc_id);
+
+ debug_timer.expires += DEBUG_INTERVAL;
+
+ add_timer(&debug_timer);
+}
+
+static void start_debug_timer(int msc_id) {
+ static int dbg_tm_need_init = 1;
+
+ if (dbg_tm_need_init) {
+ dbg_tm_need_init = 0;
+ init_timer(&debug_timer);
+ debug_timer.function = debug_func;
+ }
+
+ debug_timer.expires = jiffies + DEBUG_INTERVAL;
+ debug_timer.data = (unsigned long)msc_id;
+
+ add_timer(&debug_timer);
+}
+
+static void stop_debug_timer(int msc_id __attribute((unused))) {
+ del_timer_sync(&debug_timer);
+}
+
#endif
void jz_mmc_set_clock(struct jz_mmc_host *host, int rate);
@@ -81,7 +173,7 @@ void jz_mmc_set_clock(struct jz_mmc_host *host, int rate)
*/
// Cause there is only ONE devider in CPM, the clock must only <= 24MHz
-#ifndef CONFIG_SOC_JZ4750
+#if !defined(CONFIG_SOC_JZ4750) && !defined(CONFIG_SOC_JZ4750D)
#if 0
if (rate > SD_CLOCK_FAST) {
cpm_set_clock(CGU_MSCCLK, 48 * 1000 * 1000);
@@ -255,11 +347,15 @@ void jz_mmc_data_start(struct jz_mmc_host *host)
struct mmc_data *data = host->curr.data;
unsigned int nob = data->blocks;
unsigned int block_size = data->blksz;
- //unsigned int *buf = 0;
- //int count;
- int unaligned_front, unaligned_behind, tail;
int channel;
- int mode, i;
+ int mode;
+#ifndef USE_DMA_DESC
+ int i;
+ int j = 0;
+ int ds = 4;
+ struct scatterlist *sgentry;
+#endif
+
if (data->flags & MMC_DATA_WRITE) {
channel = host->dma.txchannel;
@@ -281,131 +377,35 @@ void jz_mmc_data_start(struct jz_mmc_host *host)
dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
host->dma.dir);
- for (i = 0; i < host->dma.len; i++) {
- host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
- host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
-
- unaligned_front = host->sg_cpu[i].dtadr & (DMA_TS - 1); // bytes
- unaligned_behind = (host->sg_cpu[i].dtadr + host->sg_cpu[i].dcmd) & (DMA_TS - 1); // byte
-
- if((int)(host->sg_cpu[i].dcmd - unaligned_front) > DMA_TS) {
-
-
- if(unaligned_front == 0 && unaligned_behind == 0) {
-
- /*
- dma_cache_wback_inv((unsigned long)
- CKSEG0ADDR(sg_dma_address(data->sg)) +
- data->sg->offset,
- host->sg_cpu[i].dcmd);
- */
- dma_cache_wback_inv((unsigned long)CKSEG0ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
-
- jz_mmc_start_dma(channel, host->sg_cpu[i].dtadr,
- host->sg_cpu[i].dcmd, mode, DMA_TS);
-
- host->flag_cp = 0;
-
- } else {
- /*
- printk("%s: addr unaligned\n", __FUNCTION__);
- printk("host->sg_cpu[i].dtadr = %x\n", host->sg_cpu[i].dtadr);
- printk("host->sg_cpu[i].dcmd = %d\n", host->sg_cpu[i].dcmd);
- printk("unaligned_front = %d\n", unaligned_front);
- printk("unaligned_behind = %d\n", unaligned_behind);
- */
-
- memset(host->dma_buf, 0, 4096);
- tail = host->sg_cpu[i].dcmd % DMA_TS;
-
- if(tail) {
- if(mode == DMA_MODE_READ) {
-
- dma_cache_inv((unsigned long)host->dma_buf, host->sg_cpu[i].dcmd);
-
- jz_mmc_receive_dma(host, channel, CPHYSADDR(MSC_RXFIFO(host->pdev_id)),
- CPHYSADDR(host->dma_buf), host->sg_cpu[i].dcmd / DMA_TS,
- (tail + 3) / 4);
-
- host->flag_cp = 1;
-
-/*
- dma_cache_inv((unsigned long)CKSEG0ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
- jz_mmc_start_dma(channel, host->sg_cpu[i].dtadr, host->sg_cpu[i].dcmd,
- mode, 4);
-
- host->flag_cp = 0;
-*/
-
- } else {
-
- memcpy(host->dma_buf, (void *)CKSEG0ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
-
- dma_cache_wback_inv((unsigned long)host->dma_buf, host->sg_cpu[i].dcmd);
-
- jz_mmc_send_dma(host, channel, CPHYSADDR(host->dma_buf),
- CPHYSADDR(MSC_TXFIFO(host->pdev_id)),
- host->sg_cpu[i].dcmd / DMA_TS, (tail + 3) / 4);
-/*
- dma_cache_wback_inv((unsigned long)CKSEG0ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
- jz_mmc_start_dma(channel, host->sg_cpu[i].dtadr, host->sg_cpu[i].dcmd,
- mode, 4);
-*/
- host->flag_cp = 0;
- }
- } else {
- if(mode == DMA_MODE_READ) {
-/*
- printk("host->sg_cpu[i].dtadr = %x\n", host->sg_cpu[i].dtadr);
- printk("unaligned_front = %d\n", unaligned_front);
- printk("unaligned_behind = %d\n", unaligned_behind);
- printk("host->sg_cpu[i].dcmd = %d\n", host->sg_cpu[i].dcmd);
-*/
- dma_cache_inv((unsigned long)host->dma_buf, host->sg_cpu[i].dcmd);
-
- jz_mmc_start_dma(channel, CPHYSADDR(host->dma_buf), host->sg_cpu[i].dcmd,
- mode, DMA_TS);
-
- host->flag_cp = 1;
-
- } else {
- memcpy(host->dma_buf, (void *)CKSEG1ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
-
- dma_cache_wback_inv((unsigned long)host->dma_buf, host->sg_cpu[i].dcmd);
-
- jz_mmc_start_dma(channel, CPHYSADDR(host->dma_buf), host->sg_cpu[i].dcmd,
- mode, DMA_TS);
-
- host->flag_cp = 0;
- }
- }
-
- }
- } else {
-
- if(mode == DMA_MODE_READ) {
- dma_cache_inv((unsigned long)CKSEG0ADDR(host->sg_cpu[i].dtadr), host->sg_cpu[i].dcmd);
- jz_mmc_start_dma(channel, host->sg_cpu[i].dtadr, host->sg_cpu[i].dcmd, mode, 4);
+#ifdef USE_DMA_DESC
+ jz_mmc_start_scatter_dma(channel, host, data->sg, host->dma.len, mode);
+#ifdef DEBUG
+ start_debug_timer(host->pdev_id);
+#endif
+#else
+ j = 0;
+ for_each_sg(data->sg, sgentry, host->dma.len, i) {
+ host->sg_cpu[j].dtadr = sg_dma_address(sgentry);
+ host->sg_cpu[j].dcmd = sg_dma_len(sgentry);
+ dma_cache_wback_inv((unsigned long)CKSEG0ADDR(sg_dma_address(sgentry) + data->sg->offset),
+ host->sg_cpu[j].dcmd);
+
+ if ((likely(host->sg_cpu[j].dcmd % 32 == 0)))
+ ds = 32; /* 32 byte */
+ else if (host->sg_cpu[j].dcmd % 16 == 0)
+ ds = 16; /* 16 byte */
+ else
+ ds = 4; /* default to 4 byte */
- host->flag_cp = 0;
- } else {
- memset(host->dma_buf, 0, 4096);
- memcpy(host->dma_buf, (void *)CKSEG1ADDR(host->sg_cpu[i].dtadr),
- host->sg_cpu[i].dcmd);
- dma_cache_wback_inv((unsigned long)host->dma_buf, host->sg_cpu[i].dcmd);
+ /* FIXME: bug here!!!!! wait for current dma done, then next sg */
+ jz_mmc_start_dma(channel, host->sg_cpu[j].dtadr,
+ host->sg_cpu[j].dcmd, mode, ds);
- jz_mmc_start_dma(channel, CPHYSADDR(host->dma_buf), host->sg_cpu[i].dcmd, mode, 4);
+ j++;
- host->flag_cp = 0;
- }
- }
}
+#endif
}
#else
@@ -492,9 +492,9 @@ static void jz_mmc_execute_cmd(struct jz_mmc_host *host, struct mmc_command *cmd
{
u32 timeout = 0x7fffff;
unsigned int stat;
- int err;
unsigned int stat_err_bits = 0;
u32 cmdarg = 0;
+ int err = 0;
WARN_ON(host->curr.cmd != NULL);
host->curr.cmd = cmd;
@@ -559,6 +559,9 @@ static void jz_mmc_execute_cmd(struct jz_mmc_host *host, struct mmc_command *cmd
REG_MSC_ARG(host->pdev_id) = cmd->arg;
/* Set command */
+#ifdef USE_DMA_BUSRT_64
+ cmdat |= MSC_CMDAT_RTRG_EQUALT_16;
+#endif
REG_MSC_CMDAT(host->pdev_id) = cmdat;
TRACE_CMD_REQ();
@@ -608,17 +611,15 @@ static void jz_mmc_execute_cmd(struct jz_mmc_host *host, struct mmc_command *cmd
}
}
- //timeout = 0x3fffff;
- //while ( timeout-- && ((stat = REG_MSC_STAT(host->pdev_id)) & MSC_STAT_CLK_EN))
- ;
- //if (timeout == 0)
- // printk("the clock never stopped!!!\n");
- //stat |= stat_err_bits;
- //printk("ireg = %#0x stat = %#0x timeout = %#0x\n", REG_MSC_IREG(host->pdev_id), REG_MSC_STAT(host->pdev_id), timeout);
- //printk("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
- //printk("ireg = %#0x stat = %#0x\n", REG_MSC_IREG(host->pdev_id), REG_MSC_STAT(host->pdev_id));
- //if (MMC_APP_CMD == cmd->opcode)
- // udelay(100);
+ TRACE_DATA_REQ();
+#ifndef USE_DMA
+ if (host->curr.data) {
+ if (host->curr.data->flags & MMC_DATA_READ)
+ jz_mmc_receive_pio(host);
+ else
+ jz_mmc_send_pio(host);
+ }
+#endif
jz_mmc_cmd_done(host, stat);
#ifdef USE_DMA
@@ -627,18 +628,15 @@ static void jz_mmc_execute_cmd(struct jz_mmc_host *host, struct mmc_command *cmd
jz_mmc_data_start(host);
/* in case that the controller never raise interrupt(May be there are some problem, isn't it?), we must finish the request here!!! */
- //err = wait_event_interruptible(host->msc_wait_queue, ((host->msc_ack) & (!host->eject)));
err = wait_event_interruptible_timeout(host->msc_wait_queue, ((host->msc_ack) | host->eject), 2 * HZ);
if(err == -ERESTARTSYS) {
printk("err == -ERESTARTSYS\n");
-
host->curr.mrq->cmd->error = -ENOMEDIUM;
jz_mmc_finish_request(host, host->curr.mrq);
}
-
}
#else
-
+#if 0
if (host->curr.data) {
if (host->curr.data->flags & MMC_DATA_READ)
jz_mmc_receive_pio(host);
@@ -646,6 +644,7 @@ static void jz_mmc_execute_cmd(struct jz_mmc_host *host, struct mmc_command *cmd
jz_mmc_send_pio(host);
}
#endif
+#endif
}
@@ -659,6 +658,10 @@ static int jz_mmc_data_done(struct jz_mmc_host *host)
if (!data)
return 0;
+#ifdef DEBUG
+ stop_debug_timer(host->pdev_id);
+#endif
+
stat = REG_MSC_STAT(host->pdev_id);
stat_err_bits = stat & MSC_STAT_ERR_BITS;
@@ -673,18 +676,6 @@ static int jz_mmc_data_done(struct jz_mmc_host *host)
REG_MSC_IREG(host->pdev_id) = MSC_IREG_PRG_DONE; /* clear status */
}
-#if 1
- if(host->flag_cp) {
-
- //memcpy((unsigned long)CKSEG0ADDR(sg_dma_address(data->sg)) +
- // data->sg->offset, host->dma_buf,
- // host->sg_cpu[0].dcmd);
-
- memcpy((void *)CKSEG1ADDR(host->sg_cpu[0].dtadr), host->dma_buf, host->sg_cpu[0].dcmd);
-
- }
-#endif
-
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma.len,
host->dma.dir);
@@ -703,7 +694,7 @@ static int jz_mmc_data_done(struct jz_mmc_host *host)
printk("jz-msc%d: MMC/SD/SDIO CRC error, MMC_STAT 0x%x, cmd=%d\n",
host->pdev_id, stat,
host->curr.mrq? host->curr.mrq->cmd->opcode : -1);
- data->error = -EILSEQ;
+ //data->error = -EILSEQ;
}
/*
* There appears to be a hardware design bug here. There seems to
@@ -716,7 +707,9 @@ static int jz_mmc_data_done(struct jz_mmc_host *host)
else
data->bytes_xfered = 0;
- jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
+ TRACE_DATA_DONE();
+
+ // jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
host->curr.data = NULL;
if (host->curr.mrq->stop) {
@@ -745,48 +738,18 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
unsigned int ireg = 0;
int handled = 0;
-#if 1
ireg = REG_MSC_IREG(host->pdev_id);
if (ireg) {
-
- //if(host->curr.data)
- // handled = 1;
-
if (ireg & MSC_IREG_DATA_TRAN_DONE) {
- //REG_MSC_IREG(host->pdev_id) = MSC_IREG_DATA_TRAN_DONE;
jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
//schedule_work( &(((struct jz_mmc_host *) devid)->msc_jiq_work) );
queue_work(host->msc_work_queue, &(((struct jz_mmc_host *) devid)->msc_jiq_work));
- //host->msc_ack = 1;
- //wake_up_interruptible(&host->msc_wait_queue);
handled = 1;
}
}
return IRQ_RETVAL(handled);
-#endif
-
-#if 0
- ireg = REG_MSC_IREG(host->pdev_id);
-
- if (ireg) {
-
- if (ireg & MSC_IREG_DATA_TRAN_DONE) {
- REG_MSC_IREG(host->pdev_id) = MSC_IREG_DATA_TRAN_DONE;
- //while (!(REG_MSC_STAT(host->pdev_id) & MSC_STAT_PRG_DONE)) ;
- // REG_MSC_IREG(host->pdev_id) = MSC_STAT_PRG_DONE;
- jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
-
- handled |= jz_mmc_data_done(host);
-
- host->msc_ack = 1;
- wake_up_interruptible(&host->msc_wait_queue);
- }
- }
-
- return IRQ_RETVAL(handled);
-#endif
}
static int jz_mmc_msc_init(struct jz_mmc_host *host)
@@ -796,7 +759,7 @@ static int jz_mmc_msc_init(struct jz_mmc_host *host)
jz_mmc_reset(host);
// __msc_start_clk(host->pdev_id);
REG_MSC_LPM(host->pdev_id) = 0x1; // Low power mode
- REG_MSC_RDTO(host->pdev_id) = 0xffff;
+ REG_MSC_RDTO(host->pdev_id) = 0xffffffff;
host->msc_ack = 0;
init_waitqueue_head(&host->msc_wait_queue);
diff --git a/drivers/mmc/host/jzmmc/jz_mmc_main.c b/drivers/mmc/host/jzmmc/jz_mmc_main.c
index 2c7ecedb4e1..ad994921245 100644
--- a/drivers/mmc/host/jzmmc/jz_mmc_main.c
+++ b/drivers/mmc/host/jzmmc/jz_mmc_main.c
@@ -113,7 +113,7 @@ static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct jz_mmc_host *host = mmc_priv(mmc);
struct jz_mmc_functions *functions = host->plat->driver_data;
- void *dev;
+ //void *dev;
if(!functions) {
// printk("%s: functions is NULL!\n", __FUNCTION__);
@@ -126,11 +126,11 @@ static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch(ios->power_mode) {
case MMC_POWER_ON:
- host->plat->power_on((struct device *)dev);
+ host->plat->power_on(NULL);
host->cmdat |= CMDAT_INIT;
break;
case MMC_POWER_OFF:
- host->plat->power_off((struct device *)dev);
+ host->plat->power_off(NULL);
break;
default:
break;
@@ -177,7 +177,9 @@ static int jz_mmc_probe(struct platform_device *pdev)
struct resource *memres = NULL;
struct resource *dmares = NULL;
int i;
+#ifndef USE_DMA_DESC
int ret = 0;
+#endif
if (pdev == NULL) {
printk(KERN_ERR "%s: pdev is NULL\n", __func__);
@@ -233,13 +235,16 @@ static int jz_mmc_probe(struct platform_device *pdev)
host->memres = memres;
host->dmares = dmares;
host->imask = 0xffff;
+#ifndef USE_DMA_DESC
host->sg_cpu =
dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma,
GFP_KERNEL);
+
if (!host->sg_cpu) {
ret = -ENOMEM;
goto out;
}
+#endif
spin_lock_init(&host->lock);
/*
@@ -277,9 +282,11 @@ static int jz_mmc_probe(struct platform_device *pdev)
return 0;
out:
+#ifndef USE_DMA_DESC
if (host->sg_cpu)
dma_free_coherent(&pdev->dev, PAGE_SIZE,
host->sg_cpu, host->sg_dma);
+#endif
return -1;
}
@@ -304,43 +311,44 @@ static int jz_mmc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
struct jz_mmc_host *host = mmc_priv(mmc);
int ret = 0;
+ host->sleeping = 1;
+
printk("enter jz_mmc_suspend......\n");
if (mmc) {
-
- if (host->plat->detect_pin)
- enable_irq_wake(host->plat->detect_pin);
-
if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) {
ret = mmc_suspend_host(mmc, state);
}
}
+ printk("leave jz_mmc_suspend......\n");
return ret;
}
+extern int jz_mmc_detect(struct jz_mmc_host *host, int from_resuming);
static int jz_mmc_resume(struct platform_device *dev)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
-// struct jz_mmc_host *host = mmc_priv(mmc);
- int ret = 0;
+ struct jz_mmc_host *host = mmc_priv(mmc);
printk("enter jz_mmc_resume......\n");
if (mmc) {
- if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) {
- ret = mmc_resume_host(mmc);
- //disable_irq_wake(host->plat->detect_pin);
- }
-
+ if ( (mmc->card == NULL) || (mmc->card->type != MMC_TYPE_SDIO) )
+ jz_mmc_detect(host, 1);
}
- return ret;
+ return 0;
}
+#else
+#define jz_mmc_suspend NULL
+#define jz_mmc_resume NULL
+#endif
static struct platform_driver jz_mmc0_driver = {
.probe = jz_mmc_probe,
diff --git a/drivers/mtd/mtdblock-jz.c b/drivers/mtd/mtdblock-jz.c
index 25bd79876e2..7ab8e306453 100644
--- a/drivers/mtd/mtdblock-jz.c
+++ b/drivers/mtd/mtdblock-jz.c
@@ -1,4 +1,4 @@
-/*
+/*
* Direct MTD block device access
*
* (C) Nancy <yrtan@ingenic.cn>
@@ -60,18 +60,18 @@ struct mtdblk_zone_t {
int total_phys_block;
int total_virt_block;
int bad_block_num;
-
+
int free_phys_block;
int free_virt_block;
unsigned int used_block;
unsigned int bad_block;
unsigned int *block_lookup; //index: virt_block value:block_info's index->phy_block
struct mtdblk_block_info *block_info;
-};
+};
static struct mtdblk_dev {
struct mtd_info *mtd;
- int virt_block;
+ int virt_block;
int new_phys_block;
int old_phys_block;
@@ -136,7 +136,7 @@ static int mtdblock_move_to_another_block(struct mtdblk_dev *mtdblk, int old_phy
struct mtd_oob_ops oobops;
unsigned char *tmp_block_cache;
unsigned long long pos;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift) );
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift) );
int new_phys_block, phys_block, i , ret, readfail=0;
// tmp_block_cache = kmalloc(mtdblk->mtd->erasesize, GFP_KERNEL);
@@ -157,7 +157,7 @@ static int mtdblock_move_to_another_block(struct mtdblk_dev *mtdblk, int old_phy
for(i=0; i<ppb; i++) {
do {
oobops.datbuf = &tmp_block_cache[i<<this->page_shift];
- ret = mtd->read_oob(mtd, pos, &oobops);
+ ret = mtd->read_oob(mtd, pos, &oobops);
if(ret){
readfail ++;
if (readfail < ECC_FAILD_RETRY)
@@ -185,30 +185,30 @@ static int mtdblock_move_to_another_block(struct mtdblk_dev *mtdblk, int old_phy
ret = erase_block(mtd, phys_block);
block_info[phys_block].lifetime++;
- /* if erase process error, tagged to be bad block,
+ /* if erase process error, tagged to be bad block,
* and find a new free phys_block to program
*/
if( ret < 0 ) {
printk("%s: erase failed , mark to bad block: 0x%x \n",__FILE__, phys_block);
phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
}
-
+
}while(ret < 0);
-
+
//go for write
pos = (unsigned long long)phys_block<<this->phys_erase_shift;
for(i=0; i<ppb; i++){
oobops.datbuf = &tmp_block_cache[i<<this->page_shift];
- ret =mtd->write_oob(mtd, pos, &oobops);
+ ret =mtd->write_oob(mtd, pos, &oobops);
if (ret ){
printk("%s: write failed , mark to bad block: 0x%x \n",__FILE__, phys_block);
phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
goto write_retry;
- }
+ }
pos += mtd->writesize;
- }
-// kfree(tmp_block_cache);
+ }
+// kfree(tmp_block_cache);
new_phys_block = phys_block;
return new_phys_block;
}
@@ -285,14 +285,14 @@ static int mtdblock_block_info_map_bad_block (struct mtdblk_dev *mtdblk, int phy
static int mtdblock_block_lookup_map_entry (struct mtdblk_dev *mtdblk, int virt_block, int phys_block)
{
struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
-
+
if(NULL == zone_ptr)
printk("%s: zone_ptr is null\n",__FUNCTION__);
if(virt_block >= zone_ptr->total_virt_block || virt_block < 0){
dprintk("virt_block address Abnormal\n");
return -EINVAL;
- }
+ }
if (!(zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_VALID_ENTRY)) {
dprintk("map %d -> %d free %d\n", virt_block, phys_block,zone_ptr->free_phys_block);
zone_ptr->block_lookup[virt_block] = phys_block;
@@ -303,7 +303,7 @@ static int mtdblock_block_lookup_map_entry (struct mtdblk_dev *mtdblk, int virt_
zone_ptr->used_block++;
return 0;
} else {
- dprintk("Error: map block address 0x%x -> (new) 0x%x, (old) 0x%x\n",
+ dprintk("Error: map block address 0x%x -> (new) 0x%x, (old) 0x%x\n",
virt_block, phys_block, zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_BLOCK_ADDR);
return -EINVAL;
}
@@ -313,7 +313,7 @@ static int mtdblock_block_lookup_unmap_entry (struct mtdblk_dev *mtdblk, int vir
{
struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
int phys_block;
-
+
if (zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_VALID_ENTRY) {
//dprintk("unmap %d -> %d\n", virt_block, zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_BLOCK_ADDR);
zone_ptr->block_lookup[virt_block] &= ~MTDBLOCK_BIT_VALID_ENTRY;
@@ -333,7 +333,7 @@ static int mtdblock_address_translate (struct mtdblk_dev *mtdblk, int virt_block
{
struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
unsigned int entry;
-
+
entry = zone_ptr->block_lookup[virt_block];
if (!(entry & MTDBLOCK_BIT_VALID_ENTRY))
return -EINVAL;
@@ -347,13 +347,13 @@ static int mtdblock_address_translate (struct mtdblk_dev *mtdblk, int virt_block
static void mtdblock_init_block_cache(struct mtdblk_dev *mtdblk)
{
struct nand_chip *this = mtdblk->mtd->priv;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
unsigned short spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
mtdblk->block_cache_state = STATE_UNUSED;
memset(mtdblk->page_state, 0, ppb);
memset(mtdblk->page_offset_state, 0, ppb*spp);
-
+
//must clear write buffer before using it.
mtdblk->page_num = -1;
memset(mtdblk->block_cache_data, 0xFF, mtdblk->mtd->erasesize);
@@ -362,18 +362,18 @@ static void mtdblock_init_block_cache(struct mtdblk_dev *mtdblk)
static void mtdblock_setup_block_cache ( struct mtdblk_dev *mtdblk, int virt_block, int new_phys_block, int old_phys_block)
{
struct nand_chip *this = mtdblk->mtd->priv;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
unsigned short spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
mtdblk->old_phys_block = old_phys_block;
mtdblk->new_phys_block = new_phys_block;
mtdblk->virt_block = virt_block;
mtdblk->page_num = -1;
-
+
mtdblk->block_cache_state = STATE_USED;
memset(mtdblk->page_state, 0, ppb);
memset(mtdblk->page_offset_state, 0, ppb*spp);
-
+
//must clear write buffer before using it.
memset(mtdblk->block_cache_data, 0xFF, mtdblk->mtd->erasesize);
}
@@ -387,7 +387,7 @@ static int mtdblock_fill_block_cache(struct mtdblk_dev *mtdblk)
unsigned short page, sector;
unsigned long phys_page;
unsigned long long pos;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
unsigned short sectors_per_page = mtd->writesize >> 9;
unsigned char *page_buf = mtdblk->g_page_buf;
static int fill_block1 = 0;
@@ -434,7 +434,7 @@ page_retry:
if(sector != sectors_per_page){
phys_page = (phys_block * ppb) + page;
pos = (unsigned long long)phys_page<<this->page_shift;
-page_offset_retry:
+page_offset_retry:
oobops.datbuf = page_buf;
ret = mtd->read_oob(mtd, pos, &oobops);
@@ -464,7 +464,7 @@ static int mtdblock_erase_block(struct mtdblk_dev *mtdblk, int phys_block)
struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
struct mtdblk_block_info *block_info = zone_ptr->block_info;
struct mtd_info *mtd = mtdblk->mtd;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
unsigned long long pos;
int ret;
@@ -494,13 +494,13 @@ static int mtdblock_erase_block(struct mtdblk_dev *mtdblk, int phys_block)
static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block)
{
struct mtd_info *mtd = mtdblk->mtd;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
struct mtdblk_block_info *block_info = mtdblk->zone->block_info;
struct mtd_oob_ops oobops;
unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
unsigned long long pos;
int ret,i;
-
+
dprintk("W %d-%d\n", mtdblk->virt_block,phys_block);
memset(&oobops, 0, sizeof(oobops));
oobops.mode = MTD_OOB_AUTO;
@@ -511,7 +511,7 @@ static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block)
/* spare area mark need to be changed Nancy mark */
memset((unsigned char *)&fsoobbuf, 0xff, sizeof(fsoobbuf));
- fsoobbuf.block_addr_field1 = mtdblk->virt_block;
+ fsoobbuf.block_addr_field1 = mtdblk->virt_block;
fsoobbuf.block_addr_field2 = mtdblk->virt_block;
fsoobbuf.lifetime = block_info[phys_block].lifetime;
for(i=0; i<ppb; i++){
@@ -520,7 +520,7 @@ static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block)
/* clear page cache if it is out of time! */
if (mtdblk->page_num == (phys_block * ppb) + i)
mtdblk->page_num = ~0;
-
+
ret = mtd->write_oob(mtd, pos, &oobops);
if (ret)
return -1;
@@ -531,12 +531,12 @@ static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block)
int mtdblock_flush_cache (struct mtdblk_dev *mtdblk)
{
struct mtd_info *mtd = mtdblk->mtd;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
struct mtd_oob_ops oobops;
struct mtdblk_block_info *block_info = mtdblk->zone->block_info;
unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
unsigned long phys_page;
- unsigned long long pos;
+ unsigned long long pos;
unsigned char *buf = mtdblk->g_page_buf;
int phys_block, page;
int ret = 0;
@@ -550,20 +550,19 @@ int mtdblock_flush_cache (struct mtdblk_dev *mtdblk)
oobops.ooblen = sizeof(fsoobbuf);
oobops.ooboffs = 2 ;
oobops.oobbuf = (unsigned char *)&fsoobbuf;
-
+
/* un-dirty data read from old block */
mtdblock_fill_block_cache(mtdblk);
/* erase a free block */
- phys_block = mtdblk->new_phys_block;
-
+ phys_block = mtdblk->new_phys_block;
+
restart:
do {
- if (!(block_info[phys_block].tag & MTDBLOCK_BIT_EMPTY_BLOCK)) {
ret = erase_block(mtd, phys_block);
block_info[phys_block].lifetime++;
- /* if erase process error, tagged to be bad block,
+ /* if erase process error, tagged to be bad block,
* and find a new free phys_block to program
*/
if( ret < 0 ) {
@@ -572,13 +571,10 @@ restart:
__FILE__, phys_block, mtdblk->new_phys_block);
phys_block = mtdblk->new_phys_block;
}
- }
- else
- ret = 1;
} while(ret < 0);
ret = mtdblock_program_block(mtdblk, phys_block);
- /* if write process error, tagged to be bad block,
+ /* if write process error, tagged to be bad block,
* and find a new free phys_block to program
*/
if(ret < 0){
@@ -590,35 +586,35 @@ restart:
}
/* Now, program new block done correctly */
- /* if write_verify_enable, read the block back with ECC check,
+ /* if write_verify_enable, read the block back with ECC check,
* if Ecc check fail, do Re-programming( back to restart )
*/
if( get_mtdblock_write_verify_enable() ){
for (page = 0; page < ppb; page++) {
phys_page = (phys_block * ppb) + page;
pos = (unsigned long long)phys_page<<this->page_shift;
-
- oobops.datbuf = buf;
+
+ oobops.datbuf = buf;
ret = mtd->read_oob(mtd, pos, &oobops);
if (ret ){
phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
- mtdblk->new_phys_block = phys_block;
- goto restart;
+ mtdblk->new_phys_block = phys_block;
+ goto restart;
}
- }
+ }
}
if (mtdblk->old_phys_block != mtdblk->new_phys_block) {
- phys_block = mtdblk->old_phys_block;
+ phys_block = mtdblk->old_phys_block;
ret = mtdblock_erase_block(mtdblk, phys_block);
if (ret)
{
- mtdblock_block_info_map_bad_block(mtdblk, phys_block);
+ mtdblock_block_info_map_bad_block(mtdblk, phys_block);
pos = (unsigned long long)phys_block << this->phys_erase_shift;
-
+
mtd->block_markbad(mtd, pos);
- printk("%s:erase old_phys_block %d faild,mark it bad\n",__FUNCTION__,phys_block);
+ printk("%s:erase old_phys_block %d faild,mark it bad\n",__FUNCTION__,phys_block);
}
- }
+ }
mtdblock_init_block_cache(mtdblk);
return 0;
}
@@ -630,15 +626,15 @@ static int mtdblock_mark_bad_block_to_nand(struct mtdblk_dev *mtdblk, int phys_b
unsigned long long pos;
int ret;
- /* TODO: when reading error, there is no need to unmap mtdblk->virt_block which
+ /* TODO: when reading error, there is no need to unmap mtdblk->virt_block which
will be written, unmapping is just needed when programming occurs error. */
mtdblock_block_lookup_unmap_entry(mtdblk, mtdblk->virt_block);
mtdblock_block_info_map_bad_block(mtdblk, phys_block);
- ret = erase_block(mtd, phys_block);
+ ret = erase_block(mtd, phys_block);
if(ret)
printk("%s erase block %d for marking bad failed\n", __FILE__, phys_block);
-
+
pos = (unsigned long long)phys_block << this->phys_erase_shift;
mtd->block_markbad(mtd, pos);
@@ -647,13 +643,13 @@ static int mtdblock_mark_bad_block_to_nand(struct mtdblk_dev *mtdblk, int phys_b
printk("%s ERROR: can't find_free_block!!\n", __FILE__);
mtdblock_block_lookup_map_entry(mtdblk, mtdblk->virt_block, phys_block);
-
+
return phys_block;
}
/*
* Cache stuff...
- *
+ *
* Since typical flash erasable sectors are much larger than what Linux's
* buffer cache can handle, we must implement read-modify-write on flash
* sectors for each block write requests. To avoid over-erasing flash sectors
@@ -669,7 +665,7 @@ static void erase_callback(struct erase_info *done)
static int erase_block (struct mtd_info *mtd, int phys_block )
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
struct erase_info erase;
DECLARE_WAITQUEUE(wait, current);
wait_queue_head_t wait_q;
@@ -701,29 +697,29 @@ static int erase_block (struct mtd_info *mtd, int phys_block )
return 0;
}
-static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
+static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
int len, const char *buf)
{
struct mtd_info *mtd = mtdblk->mtd;
struct nand_chip *this = mtd->priv;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
- unsigned long virt_page;
- int virt_block, old_phys_block, new_phys_block, page_offset;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned long virt_page;
+ int virt_block, old_phys_block, new_phys_block, page_offset;
int page_num_in_block;
unsigned short sectors_per_page = mtd->writesize >> 9;
virt_page = sector / sectors_per_page;
page_offset = sector % sectors_per_page;
- virt_block = virt_page / ppb;
+ virt_block = virt_page / ppb;
page_num_in_block = virt_page % ppb;
if (mtdblock_address_translate(mtdblk, virt_block, &old_phys_block) < 0) {
//dprintk("virtual block 0x%x not mapped\n",virt_block);
-
+
mutex_lock(&mtdblk->cache_mutex);
mtdblock_flush_cache(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
-
+
if (mtdblock_find_free_block(mtdblk, &new_phys_block)) {
printk("%s ERROR: can't find_free_block!!", __FILE__);
return -1;
@@ -733,7 +729,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
} else {
if ( STATE_USED == mtdblk->block_cache_state ) {
if ( mtdblk->virt_block!= virt_block) {
- // Commit before we start a new cache.
+ // Commit before we start a new cache.
mutex_lock(&mtdblk->cache_mutex);
mtdblock_flush_cache(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
@@ -744,25 +740,25 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
}
mtdblock_block_lookup_unmap_entry(mtdblk, virt_block);
mtdblock_setup_block_cache(mtdblk, virt_block, new_phys_block,
- old_phys_block);
- mtdblock_block_lookup_map_entry(mtdblk, virt_block, new_phys_block);
+ old_phys_block);
+ mtdblock_block_lookup_map_entry(mtdblk, virt_block, new_phys_block);
} else {
//dprintk("cache hit: 0x%x\n", virt_page);
}
} else {
//dprintk("in else:with existing mapping: 0x%x -> 0x%x\n", virt_block, old_phys_block);
-
+
if (mtdblock_find_free_block(mtdblk, &new_phys_block)) {
printk("%s ERROR: can't find_free_block!!", __FILE__);
return -1;
}
mtdblock_block_lookup_unmap_entry(mtdblk, virt_block);
mtdblock_setup_block_cache(mtdblk, virt_block, new_phys_block,
- old_phys_block);
+ old_phys_block);
mtdblock_block_lookup_map_entry(mtdblk, virt_block,
new_phys_block);
- }
- }
+ }
+ }
mtdblk->page_state[page_num_in_block] = 1;
mtdblk->page_offset_state[(page_num_in_block*sectors_per_page) + page_offset] = 1;
memcpy(&mtdblk->block_cache_data[(page_num_in_block<<this->page_shift) +(page_offset<<9)],
@@ -772,14 +768,14 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
-static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long sector,
+static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long sector,
int len, char *buf)
{
struct mtd_info *mtd = mtdblk->mtd;
struct nand_chip *this = mtd->priv;
struct mtd_oob_ops oobops;
- unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
- int ret, virt_block, phys_block, page_offset;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ int ret, virt_block, phys_block, page_offset;
unsigned long virt_page, phys_page, page_num_in_block;
unsigned long long pos;
unsigned short sectors_per_page = mtd->writesize >> 9;
@@ -787,9 +783,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long sector,
virt_page = sector / sectors_per_page;
page_offset = sector % sectors_per_page;
- virt_block = virt_page / ppb;
+ virt_block = virt_page / ppb;
- if (virt_block == mtdblk->virt_block) { /* if block already in cache */
+ if ((STATE_USED == mtdblk->block_cache_state) && (virt_block == mtdblk->virt_block)) { /* if block already in cache */
page_num_in_block = virt_page % ppb;
if (mtdblk->page_offset_state[(page_num_in_block*sectors_per_page) + page_offset])
memcpy(buf, &mtdblk->block_cache_data[(page_num_in_block<<this->page_shift) + (page_offset<<SECTOR_SHIFT)], len);
@@ -816,7 +812,7 @@ read_retry:
mutex_unlock(&mtdblk->cache_mutex);
}
}
-
+
if (readfail != 0){
printk("%s: page %d uncorretable ecc ---> correctable ecc due to %d times read retry,but still move this block\n",
__FILE__,(int)phys_page,readfail);
@@ -825,7 +821,7 @@ read_retry:
mutex_unlock(&mtdblk->cache_mutex);
readfail = 0;
}
-
+
mtdblk->page_num = phys_page;
}
memcpy(buf, &mtdblk->page_cache_data[page_offset<<SECTOR_SHIFT],len);
@@ -835,7 +831,7 @@ read_retry:
if ( mtdblock_address_translate( mtdblk, virt_block, &phys_block) < 0) {
// In a Flash Memory device, there might be a logical block that is
// not allcated to a physical block due to the block not being used.
- // All data returned should be set to 0xFF when accessing this logical
+ // All data returned should be set to 0xFF when accessing this logical
// block.
memset(buf, 0xFF, SECTOR_SIZE);
break;
@@ -859,14 +855,14 @@ read_retry:
mutex_lock(&mtdblk->cache_mutex);
mtdblock_flush_cache(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
-
- printk("--%s %s: move to another block\n",
+
+ printk("--%s %s: move to another block\n",
__FILE__, __FUNCTION__);
mtdblock_move_to_another_block(mtdblk, phys_block);
-
+
}
}
-
+
if (readfail != 0){
printk("%s: page %d uncorretable ecc ---> correctable ecc due to %d times read retry,but still move this block\n",
__FILE__,(int)phys_page, readfail);
@@ -877,13 +873,13 @@ read_retry:
mtdblock_move_to_another_block(mtdblk, phys_block);
readfail = 0;
}
-
+
mtdblk->page_num = phys_page;
}
memcpy(buf, &mtdblk->page_cache_data[page_offset<<SECTOR_SHIFT],len);
break;
}
- } while(1);
+ } while(1);
}
return 0;
@@ -907,11 +903,11 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
if (unlikely(dev->mtd->flags & MTD_MTDBLOCK_JZ_INVALID)) {
return 0;
}
-
+
return do_cached_write(mtdblk, block, SECTOR_SIZE, buf);
}
-#if defined(CONFIG_UDC_USE_LB_CACHE)
+#if 1//defined(CONFIG_UDC_USE_LB_CACHE)
int udc_mtdblock_readsect(struct mtdblk_dev *mtdblk,
unsigned long block, char *buf, int size)
{
@@ -968,7 +964,7 @@ static int mtdblock_init_mtdblk(int dev, struct mtd_info *mtd)
mtdblk->count = 1;
mtdblk->mtd = mtd;
mutex_init(&mtdblk->cache_mutex);
- ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ ppb = (1 << (this->phys_erase_shift - this->page_shift));
spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
if (!jz_mtdblock_cache || !jz_mtdblock_cache[dev]) {
@@ -990,7 +986,7 @@ static int mtdblock_init_mtdblk(int dev, struct mtd_info *mtd)
mtdblk->page_state = kmalloc(ppb, GFP_KERNEL);
mtdblk->page_offset_state = kmalloc(ppb*spp, GFP_KERNEL);
mtdblk->page_cache_data = kmalloc(mtdblk->mtd->writesize, GFP_KERNEL);
- mtdblk->g_page_buf = kmalloc(mtdblk->mtd->writesize, GFP_KERNEL);
+ mtdblk->g_page_buf = kmalloc(mtdblk->mtd->writesize, GFP_KERNEL);
if(!mtdblk->page_state ||
!mtdblk->page_offset_state ||
@@ -1032,7 +1028,7 @@ static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
if(!zone_ptr)
return -ENOMEM;
memset(zone_ptr, 0, sizeof(*zone_ptr));
-
+
badblock_table = get_jz_badblock_table();
zone_ptr->total_phys_block = mtd->size >> this->phys_erase_shift;
zone_ptr->bad_block_num = badblock_table[dev];
@@ -1044,8 +1040,8 @@ static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
printk("NOTICE: If you are using Yaffs2 or Jffs2, you can ignore ERROR 1 \n\n");
zone_ptr->total_virt_block = zone_ptr->total_phys_block - 1;
}
- zone_ptr->free_phys_block = zone_ptr->total_phys_block;
- zone_ptr->free_virt_block = zone_ptr->total_virt_block;
+ zone_ptr->free_phys_block = zone_ptr->total_phys_block;
+ zone_ptr->free_virt_block = zone_ptr->total_virt_block;
zone_ptr->block_lookup = kzalloc(sizeof(unsigned int) * zone_ptr->total_virt_block, GFP_KERNEL);
zone_ptr->block_info = kmalloc(sizeof(struct mtdblk_block_info) * zone_ptr->total_phys_block, GFP_KERNEL);
@@ -1053,7 +1049,7 @@ static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
if(!zone_ptr->block_lookup ||
!zone_ptr->block_info)
return -ENOMEM;
-
+
mtdblk->zone = zone_ptr;
for (phys_block = 0; phys_block < zone_ptr->total_phys_block; phys_block++) {
@@ -1063,7 +1059,7 @@ static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
mtd->read_oob(mtd, pos, &oobops);
pos += (1<<this->page_shift);
i++;
- } while(fsoobbuf.block_addr_field1 != fsoobbuf.block_addr_field2
+ } while(fsoobbuf.block_addr_field1 != fsoobbuf.block_addr_field2
&& i < get_mtdblock_oob_copies());
zone_ptr->block_info[phys_block].tag = MTDBLOCK_BIT_FREE_BLOCK;
@@ -1071,20 +1067,20 @@ static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
zone_ptr->block_info[phys_block].lifetime = 0;
else
zone_ptr->block_info[phys_block].lifetime = fsoobbuf.lifetime;
-
+
virt_block = fsoobbuf.block_addr_field1;
/*bad block scan. notice: badblock mark is in the last page of eraseblock*/
pos = (unsigned long long)phys_block<<this->phys_erase_shift;
if(mtd->block_isbad(mtd, pos) ){
mtdblock_block_info_map_bad_block(mtdblk, phys_block);
- dprintk("found bad block 0x%x -> 0x%x\n",
+ dprintk("found bad block 0x%x -> 0x%x\n",
virt_block, phys_block);
continue;
}
mtdblock_block_lookup_map_entry(mtdblk, virt_block, phys_block);
}
-
+
return 0;
}
@@ -1109,11 +1105,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
if (!mtd_blk[i])
return 0;
}
-
+#if 0
if (mtd->flags & MTD_MTDBLOCK_JZ_INVALID) {
dprintk(" mtdblock%d doesn't work over mtdblock-jz.\n",dev);
return 0;
}
+#endif
//dprintk(" mtdblock%d works over mtdblock-jz.\n",dev);
@@ -1195,7 +1192,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
} else if (mtdblklog) {
printk("%s: decrease use count\n", __FUNCTION__);
}
-
+
return 0;
}
@@ -1226,8 +1223,8 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
dev->mtd = mtd;
dev->devnum = mtd->index;
- badblock_table = get_jz_badblock_table();
- reserved_sectors = badblock_table[dev->devnum ] << (this->phys_erase_shift - 9) ;
+ badblock_table = get_jz_badblock_table();
+ reserved_sectors = badblock_table[dev->devnum ] << (this->phys_erase_shift - 9) ;
dev->size = (mtd->size >> 9) - reserved_sectors;
dev->tr = tr;
@@ -1242,7 +1239,7 @@ static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo
memset(geo, 0, sizeof(*geo));
geo->heads = 4;
geo->sectors = 16;
- geo->cylinders = dev->size/(4*16);
+ geo->cylinders = dev->size/(4*16);
return 0;
}
diff --git a/drivers/mtd/nand/jz4750_nand.c b/drivers/mtd/nand/jz4750_nand.c
index 18a56c85a90..e40dcd40156 100644
--- a/drivers/mtd/nand/jz4750_nand.c
+++ b/drivers/mtd/nand/jz4750_nand.c
@@ -1,6 +1,6 @@
/*
* linux/drivers/mtd/nand/jz4750_nand.c
- *
+ *
* JZ4750 NAND driver
*
* Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc.
@@ -24,8 +24,9 @@
#include <asm/io.h>
#include <asm/jzsoc.h>
+#include "mtd/mtd_bch4bit_n8.h"
-/* 32bit instead of 16byte burst is used by DMA to read or
+/* 32bit instead of 16byte burst is used by DMA to read or
write NAND and BCH avoiding grabbing bus for too long */
#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT
#define DIV_DS_NAND 4
@@ -104,7 +105,7 @@ extern char all_use_planes;
int nr_partitions; /* Number of partitions */
-/*
+/*
* Define partitions for flash devices
*/
#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1)
@@ -443,7 +444,7 @@ static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx)
* jzsoc_nand_bch_correct_data
* @mtd: mtd info structure
* @dat: data to be corrected
- * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and
+ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and
* BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH)
* @calc_ecc: no used
*/
@@ -604,6 +605,8 @@ static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat
return 0;
}
+extern int nand_sw_bch_ops(struct mtd_info *mtd, u8 *oobdata, int ops);
+
#if defined(CONFIG_MTD_NAND_DMA)
/**
@@ -626,6 +629,8 @@ static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *c
u8 *oobbuf;
jz_dma_desc_8word *desc;
+ nand_sw_bch_ops(mtd, chip->oob_poi, 1);
+
#if defined(CONFIG_MTD_NAND_DMABUF)
memcpy(prog_buf, buf, pagesize);
memcpy(prog_buf + pagesize, chip->oob_poi, oobsize);
@@ -718,7 +723,7 @@ static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *c
do {
err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ);
}while(err == -ERESTARTSYS);
-
+
nand_status = NAND_NONE;
dprintk("nand prog after wake up\n");
if (!err) {
@@ -788,7 +793,9 @@ static void nand_write_page_hwecc_bch_cpu(struct mtd_info *mtd, struct nand_chip
uint32_t *eccpos = chip->ecc.layout->eccpos;
static struct buf_be_corrected buf_calc0;
struct buf_be_corrected *buf_calc = &buf_calc0;
-
+
+ nand_sw_bch_ops(mtd, chip->oob_poi, 1);
+
for (i = 0; i < eccsteps; i++, p += eccsize) {
buf_calc->data = (u8 *)buf + eccsize * i;
buf_calc->oob = chip->oob_poi + oob_per_eccsize * i;
@@ -1112,6 +1119,7 @@ static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
}
chip->read_buf(mtd, chip->oob_poi, oobsize);
+ nand_sw_bch_ops(mtd, chip->oob_poi, 0);
/* Read second page OOB */
page += ppb;
if (sndcmd) {
@@ -1119,6 +1127,7 @@ static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip
sndcmd = 0;
}
chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize);
+ nand_sw_bch_ops(mtd, chip->oob_poi + oobsize, 0);
return 0;
}
@@ -1127,7 +1136,7 @@ static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chi
int global_page)
{
int status = 0, page;
- const uint8_t *buf = chip->oob_poi;
+ uint8_t *buf = chip->oob_poi;
int pagesize = mtd->writesize >> 1;
int oobsize = mtd->oobsize >> 1;
int ppb = mtd->erasesize / mtd->writesize;
@@ -1144,7 +1153,8 @@ static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chi
}
else
chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift)));
-
+
+ nand_sw_bch_ops(mtd, buf, 1);
chip->write_buf(mtd, buf, oobsize);
/* Send first command to program the OOB data */
chip->cmdfunc(mtd, 0x11, -1, -1);
@@ -1154,6 +1164,7 @@ static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chi
page += ppb;
buf += oobsize;
chip->cmdfunc(mtd, 0x81, pagesize, page);
+ nand_sw_bch_ops(mtd, buf, 1);
chip->write_buf(mtd, buf, oobsize);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
@@ -1173,7 +1184,7 @@ static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page)
page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
/* send cmd 0x60, the MSB should be valid if realplane is 4 */
- if (chip->realplanenum == 2)
+ if (chip->realplanenum == 2)
{
if(global_mafid == 0x2c)
chip->cmdfunc(mtd, 0x60, -1, page);
@@ -1315,7 +1326,7 @@ static int jz4750_nand_dma_init(struct mtd_info *mtd)
if (!read_buf)
return -ENOMEM;
#endif
- /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value
+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value
* of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */
errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL);
if (!errs)
@@ -1467,10 +1478,10 @@ static int jz4750_nand_dma_init(struct mtd_info *mtd)
/* set descriptor for __nand_sync() */
desc++;
#if USE_IRQ
- desc->dcmd =
+ desc->dcmd =
DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE;
#else
- desc->dcmd =
+ desc->dcmd =
DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
#endif
desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */
@@ -1479,8 +1490,8 @@ static int jz4750_nand_dma_init(struct mtd_info *mtd)
desc->dreqt = DMAC_DRSR_RS_NAND;
dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
- /* eccsteps*2 + 2 + 2 + 2:
- dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr)
+ /* eccsteps*2 + 2 + 2 + 2:
+ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr)
+ dma_desc_nand_cmd_pgprog(sync) */
dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word)));
/* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */
@@ -1748,7 +1759,7 @@ int __init jznand_init(void)
this->chip_delay = 20;
/* Scan to find existance of the device */
ret = nand_scan_ident(jz_mtd, nand_chips);
-
+
#ifdef CONFIG_MTD_HW_BCH_ECC
if (!ret) {
if (this->planenum == 2) {
@@ -1858,11 +1869,11 @@ static int jz4750_nand_dma_exit(struct mtd_info *mtd)
#endif
/* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes),
- * and the space for the value of ddr and dcs of channel 0 and channel
+ * and the space for the value of ddr and dcs of channel 0 and channel
* nand_dma_chan (4 * (2 + 2) bytes) */
kfree(errs);
- /* space for dma_desc_nand_read contains dma_desc_nand_prog,
+ /* space for dma_desc_nand_read contains dma_desc_nand_prog,
* dma_desc_enc and dma_desc_dec */
free_page((u32)dma_desc_nand_read);
diff --git a/drivers/mtd/nand/jz4760_nand.c b/drivers/mtd/nand/jz4760_nand.c
index b105a29f643..c894254bc91 100644
--- a/drivers/mtd/nand/jz4760_nand.c
+++ b/drivers/mtd/nand/jz4760_nand.c
@@ -1,6 +1,6 @@
/*
* linux/drivers/mtd/nand/jz4760_nand.c
- *
+ *
* JZ4760 NAND driver
*
* Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc.
@@ -94,10 +94,8 @@
#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */
#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */
-#define NAND_ADDR_OFFSET0 0x00800000 /* address port offset for share mode */
-#define NAND_CMD_OFFSET0 0x00400000 /* command port offset for share mode */
-#define NAND_ADDR_OFFSET1 0x00000008 /* address port offset for unshare mode */
-#define NAND_CMD_OFFSET1 0x00000004 /* command port offset for unshare mode */
+#define NAND_ADDR_OFFSET 0x00800000 /* address port offset for unshare mode */
+#define NAND_CMD_OFFSET 0x00400000 /* command port offset for unshare mode */
#if defined(CONFIG_MTD_NAND_DMA)
#define USE_IRQ 1
@@ -147,7 +145,7 @@ static struct mtd_info *jz_mtd = NULL;
extern struct mtd_info *jz_mtd1;
extern char all_use_planes;
-/*
+/*
* Define partitions for flash devices
*/
#if defined(CONFIG_JZ4760_CYGNUS) || defined(CONFIG_JZ4760_LEPUS)
@@ -162,13 +160,9 @@ static struct mtd_partition partition_info[] = {
use_planes: 0},
{name:"NAND ROOTFS partition",
offset:8 * 0x100000LL,
- size:120 * 0x100000LL,
+ size:504 * 0x100000LL,
use_planes: 0},
- {name:"NAND DATA1 partition",
- offset:128 * 0x100000LL,
- size:384 * 0x100000LL,
- use_planes: 1},
- {name:"NAND DATA2 partition",
+ {name:"NAND DATA partition",
offset:512 * 0x100000LL,
size:512 * 0x100000LL,
use_planes: 1},
@@ -375,9 +369,9 @@ static void jz_device_setup(void)
// 22 CS2# -
// 23 CS3# -
// 24 CS4# -
-#define GPIO_CS2_N (32*2+22)
-#define GPIO_CS3_N (32*2+23)
-#define GPIO_CS4_N (32*2+24)
+#define GPIO_CS2_N (32*0+22)
+#define GPIO_CS3_N (32*0+23)
+#define GPIO_CS4_N (32*0+24)
#ifdef CONFIG_MTD_NAND_BUS_WIDTH_16
#define SMCR_VAL 0x0d444440
@@ -473,7 +467,7 @@ static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx)
* jzsoc_nand_bch_correct_data
* @mtd: mtd info structure
* @dat: data to be corrected
- * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and
+ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and
* BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH)
* @calc_ecc: no used
*/
@@ -482,7 +476,7 @@ static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_cha
u32 stat, i;
u32 *errs = (u32 *)errs0;
int ret = 0;
-
+
if (REG_BDMAC_DCCSR(0) & BDMAC_DCCSR_BERR) {
stat = errs[0];
dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]);
@@ -497,10 +491,15 @@ static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_cha
printk("NAND:err count[%d] is too big\n",errcnt);
else
{
+ /*begin at the second DWORD*/
+ errs = (u32 *)&errs0[4];
for(i = 0;i < errcnt;i++)
{
- /*errs[i>>2] >> ((i % 2) << 4) means when errcnt is even, errs[index] >> 16*/
- bch_correct(mtd, dat, ((errs[i>>2] >> ((i % 2) << 4))) & BCH_ERR_INDEX_MASK);
+ /* errs[i>>1] get the error report regester value,
+ * (i+1) the error bit index.
+ * errs[i>>1] >> (((i + 1) % 2) << 4) means when error
+ * bit index is even, errs[i>>1] >> 16*/
+ bch_correct(mtd, dat, ((errs[i>>1] >> (((i + 1) % 2) << 4))) & BCH_ERR_INDEX_MASK);
}
}
}
@@ -530,7 +529,7 @@ static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_cha
short k;
u32 stat;
int ret = 0;
-
+
/* Write data to REG_BCH_DR */
for (k = 0; k < eccsize; k++) {
REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k];
@@ -670,6 +669,8 @@ static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat
return 0;
}
+extern int nand_sw_bch_ops(struct mtd_info *mtd, u8 *oobdata, int ops);
+
#if defined(CONFIG_MTD_NAND_DMA)
/**
@@ -692,6 +693,8 @@ static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *c
u8 *oobbuf;
jz_bdma_desc_8word *desc;
+ nand_sw_bch_ops(mtd, chip->oob_poi, 1);
+
#if defined(CONFIG_MTD_NAND_DMABUF)
memcpy(prog_buf, buf, pagesize);
memcpy(prog_buf + pagesize, chip->oob_poi, oobsize);
@@ -786,7 +789,7 @@ static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *c
do {
err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ);
}while(err == -ERESTARTSYS);
-
+
nand_status = NAND_NONE;
dprintk("nand prog after wake up\n");
if (!err) {
@@ -857,6 +860,8 @@ static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *ch
static struct buf_be_corrected buf_calc0;
struct buf_be_corrected *buf_calc = &buf_calc0;
+ nand_sw_bch_ops(mtd, chip->oob_poi, 1);
+
for (i = 0; i < eccsteps; i++, p += eccsize) {
buf_calc->data = (u8 *)buf + eccsize * i;
buf_calc->oob = chip->oob_poi + oob_per_eccsize * i;
@@ -1042,7 +1047,7 @@ static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chi
if (pagesize != 512)
__nand_cmd(NAND_CMD_READSTART);
-
+
#if USE_IRQ
do {
err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ);
@@ -1081,7 +1086,7 @@ static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chi
else
mtd->ecc_stats.corrected += stat;
}
-
+
#if defined(CONFIG_MTD_NAND_DMABUF)
memcpy(buf, read_buf, pagesize);
memcpy(chip->oob_poi, read_buf + pagesize, oobsize);
@@ -1194,6 +1199,8 @@ static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
}
chip->read_buf(mtd, chip->oob_poi, oobsize);
+ nand_sw_bch_ops(mtd, chip->oob_poi, 0);
+
/* Read second page OOB */
page += ppb;
if (sndcmd) {
@@ -1201,6 +1208,8 @@ static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip
sndcmd = 0;
}
chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize);
+ nand_sw_bch_ops(mtd, chip->oob_poi + oobsize, 0);
+
return 0;
}
@@ -1227,6 +1236,7 @@ static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chi
else
chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift)));
+ nand_sw_bch_ops(mtd, buf, 1);
chip->write_buf(mtd, buf, oobsize);
/* Send first command to program the OOB data */
chip->cmdfunc(mtd, 0x11, -1, -1);
@@ -1236,6 +1246,7 @@ static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chi
page += ppb;
buf += oobsize;
chip->cmdfunc(mtd, 0x81, pagesize, page);
+ nand_sw_bch_ops(mtd, buf, 1);
chip->write_buf(mtd, buf, oobsize);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
@@ -1255,7 +1266,7 @@ static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page)
page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
/* send cmd 0x60, the MSB should be valid if realplane is 4 */
- if (chip->realplanenum == 2)
+ if (chip->realplanenum == 2)
{
if(global_mafid == 0x2c)
chip->cmdfunc(mtd, 0x60, -1, page);
@@ -1377,7 +1388,7 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
dma_desc_pPN = (jz_bdma_desc_8word *)__get_free_page(GFP_KERNEL);
dma_desc_rPN = (jz_bdma_desc_8word *)__get_free_page(GFP_KERNEL);
pn_buf = kmalloc(2 * sizeof(unsigned int), GFP_KERNEL);
-
+
memset(dma_desc_pPN, 0, 4096);
memset(dma_desc_rPN, 0, 4096);
memset(pn_buf, 0, 2 * sizeof(unsigned int));
@@ -1390,7 +1401,7 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
#else
*pn_buf = PN_ENABLE;
#endif
-
+
*(pn_buf + 1) = PN_DISABLE;
dma_cache_wback_inv((unsigned int)pn_buf, 2 * sizeof(unsigned int));
#endif /* USE_PN */
@@ -1407,7 +1418,7 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
if (!read_buf)
return -ENOMEM;
#endif
- /* space for the error reports of bch decoding((4 * ERRS_SIZE * eccsteps) bytes), and the space for the value
+ /* space for the error reports of bch decoding((4 * ERRS_SIZE * eccsteps) bytes), and the space for the value
* of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */
errs = (u32 *)kmalloc(4 * (2 + 2 + ERRS_SIZE * eccsteps), GFP_KERNEL);
if (!errs)
@@ -1519,7 +1530,7 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
desc->dcnt = 1; /* size: 1 word */
desc->dreqt = BDMAC_DRSR_RS_AUTO;
dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs);
-
+
#if USE_PN
desc = dma_desc_pPN;
next = CPHYSADDR((u32)dma_desc_nand_prog);
@@ -1599,10 +1610,10 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
/* set descriptor for __nand_sync() */
desc++;
#if USE_IRQ
- desc->dcmd =
+ desc->dcmd =
BDMAC_DCMD_SWDH_32 | BDMAC_DCMD_DWDH_32 | BDMAC_DCMD_DS_32BIT | BDMAC_DCMD_TIE;
#else
- desc->dcmd =
+ desc->dcmd =
BDMAC_DCMD_SWDH_32 | BDMAC_DCMD_DWDH_32 | BDMAC_DCMD_DS_32BIT;
#endif
desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */
@@ -1612,8 +1623,8 @@ static int jz4760_nand_dma_init(struct mtd_info *mtd)
desc->dreqt = BDMAC_DRSR_RS_NAND;
dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
- /* eccsteps*2 + 2 + 2 + 2:
- dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr)
+ /* eccsteps*2 + 2 + 2 + 2:
+ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr)
+ dma_desc_nand_cmd_pgprog(sync) */
dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_bdma_desc_8word)));
/* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */
@@ -1804,7 +1815,7 @@ int __init jznand_init(void)
#else
printk(KERN_INFO " CPU mode.\n");
#endif
-
+
cpm_start_clock(CGM_BDMA);
/* Allocate memory for MTD device structure and private data */
@@ -1837,8 +1848,8 @@ int __init jznand_init(void)
jz_mtd->priv = this;
- addr_offset = NAND_ADDR_OFFSET0;
- cmd_offset = NAND_CMD_OFFSET0;
+ addr_offset = NAND_ADDR_OFFSET;
+ cmd_offset = NAND_CMD_OFFSET;
/* Set & initialize NAND Flash controller */
jz_device_setup();
@@ -1953,11 +1964,11 @@ static int jz4760_nand_dma_exit(struct mtd_info *mtd)
#endif
/* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes),
- * and the space for the value of ddr and dcs of channel 0 and channel
+ * and the space for the value of ddr and dcs of channel 0 and channel
* nand_dma_chan (4 * (2 + 2) bytes) */
kfree(errs);
- /* space for dma_desc_nand_read contains dma_desc_nand_prog,
+ /* space for dma_desc_nand_read contains dma_desc_nand_prog,
* dma_desc_enc and dma_desc_dec */
free_page((u32)dma_desc_nand_read);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index acd69924c9b..acb90ead5ef 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -53,17 +53,18 @@
#endif
#include <asm/jzsoc.h>
+#include "mtd/mtd_bch4bit_n8.h"
u8 nand_nce; /* indicates which chip select on JZSOC is used for current nand chip */
int global_page; /* page index of large page used for nand with multiple planes */
int global_mafid; /* ID of manufacture */
struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */
-/* indicates whether multiple planes operation is used by all partitions
+/* indicates whether multiple planes operation is used by all partitions
if multiple planes is supported by NAND */
char all_use_planes = 1;
-/* The pointer to the address of block cache for partitions which work
+/* The pointer to the address of block cache for partitions which work
over mtdblock-jz */
extern struct mtd_partition partition_info[]; /* defined in jz47xx_nand.c */
unsigned char **jz_mtdblock_cache = NULL; /* used by mtdblock-jz.c */
@@ -93,9 +94,9 @@ static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 36,
.eccpos = {
28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
@@ -105,8 +106,8 @@ static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 28,
.eccpos = {
24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51},
.oobfree = {
{.offset = 2,
@@ -165,9 +166,9 @@ static struct nand_ecclayout nand_oob_128 = {
.eccbytes = 104,
.eccpos = {
24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
@@ -853,7 +854,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
/* Hardware controller shared among independend devices */
if (!chip->controller->active)
chip->controller->active = chip;
-
+
if (new_state == FL_PM_SUSPENDED)
printk("%s(): chip->controller->active: 0x%p, chip: 0x%p, chip->state: 0x%d.\n", __func__, chip->controller->active, chip, chip->state);
if (chip->controller->active == chip && chip->state == FL_READY) {
@@ -1164,7 +1165,7 @@ static int nand_read_page_hwecc_rs(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t page;
uint8_t flag = 0;
-
+
page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0];
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
@@ -1475,7 +1476,7 @@ static int nand_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
return -EINVAL;
if (!len)
return 0;
-
+
nand_get_device(chip, mtd, FL_READING);
chip->ops.len = len;
@@ -1491,6 +1492,37 @@ static int nand_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
return ret;
}
+int nand_sw_bch_ops(struct mtd_info *mtd, u8 *oobdata, int ops)
+{
+#if !defined(CONFIG_SOC_JZ4750) && !defined(CONFIG_SOC_JZ4750D) && !defined(CONFIG_SOC_JZ4760)
+ //dprintk("%s: Not using jz4750 or jz4760\n", __FUNCTION__);
+ return 0;
+#endif
+
+ int i, cnt, off, length;
+ unsigned char *oobp = oobdata;
+ struct nand_chip *chip = mtd->priv;
+
+ off = chip->ecc.layout->oobfree[0].offset;
+ length = 16;
+
+ if (ops) //encode
+ {
+ do_bch_encode(oobp + off, oobp + length + off, length);
+ }
+ else //decode
+ {
+ cnt = 0;
+ for (i = 0; i < 32; i++)
+ if (*(oobp + i) == 0xff)
+ cnt++;
+
+ if (cnt < 24)
+ do_bch_decode_and_correct (oobp + off, oobp + length + off, length);
+ }
+ return 0;
+}
+
/**
* nand_read_oob_std - [REPLACABLE] the most common OOB data read function
* @mtd: mtd info structure
@@ -1506,6 +1538,8 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
sndcmd = 0;
}
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_sw_bch_ops(mtd, chip->oob_poi, 0);
+
return sndcmd;
}
@@ -1561,6 +1595,8 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf = chip->oob_poi;
int length = mtd->oobsize;
+ nand_sw_bch_ops(mtd, chip->oob_poi, 1);
+
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, buf, length);
/* Send command to program the OOB data */
@@ -3102,7 +3138,7 @@ int nand_scan_tail(struct mtd_info *mtd)
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
- /* Create jz_mtd1 for one plane operation if the NAND support multiple
+ /* Create jz_mtd1 for one plane operation if the NAND support multiple
planes operation, because some partitions will only use one plane. */
if ((chip->planenum == 2) && !all_use_planes) {
int i, len, numblocks;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index cd0914ec898..0477566e270 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -139,6 +139,7 @@ ep_matches (
if (!gadget->is_dualspeed && max > 64)
return 0;
/* FALLTHROUGH */
+ break;
case USB_ENDPOINT_XFER_ISOC:
/* ISO: limit 1023 bytes full speed, 1024 high speed */
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index d2aa076dfbe..bfc1c06240c 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -127,7 +127,7 @@ config USB_MUSB_OTG
endchoice
config USB_MUSB_PERIPHERAL_HOTPLUG
bool "Support Ingenic USB Device Controller Hotplug"
- depends on SOC_JZ4760
+ depends on SOC_JZ4760 && USB_GADGET_MUSB_HDRC
# enable peripheral support (including with OTG)
config USB_GADGET_MUSB_HDRC
diff --git a/drivers/usb/musb/jz4760.c b/drivers/usb/musb/jz4760.c
index 0d0cd34dd14..a45e873742c 100644
--- a/drivers/usb/musb/jz4760.c
+++ b/drivers/usb/musb/jz4760.c
@@ -1,3 +1,5 @@
+#ifndef __JZ4760_C__
+#define __JZ4760_C__
/*
* Author: River <zwang@ingenic.cn>
*/
@@ -166,6 +168,7 @@ static void jz_musb_set_vbus(struct musb *musb, int is_on)
#define GPIO_OTG_ID_PIN __GPIO('E', 2)
#endif
+#define OTG_HOTPLUG_PIN __GPIO('E', 19)
#define GPIO_OTG_ID_IRQ (IRQ_GPIO_0 + GPIO_OTG_ID_PIN)
#define GPIO_OTG_STABLE_JIFFIES 10
@@ -204,12 +207,18 @@ static void do_otg_id_pin_state(struct musb *musb)
if (pin) {
/* B */
- __gpio_as_irq_fall_edge(GPIO_OTG_ID_PIN);
+#ifdef CONFIG_USB_MUSB_PERIPHERAL_HOTPLUG
+ __gpio_unmask_irq(OTG_HOTPLUG_PIN);
+#endif
+ __gpio_as_irq_fall_edge(GPIO_OTG_ID_PIN);
} else {
-
/* A */
- if (is_otg_enabled(musb))
+ if (is_otg_enabled(musb)) {
+#ifdef CONFIG_USB_MUSB_PERIPHERAL_HOTPLUG
+ __gpio_mask_irq(OTG_HOTPLUG_PIN); // otg's host mode not support hotplug
+#endif
__gpio_as_irq_rise_edge(GPIO_OTG_ID_PIN);
+ }
}
return;
@@ -291,3 +300,5 @@ int musb_platform_exit(struct musb *musb)
return 0;
}
+
+#endif
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index cfed9af3f5a..73b7b3818da 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1,3 +1,4 @@
+
/*
* MUSB OTG driver peripheral support
*
@@ -299,7 +300,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
csr);
#ifndef CONFIG_MUSB_PIO_ONLY
- if (is_dma_capable() && musb_ep->dma) {
+ if (is_dma_capable() && musb_ep->dma && request->dma % 4 == 0) {
struct dma_controller *c = musb->dma_controller;
use_dma = (request->dma != DMA_ADDR_INVALID);
@@ -626,7 +627,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
len = musb_readw(epio, MUSB_RXCOUNT);
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
- if (is_dma_capable() && musb_ep->dma) {
+ if (is_dma_capable() && musb_ep->dma && request->dma % 4 == 0) {
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
diff --git a/drivers/video/jz4760_lcd.c b/drivers/video/jz4760_lcd.c
index ba92933d193..9a1d1b99ad5 100644
--- a/drivers/video/jz4760_lcd.c
+++ b/drivers/video/jz4760_lcd.c
@@ -467,8 +467,8 @@ static void ctrl_disable(void)
__lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */
else {
int cnt;
- /* when CPU main freq is 336MHz,wait for 16ms */
- cnt = 336000 * 16;
+ /* when CPU main freq is 336MHz,wait for 30ms */
+ cnt = 528000 * 30;
__lcd_set_dis(); /* regular disable */
//__lcd_clr_ena();
while(!__lcd_disable_done() && cnt) {
@@ -1893,7 +1893,8 @@ static int jz4760_fb_suspend(struct platform_device *pdev, pm_message_t state)
printk("%s(): called.\n", __func__);
screen_off();
- ctrl_disable();
+ //ctrl_disable();
+ __lcd_clr_ena();
__cpm_stop_lcd();
@@ -1910,13 +1911,8 @@ static int jz4760_fb_resume(struct platform_device *pdev)
printk("%s(): called.\n", __func__);
__cpm_start_lcd();
-
- __gpio_set_pin(GPIO_DISP_OFF_N);
- __lcd_special_on();
+ screen_on();
__lcd_set_ena();
- mdelay(200);
-
- __lcd_set_backlight_level(cfb->backlight_level);
return 0;
}
diff --git a/drivers/video/jz4760_lcd.h b/drivers/video/jz4760_lcd.h
index f95e1345e32..9ee7c1cc990 100644
--- a/drivers/video/jz4760_lcd.h
+++ b/drivers/video/jz4760_lcd.h
@@ -22,7 +22,7 @@
struct jz4760_lcd_dma_desc {
unsigned int next_desc; /* LCDDAx */
unsigned int databuf; /* LCDSAx */
- unsigned int frame_id; /* LCDFIDx */
+ unsigned int frame_id; /* LCDFIDx */
unsigned int cmd; /* LCDCMDx */
unsigned int offsize; /* Stride Offsize(in word) */
unsigned int page_width; /* Stride Pagewidth(in word) */
@@ -190,7 +190,7 @@ struct jz4760lcd_info {
__gpio_set_pin(SPEN); \
udelay(400); \
} while(0)
-
+
#define __lcd_special_pin_init() \
do { \
__gpio_as_output(SPEN); /* use SPDA */ \
@@ -295,7 +295,7 @@ do { \
__spi_write_reg1((reg<<2), val); \
udelay(100); \
}while(0)
-
+
#define __lcd_special_pin_init() \
do { \
__gpio_as_output(SPEN); /* use SPDA */\
@@ -384,7 +384,7 @@ do { \
__spi_write_reg1((reg<<2|2), val); \
udelay(100); \
}while(0)
-
+
#define __lcd_special_pin_init() \
do { \
__gpio_as_output(SPEN); /* use SPDA */\
@@ -434,7 +434,7 @@ do { \
__spi_write_reg(0x36, 0x20); \
*/
// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
-
+
#define __lcd_special_off() \
do { \
__spi_write_reg(0x00, 0x03); \
@@ -442,16 +442,174 @@ do { \
#endif /* CONFIG_JZ4760_LCD_FOXCONN_PT035TN01 or CONFIG_JZ4760_LCD_INNOLUX_PT035TN01_SERIAL */
+#if defined(CONFIG_JZ4760_LCD_TOPPOLY_TD043MGEB1)
+#if defined(CONFIG_JZ4760_LEPUS) /* board pavo */
+ #define SPEN (32*1+29) /*LCD_CS*/
+ #define SPCK (32*1+28) /*LCD_SCL*/
+ #define SPDA (32*1+21) /*LCD_SDA*/
+ #define LCD_RET (32*5+6) /*LCD_DISP_N use for lcd reset*/
+//#define LCD_STBY (32*4+25) /*LCD_STBY, use for lcd standby*/
+#else
+#error "driver/video/jz_toppoly_td043mgeb1.h, please define SPI pins on your board."
+#endif
+
+#if 0
+#define __spi_write_reg(reg, val) \
+ do { \
+ unsigned char no; \
+ unsigned short value; \
+ unsigned char a=0; \
+ unsigned char b=0; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ a=reg; \
+ b=val; \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(500); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(500); \
+ value=((a<<10)|(b&0xFF)); \
+ for(no=0;no<16;no++) \
+ { \
+ if((value&0x8000)==0x8000){ \
+ __gpio_set_pin(SPDA);} \
+ else{ \
+ __gpio_clear_pin(SPDA); } \
+ udelay(500); \
+ __gpio_set_pin(SPCK); \
+ value=(value<<1); \
+ udelay(500); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ __gpio_set_pin(SPEN); \
+ udelay(4000); \
+ } while (0)
+#define __spi_read_reg(reg,val) \
+ do{ \
+ unsigned char no; \
+ unsigned short value; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ value = ((reg << 2) | (1 << 1)); \
+ val = 0; \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(50); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(50); \
+ for (no = 0; no < 16; no++ ) { \
+ udelay(50); \
+ if(no < 8) \
+ { \
+ if (value & 0x80) /* send data */ \
+ __gpio_set_pin(SPDA); \
+ else \
+ __gpio_clear_pin(SPDA); \
+ udelay(50); \
+ __gpio_set_pin(SPCK); \
+ value = (value << 1); \
+ udelay(50); \
+ __gpio_clear_pin(SPCK); \
+ if(no == 7) \
+ __gpio_as_input(SPDA); \
+ } \
+ else \
+ { \
+ udelay(100); \
+ __gpio_set_pin(SPCK); \
+ udelay(50); \
+ val = (val << 1); \
+ val |= __gpio_get_pin(SPDA); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ } \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while(0)
+
+#endif
+
+#define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ __gpio_set_pin(SPEN); \
+ __gpio_as_output(LCD_RET); \
+ udelay(500); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(1000); \
+ __gpio_set_pin(LCD_RET); \
+ udelay(1000); \
+ } while (0)
+
+#if 0
+#define __lcd_special_on() \
+ do { \
+ udelay(1000); \
+ __spi_write_reg(0x02, 0x07); \
+ __spi_write_reg(0x03, 0x5F); \
+ __spi_write_reg(0x04, 0x17); \
+ __spi_write_reg(0x05, 0x20); \
+ __spi_write_reg(0x06, 0x08); \
+ __spi_write_reg(0x07, 0x20); \
+ __spi_write_reg(0x08, 0x20); \
+ __spi_write_reg(0x09, 0x20); \
+ __spi_write_reg(0x0A, 0x20); \
+ __spi_write_reg(0x0B, 0x20); \
+ __spi_write_reg(0x0C, 0x20); \
+ __spi_write_reg(0x0D, 0x22); \
+ __spi_write_reg(0x0E, 0x2F); \
+ __spi_write_reg(0x0F, 0x2f); \
+ __spi_write_reg(0x10, 0x2F); \
+ __spi_write_reg(0x11, 0x15); \
+ __spi_write_reg(0x12, 0xaa); \
+ __spi_write_reg(0x13, 0xFF); \
+ __spi_write_reg(0x14, 0x86); \
+ __spi_write_reg(0x15, 0x8e); \
+ __spi_write_reg(0x16, 0xd6); \
+ __spi_write_reg(0x17, 0xfe); \
+ __spi_write_reg(0x18, 0x28); \
+ __spi_write_reg(0x19, 0x52); \
+ __spi_write_reg(0x1A, 0x7c); \
+ __spi_write_reg(0x1B, 0xe9); \
+ __spi_write_reg(0x1C, 0x42); \
+ __spi_write_reg(0x1D, 0x88); \
+ __spi_write_reg(0x1E, 0xb8); \
+ __spi_write_reg(0x1F, 0xff); \
+ __spi_write_reg(0x20, 0xf0); \
+ __spi_write_reg(0x21, 0xf0); \
+ __spi_write_reg(0x22, 0x08); \
+ } while (0)
+#endif
+
+#if 1
+#define __lcd_special_off() \
+ do { \
+ __gpio_clear_pin(LCD_RET); \
+ __gpio_as_input(LCD_RET); \
+ } while (0)
+#endif
+
+#endif /* LCD_TOPPOLY_TD043MGEB1 */
+
#if defined(CONFIG_JZ4760_LCD_TRULY_TFT_GG1P0319LTSW_W)
static inline void CmdWrite(unsigned int cmd)
-{
+{
while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */
udelay(30);
REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd;
}
static inline void DataWrite(unsigned int data)
-{
+{
while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */
// udelay(30);
REG_SLCD_DATA = SLCD_DATA_RS_DATA | data;
@@ -460,11 +618,11 @@ static inline void DataWrite(unsigned int data)
static inline void delay(long delay_time)
{
- long cnt;
+ long cnt;
// delay_time *= (384/8);
delay_time *= (43/8);
-
+
for (cnt=0;cnt<delay_time;cnt++)
{
asm("nop\n"
@@ -495,17 +653,17 @@ static inline void delay(long delay_time)
/*---- LCD Initial ----*/
static void SlcdInit(void)
-{
- delay(10000);
+{
+ delay(10000);
CmdWrite(0x0301); //reset
delay(10000);
- CmdWrite(0x0101);
- CmdWrite(0x0301);
- CmdWrite(0x0008);
+ CmdWrite(0x0101);
+ CmdWrite(0x0301);
+ CmdWrite(0x0008);
CmdWrite(0x2201); //reset
CmdWrite(0x0000);
CmdWrite(0x0080); //0x0020
- delay(10000);
+ delay(10000);
CmdWrite(0x2809);
CmdWrite(0x1900);
@@ -526,7 +684,7 @@ static void SlcdInit(void)
CmdWrite(0x2070);
CmdWrite(0x1e81);
CmdWrite(0x1b01);
-
+
CmdWrite(0x0200);
CmdWrite(0x0504); //y address increcement
CmdWrite(0x0D00); //*240
@@ -576,46 +734,46 @@ static void SlcdInit(void)
CmdWrite(0x0000);
CmdWrite(0x01A0);
CmdWrite(0x3B01);
-
+
CmdWrite(0x2809);
- delay(1000);
+ delay(1000);
CmdWrite(0x1900);
- delay(1000);
+ delay(1000);
CmdWrite(0x2110);
- delay(1000);
+ delay(1000);
CmdWrite(0x1805);
- delay(1000);
+ delay(1000);
CmdWrite(0x1E01);
- delay(1000);
+ delay(1000);
CmdWrite(0x1847);
- delay(1000);
+ delay(1000);
CmdWrite(0x1867);
- delay(1000);
+ delay(1000);
CmdWrite(0x18F7);
- delay(1000);
- CmdWrite(0x2100);
- delay(1000);
+ delay(1000);
+ CmdWrite(0x2100);
+ delay(1000);
CmdWrite(0x2809);
- delay(1000);
- CmdWrite(0x1A05);
- delay(1000);
- CmdWrite(0x19E8);
- delay(1000);
+ delay(1000);
+ CmdWrite(0x1A05);
+ delay(1000);
+ CmdWrite(0x19E8);
+ delay(1000);
CmdWrite(0x1F64);
- delay(1000);
- CmdWrite(0x2045);
- delay(1000);
- CmdWrite(0x1E81);
- delay(1000);
- CmdWrite(0x1B09);
- delay(1000);
+ delay(1000);
+ CmdWrite(0x2045);
+ delay(1000);
+ CmdWrite(0x1E81);
+ delay(1000);
+ CmdWrite(0x1B09);
+ delay(1000);
CmdWrite(0x0020);
- delay(1000);
+ delay(1000);
CmdWrite(0x0120);
- delay(1000);
-
+ delay(1000);
+
CmdWrite(0x3B01);
- delay(1000);
+ delay(1000);
/* Set Window(239,319), Set Cursor(239,319) */
CmdWrite(0x0510);
@@ -629,7 +787,7 @@ static void SlcdInit(void)
CmdWrite(0x42EF);
CmdWrite(0x443F);
CmdWrite(0x4301);
-
+
}
#if defined(CONFIG_JZ4760_LEPUS)
@@ -701,7 +859,8 @@ do { \
#define __lcd_display_off() \
do { \
- __lcd_special_off(); \
+ __lcd_special_off(); \
+ __gpio_clear_pin(GPIO_LCD_VCC_EN_N); \
} while (0)
#else /* other boards */
diff --git a/fs/sync.c b/fs/sync.c
index 3422ba61d86..86dc6378876 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -18,6 +18,10 @@
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
+static struct mtdblk_dev *g_udc_mtdblk;
+extern struct mtdblk_dev *udc_get_mtdblk(void);
+extern void udc_flush_cache(struct mtdblk_dev *mtdblk);
+
/*
* Do the filesystem syncing work. For simple filesystems sync_inodes_sb(sb, 0)
* just dirties buffers with inodes so we have to submit IO for these buffers
@@ -35,6 +39,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
sync_inodes_sb(sb, wait);
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, wait);
+
return __sync_blockdev(sb->s_bdev, wait);
}
@@ -80,6 +85,7 @@ EXPORT_SYMBOL_GPL(sync_filesystem);
* flags again, which will cause process A to resync everything. Fix that with
* a local mutex.
*/
+extern struct kmem_cache *fat_inode_cachep;
static void sync_filesystems(int wait)
{
struct super_block *sb;
@@ -110,6 +116,9 @@ restart:
}
spin_unlock(&sb_lock);
mutex_unlock(&mutex);
+
+ g_udc_mtdblk = udc_get_mtdblk();
+ udc_flush_cache(g_udc_mtdblk);
}
/*
diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
index bf7f54a6ee0..70e64d55776 100644
--- a/fs/yaffs2/Makefile
+++ b/fs/yaffs2/Makefile
@@ -5,6 +5,6 @@
obj-y := yaffs2.o
obj-$(CONFIG_YAFFS_FS) := yaffs_mtdif.o yaffs_mtdif2.o
obj-$(CONFIG_YAFFS_FS) += yaffs_ecc.o yaffs_fs.o yaffs_guts.o
-obj-$(CONFIG_YAFFS_FS) += yaffs_packedtags2.o yaffs_qsort.o
+obj-$(CONFIG_YAFFS_FS) += yaffs_packedtags2.o yaffs_qsort.o bch4bit_n8_decoder.o bch4bit_n8_encoder.o bch4bit_n8_global.o
obj-$(CONFIG_YAFFS_FS) += yaffs_tagscompat.o yaffs_tagsvalidity.o
obj-$(CONFIG_YAFFS_FS) += yaffs_checkptrw.o yaffs_nand.o
diff --git a/fs/yaffs2/bch4bit_n8_decoder.c b/fs/yaffs2/bch4bit_n8_decoder.c
new file mode 100644
index 00000000000..b4d1e9e6d2b
--- /dev/null
+++ b/fs/yaffs2/bch4bit_n8_decoder.c
@@ -0,0 +1,470 @@
+/*******************************************************************************
+*
+* File Name: bch_decoder.c
+* Revision: 2.0
+* Date: March, 2007
+* Email: nandsupport@micron.com
+* Company: Micron Technology, Inc.
+*
+* Description: Micron NAND BCH Decoder
+*
+* References:
+* 1. Error Control Coding, Lin & Costello, 2nd Ed., 2004
+* 2. Error Control Codes, Blahut, 1983
+**
+* Disclaimer This software code and all associated documentation, comments or other
+* of Warranty: information (collectively "Software") is provided "AS IS" without
+* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY
+* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES
+* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT
+* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE
+* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
+* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR
+* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
+* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE
+* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI,
+* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING,
+* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION,
+* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE
+* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGES. Because some jurisdictions prohibit the exclusion or
+* limitation of liability for consequential or incidental damages, the
+* above limitation may not apply to you.
+*
+* Copyright 2007 Micron Technology, Inc. All rights reserved.
+*
+* Rev Author Date Changes
+* --- --------------- ---------- -------------------------------
+* 1.0 ZS 08/07/2006 Initial release
+* 2.0 PF 03/05/2007 Fixed bug that caused some codewords
+* to not be corrected
+*
+*
+*******************************************************************************/
+
+#include "mtd/mtd_bch4bit_n8.h"
+
+#if BCH4_DEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#endif
+
+int bb[rr_max] ; // Syndrome polynomial
+int s[rr_max]; // Syndrome values
+int syn_error; // Syndrome error indicator
+int location[tt_max]; // Error location
+static int ttx2; // 2t
+
+static unsigned char spdata[nn_max];
+static void data_syndrome(unsigned char *bit_data, int len)
+{
+/* Parallel computation of 2t syndromes.
+ * Use the same lookahead matrix T_G_R of parallel computation of parity check bits.
+ * The incoming streams are fed into registers from left hand
+ */
+ int i, j, iii, idx;
+ unsigned int Temp, bb_temp, bb_pack;
+ unsigned char ch;
+
+ // Initialize the parity bits.
+ bb_pack = 0;
+
+ // Compute syndrome polynomial: S(x) = C(x) mod g(x)
+ // S(t) = T_G_R S(t-1) + R(t)
+ // Ref: L&C, pp. 225, Fig. 6.11
+ for (iii = (len + rr) - 1; iii >= 0; iii--)
+ {
+ bb_temp = (bb_pack >> 1);
+ Temp = (bb_pack & 1) * 0xF72DA17E;
+ bb_temp = bb_temp ^ (bit_data[iii] << 31);
+ bb_pack = bb_temp ^ Temp;
+ }
+
+#if 1
+ idx = 0;
+ for (i = 0; i < rr; i += 8)
+ {
+ ch = bb_pack >> 24;
+ bb[i + 7] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 6] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 5] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 4] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 3] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 2] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 1] = ch & 1;
+ ch = ch >> 1;
+ bb[i + 0] = ch & 1;
+ bb_pack = bb_pack << 8;
+ }
+#endif
+
+
+ // Computation 2t syndromes based on S(x)
+ // Odd syndromes
+#if 0
+ syn_error = 0 ;
+ for (i = 1; i <= ttx2 - 1; i = i+2)
+ {
+ s[i] = 0 ;
+ for (j = 0; j < rr; j++)
+ if (bb[j] != 0)
+ s[i] ^= alpha_to[(index_of[bb[j]] + i*j) % nn] ;
+ if (s[i] != 0)
+ syn_error = 1 ; // set flag if non-zero syndrome => error
+ }
+#else
+ syn_error = 0 ;
+ s[1] = s[3] = s[5] = s[7] = 0;
+ for (j = 0; j < rr; j++)
+ {
+ if (bb[j] != 0)
+ {
+ s[1] ^= alpha_to[j * 1];
+ s[3] ^= alpha_to[j * 3];
+ s[5] ^= alpha_to[j * 5];
+ s[7] ^= alpha_to[j * 7];
+ }
+ }
+ if (s[1] != 0 || s[3] != 0 || s[5] != 0 || s[7] != 0)
+ syn_error = 1 ; // set flag if non-zero syndrome => error
+#endif
+
+ // Even syndrome = (Odd syndrome) ** 2
+ for (i = 2; i <= ttx2; i = i + 2)
+ {
+ j = i / 2;
+ if (s[j] == 0)
+ s[i] = 0;
+ else
+ s[i] = alpha_to[(2 * index_of[s[j]]) % nn];
+ }
+
+#if BCH4_DEBUG
+ {
+ printf("# The syndrome from parallel decoder is:\n");
+ for (i = 1; i <= ttx2; i++)
+ printf(" %4d (%4d) == 0x%04x (0x%x)\n", s[i],index_of[s[i]],s[i], index_of[s[i]]) ;
+ printf("\n\n") ;
+ }
+#endif
+}
+
+static int data_decode_bch(unsigned char *bit_data, unsigned int *error_pos, int len)
+{
+ register int i, j, elp_sum ;
+ int L[ttx2+3]; // Degree of ELP
+ int u_L[ttx2+3]; // Difference between step number and the degree of ELP
+ int reg[tt+3]; // Register state
+ int elp[ttx2+4][ttx2+4]; // Error locator polynomial (ELP)
+ int desc[ttx2+4]; // Discrepancy 'mu'th discrepancy
+ int u; // u = 'mu' + 1 and u ranges from -1 to 2*t (see L&C)
+ int q, flag; //
+ int err_count;
+
+ data_syndrome(bit_data, len);
+
+ if (!syn_error)
+ {
+ flag = 1 ; // No errors
+ *error_pos = 0;
+ }
+ else
+ {
+ // Having errors, begin decoding procedure
+ // Simplified Berlekamp-Massey Algorithm for Binary BCH codes
+ // Ref: Blahut, pp.191, Chapter 7.6
+ // Ref: L&C, pp.212, Chapter 6.4
+ //
+ // Following the terminology of Lin and Costello's book:
+ // desc[u] is the 'mu'th discrepancy, where
+ // u='mu'+1 and
+ // 'mu' (the Greek letter!) is the step number ranging
+ // from -1 to 2*t (see L&C)
+ // l[u] is the degree of the elp at that step, and
+ // u_L[u] is the difference between the step number
+ // and the degree of the elp.
+
+#if BCH4_DEBUG
+ printf("Beginning Berlekamp loop\n");
+#endif
+
+ // initialise table entries
+ for (i = 1; i <= ttx2; i++)
+ s[i] = index_of[s[i]];
+
+ desc[0] = 0; /* index form */
+ desc[1] = s[1]; /* index form */
+ elp[0][0] = 1; /* polynomial form */
+ elp[1][0] = 1; /* polynomial form */
+ //elp[2][0] = 1; /* polynomial form */
+ for (i = 1; i < ttx2; i++)
+ {
+ elp[0][i] = 0; /* polynomial form */
+ elp[1][i] = 0; /* polynomial form */
+ //elp[2][i] = 0; /* polynomial form */
+ }
+ L[0] = 0;
+ L[1] = 0;
+ //L[2] = 0;
+ u_L[0] = -1;
+ u_L[1] = 0;
+ //u_L[2] = 0;
+ u = -1;
+
+ do {
+ // even loops always produce no discrepany so they can be skipped
+ u = u + 2;
+#if BCH4_DEBUG
+ printf("Loop %d:\n", u);
+ printf(" desc[%d] = %x\n", u, desc[u]);
+#endif
+ if (desc[u] == -1)
+ {
+ L[u + 2] = L[u];
+ for (i = 0; i <= L[u]; i++)
+ elp[u + 2][i] = elp[u][i];
+ }
+ else
+ {
+ // search for words with greatest u_L[q] for which desc[q]!=0
+ q = u - 2;
+ if (q<0) q=0;
+ // Look for first non-zero desc[q]
+ while ((desc[q] == -1) && (q > 0))
+ q=q-2;
+
+ if (q < 0)
+ q = 0;
+
+ // Find q such that desc[u]!=0 and u_L[q] is maximum
+ if (q > 0)
+ {
+ j = q;
+ do {
+ j = j - 2;
+ if (j < 0) j = 0;
+ if ((desc[j] != -1) && (u_L[q] < u_L[j]))
+ q = j;
+ } while (j > 0);
+ }
+
+ // store degree of new elp polynomial
+ if (L[u] > L[q] + u - q)
+ L[u + 2] = L[u];
+ else
+ L[u + 2] = L[q] + u - q;
+
+ // Form new elp(x)
+ for (i = 0; i < ttx2; i++)
+ elp[u + 2][i] = 0;
+ for (i = 0; i <= L[q]; i++)
+ if (elp[q][i] != 0)
+ elp[u + 2][i + u - q] = alpha_to[(desc[u] + nn - desc[q] + index_of[elp[q][i]]) % nn];
+
+ for (i = 0; i <= L[u]; i++)
+ elp[u + 2][i] ^= elp[u][i];
+ }
+
+ u_L[u + 2] = u+1 - L[u + 2];
+
+ // Form (u+2)th discrepancy. No discrepancy computed on last iteration
+ if (u < ttx2)
+ {
+ if (s[u + 2] != -1)
+ desc[u + 2] = alpha_to[s[u + 2]];
+ else
+ desc[u + 2] = 0;
+
+ for (i = 1; i <= L[u + 2]; i++)
+ if ((s[u + 2 - i] != -1) && (elp[u + 2][i] != 0))
+ desc[u + 2] ^= alpha_to[(s[u + 2 - i] + index_of[elp[u + 2][i]]) % nn];
+ // put desc[u+2] into index form
+ desc[u + 2] = index_of[desc[u + 2]];
+
+ }
+
+#if BCH4_DEBUG
+ {
+ printf(" deg(elp) = %2d --> elp(%2d):", L[u], u);
+ for (i=0; i<=L[u]; i++)
+ printf(" 0x%x", elp[u][i]);
+ printf("\n");
+ printf(" deg(elp) = %2d --> elp(%2d):", L[u+2], u+2);
+ for (i=0; i<=L[u+2]; i++)
+ printf(" 0x%x", elp[u+2][i]);
+ printf("\n");
+ printf(" u_L[%2d] = %2d\n", u, u_L[u]);
+ printf(" u_L[%2d] = %2d\n", u+2, u_L[u+2]);
+ }
+#endif
+ } while ((u < (ttx2-1)) && (L[u + 2] <= tt));
+
+
+#if BCH4_DEBUG
+ printf("\n");
+#endif
+ u=u+2;
+ L[ttx2-1] = L[u];
+
+ if (L[ttx2-1] > tt)
+ flag = 0;
+ else
+ {
+ // Chien's search to find roots of the error location polynomial
+ // Ref: L&C pp.216, Fig.6.1
+#if BCH4_DEBUG
+ printf("Chien Search: L[%d]=%d=%x\n", ttx2-1,L[ttx2-1],L[ttx2-1]);
+ printf("Sigma(x) = \n");
+
+ for (i = 0; i <= L[u]; i++)
+ if (elp[u][i] != 0)
+ printf(" %4d (%4d)\n", elp[u][i], index_of[elp[u][i]]);
+ else
+ printf(" 0\n");
+#endif
+
+ for (i = 1; i <= L[ttx2-1]; i++)
+ {
+ reg[i] = index_of[elp[u][i]];
+#if BCH4_DEBUG
+ printf(" reg[%d]=%d=%x\n", i,reg[i],reg[i]);
+#endif
+ }
+
+ err_count = 0 ;
+ // Begin chien search
+ for (i = 1; i <= nn; i++)
+ {
+ elp_sum = 1 ;
+ for (j = 1; j <= L[ttx2-1]; j++)
+ if (reg[j] != -1)
+ {
+ reg[j] = (reg[j] + j) % nn ;
+ elp_sum ^= alpha_to[reg[j]] ;
+
+ }
+
+ // store root and error location number indices
+ if (!elp_sum)
+ {
+ err_count++ ;
+ *(error_pos + err_count) = nn - i;
+ }
+ }
+
+ // Number of roots = degree of elp hence <= tt errors
+ if (err_count == L[ttx2-1])
+ {
+ flag = 1;
+ *error_pos = err_count;
+ }
+ // Number of roots != degree of ELP => >tt errors and cannot solve
+ else
+ flag = 0;
+ }
+ }
+ return flag;
+}
+
+
+int do_bch_decode (unsigned char *inbuf, unsigned char *paritybuf, unsigned int *error_pos, int len)
+{
+ int in_count, i, j, idx;
+ unsigned char ch;
+
+ ttx2 = 2 * tt;
+ /* split bits from paritybuf and store in data array[]. */
+ idx = 0;
+ for (i = 0; i <= rr - 8; i += 8)
+ {
+ ch = paritybuf[idx++];
+ spdata[i + 7] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 6] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 5] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 4] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 3] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 2] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 1] = ch & 1;
+ ch = ch >> 1;
+ spdata[i + 0] = ch & 1;
+ }
+
+ /* split bits from data and store in data array []. */
+ in_count = rr;
+ for (i = 0; i < len; i++)
+ {
+ ch = inbuf[i];
+
+ spdata[in_count + 7] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 6] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 5] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 4] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 3] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 2] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 1] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 0] = ch & 1;
+
+ in_count += 8;
+ }
+
+ /* decode data bch. */
+ return data_decode_bch(spdata, error_pos, len * 8);
+
+}
+
+void do_bch_correct_data (unsigned char *inbuf, unsigned int *errpos)
+{
+ int i;
+ for (i = errpos[0]; i > 0 ; i--)
+ {
+ if (errpos[i] >= rr)
+ {
+ int pos;
+ pos = errpos[i] - rr;
+ inbuf[pos >> 3] = inbuf[pos >> 3] ^ (1 << ((8 - pos - 1) & 7));
+ }
+ }
+}
+
+
+extern int printk(char *, ...);
+
+void do_bch_decode_and_correct (unsigned char *inbuf, unsigned char *paritybuf, int len)
+{
+ int flag, errpos[64];
+
+ flag = do_bch_decode (inbuf, paritybuf, errpos, len);
+ if (flag == 1)
+ {
+ if (errpos[0] != 0)
+ {
+ //printk("{Software bch_decode: correct error}\n");
+ do_bch_correct_data (inbuf, errpos);
+ }
+ }
+ else
+ printk("{Software bch_decode: uncorrect error}\n");
+}
+
diff --git a/fs/yaffs2/bch4bit_n8_encoder.c b/fs/yaffs2/bch4bit_n8_encoder.c
new file mode 100644
index 00000000000..1bde1e31ff1
--- /dev/null
+++ b/fs/yaffs2/bch4bit_n8_encoder.c
@@ -0,0 +1,155 @@
+/*******************************************************************************
+*
+* File Name: bch_encoder.c
+* Revision: 1.0
+* Date: August, 2006
+* Email: nandsupport@micron.com
+* Company: Micron Technology, Inc.
+*
+* Description: Micron NAND BCH Encoder
+*
+* References:
+* 1. Error Control Coding, Lin & Costello, 2nd Ed., 2004
+* 2. Error Control Codes, Blahut, 1983
+**
+* Disclaimer This software code and all associated documentation, comments or other
+* of Warranty: information (collectively "Software") is provided "AS IS" without
+* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY
+* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES
+* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT
+* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE
+* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
+* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR
+* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
+* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE
+* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI,
+* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING,
+* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION,
+* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE
+* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGES. Because some jurisdictions prohibit the exclusion or
+* limitation of liability for consequential or incidental damages, the
+* above limitation may not apply to you.
+*
+* Copyright 2006 Micron Technology, Inc. All rights reserved.
+*
+* Rev Author Date Changes
+* --- --------------- ---------- -------------------------------
+* 1.0 ZS 08/07/2006 Initial release
+*
+*
+*******************************************************************************/
+
+#include "mtd/mtd_bch4bit_n8.h"
+
+#if BCH4_DEBUG
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+static unsigned char spdata[kk_max]; // Information data and received data
+static void data_encode_bch(unsigned char *bit_data, unsigned char *paritybuf, int len)
+/* Parallel computation of n - k parity check bits.
+ * Use lookahead matrix T_G_R.
+ * The incoming streams are fed into registers from the right hand
+ */
+{
+ int iii;
+ unsigned int Temp, bb_temp, bb_pack;
+#if BCH4_DEBUG
+ int bb_idx, idx, bb_bit[rr_max];
+ unsigned char *pp2, ch;
+#endif
+
+ // Initialize the parity bits.
+ bb_pack = 0;
+
+ // Compute parity checks
+ // S(t) = T_G_R [ S(t-1) + M(t) ]
+ // Ref: Parallel CRC, Shieh, 2001
+ for (iii = len - 1; iii >= 0; iii--)
+ {
+ bb_pack = bb_pack ^ bit_data[iii];
+ bb_temp = (bb_pack >> 1);
+ Temp = (bb_pack & 1) * 0xF72DA17E;
+ bb_pack = bb_temp ^ Temp;
+ }
+
+#if BCH4_DEBUG
+ idx = 0;
+ pp2 = (unsigned char *)&bb_pack;
+ for (i = 0; i < rr; i += 8)
+ {
+ ch = bb_pack >> 24;
+ bb_bit[i + 7] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 6] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 5] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 4] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 3] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 2] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 1] = ch & 1;
+ ch = ch >> 1;
+ bb_bit[i + 0] = ch & 1;
+ bb_pack = bb_pack << 8;
+ }
+
+ printf(" Parity bb \n");
+ for (i = rr-1; i >= 0; i--)
+ printf("%d", bb_bit[i]);
+ printf(" \n");
+#endif
+
+ paritybuf[0] = (bb_pack >> 24);
+ paritybuf[1] = (bb_pack >> 16);
+ paritybuf[2] = (bb_pack >> 8);
+ paritybuf[3] = (bb_pack >> 0);
+
+#if BCH4_DEBUG
+ for (i = 0; i < bb_idx; i++)
+ printf("0x%02x, ", paritybuf[i]);
+ printf(" \n");
+#endif
+}
+
+void do_bch_encode (unsigned char *inbuf, unsigned char *paritybuf, int len)
+{
+ int in_count, i;
+ unsigned char ch;
+ /* split bits from data and store in data array []. */
+ in_count = 0;
+ for (i = 0; i < len; i++)
+ {
+ ch = inbuf[i];
+
+ spdata[in_count + 7] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 6] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 5] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 4] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 3] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 2] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 1] = ch & 1;
+ ch = ch >> 1;
+ spdata[in_count + 0] = ch & 1;
+
+ in_count += 8;
+ }
+
+ /* encode data bch. */
+ data_encode_bch(spdata, paritybuf, len * 8);
+}
+
diff --git a/fs/yaffs2/bch4bit_n8_global.c b/fs/yaffs2/bch4bit_n8_global.c
new file mode 100644
index 00000000000..742cb82515e
--- /dev/null
+++ b/fs/yaffs2/bch4bit_n8_global.c
@@ -0,0 +1,268 @@
+/*******************************************************************************
+*
+* File Name: bch_global.c
+* Revision: 1.0
+* Date: August, 2006
+* Email: nandsupport@micron.com
+* Company: Micron Technology, Inc.
+*
+* Description: Micron NAND BCH Global Package
+*
+* Function: 1. Create Galois Field
+* 2. Create Generator Polynomial
+* 3. Create Parallel Generator Polynomial
+*
+* References:
+* 1. Error Control Coding, Lin & Costello, 2nd Ed., 2004
+* 2. Error Control Codes, Blahut, 1983
+* 3. Parallel CRC, Shieh, 2001
+*
+**
+* Disclaimer This software code and all associated documentation, comments or other
+* of Warranty: information (collectively "Software") is provided "AS IS" without
+* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY
+* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES
+* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT
+* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE
+* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
+* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR
+* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
+* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE
+* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI,
+* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING,
+* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION,
+* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE
+* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGES. Because some jurisdictions prohibit the exclusion or
+* limitation of liability for consequential or incidental damages, the
+* above limitation may not apply to you.
+*
+* Copyright 2006 Micron Technology, Inc. All rights reserved.
+*
+*
+* Rev Author Date Changes
+* --- --------------- ---------- -------------------------------
+* 1.0 ZS 08/07/2006 Initial release
+* 2.0 PF 03/05/2007 Expanded constants to allow
+* larger fields
+*
+*
+/*******************************************************************************/
+
+int mm = 8, nn = 255, tt = 4; // BCH code parameters
+
+//mm = 8, nn = 255
+int alpha_to[256] = { // Galois field
+0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,0x00000080,
+0x00000071,0x000000e2,0x000000b5,0x0000001b,0x00000036,0x0000006c,0x000000d8,0x000000c1,
+0x000000f3,0x00000097,0x0000005f,0x000000be,0x0000000d,0x0000001a,0x00000034,0x00000068,
+0x000000d0,0x000000d1,0x000000d3,0x000000d7,0x000000df,0x000000cf,0x000000ef,0x000000af,
+0x0000002f,0x0000005e,0x000000bc,0x00000009,0x00000012,0x00000024,0x00000048,0x00000090,
+0x00000051,0x000000a2,0x00000035,0x0000006a,0x000000d4,0x000000d9,0x000000c3,0x000000f7,
+0x0000009f,0x0000004f,0x0000009e,0x0000004d,0x0000009a,0x00000045,0x0000008a,0x00000065,
+0x000000ca,0x000000e5,0x000000bb,0x00000007,0x0000000e,0x0000001c,0x00000038,0x00000070,
+0x000000e0,0x000000b1,0x00000013,0x00000026,0x0000004c,0x00000098,0x00000041,0x00000082,
+0x00000075,0x000000ea,0x000000a5,0x0000003b,0x00000076,0x000000ec,0x000000a9,0x00000023,
+0x00000046,0x0000008c,0x00000069,0x000000d2,0x000000d5,0x000000db,0x000000c7,0x000000ff,
+0x0000008f,0x0000006f,0x000000de,0x000000cd,0x000000eb,0x000000a7,0x0000003f,0x0000007e,
+0x000000fc,0x00000089,0x00000063,0x000000c6,0x000000fd,0x0000008b,0x00000067,0x000000ce,
+0x000000ed,0x000000ab,0x00000027,0x0000004e,0x0000009c,0x00000049,0x00000092,0x00000055,
+0x000000aa,0x00000025,0x0000004a,0x00000094,0x00000059,0x000000b2,0x00000015,0x0000002a,
+0x00000054,0x000000a8,0x00000021,0x00000042,0x00000084,0x00000079,0x000000f2,0x00000095,
+0x0000005b,0x000000b6,0x0000001d,0x0000003a,0x00000074,0x000000e8,0x000000a1,0x00000033,
+0x00000066,0x000000cc,0x000000e9,0x000000a3,0x00000037,0x0000006e,0x000000dc,0x000000c9,
+0x000000e3,0x000000b7,0x0000001f,0x0000003e,0x0000007c,0x000000f8,0x00000081,0x00000073,
+0x000000e6,0x000000bd,0x0000000b,0x00000016,0x0000002c,0x00000058,0x000000b0,0x00000011,
+0x00000022,0x00000044,0x00000088,0x00000061,0x000000c2,0x000000f5,0x0000009b,0x00000047,
+0x0000008e,0x0000006d,0x000000da,0x000000c5,0x000000fb,0x00000087,0x0000007f,0x000000fe,
+0x0000008d,0x0000006b,0x000000d6,0x000000dd,0x000000cb,0x000000e7,0x000000bf,0x0000000f,
+0x0000001e,0x0000003c,0x00000078,0x000000f0,0x00000091,0x00000053,0x000000a6,0x0000003d,
+0x0000007a,0x000000f4,0x00000099,0x00000043,0x00000086,0x0000007d,0x000000fa,0x00000085,
+0x0000007b,0x000000f6,0x0000009d,0x0000004b,0x00000096,0x0000005d,0x000000ba,0x00000005,
+0x0000000a,0x00000014,0x00000028,0x00000050,0x000000a0,0x00000031,0x00000062,0x000000c4,
+0x000000f9,0x00000083,0x00000077,0x000000ee,0x000000ad,0x0000002b,0x00000056,0x000000ac,
+0x00000029,0x00000052,0x000000a4,0x00000039,0x00000072,0x000000e4,0x000000b9,0x00000003,
+0x00000006,0x0000000c,0x00000018,0x00000030,0x00000060,0x000000c0,0x000000f1,0x00000093,
+0x00000057,0x000000ae,0x0000002d,0x0000005a,0x000000b4,0x00000019,0x00000032,0x00000064,
+0x000000c8,0x000000e1,0x000000b3,0x00000017,0x0000002e,0x0000005c,0x000000b8,};
+
+int index_of[256] = { // Galois field
+0xffffffff,0x00000000,0x00000001,0x000000e7,0x00000002,0x000000cf,0x000000e8,0x0000003b,
+0x00000003,0x00000023,0x000000d0,0x0000009a,0x000000e9,0x00000014,0x0000003c,0x000000b7,
+0x00000004,0x0000009f,0x00000024,0x00000042,0x000000d1,0x00000076,0x0000009b,0x000000fb,
+0x000000ea,0x000000f5,0x00000015,0x0000000b,0x0000003d,0x00000082,0x000000b8,0x00000092,
+0x00000005,0x0000007a,0x000000a0,0x0000004f,0x00000025,0x00000071,0x00000043,0x0000006a,
+0x000000d2,0x000000e0,0x00000077,0x000000dd,0x0000009c,0x000000f2,0x000000fc,0x00000020,
+0x000000eb,0x000000d5,0x000000f6,0x00000087,0x00000016,0x0000002a,0x0000000c,0x0000008c,
+0x0000003e,0x000000e3,0x00000083,0x0000004b,0x000000b9,0x000000bf,0x00000093,0x0000005e,
+0x00000006,0x00000046,0x0000007b,0x000000c3,0x000000a1,0x00000035,0x00000050,0x000000a7,
+0x00000026,0x0000006d,0x00000072,0x000000cb,0x00000044,0x00000033,0x0000006b,0x00000031,
+0x000000d3,0x00000028,0x000000e1,0x000000bd,0x00000078,0x0000006f,0x000000de,0x000000f0,
+0x0000009d,0x00000074,0x000000f3,0x00000080,0x000000fd,0x000000cd,0x00000021,0x00000012,
+0x000000ec,0x000000a3,0x000000d6,0x00000062,0x000000f7,0x00000037,0x00000088,0x00000066,
+0x00000017,0x00000052,0x0000002b,0x000000b1,0x0000000d,0x000000a9,0x0000008d,0x00000059,
+0x0000003f,0x00000008,0x000000e4,0x00000097,0x00000084,0x00000048,0x0000004c,0x000000da,
+0x000000ba,0x0000007d,0x000000c0,0x000000c8,0x00000094,0x000000c5,0x0000005f,0x000000ae,
+0x00000007,0x00000096,0x00000047,0x000000d9,0x0000007c,0x000000c7,0x000000c4,0x000000ad,
+0x000000a2,0x00000061,0x00000036,0x00000065,0x00000051,0x000000b0,0x000000a8,0x00000058,
+0x00000027,0x000000bc,0x0000006e,0x000000ef,0x00000073,0x0000007f,0x000000cc,0x00000011,
+0x00000045,0x000000c2,0x00000034,0x000000a6,0x0000006c,0x000000ca,0x00000032,0x00000030,
+0x000000d4,0x00000086,0x00000029,0x0000008b,0x000000e2,0x0000004a,0x000000be,0x0000005d,
+0x00000079,0x0000004e,0x00000070,0x00000069,0x000000df,0x000000dc,0x000000f1,0x0000001f,
+0x0000009e,0x00000041,0x00000075,0x000000fa,0x000000f4,0x0000000a,0x00000081,0x00000091,
+0x000000fe,0x000000e6,0x000000ce,0x0000003a,0x00000022,0x00000099,0x00000013,0x000000b6,
+0x000000ed,0x0000000f,0x000000a4,0x0000002e,0x000000d7,0x000000ab,0x00000063,0x00000056,
+0x000000f8,0x0000008f,0x00000038,0x000000b4,0x00000089,0x0000005b,0x00000067,0x0000001d,
+0x00000018,0x00000019,0x00000053,0x0000001a,0x0000002c,0x00000054,0x000000b2,0x0000001b,
+0x0000000e,0x0000002d,0x000000aa,0x00000055,0x0000008e,0x000000b3,0x0000005a,0x0000001c,
+0x00000040,0x000000f9,0x00000009,0x00000090,0x000000e5,0x00000039,0x00000098,0x000000b5,
+0x00000085,0x0000008a,0x00000049,0x0000005c,0x0000004d,0x00000068,0x000000db,0x0000001e,
+0x000000bb,0x000000ee,0x0000007e,0x00000010,0x000000c1,0x000000a5,0x000000c9,0x0000002f,
+0x00000095,0x000000d8,0x000000c6,0x000000ac,0x00000060,0x00000064,0x000000af,0x00000057,
+};
+
+
+
+int rr = 32;
+
+int T_G_R[32][32] = { // Parallel lookahead table
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00000001,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,
+};
+
+unsigned int T_G_R_PACK[128] = {
+0x00000001, 0x80000001, 0x40000001, 0x20000001, 0x10000000, 0x08000001, 0x04000001, 0x02000001,
+0x01000000, 0x00800000, 0x00400001, 0x00200000, 0x00100001, 0x00080001, 0x00040000, 0x00020001,
+0x00010001, 0x00008000, 0x00004001, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000201,
+0x00000100, 0x00000081, 0x00000041, 0x00000021, 0x00000011, 0x00000009, 0x00000005, 0x00000002,
+};
+
+
diff --git a/fs/yaffs2/utils/Makefile b/fs/yaffs2/utils/Makefile
index 008f18914f5..ba8c0e55009 100644
--- a/fs/yaffs2/utils/Makefile
+++ b/fs/yaffs2/utils/Makefile
@@ -40,7 +40,7 @@ MAKETOOLS = #mipsel-linux-
CC=$(MAKETOOLS)gcc
-COMMONLINKS = yaffs_ecc.c
+COMMONLINKS = yaffs_ecc.c bch4bit_n8_encoder.c bch4bit_n8_global.c
COMMONOBJS = $(COMMONLINKS:.c=.o)
ifeq ($(CONFIG_YAFFS_ECC_RS), y)
diff --git a/fs/yaffs2/utils/mkyaffs2image.c b/fs/yaffs2/utils/mkyaffs2image.c
index 857703355be..d59845eaf23 100644
--- a/fs/yaffs2/utils/mkyaffs2image.c
+++ b/fs/yaffs2/utils/mkyaffs2image.c
@@ -1,7 +1,7 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
*
- * makeyaffsimage.c
+ * makeyaffsimage.c
*
* Makes a YAFFS file system image that can be used to load up a file system.
*
@@ -18,13 +18,13 @@
* Nick Bane modifications flagged NCB
*
* Endian handling patches by James Ng.
- *
+ *
* mkyaffs2image hacks by NCB
*
* Changes by Sergey Kubushin flagged KSI
*
*/
-
+
/* KSI:
* All this nightmare should be rewritten from ground up. Why save return
* values if nobody checks them? The read/write function returns only one
@@ -38,7 +38,7 @@
* And BTW, what was one supposed to do with that file that this horror
* occasionally managed to generate?
*/
-
+
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
@@ -52,6 +52,7 @@
#include "yaffs_guts.h"
#include "yaffs_packedtags2.h"
+#include "mtd/mtd_bch4bit_n8.h"
unsigned yaffs_traceMask=0;
@@ -92,9 +93,9 @@ static struct nand_oobinfo oob_layout[] = {
.eccbytes = 36,
.eccpos = {
28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {{2, 26}}
},
@@ -167,15 +168,15 @@ void process_file(char *file_name);
static int obj_compare(const void *a, const void * b)
{
objItem *oa, *ob;
-
+
oa = (objItem *)a;
ob = (objItem *)b;
-
+
if(oa->dev < ob->dev) return -1;
if(oa->dev > ob->dev) return 1;
if(oa->ino < ob->ino) return -1;
if(oa->ino > ob->ino) return 1;
-
+
return 0;
}
@@ -189,7 +190,7 @@ static void add_obj_to_list(dev_t dev, ino_t ino, int obj)
obj_list[n_obj].obj = obj;
n_obj++;
qsort(obj_list,n_obj,sizeof(objItem),obj_compare);
-
+
}
else
{
@@ -207,7 +208,7 @@ static int find_obj_in_list(dev_t dev, ino_t ino)
test.dev = dev;
test.ino = ino;
-
+
if(n_obj > 0)
{
i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare);
@@ -263,7 +264,7 @@ void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt)
{
int i, j = 0, k, n;
unsigned char pt2_byte_buf[PT2_BYTES];
-
+
*((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber;
*((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId;
*((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId;
@@ -280,12 +281,12 @@ void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt)
k = oob_layout[layout_no].oobfree[j][0];
n = oob_layout[layout_no].oobfree[j][1];
-
+
if (n == 0) {
fprintf(stderr, "No OOB space for tags");
exit(-1);
}
-
+
for (i = 0; i < PT2_BYTES; i++) {
if (n == 0) {
j++;
@@ -312,13 +313,13 @@ static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
if(error < 0) return error;
yaffs_InitialiseTags(&t);
-
+
t.chunkId = chunkId;
// t.serialNumber = 0;
t.serialNumber = 1; // **CHECK**
t.byteCount = nBytes;
t.objectId = objId;
-
+
t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
// added NCB **CHECK**
@@ -337,12 +338,18 @@ static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
yaffs_PackTags2(&pt,&t);
memset(spare_buf, 0xff, spareSize);
-
+
if (layout_no == 0) {
memcpy(spare_buf, &pt, sizeof(yaffs_PackedTags2));
} else {
nandmtd2_pt2buf(spare_buf, &pt);
- }
+ }
+
+ /* In oob area, bad block status: 2 Bytes, yaffs info: 16 Bytes.
+ We use software 4-bit bch algorithm to encode yaffs info, and
+ put the 4-Bytes parity data in (spare_buf + 2 + 16) area. */
+ memset(spare_buf + 18, 0xff, spareSize - 18);
+ do_bch_encode(spare_buf + 2, spare_buf + 2 + 16, 16);
#ifdef CONFIG_MTD_HW_BCH_ECC
/* When programming using usb boot, the data in oob after eccpos should be
@@ -359,7 +366,7 @@ static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
(((x) & 0xFF00) >> 8))
-
+
/* KSI: Removed for now. TBD later when the proper util (from scratch) is written */
#if 0
// This one is easier, since the types are more standard. No funky shifts here.
@@ -370,7 +377,7 @@ static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
// name = skip. Char array. Not swapped.
oh->yst_mode = SWAP32(oh->yst_mode);
-#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
+#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
// In fact, WinCE would be *THE* place where this would be an issue!
oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
@@ -424,19 +431,19 @@ static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
{
__u8 bytes[MAX_CHUNKSIZE];
-
-
+
+
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
-
+
memset(bytes,0xff,chunkSize);
-
+
oh->type = t;
oh->parentObjectId = parent;
-
+
strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
-
-
+
+
if(t != YAFFS_OBJECT_TYPE_HARDLINK)
{
oh->yst_mode = s->st_mode;
@@ -448,17 +455,17 @@ static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, in
oh->yst_ctime = s->st_ctime;
oh->yst_rdev = s->st_rdev;
}
-
+
if(t == YAFFS_OBJECT_TYPE_FILE)
{
oh->fileSize = s->st_size;
}
-
+
if(t == YAFFS_OBJECT_TYPE_HARDLINK)
{
oh->equivalentObjectId = equivalentObj;
}
-
+
if(t == YAFFS_OBJECT_TYPE_SYMLINK)
{
strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
@@ -471,9 +478,9 @@ static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, in
object_header_little_to_big_endian(oh);
}
#endif
-
+
return write_chunk(bytes,objId,0,0xffff);
-
+
}
@@ -484,14 +491,14 @@ static int process_directory(int parent, const char *path)
struct dirent *entry;
nDirectories++;
-
+
dir = opendir(path);
if(dir)
{
while((entry = readdir(dir)) != NULL)
{
-
+
/* Ignore . and .. */
if(strcmp(entry->d_name,".") &&
strcmp(entry->d_name,".."))
@@ -500,11 +507,11 @@ static int process_directory(int parent, const char *path)
struct stat stats;
int equivalentObj;
int newObj;
-
+
sprintf(full_name,"%s/%s",path,entry->d_name);
-
+
lstat(full_name,&stats);
-
+
if(S_ISLNK(stats.st_mode) ||
S_ISREG(stats.st_mode) ||
S_ISDIR(stats.st_mode) ||
@@ -513,12 +520,12 @@ static int process_directory(int parent, const char *path)
S_ISCHR(stats.st_mode) ||
S_ISSOCK(stats.st_mode))
{
-
+
newObj = obj_id++;
nObjects++;
-
+
printf("Object %d, %s is a ",newObj,full_name);
-
+
/* We're going to create an object for it */
if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
{
@@ -526,20 +533,20 @@ static int process_directory(int parent, const char *path)
printf("hard link to object %d\n",equivalentObj);
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
}
- else
+ else
{
-
+
add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
-
+
if(S_ISLNK(stats.st_mode))
{
-
+
char symname[500];
-
+
memset(symname,0, sizeof(symname));
-
+
readlink(full_name,symname,sizeof(symname) -1);
-
+
printf("symlink to \"%s\"\n",symname);
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
@@ -555,7 +562,7 @@ static int process_directory(int parent, const char *path)
__u8 bytes[MAX_CHUNKSIZE];
int nBytes;
int chunk = 0;
-
+
h = open(full_name,O_RDONLY);
if(h >= 0)
{
@@ -566,9 +573,9 @@ static int process_directory(int parent, const char *path)
write_chunk(bytes,newObj,chunk,nBytes);
memset(bytes,0xff,chunkSize);
}
- if(nBytes < 0)
+ if(nBytes < 0)
error = nBytes;
-
+
printf("%d data chunks written\n",chunk);
close(h);
}
@@ -576,9 +583,9 @@ static int process_directory(int parent, const char *path)
{
perror("Error opening file");
}
-
- }
-
+
+ }
+
}
else if(S_ISSOCK(stats.st_mode))
{
@@ -623,7 +630,7 @@ static int process_directory(int parent, const char *path)
*/
closedir(dir);
}
-
+
return 0;
}
@@ -631,12 +638,12 @@ static int process_directory(int parent, const char *path)
void process_file(char *file_name)
{
printf("file, ");
-
+
int h;
__u8 bytes[MAX_CHUNKSIZE];
int nBytes;
int chunk = 0;
-
+
h = open(file_name,O_RDONLY);
if(h >= 0)
{
@@ -662,8 +669,8 @@ void process_file(char *file_name)
void usage(void)
{
- /* ECC for oob should conform with CONFIG_YAFFS_ECC_XX when building linux kernel, but ecc
- for oob isn't required when using BCH ECC, as oob will be corrected together with data
+ /* ECC for oob should conform with CONFIG_YAFFS_ECC_XX when building linux kernel, but ecc
+ for oob isn't required when using BCH ECC, as oob will be corrected together with data
when using BCH ECC. */
#if defined(CONFIG_YAFFS_ECC_RS)
printf("Reed-solomn ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n"
@@ -695,9 +702,9 @@ int main(int argc, char *argv[])
{
struct stat stats;
int i;
-
+
printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n");
-
+
if ((argc < 4) || (sscanf(argv[1], "%u", &layout_no) != 1))
{
usage();
@@ -724,10 +731,10 @@ int main(int argc, char *argv[])
}
i = 0;
-
+
while (oob_layout[i].useecc != -1)
i++;
-
+
if (layout_no >= i)
usage();
@@ -737,13 +744,13 @@ int main(int argc, char *argv[])
usage();
convert_endian = 1;
}
-
+
if(stat(argv[2],&stats) < 0)
{
printf("Could not stat %s\n",argv[2]);
exit(1);
}
-
+
if(!S_ISDIR(stats.st_mode))
{
printf(" %s is not a directory. For a file, just pad oob to data area.\n",argv[2]);
@@ -751,8 +758,8 @@ int main(int argc, char *argv[])
}
outFile = open(argv[3],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
-
-
+
+
if(outFile < 0)
{
printf("Could not open output file %s\n",argv[3]);
@@ -772,9 +779,9 @@ int main(int argc, char *argv[])
if(error)
error = process_directory(YAFFS_OBJECTID_ROOT,argv[2]);
-
+
close(outFile);
-
+
if(error < 0)
{
perror("operation incomplete");
@@ -786,9 +793,9 @@ int main(int argc, char *argv[])
"%d objects in %d directories\n"
"%d NAND pages\n",nObjects, nDirectories, nPages);
}
-
+
close(outFile);
-
+
exit(0);
-}
+}
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index 7afea40ac1c..bebe61ace00 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -1655,6 +1655,25 @@ static int yaffs_do_sync_fs(struct super_block *sb)
}
**/
+static int yaffs_do_sync_fs(struct super_block *sb)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushEntireDeviceCache(dev);
+
+ yaffs_CheckpointSave(dev);
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ yaffs_GrossUnlock(dev);
+
+ return 0;
+}
+
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
static void yaffs_write_super(struct super_block *sb)
#else
@@ -1678,6 +1697,8 @@ static int yaffs_sync_fs(struct super_block *sb)
T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
+ yaffs_do_sync_fs(sb);
+
return 0; /* yaffs_do_sync_fs(sb);*/
}
diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
index 23e28862d49..95b1b94b72e 100644
--- a/fs/yaffs2/yaffs_packedtags2.c
+++ b/fs/yaffs2/yaffs_packedtags2.c
@@ -14,6 +14,7 @@
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_tagsvalidity.h"
+#include "mtd/mtd_bch4bit_n8.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
@@ -100,6 +101,19 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
+#else
+ {
+ unsigned char buf[6], *p;
+ p = (unsigned int *)&pt->t;
+
+ buf[4] = 0xff;
+ buf[5] = 0xff;
+
+ do_bch_encode ((unsigned char *)p, buf, 16);
+ pt->ecc.colParity = buf[0];
+ pt->ecc.lineParity = (buf[4] << 24) | (buf[3] << 16) | (buf[2] << 8) | buf[1];
+ pt->ecc.lineParityPrime = buf[5];
+ }
#endif
}
diff --git a/include/linux/ft5x0x_ts.h b/include/linux/ft5x0x_ts.h
new file mode 100644
index 00000000000..15c6f4eb4ca
--- /dev/null
+++ b/include/linux/ft5x0x_ts.h
@@ -0,0 +1,23 @@
+#ifndef __LINUX_FT5X0X_TS_H__
+#define __LINUX_FT5X0X_TS_H__
+
+#define SCREEN_MAX_X 800
+#define SCREEN_MAX_Y 480
+#define PRESS_MAX 255
+
+#define FT5X0X_NAME "ft5x0x_ts"
+
+struct ft5x0x_ts_platform_data{
+ u16 intr; /* irq number */
+};
+
+enum ft5x0x_ts_regs {
+ FT5X0X_REG_PMODE = 0xA5, /* Power Consume Mode */
+};
+
+//FT5X0X_REG_PMODE
+#define PMODE_ACTIVE 0x00
+#define PMODE_MONITOR 0x01
+#define PMODE_STANDBY 0x02
+#define PMODE_HIBERNATE 0x03
+#endif
diff --git a/include/mtd/mtd_bch4bit_n8.h b/include/mtd/mtd_bch4bit_n8.h
new file mode 100644
index 00000000000..83c2fe2638d
--- /dev/null
+++ b/include/mtd/mtd_bch4bit_n8.h
@@ -0,0 +1,23 @@
+
+
+#define nn_max 32768 /* Length of codeword, n = 2**m - 1 */
+#define tt_max 32 /* Number of errors that can be corrected */
+#define kk_max 32768 /* Length of information bit, kk = nn - rr */
+#define rr_max 32 /* Number of parity checks, rr = deg[g(x)] */
+#define BCH4_DEBUG 0
+
+//Encoder
+extern int mm, nn, kk, tt, rr; // BCH code parameters
+extern int T_G_R[32][32]; // Parallel lookahead table
+extern int T_G_R_PACK[32];
+
+// Decoder
+//extern int ttx2; // 2t
+extern int alpha_to[], index_of[] ; // Galois field
+
+
+//Enc, Dec functions
+extern void do_bch_encode (unsigned char *inbuf, unsigned char *paritybuf, int len);
+extern void do_bch_correct_data (unsigned char *inbuf, unsigned int *errpos);
+extern int do_bch_decode (unsigned char *inbuf, unsigned char *paritybuf, unsigned int *error_pos, int len);
+extern void do_bch_decode_and_correct (unsigned char *inbuf, unsigned char *paritybuf, int len);
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 0cb0cb100d0..324e0321846 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -42,7 +42,7 @@ config I2S_ICODEC
help
Answer Y if you have an internal I2S codec.
-config I2S_DLV
+config I2S_DLV_4750
bool "Internal On-Chip codec on Jz4750 or Jz4750d"
depends on SOC_JZ4750 || SOC_JZ4750D || SOC_JZ4750L
help
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index b31f889fdbb..43dbf3037e4 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -11,8 +11,8 @@ obj-$(CONFIG_SOUND_OSS) += sound.o
#
obj-$(CONFIG_SOUND_JZ_AC97) += jz_ac97.o ac97_codec.o
obj-$(CONFIG_I2S_AK4642EN) += ak4642en.o
-obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz_i2s.o
-obj-$(CONFIG_I2S_DLV) += jzdlv.o jz_i2s.o
+obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz4740_i2s.o
+obj-$(CONFIG_I2S_DLV_4750) += jzdlv.o jz_i2s.o
obj-$(CONFIG_I2S_DLV_4760) += jz4760_dlv.o jz4760_i2s.o
obj-$(CONFIG_SOUND_JZ_PCM) += jz_pcm_tlv320aic1106_dma.o
diff --git a/sound/oss/jz4740_i2s.c b/sound/oss/jz4740_i2s.c
new file mode 100644
index 00000000000..f8fc5fce20d
--- /dev/null
+++ b/sound/oss/jz4740_i2s.c
@@ -0,0 +1,2936 @@
+/*
+ * linux/drivers/sound/Jz_i2s.c
+ *
+ * JzSOC On-Chip I2S audio driver.
+ *
+ * Copyright (C) 2005 by Junzheng Corp.
+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
+ * dma channel 4&3,noah is tested.
+ *
+ * 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.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#if defined(CONFIG_I2S_DLV)
+#include "jzdlv.h"
+#endif
+
+#define DPRINTK(args...) printk(args)
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+#define NR_I2S 2
+#define JZCODEC_RW_BUFFER_SIZE 5
+#define JZCODEC_RW_BUFFER_TOTAL 4
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+#define USE_WAIT_EVENT
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+mixer_info info;
+_old_mixer_info old_info;
+int codec_volue_shift;
+hpvol_shift_t hpvol_shift_table[72];
+int abnormal_data_count;
+unsigned long i2s_clk;
+
+void (*set_codec_mode)(void) = NULL;
+void (*clear_codec_mode)(void) = NULL;
+void (*set_codec_gpio_pin)(void) = NULL;
+void (*each_time_init_codec)(void) = NULL;
+int (*set_codec_startup_param)(void) = NULL;
+void (*set_codec_volume_table)(void) = NULL;
+void (*set_codec_record)(int mode) = NULL;
+void (*set_codec_replay)(void) = NULL;
+void (*set_codec_replay_record)(int mode) = NULL;
+void (*turn_on_codec)(void) = NULL;
+void (*turn_off_codec)(void) = NULL;
+void (*set_codec_speed)(int rate) = NULL;
+void (*reset_codec)(void) = NULL;
+void (*codec_mixer_old_info_id_name)(void) = NULL;
+void (*codec_mixer_info_id_name)(void) = NULL;
+void (*set_codec_bass)(int val) = NULL;
+void (*set_codec_volume)(int val) = NULL;
+void (*set_codec_mic)(int val) = NULL;
+void (*set_codec_line)(int val) = NULL;
+void (*i2s_resume_codec)(void) = NULL;
+void (*i2s_suspend_codec)(int wr,int rd) = NULL;
+void (*init_codec_pin)(void) = NULL;
+void (*set_codec_some_func)(void) = NULL;
+void (*clear_codec_record)(void) = NULL;
+void (*clear_codec_replay)(void) = NULL;
+void (*set_replay_hp_or_speaker)(void) = NULL;
+void (*set_codec_direct_mode)(void) = NULL;
+void (*clear_codec_direct_mode)(void) = NULL;
+void (*set_codec_linein2hp)(void) = NULL;
+void (*clear_codec_linein2hp)(void) = NULL;
+
+static int jz_audio_rate;
+static int jz_audio_format;
+static int jz_audio_volume;
+static int jz_audio_channels;
+static int jz_audio_b; /* bits expand multiple */
+static int jz_audio_fragments; /* unused fragment amount */
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+
+static int codec_bass_gain;
+static int audio_mix_modcnt;
+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */
+#if defined(CONFIG_I2S_DLV)
+int jz_dlv_vol_mute = 0; /* Added by River. */
+int jz_mic_only = 1;
+static int jz_codec_config = 0;
+static unsigned long ramp_up_start;
+static unsigned long ramp_up_end;
+static unsigned long gain_up_start;
+static unsigned long gain_up_end;
+static unsigned long ramp_down_start;
+static unsigned long ramp_down_end;
+static unsigned long gain_down_start;
+static unsigned long gain_down_end;
+#endif
+
+static int codec_mic_gain;
+static int pop_dma_flag;
+static int last_dma_buffer_id;
+static int drain_flag;
+static int use_mic_line_flag;
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+static void jz_update_filler(int bits, int channels);
+
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(signed long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample);
+#endif
+static void jz_audio_reset(void);
+static struct file_operations jz_i2s_audio_fops;
+
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+
+static volatile int pop_wait_event;
+
+struct jz_i2s_controller_info
+{
+ int io_base;
+ int dma1; /* for play */
+ int dma2; /* for record */
+ char *name;
+ int dev_audio;
+ struct i2s_codec *i2s_codec[NR_I2S];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; /* byte index to next-in to DMA buffer */
+ int nextOut; /* byte index to next-out from DMA buffer */
+ int count; /* current byte count in DMA buffer */
+ int finish; /* current transfered byte count in DMA buffer */
+ unsigned total_bytes; /* total bytes written or read */
+ unsigned blocks;
+ unsigned error; /* over/underrun */
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+
+static struct jz_i2s_controller_info *i2s_controller = NULL;
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl i2s accessing routines */
+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */
+ void (*codec_write) (u8 reg, u16 val);
+ /* Wait for codec-ready */
+ void (*codec_wait) (struct i2s_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+
+typedef struct buffer_queue_s
+{
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+typedef struct left_right_sample_s
+{
+ signed long left;
+ signed long right;
+} left_right_sample_t;
+
+static unsigned long pop_turn_onoff_buf;
+static unsigned long pop_turn_onoff_pbuf;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static left_right_sample_t save_last_samples[64];
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_dma_tran_count = count / jz_audio_b;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+#if 1
+ jz_set_oss_dma(chan, mode, jz_audio_format);
+#else
+ set_dma_mode(chan, mode);
+#endif
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+{
+ int id1, id2;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(drain_flag == 1)
+ wake_up(&drain_wait_queue);
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else
+ in_busy_queue.count = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma1;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(pop_dma_flag == 1) {
+ pop_dma_flag = 0;
+ wake_up(&pop_wait_queue);
+ } else {
+ if(drain_flag == 1) {
+ /* Is replay dma buffer over ? */
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ drain_flag = 0;
+ wake_up(&drain_wait_queue);
+ }
+ }
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void jz_i2s_initHw(int set)
+{
+#if defined(CONFIG_MIPS_JZ_URANUS)
+ i2s_clk = 48000000;
+#else
+ i2s_clk = __cpm_get_i2sclk();
+#endif
+ __i2s_disable();
+ if(set)
+ __i2s_reset();
+ schedule_timeout(5);
+ if(each_time_init_codec)
+ each_time_init_codec();
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(12);
+ __i2s_set_receive_trigger(4);
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+
+ /* recording */
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ /* playing */
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /* alloc DMA buffer */
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ /* playing */
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0;
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ /* recording */
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0;
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_initHw(0);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ jz_audio_speed = rate;
+#if defined(CONFIG_I2S_DLV)
+ if (rate > 96000)
+ rate = 96000;
+#else
+ if (rate > 48000)
+ rate = 48000;
+#endif
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+ if(set_codec_speed)
+ set_codec_speed(rate);
+
+ return jz_audio_rate;
+}
+
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long data;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt++;
+ data = *(s++);
+ *(dp ++) = ((data << 16) >> 24) + 0x80;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = ((d1 << 16) >> 24) + 0x80;
+ d2 = *(s++);
+ *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ d2 = *(s++);
+ if(abnormal_data_count > 0) {
+ d1 = d2 = 0;
+ abnormal_data_count --;
+ }
+ *(dp ++) = (d1 << 16) >> 16;
+ *(dp ++) = (d2 << 16) >> 16;
+ }
+
+ return cnt;
+}
+
+static void replay_fill_1x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ unsigned long ddata;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count--;
+ cnt += 1;
+ data = *(s++) - 0x80;
+ ddata = (unsigned long) data << 8;
+ *(dp ++) = ddata;
+ *(dp ++) = ddata;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = ddata;
+ save_last_samples[id].right = ddata;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_2x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1;
+ unsigned long dd1;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 1;
+ cnt += 1 ;
+ d1 = *(s++) - 0x80;
+ dd1 = (unsigned long) d1 << 8;
+ *(dp ++) = dd1;
+ /* save last left */
+ if(count == 2)
+ save_last_samples[id].left = dd1;
+ /* save last right */
+ if(count == 1)
+ save_last_samples[id].right = dd1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_1x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2 ;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+#if defined(CONFIG_I2S_ICODEC)
+ l1 >>= codec_volue_shift;
+#endif
+ *(dp ++) = l1;
+ *(dp ++) = l1;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = l1;
+ save_last_samples[id].right = l1;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+#if defined(CONFIG_I2S_ICODEC)
+ int mute_cnt = 0;
+ signed long tmp1,tmp2;
+ volatile signed long *before_dp;
+ int sam_rate = jz_audio_rate / 20;
+
+ tmp1 = tmp2 = 0;
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+ l1 >>= codec_volue_shift;
+
+ if(l1 == 0) {
+ mute_cnt ++;
+ if(mute_cnt >= sam_rate) {
+ before_dp = dp - 10;
+ *(before_dp) = (signed long)1;
+ before_dp = dp - 11;
+ *(before_dp) = (signed long)1;
+ mute_cnt = 0;
+ }
+ } else
+ mute_cnt = 0;
+
+ *(dp ++) = l1;
+
+ tmp1 = tmp2;
+ tmp2 = l1;
+ }
+
+ /* save last left */
+ save_last_samples[id].left = tmp1;
+ /* save last right */
+ save_last_samples[id].right = tmp2;
+#endif
+#if defined(CONFIG_I2S_DLV)
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+#endif
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x18_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed long d1;
+ signed long l1;
+ volatile signed long *s = (signed long *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 4;
+ cnt += 4;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ }
+
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case AFMT_S16_LE:
+#if defined(CONFIG_I2S_DLV)
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ //write_codec_file(2, 0x60);
+#endif
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+ case 18:
+ __i2s_set_oss_sample_size(18);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case AFMT_QUERY:
+ break;
+ }
+
+ return jz_audio_format;
+}
+
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ if(set_codec_some_func)
+ set_codec_some_func();
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+#endif
+ break;
+ case 2:
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+#endif
+ break;
+ case 0:
+ break;
+ }
+
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+ /* inititalize internal I2S codec */
+ if(init_codec_pin)
+ init_codec_pin();
+
+#if defined(CONFIG_I2S_ICDC)
+ /* initialize AIC but not reset it */
+ jz_i2s_initHw(0);
+#endif
+ if(reset_codec)
+ reset_codec();
+}
+
+static void jz_audio_reset(void)
+{
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#if defined(CONFIG_I2S_DLV)
+ REG_AIC_I2SCR = 0x10;
+#endif
+ init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ for (i = 0; i < NR_I2S; i++)
+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->i2s_codec[i];
+
+ return 0;
+}
+
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_i2s_llseek,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+};
+
+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ long val = 0;
+ switch (cmd) {
+ case SOUND_MIXER_INFO:
+
+ if(codec_mixer_info_id_name)
+ codec_mixer_info_id_name();
+ info.modify_counter = audio_mix_modcnt;
+
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ case SOUND_OLD_MIXER_INFO:
+
+ if(codec_mixer_old_info_id_name)
+ codec_mixer_old_info_id_name();
+
+ return copy_to_user((void *)arg, &old_info, sizeof(info));
+ case SOUND_MIXER_READ_STEREODEVS:
+
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_SPEAKER:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ switch(val) {
+ case 100:
+ if(set_codec_direct_mode)
+ set_codec_direct_mode();
+ break;
+ case 0:
+ if(clear_codec_direct_mode)
+ clear_codec_direct_mode();
+ break;
+ }
+ break;
+ case SOUND_MIXER_WRITE_BASS:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_bass_gain = val;
+ if(set_codec_bass)
+ set_codec_bass(val);
+
+ return 0;
+ case SOUND_MIXER_READ_BASS:
+
+ val = codec_bass_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+
+ jz_audio_volume = val;
+ if(set_codec_volume)
+ set_codec_volume(val);
+
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+
+ val = jz_audio_volume;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_MIC:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_mic_gain = val;
+ use_mic_line_flag = USE_MIC;
+ if(set_codec_mic)
+ set_codec_mic(val);
+
+ return 0;
+ case SOUND_MIXER_READ_MIC:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_LINE:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ use_mic_line_flag = USE_LINEIN;
+ codec_mic_gain = val;
+ if(set_codec_line)
+ set_codec_line(val);
+
+ return 0;
+ case SOUND_MIXER_READ_LINE:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ default:
+ return -ENOSYS;
+ }
+ audio_mix_modcnt ++;
+ return 0;
+}
+
+
+int i2s_probe_codec(struct i2s_codec *codec)
+{
+ /* generic OSS to I2S wrapper */
+ codec->mixer_ioctl = i2s_mixer_ioctl;
+ return 1;
+}
+
+
+/* I2S codec initialisation. */
+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
+{
+ int num_i2s = 0;
+ struct i2s_codec *codec;
+
+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct i2s_codec));
+ codec->private_data = controller;
+ codec->id = num_i2s;
+
+ if (i2s_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->i2s_codec[num_i2s] = codec;
+ }
+ return num_i2s;
+}
+
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels))
+ {
+
+ case TYPE(AFMT_U8, 1):
+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ jz_audio_b = 4;
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ jz_audio_b = 2;
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ case TYPE(18, 2):
+ jz_audio_b = 1;
+ replay_filler = replay_fill_2x18_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ default:
+ ;
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_jz_root;
+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+{
+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
+ return -EIO;
+ return 0;
+}
+
+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
+{
+}
+#endif
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name;
+ int adev; /* No of Audio device. */
+
+ name = controller->name;
+ /* initialize AIC controller and reset it */
+ jz_i2s_initHw(1);
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize I2S codec and register /dev/mixer */
+ if (jz_i2s_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_i2s_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ printk(JZ_SOC_NAME": On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ controller->dev_audio = adev;
+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8);
+ if(!pop_turn_onoff_buf)
+ printk("pop_turn_onoff_buf alloc is wrong!\n");
+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf);
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma1);
+dma1_failed:
+ free_pages((unsigned long)controller->tmp2, 8);
+tmp2_failed:
+ free_pages((unsigned long)controller->tmp1, 8);
+tmp1_failed:
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+proc_failed:
+ /* unregister mixer dev */
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+
+ (*controller)->name = "Jz I2S controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+ init_waitqueue_head(&pop_wait_queue);
+ init_waitqueue_head(&drain_wait_queue);
+ pop_wait_event = 0;
+
+ return 0;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ jz_i2s_full_reset(controller);
+ controller->dev_audio = -1;
+ if (old_mksound)
+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, 8);
+ free_pages((unsigned long)controller->tmp2, 8);
+ free_pages((unsigned long)pop_turn_onoff_buf, 8);
+
+ if (adev >= 0) {
+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+#if 0 /* Deprecated PM API */
+//#if CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ if(i2s_suspend_codec)
+ i2s_suspend_codec(controller->opened1,controller->opened2);
+ printk("Aic and codec are suspended!\n");
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ if(i2s_resume_codec)
+ i2s_resume_codec();
+
+#if defined(CONFIG_I2S_AK4642EN)
+ jz_i2s_initHw(0);
+ jz_audio_reset();
+ __i2s_enable();
+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed);
+ /* playing */
+ if(controller->opened1) {
+ if(set_codec_replay)
+ set_codec_replay();
+ int dma = controller->dma1;
+ int id;
+ unsigned long flags;
+ disable_dma(dma);
+ if(__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if(__dmac_channel_transmit_end_detected(dma))
+ __dmac_channel_clear_transmit_end(dma);
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ while((id = get_buffer_id(&out_busy_queue)) >= 0)
+ put_buffer_id(&out_empty_queue, id);
+
+ out_busy_queue.count=0;
+ if((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_empty_queue, id);
+ }
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ } else
+ printk("pm out_empty_queue empty");
+ }
+
+ /* recording */
+ if(controller->opened2) {
+ if(set_codec_record)
+ set_codec_record(use_mic_line_flag);
+ int dma = controller->dma2;
+ int id1, id2;
+ unsigned long flags;
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ }
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_full_queue, id2);
+ }
+ in_busy_queue.count = 0;
+ }
+#endif
+
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
+ break;
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+#if defined(CONFIG_I2S_DLV)
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf) {
+ pop_wait_event = 1;
+ wake_up(&pop_wait_queue);
+ }
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int __init init_jz_i2s(void)
+{
+ int errno;
+#if defined(CONFIG_I2S_DLV)
+ int retval;
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+#endif
+ use_mic_line_flag = USE_NONE;
+ abnormal_data_count = 0;
+ if(set_codec_mode)
+ set_codec_mode();
+
+ drain_flag = 0;
+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
+ return errno;
+ if(set_codec_gpio_pin)
+ set_codec_gpio_pin();
+
+ attach_jz_i2s(i2s_controller);
+ if(set_codec_startup_param)
+ set_codec_startup_param();
+ if(set_codec_volume_table)
+ set_codec_volume_table();
+
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+#endif
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+#if 0 /* Deprecated PM API */
+//#ifdef CONFIG_PM
+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (i2s_controller->pm)
+ i2s_controller->pm->data = i2s_controller;
+#endif
+
+ printk(JZ_SOC_NAME ": I2S OSS audio driver initialized.\n");
+
+ return 0;
+}
+
+static void __exit cleanup_jz_i2s(void)
+{
+#ifdef CONFIG_PM
+ /* pm_unregister(i2s_controller->pm); */
+#endif
+#if defined(CONFIG_I2S_DLV)
+ free_irq(IRQ_AIC, NULL);
+#endif
+ unload_jz_i2s(i2s_controller);
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ if(clear_codec_mode)
+ clear_codec_mode();
+}
+
+module_init(init_jz_i2s);
+module_exit(cleanup_jz_i2s);
+
+#if defined(CONFIG_SOC_JZ4730)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,con;
+
+ if(elements_in_queue(&in_busy_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&ctrl->adc_wait, &wait);
+ for (con = 0; con < 1000; con ++) {
+ udelay(1);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ return 0;
+}
+
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+
+ if(elements_in_queue(&out_full_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&(ctrl->dac_wait), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if(count <= 0)
+ break;
+ }
+ if (nonblock) {
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4740)
+#define MAXDELAY 50000
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,ele,i=0;
+ int tfl;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(10);
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+
+ /* wait for TX fifo */
+ while (1) {
+ tfl = __aic_get_transmit_resident();
+ if (tfl == 0)
+ break;
+ udelay(2);
+ }
+
+ return 0;
+}
+
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,i=0;
+
+ for (;;) {
+ if ( i < MAXDELAY )
+ {
+ udelay(10);
+ i++;
+ }
+ else
+ break;
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ if (nonblock) {
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) || defined(CONFIG_SOC_JZ4750L)
+#define MAXDELAY 50000
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ //DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,i=0;
+
+ //add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+ //set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ //spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ //spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ /*if (signal_pending(current))
+ break;*/
+ if (nonblock) {
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ /*if (signal_pending(current))
+ return -ERESTARTSYS;*/
+ return 0;
+}
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count,ele,busyele,emptyele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(200);
+
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ } else {//non-blocked
+ //mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ //mdelay(100);
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ unsigned long flags;
+ unsigned int dacflag;
+ unsigned int timeout = 0xfff;
+#if defined(CONFIG_I2S_DLV)
+ unsigned long tfl;
+#endif
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+#endif
+ if (controller == NULL)
+ return -ENODEV;
+
+ pop_dma_flag = 0;
+ pop_wait_event = 0;
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+#endif
+ //gain_down_end = jiffies;
+ /*while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }*/
+ mdelay(100);
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_replay)
+ clear_codec_replay();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_record)
+ clear_codec_record();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+
+ //ramp_down_end = jiffies;
+ if (use_mic_line_flag == USE_LINEIN) {
+ unset_record_line_input_audio_with_audio_data_replay();
+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ unset_record_mic_input_audio_with_audio_data_replay();
+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+
+#if 0
+ unset_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+#endif
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ abnormal_data_count = 0;
+ } else if (controller->opened1 == 1) {
+ //controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* add some mute to anti-pop */
+#if defined(CONFIG_I2S_ICODEC)
+ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right);
+#endif
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+#endif
+ if (!jz_dlv_vol_mute) {
+ dacflag = read_codec_file(1);
+ if (!(dacflag & 0x20)) {
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+ }
+ }else
+ mdelay(280);
+
+ //gain_down_end = jiffies;
+ while (1) {
+ timeout --;
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ break;
+ udelay(500);
+ } else if (!timeout){
+ break;
+ }
+ mdelay(2);
+ }
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_replay)
+ clear_codec_replay();
+#endif
+ __aic_flush_fifo();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+ unset_audio_data_replay();
+#endif
+ __i2s_disable();
+#if defined(CONFIG_I2S_ICODEC)
+ if(turn_off_codec)
+ turn_off_codec();
+#endif
+ } else if (controller->opened2 == 1) {
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_record)
+ clear_codec_record();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* unset Record MIC input audio with direct playback */
+ unset_record_mic_input_audio_with_direct_playback();
+#endif
+#if 1
+ /* unset Record MIC input audio without playback */
+ unset_record_mic_input_audio_without_playback();
+#endif
+#if 0
+ unset_playback_line_input_audio_direct_only();
+#endif
+#if 0
+ /* tested */
+ /* unset Record LINE input audio without playback */
+ unset_record_line_input_audio_without_playback();
+#endif
+#endif
+ __i2s_disable();
+#if defined(CONFIG_I2S_ICODEC)
+ if(turn_off_codec)
+ turn_off_codec();
+#endif
+ abnormal_data_count = 0;
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+/* __cpm_stop_idct();
+ __cpm_stop_db();
+ __cpm_stop_me();
+ __cpm_stop_mc();
+ __cpm_stop_ipu();*/
+#endif
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ controller->opened1 = 0;
+ controller->opened2 = 0;
+ //print_pop_duration();
+ //__dmac_disable_module(0);
+ } else if ( controller->opened1 == 1 ) {
+ controller->opened1 = 0;
+ //print_pop_duration();
+ } else if ( controller->opened2 == 1 ) {
+ controller->opened2 = 0;
+ }
+
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+#endif
+ if (controller == NULL)
+ return -ENODEV;
+
+ mdelay(2);
+#if defined(CONFIG_I2S_DLV)
+ REG_DMAC_DMACKE(0) = 0x3f;
+#endif
+ pop_dma_flag = 0;
+ pop_wait_event = 0;
+
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ } else if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+ } else if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();
+ REG_AIC_FR |= (1 << 6);
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_ICODEC)
+ if (set_codec_replay_record)
+ set_codec_replay_record(use_mic_line_flag);
+#endif
+#if defined(CONFIG_I2S_DLV)
+ if (use_mic_line_flag == USE_NONE) {
+ printk("you select mic or line recording please.or use mic recording!\n");
+ use_mic_line_flag = USE_MIC;
+ }
+ if (use_mic_line_flag == USE_LINEIN) {
+ /* Record LINE input audio with Audio data replay (full duplex for linein) */
+ /* codec_test_line */
+ set_record_line_input_audio_with_audio_data_replay();
+
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ /* Record MIC input audio with Audio data replay (full duplex) */
+ /* codec_test_mic */
+ set_record_mic_input_audio_with_audio_data_replay();
+ }
+#if 0
+ /* Record playing audio mixed with MIC input audio */
+ set_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_ICODEC)
+ if(set_codec_replay)
+ set_codec_replay();
+#endif
+#if defined(CONFIG_I2S_DLV)
+ //mdelay(10);
+ /* Audio data replay */
+ set_audio_data_replay();
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_ICODEC)
+ abnormal_data_count = 0;
+ if(set_codec_record)
+ set_codec_record(use_mic_line_flag);
+#endif
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* Record MIC input audio with direct playback */
+ set_record_mic_input_audio_with_direct_playback();
+#endif
+
+#if 1
+ /* set Record MIC input audio without playback */
+ set_record_mic_input_audio_without_playback();
+#endif
+#if 0
+ /* set Playback LINE input audio direct only */
+ set_playback_line_input_audio_direct_only();
+#endif
+#if 0
+ /* tested */
+ /* set Record LINE input audio without playback */
+ set_record_line_input_audio_without_playback();
+#endif
+ mdelay(1);
+#endif
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ __aic_reset();
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+#endif
+
+ __i2s_enable();
+
+#if defined(CONFIG_I2S_DLV)
+ ndelay(100);
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_DLV)
+ //set SB_ADC or SB_DAC
+ __dmac_enable_module(0);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_DLV)
+ if (jz_mic_only)
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ else
+ write_codec_file_bit(5, 0, 7);//SB_DAC->0
+ mdelay(500);
+#endif
+ }
+#endif
+ return 0;
+}
+
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ count_info cinfo;
+ audio_buf_info abinfo;
+ int id, i;
+
+ val = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+#if 0
+ jz_audio_reset();
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#endif
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ /* set smaple rate */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+
+ return 0;
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg);
+ return put_user(jz_audio_fragsize, (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT:
+ /* Select sample format */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY)
+ jz_audio_set_format(controller->dev_audio,val);
+ else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ }
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE))
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ int i;
+ unsigned long bytes = 0;
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n");
+
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ /* unused fragment amount */
+ abinfo.fragments = jz_audio_fragments;
+ /* amount of fragments */
+ abinfo.fragstotal = jz_audio_fragstotal;
+ /* fragment size in bytes */
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n");
+
+ /* write size count without blocking in bytes */
+ abinfo.bytes = (int)bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ {
+ int i;
+ unsigned long bytes = 0;
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n");
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n");
+
+ abinfo.bytes = (int)bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (jz_audio_channels == 2)
+ unfinish /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ unfinish /= 4;
+ else
+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n");
+
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ unsigned long flags;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ if (first_record_call) {
+ first_record_call = 0;
+ audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+
+ spin_unlock(&controller->lock);
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+ audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count = 0;
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ if(set_replay_hp_or_speaker)
+ set_replay_hp_or_speaker();
+
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if (jz_audio_channels == 2)
+ copy_count = jz_audio_fragsize / jz_audio_b;
+ else if(jz_audio_channels == 1)
+ copy_count = jz_audio_fragsize / 4;
+ left_count = count;
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+ audio_write_back:
+ if (file->f_flags & O_NONBLOCK)
+ udelay(2);
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ sleep_on(&tx_wait_queue);
+ }
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id);
+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id);
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+#if defined(CONFIG_I2S_DLV)
+ if (jz_codec_config == 0) {
+#if 0
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+#endif
+ if (!jz_dlv_vol_mute) {
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ wait_event(pop_wait_queue, pop_wait_event);
+ pop_wait_event = 0;
+ }
+
+ //gain_up_end = jiffies;
+ jz_codec_config = 1;
+ //SB_ADC->1
+ //write_codec_file_bit(5, 1, 4);
+ //while(1);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample)
+{
+ int i,step_len;
+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf;
+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
+ unsigned long l_sample_count,r_sample_count,sample_count;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+ signed int left_sam=0,right_sam=0,l_val,r_val;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ left_sam = (signed int)l_sample;
+ right_sam = (signed int)r_sample;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+
+ if(left_sam == 0 && right_sam == 0)
+ return;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ step_len = jz_audio_speed / 10 * 3;
+ step_len = step_len / 2;
+ step_len = 0x7fff / step_len + 1;
+
+ l_sample_count = 0;
+ l_val = left_sam;
+
+ while(1) {
+ if(l_val > 0) {
+ if(l_val >= step_len) {
+ l_val -= step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val < 0) {
+ if(l_val <= -step_len) {
+ l_val += step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val == 0)
+ break;
+ }
+
+ r_sample_count = 0;
+ r_val = right_sam;
+ while(1) {
+ if(r_val > 0) {
+ if(r_val >= step_len) {
+ r_val -= step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val < 0) {
+ if(r_val <= -step_len) {
+ r_val += step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val == 0)
+ break;
+ }
+ /* fill up */
+ if(l_sample_count > r_sample_count)
+ sample_count = l_sample_count;
+ else
+ sample_count = r_sample_count;
+
+ l_val = left_sam;
+ r_val = right_sam;
+ for(i=0;i <= sample_count;i++) {
+
+ *pop_buf = (unsigned long)l_val;
+ pop_buf ++;
+
+ if(l_val > step_len)
+ l_val -= step_len;
+ else if(l_val < -step_len)
+ l_val += step_len;
+ else if(l_val >= -step_len && l_val <= step_len)
+ l_val = 0;
+
+ *pop_buf = (unsigned long)r_val;
+ pop_buf ++;
+ if(r_val > step_len)
+ r_val -= step_len;
+ else if(r_val < -step_len)
+ r_val += step_len;
+ else if(r_val >= -step_len && r_val <= step_len)
+ r_val = 0;
+ }
+
+ *pop_buf = 0;
+ pop_buf ++;
+ *pop_buf = 0;
+
+ pop_buf ++;
+ sample_count += 2;
+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8);
+
+ pop_dma_flag = 1;
+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE);
+ sleep_on(&pop_wait_queue);
+ pop_dma_flag = 0;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+}
+#endif
diff --git a/sound/oss/jz4750_codec.h b/sound/oss/jz4750_codec.h
new file mode 100644
index 00000000000..a6e789f5fd1
--- /dev/null
+++ b/sound/oss/jz4750_codec.h
@@ -0,0 +1,75 @@
+/* header file for JZ CODEC */
+#ifndef _JZ_CODEC_H_
+#define _JZ_CODEC_H_
+
+//-------------------------------------------------
+#define CODEC_SET_MODE 1
+#define CODEC_SET_STARTUP_PARAM 5
+#define CODEC_SET_VOLUME_TABLE 6
+
+#define CODEC_SET_RECORD 7
+#define CODEC_CLEAR_RECORD 24
+
+#define CODEC_SET_REPLAY 8
+#define CODEC_CLEAR_REPLAY 25
+
+#define CODEC_SET_REPLAY_RECORD 9
+
+#define CODEC_SET_REPLAY_SPEED 12
+#define CODEC_SET_RECORD_SPEED 37
+
+#define CODEC_SET_REPLAY_CHANNEL 33
+#define CODEC_SET_REPLAY_DATA_WIDTH 34
+
+#define CODEC_SET_RECORD_CHANNEL 35
+#define CODEC_SET_RECORD_DATA_WIDTH 36
+
+#define CODEC_SET_GPIO_PIN 3
+#define CODEC_SET_BASS 16
+#define CODEC_SET_VOLUME 17
+#define CODEC_SET_MIC 18
+#define CODEC_SET_LINE 19
+#define CODEC_SET_SOME_FUNC 23
+
+#define CODEC_CLEAR_MODE 2
+
+#define CODEC_EACH_TIME_INIT 4
+#define CODEC_TURN_ON 10
+#define CODEC_TURN_OFF 11
+
+#define CODEC_RESET 13
+#define CODEC_GET_MIXER_OLD_INFO 14
+#define CODEC_GET_MIXER_INFO 15
+#define CODEC_I2S_RESUME 20
+#define CODEC_I2S_SUSPEND 21
+#define CODEC_PIN_INIT 22
+
+#define CODEC_SET_REPLAY_HP_OR_SPKR 26
+#define CODEC_SET_DIRECT_MODE 27
+#define CODEC_CLEAR_DIRECT_MODE 28
+#define CODEC_SET_LINEIN2HP 29
+#define CODEC_CLEAR_LINEIN2HP 30
+
+//------------------------------------------------
+
+#define CODEC_ANTI_POP 31
+#define CODEC_TURN_REPLAY 32
+
+#define CODEC_DAC_MUTE 38
+
+//-------------------------------------------------
+
+void register_jz_codecs(void *func);
+void dump_dlv_regs(const char* str);
+void dlv_write_reg(int addr, int val);
+//-------------------------------------------------
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+
+#define CODEC_WMODE (1 << 0)
+#define CODEC_RMODE (1 << 1)
+#define CODEC_WRMODE (CODEC_WMODE | CODEC_RMODE)
+
+#endif /* _JZ_CODEC_H_ */
diff --git a/sound/oss/jz4750_dlv.h b/sound/oss/jz4750_dlv.h
new file mode 100644
index 00000000000..b382f44944f
--- /dev/null
+++ b/sound/oss/jz4750_dlv.h
@@ -0,0 +1,27 @@
+/*
+ *
+ */
+
+#ifndef _JZ_DLV_H_
+#define _JZ_DLV_H_
+
+
+#define DLV_MAX_RATE_COUNT 11
+
+void dlv_write_reg(int addr, int val);
+void dump_dlv_regs(const char *str);
+
+/* header file for dlv */
+static void dlv_set_replay(void);
+//static void set_record_mic_input_audio_without_playback(void);
+//static void set_playback_line_input_audio_direct_only(void);
+//static void unset_playback_line_input_audio_direct_only(void);
+//static void set_record_mic_input_audio_with_direct_playback(void);
+//static void set_record_playing_audio_mixed_with_mic_input_audio(void);
+//static void unset_record_playing_audio_mixed_with_mic_input_audio(void);
+//static void set_record_mic_input_audio_with_audio_data_replay(void);
+//static void dlv_set_record_mic_with_replay(void);
+//static void unset_record_mic_input_audio_with_audio_data_replay(void);
+static void set_record_line_input_audio_with_audio_data_replay(void);
+//static void unset_record_line_input_audio_with_audio_data_replay(void);
+#endif /*_JZ_DLV_H_*/
diff --git a/sound/oss/jz4760_dlv.c b/sound/oss/jz4760_dlv.c
index a8b2b89bf85..69610f20c60 100644
--- a/sound/oss/jz4760_dlv.c
+++ b/sound/oss/jz4760_dlv.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
+#include <linux/platform_device.h>
#include <linux/sound.h>
#include <linux/slab.h>
@@ -24,6 +25,7 @@
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/mm.h>
+
#include <asm/hardirq.h>
#include <asm/jzsoc.h>
@@ -33,78 +35,151 @@
#include "jz4760_dlv.h"
#include "jz_i2s_dbg.h"
-#define HP_SENSE_DETECT 0
-#define REPLAY 1
-#define RECORD 2
-
-#define POWER_ON 0
-#define POWER_OFF 1
-
-#define switch_SB_DAC(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_DAC); \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_ADC); \
-} while (0)
-
-#define switch_SB_LINE_OUT(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_LOUT); \
-} while (0)
-
-#define switch_SB_OUT(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_HP); \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_LOUT); \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_BTL); \
-} while (0)
-
-#define switch_SB_MIX(pwrstat) \
-do { \
- /* dlv_write_reg_bit(5, pwrstat, 5);*/ \
-} while (0)
-
-#define switch_SB_ADC(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_ADC); \
-} while (0)
-
-#define switch_SB_MIC1(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MIC1); \
- dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MIC2); \
- dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MICBIAS);\
- \
-} while (0)
-
-#define switch_SB_LINE_IN(pwrstat) \
-do { \
- dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_LINE); \
- dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MICBIAS);\
- \
-} while (0)
+//#define ANTI_POP_TIMER
+#define ANTI_POP_WORK_STRUCT
+
+#ifdef ANTI_POP_WORK_STRUCT
+ #ifdef ANTI_POP_TIMER
+ #error "Error: both ANTI_POP_TIMER and ANTI_POP_TIMER are defined."
+ #endif
+#endif
+
+#ifndef ANTI_POP_WORK_STRUCT
+ #ifndef ANTI_POP_TIMER
+ #error "Error: both ANTI_POP_TIMER and ANTI_POP_TIMER are undefined."
+ #endif
+#endif
+
+enum device_t {
+ SND_DEVICE_DEFAULT = 0,
+ SND_DEVICE_CURRENT,
+ SND_DEVICE_HANDSET,
+ SND_DEVICE_HEADSET,
+ SND_DEVICE_SPEAKER,
+ SND_DEVICE_BT,
+ SND_DEVICE_BT_EC_OFF,
+ SND_DEVICE_HEADSET_AND_SPEAKER,
+ SND_DEVICE_TTY_FULL,
+ SND_DEVICE_CARKIT,
+ SND_DEVICE_FM_SPEAKER,
+ SND_DEVICE_FM_HEADSET,
+ SND_DEVICE_NO_MIC_HEADSET,
+ SND_DEVICE_COUNT
+};
+
+static unsigned int g_current_out_dev = 0;
+static unsigned int g_bluetooth_enabled = 0;
+static struct semaphore *g_dlv_sem = 0;
+static int greplay_volume;
+
+static spinlock_t g_dlv_sem_lock;
+
+#ifdef CONFIG_JZ4760_PT701
+extern int gstate_hp;
+extern int gstate_dock;
+#endif
+
+#define DLV_DEBUG_SEM(x,y...)
+//printk(x,##y);
+
+#define DLV_LOCK() \
+ do{ \
+ spin_lock(g_dlv_sem_lock); \
+ if(g_dlv_sem) \
+ down(g_dlv_sem); \
+ spin_unlock(g_dlv_sem_lock); \
+ DLV_DEBUG_SEM("dlvsemlock lock\n"); \
+ }while(0)
+
+#define DLV_UNLOCK() \
+ do{ \
+ spin_lock(g_dlv_sem_lock); \
+ if(g_dlv_sem) \
+ up(g_dlv_sem); \
+ spin_unlock(g_dlv_sem_lock); \
+ DLV_DEBUG_SEM("dlvsemlock unlock\n"); \
+ }while(0)
+
+#define DLV_LOCKINIT() \
+ do{ \
+ spin_lock(g_dlv_sem_lock); \
+ if(g_dlv_sem == NULL) \
+ g_dlv_sem = (struct semaphore *)vmalloc(sizeof(struct semaphore)); \
+ if(g_dlv_sem) \
+ init_MUTEX_LOCKED(g_dlv_sem); \
+ spin_unlock(g_dlv_sem_lock); \
+ DLV_DEBUG_SEM("dlvsemlock init\n"); \
+ }while(0)
+
+#define DLV_LOCKDEINIT() \
+ do{ \
+ spin_lock(g_dlv_sem_lock); \
+ if(g_dlv_sem) \
+ vfree(g_dlv_sem); \
+ g_dlv_sem = NULL; \
+ spin_unlock(g_dlv_sem_lock); \
+ DLV_DEBUG_SEM("dlvsemlock deinit\n"); \
+ }while(0)
+
+static int should_up = 0;
+#ifdef HP_SENSE_DETECT
+static jz_hp_switch_data_t *g_switch_data = NULL;
+#endif
/*
-#define ENTER() printk("Enter: %s, %s:%i\n", __FUNCTION__, __FILE__, __LINE__)
-#define LEAVE() printk("Leave: %s, %s:%i\n", __FUNCTION__, __FILE__, __LINE__)
+static unsigned int g_prev_dev = 0;
+static unsigned int g_codec_mode = 0;
+static unsigned int g_speaker_mute = 0;
+static unsigned int g_receiver_mute = 0;
+static unsigned int g_mic1_mute = 0;
+static unsigned int g_mic2_mute = 0;
+static unsigned int g_volumes[SND_DEVICE_COUNT];
*/
-#ifdef IOC_DEBUG
-static dlv_print_ioc_cmd(int cmd)
+/* Audio route ops */
+static void dlv_enable_hp_out(void);
+static void dlv_disable_hp_out(void);
+static void dlv_enable_btl(void);
+static void dlv_disable_btl(void);
+static void dlv_enable_speaker(void);
+static void dlv_disable_speaker(void);
+static void dlv_enable_receiver(void);
+static void dlv_disable_receiver(void);
+static void dlv_enable_line_out(void);
+static void dlv_disable_line_out(void);
+static void dlv_enable_line_in_record(int insel);
+static void dlv_disable_line_in_record(void);
+static void dlv_enable_line_in_bypass_hp(void);
+static void dlv_disable_line_in_bypass_hp(void);
+static void dlv_enable_line_in_bypass_btl(void);
+static void dlv_disable_line_in_bypass_btl(void);
+static void dlv_enable_mic_1(void);
+static void dlv_disable_mic_1(void);
+static void dlv_enable_mic_2(void);
+static void dlv_disable_mic_2(void);
+#ifdef CONFIG_JZ4760_PT701
+static void dlv_set_device(struct snd_device_config *snd_dev_cfg);
+#endif
+static void board_set_record(void);
+
+#if defined(IOC_DEBUG) || defined(ROUTETE_DEBUG)
+static void dlv_print_ioc_cmd(int cmd)
{
char *dlv_ioc_cmd[] = {
"CODEC_SET_MODE", "CODEC_CLEAR_MODE", "CODEC_SET_GPIO_PIN",
"CODEC_EACH_TIME_INIT", "CODEC_SET_STARTUP_PARAM", "CODEC_SET_VOLUME_TABLE",
"CODEC_SET_RECORD", "CODEC_SET_REPLAY", "CODEC_SET_REPLAY_RECORD",
- "CODEC_TURN_ON", "CODEC_TURN_OFF", "CODEC_SET_REPLAY_SPEED",
+ "CODEC_TURN_ON", "CODEC_TURN_OFF", "CODEC_SET_REPLAY_RATE",
"CODEC_RESET", "CODEC_GET_MIXER_OLD_INFO", "CODEC_GET_MIXER_INFO",
- "CODEC_SET_BASS", "CODEC_SET_VOLUME", "CODEC_SET_MIC",
+ "CODEC_SET_BASS", "CODEC_SET_REPLAY_VOLUME", "CODEC_SET_MIC_VOLUME",
"CODEC_SET_LINE", "CODEC_I2S_RESUME", "CODEC_I2S_SUSPEND",
"CODEC_PIN_INIT", "CODEC_SET_SOME_FUNC", "CODEC_CLEAR_RECORD",
"CODEC_CLEAR_REPLAY", "CODEC_SET_REPLAY_HP_OR_SPKR", "CODEC_SET_DIRECT_MODE",
"CODEC_CLEAR_DIRECT_MODE", "CODEC_SET_LINEIN2HP", "CODEC_CLEAR_LINEIN2HP",
"CODEC_ANTI_POP", "CODEC_TURN_REPLAY", "CODEC_SET_REPLAY_CHANNEL",
"CODEC_SET_REPLAY_FORMAT", "CODEC_SET_RECORD_CHANNEL", "CODEC_SET_RECORD_FORMAT",
- "CODEC_SET_RECORD_SPEED", "CODEC_DAC_MUTE"
+ "CODEC_SET_RECORD_RATE", "CODEC_DAC_MUTE", "CODEC_SET_LINEIN2BTL",
+ "CODEC_CLEAR_LINEIN2BTL", "CODEC_SET_DEVICE", "CODEC_MUTE_DEVICE"
};
if (cmd >= (sizeof(dlv_ioc_cmd) / sizeof(dlv_ioc_cmd[0]))) {
@@ -115,6 +190,11 @@ static dlv_print_ioc_cmd(int cmd)
}
#endif
+
+/*
+ * CODEC registers access routines
+ */
+
/**
* CODEC read register
*
@@ -148,7 +228,7 @@ void dlv_write_reg(int addr, int val)
while (__icdc_rgwr_ready()) {
;//nothing...
}
- REG_ICDC_RGADW = ((addr << ICDC_RGADW_RGADDR_BIT) | val);
+ REG_ICDC_RGADW = ((addr << ICDC_RGADW_RGADDR_LSB) | val);
__icdc_set_rgwr();
reg = __icdc_rgwr_ready();
reg = __icdc_rgwr_ready();
@@ -161,6 +241,20 @@ void dlv_write_reg(int addr, int val)
}
}
+static inline void dlv_sleep_wait_bitset(int reg, unsigned bit, int stime, int line)
+{
+ while(!(dlv_read_reg(reg) & (1 << bit))) {
+ printk("DLV waiting reg(%2x) bit(%2x) set %d \n",reg, bit, line);
+ msleep(stime);
+ }
+}
+
+static inline void dlv_sleep_wait_bitclear(int reg, unsigned bit, int stime)
+{
+ while((dlv_read_reg(reg) & (1 << bit)))
+ msleep(stime);
+}
+
/**
* CODEC write a bit of a register
*
@@ -185,49 +279,106 @@ static int dlv_write_reg_bit(int addr, int bitval, int mask_bit)
* DLV CODEC operations routines
*/
+static inline void turn_on_dac(void)
+{
+ if(__dlv_get_dac_mute()){
+ /* clear IFR_GUP */
+ __dlv_set_irq_flag(1 << IFR_GUP);
+ /* turn on dac */
+ __dlv_disable_dac_mute();
+ /* wait IFR_GUP set */
+ dlv_sleep_wait_bitset(0xb, IFR_GUP, 100,__LINE__);
+ }
+}
+
+static inline void turn_off_dac(void)
+{
+ if (!(__dlv_get_dac_mute())){
+ /* clear IFR_GDO */
+ __dlv_set_irq_flag(1 << IFR_GDO);
+ /* turn off dac */
+ __dlv_enable_dac_mute();
+ /* wait IFR_GDO set */
+ dlv_sleep_wait_bitset(0xb, IFR_GUP, 100,__LINE__);
+ }
+}
+
+static inline void turn_on_sb_hp(void)
+{
+ if (__dlv_get_sb_hp() != POWER_ON){
+ /* clear IFR_RUP */
+ __dlv_set_irq_flag(1 << IFR_RUP);
+ /* turn on sb_hp */
+ __dlv_switch_sb_hp(POWER_ON);
+ /* wait IFR_RUP set */
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ }
+
+}
+static inline void turn_off_sb_hp(void)
+{
+ if (__dlv_get_sb_hp() != POWER_OFF){
+ /* clear IFR_RDO */
+ __dlv_set_irq_flag(1 << IFR_RDO);
+ /* turn off sb_hp */
+ __dlv_switch_sb_hp(POWER_OFF);
+ /* wait IFR_RDO set */
+ dlv_sleep_wait_bitset(0xb, IFR_RDO, 100,__LINE__);
+ }
+}
+
+static void dlv_shutdown(void) {
+ unsigned long start_time = jiffies;
+
+ __dlv_enable_hp_mute();
+ udelay(500);
+ turn_off_dac();
+ turn_off_sb_hp();
+ mdelay(1);
+ __dlv_switch_sb_dac(POWER_OFF);
+
+ DPRINT_CODEC("CODEC shutdown finish in %d jiffies! pmr1 = 0x%02x, pmr2 = 0x%02x\n",
+ (jiffies - start_time), dlv_read_reg(DLV_REG_PMR1), dlv_read_reg(DLV_REG_PMR2));
+}
+
static void dlv_each_time_init(void)
{
ENTER();
__i2s_disable();
__i2s_as_slave();
__aic_internal_codec();
- //__i2s_set_oss_sample_size(16);
- //__i2s_set_iss_sample_size(16);
LEAVE();
}
-static void dlv_set_mode(void)
+static void dlv_init(void)
{
ENTER();
+ DLV_LOCKINIT();
+
+#ifdef CONFIG_JZ4760_PT701
+ /* disable speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_clear_pin(GPIO_SPK_EN);
+ /* disable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_clear_pin(GPIO_DOCK_SPK_EN);
+#endif
+ __dlv_switch_sb_micbias(POWER_ON);
+ __dlv_set_int_form(ICR_INT_HIGH_8CYCLES);
- //dlv_write_reg(8, 0x2f);
- //dlv_write_reg(9, 0xff);
- dlv_write_reg(DLV_REG_ICR, 0x0f);
- dlv_write_reg(DLV_REG_IFR, 0xff); // ???
-
- schedule_timeout(2);
+ __dlv_set_irq_mask(ICR_COMMON_MASK);
+ __dlv_set_irq_flag(0x3f);
- dlv_write_reg_bit(6, 0, 1);//PMR2.SB->0
- dlv_write_reg_bit(6, 0, 0);//PMR2.SB->0
+ __dlv_set_12m_crystal();
-// dlv_write_reg_bit(1, 0, 3);//PMR2.SB->0
+ g_current_out_dev = SND_DEVICE_SPEAKER;
- dlv_write_reg_bit(5, 0, 4);//SB_ADC->1
-// set_record_mic_input_audio_with_audio_data_replay();
-// reset_dlv_codec();
LEAVE();
}
static void dlv_reset(void)
{
ENTER();
- /* reset DLV codec. from hibernate mode to sleep mode */
- //dlv_write_reg(0, 0xf);
- //dlv_write_reg_bit(6, 0, 0);
- //dlv_write_reg_bit(6, 0, 1);
-
- //2010-01-31 Jason add
- //dlv_write_reg(22, 0x40);//mic 1
dlv_write_reg_bit(DLV_REG_AICR, 1, AICR_DAC_SERIAL);
dlv_write_reg_bit(DLV_REG_AICR, 1, AICR_ADC_SERIAL);
@@ -235,10 +386,10 @@ static void dlv_reset(void)
/* reset DLV codec. from hibernate mode to sleep mode */
dlv_write_reg(DLV_REG_AICR, 0xf);
dlv_write_reg_bit(DLV_REG_PMR1, 0, PMR1_SB);
- dlv_write_reg_bit(DLV_REG_PMR1, 0, PMR1_SB_SLEEP);
schedule_timeout(30);
+ dlv_write_reg_bit(DLV_REG_PMR1, 0, PMR1_SB_SLEEP);
dlv_write_reg(DLV_REG_CR3, 1 << CR3_MICSTEREO);//mic 1
@@ -252,136 +403,17 @@ static void dlv_reset(void)
dlv_write_reg_bit(DLV_REG_PMR2, 0, PMR2_SB_DAC);
dlv_write_reg_bit(DLV_REG_PMR2, 0, PMR2_SB_ADC);
-
schedule_timeout(2); ;//wait for stability
LEAVE();
}
-static int dlv_set_startup_param(void)
-{
- ENTER();
- LEAVE();
-// __i2s_disable_transmit_intr();
-// __i2s_disable_receive_intr();
- return 1;
-}
-
/**
- * Set audio replay
+ * Set replay rate
+ *
+ * rate: replay rate to set
+ * return: replay rate after set
*/
-static void dlv_set_replay(void)
-{
- ENTER();
-
-// dump_dlv_regs("enter dlv_set_replay");
-
- dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_HP_MUTE);
- dlv_write_reg_bit(DLV_REG_PMR1, 1, PMR1_SB_BYPASS);
-
- // OUTSEL <-- 11b
- dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_OUTSEL0);
- dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_OUTSEL1);
-
- // Disable mute
- dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_DAC_MUTE);
- dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_LINEOUT_MUTE);
- dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_BTL_MUTE);
-
- // NOMAD
- dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_NOMAD);
-
-// dump_dlv_regs("leave dlv_set_replay");
- LEAVE();
-}
-
-#if 0
-/* set Record MIC input audio with Audio data replay (full duplex) */
-static void set_record_mic_input_audio_with_audio_data_replay(void)
-{
- ENTER();
- printk("when run here ?????\n");
- dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
- dlv_write_reg(9, 0xff);
- //dlv_write_reg(8, 0x30);
- dlv_write_reg(8, 0x20);
- dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
- dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
- dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
-
- dlv_write_reg_bit(22, 0, 7);//CR3.SB_MIC->0
-
- dlv_write_reg_bit(1, 0, 7);//CR1.SB_MICBIAS->0
-
- dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
- dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
- LEAVE();
-}
-
-/* unset Record MIC input audio with Audio data replay (full duplex) */
-static void unset_record_mic_input_audio_with_audio_data_replay(void)
-{
- ENTER();
- /* ADC path */
- printk("@@@ %s", __FUNCTION__);
- dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
- dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
- dlv_write_reg(22, 0xc0);//CR3.SB_MIC1->1
-// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
- dlv_write_reg_bit(5, 1, 5);//SB_MIX->1
-
- // 2009-01-20 Jason marked
-// dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
-// dlv_write_reg_bit(6, 1, 1);//SB->1
- LEAVE();
-}
-
-/* set Record LINE input audio with Audio data replay (full duplex for linein) */
-static void set_record_line_input_audio_with_audio_data_replay(void)
-{
- ENTER();
- dlv_write_reg(9, 0xff);
- //dlv_write_reg(8, 0x30);
- dlv_write_reg(8, 0x20);
- dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
- dlv_write_reg_bit(5, 0, 3);//PMR1.SB_LIN->0
- dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
- dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //dlv_write_reg_bit(22, 1, 7);//CR3.SB_MIC->1
- dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
- dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
-
- dlv_write_reg(22, 0xc6);//line in 1
- dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
- dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
- dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
- LEAVE();
-}
-
-//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
-static void unset_record_line_input_audio_with_audio_data_replay(void)
-{
- ENTER();
- /* ADC path */
- printk("@@@ %s", __FUNCTION__);
-
- dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
- dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
- dlv_write_reg(22, 0xc0);//CR3.SB_MIC1->1
-// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
- dlv_write_reg_bit(5, 1, 5);//SB_MIX->1
-
- // 2010-01-20 Jason masked
-// dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
-// dlv_write_reg_bit(6, 1, 1);//SB->1
- LEAVE();
-}
-
-#endif
-
-static int dlv_set_replay_speed(int rate)
+static int dlv_set_replay_rate(int rate)
{
int speed = 0, val;
@@ -403,10 +435,18 @@ static int dlv_set_replay_speed(int rate)
val &= 0xf;
val = (speed << 4) | val;
dlv_write_reg(DLV_REG_CCR2, val);
+
return mrate[speed];
}
-static int dlv_set_record_speed(int rate)
+
+/**
+ * Set record rate
+ *
+ * rate: record rate to set
+ * return: record rate after set
+ */
+static int dlv_set_record_rate(int rate)
{
int speed = 0, val;
@@ -432,326 +472,1106 @@ static int dlv_set_record_speed(int rate)
return mrate[speed];
}
-#if 0
-static void reset_jzcodec(void)
-{
- ;
-}
-#endif
-
static void dlv_get_mixer_old_info(mixer_info *info)
{
strncpy(info->id, "JZDLV", sizeof(info->id));
- strncpy(info->name, "Jz internal codec dlv on jz4750", sizeof(info->name));
+ strncpy(info->name, "Jz internal codec dlv on jz4760", sizeof(info->name));
}
static void dlv_get_mixer_info(mixer_info *old_info)
{
strncpy(old_info->id, "JZDLV", sizeof(old_info->id));
- strncpy(old_info->name, "Jz internal codec dlv on jz4750", sizeof(old_info->name));
+ strncpy(old_info->name, "Jz internal codec dlv on jz4760", sizeof(old_info->name));
}
-static void dlv_set_mic(int val)
+static void dlv_turn_off(int mode)
{
- int cur_vol;
-
ENTER();
- printk("~~~~ dlv_set_mic\n");
+ if ((mode & REPLAY) && (mode & RECORD)) {
+ printk("JZ DLV: Close REPLAY and RECORD\n");
+ //dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+ schedule_timeout(20);
- /* set GIM */
+ // 2010-01-31 Jason marked
+ //dlv_write_reg_bit(5, 1, 6);//SB_OUT->1
- /* set gain */
- cur_vol = 31 * val / 100;
- cur_vol = 0x80 | cur_vol;
- dlv_write_reg(DLV_REG_GCR8, cur_vol);//GIL,GIR
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x2f);
+ } else if (mode & REPLAY) {
+ printk("JZ DLV: Close REPLAY\n");
+ //dlv_disable_receiver();
+ //dlv_shutdown();
+ __dlv_enable_hp_mute();
+ udelay(500);
+ turn_off_dac();
+ //nothing
+ } else if (mode & RECORD) {
+ printk("JZ DLV: Close RECORD\n");
+ dlv_disable_mic_1();
+ dlv_disable_mic_2();
+ }
+ DLV_LOCKDEINIT();
LEAVE();
}
-static void dlv_set_line(int val)
+static int dlv_set_channel(int ch)
{
- int cur_vol;
+ ch = (ch >= 2) + 1;
- ENTER();
- /* set gain */
- cur_vol = 31 * val / 100;
- cur_vol &= 0x1f;
- /* ???
- dlv_write_reg(11, cur_vol);//GO1L
- dlv_write_reg(12, cur_vol);//GO1R
- */
- LEAVE();
+ switch (ch) {
+ case 1:
+ // MONO->1 for Mono
+ __dlv_enable_dac_m2s();
+ break;
+ case 2:
+ // MONO->0 for Stereo
+ __dlv_disable_dac_m2s();
+ break;
+ }
+
+ return ch;
}
-static void dlv_set_volume(int val)
+static int dlv_set_data_width(unsigned int mode, unsigned int width)
{
- unsigned long cur_vol;
+ unsigned char aicr = dlv_read_reg(DLV_REG_AICR);
+ unsigned char aicr_bak = aicr;
+ int supported_width[4] = {16, 18, 20, 24};
+ int i;
- ENTER();
+ for (i = 0; i < (sizeof(supported_width) / sizeof(supported_width[0])); i++) {
+ if (supported_width[i] <= width) {
+ break;
+ }
+ }
- /* To protect circut and to avoid shutting down CODEC,
- * valume must less then 60% of the max
- */
+ if (i == (sizeof(supported_width) / sizeof(supported_width[0]))) {
+ // For 8 bit width mode, handle it as 16 bit
+ if (width == 8) {
+ i = 0;
+ } else {
+ return -1;
+ }
+ }
+
+ //printk("mode = %d, width = %d, selected %d\n", mode, width, i);
- if (val > 60) {
- val = 60;
+ switch (mode) {
+ case RECORD:
+ aicr &= ~(3 << 4);
+ aicr |= (i << 4);
+ break;
+ case REPLAY:
+ aicr &= ~(3 << 6);
+ aicr |= (i << 6);
+ break;
}
+ if (aicr != aicr_bak) {
+ dlv_write_reg(DLV_REG_AICR, aicr);
+ }
- //val = 90;
- cur_vol = 31 * (100 - val) / 100;
+ if (width == 8) {
+ return 8;
+ } else {
+ return supported_width[i];
+ }
+}
- dlv_write_reg(DLV_REG_GCR1, 0x80 | cur_vol);
+static int dlv_mute(int val)
+{
+ return dlv_write_reg_bit(DLV_REG_CR2, val ? 1 : 0, CR2_DAC_MUTE);
+}
- DPRINT_CODEC("$$$$$ val = %d, DLV_REG_CGR1 = 0x%02x\n",
- val, dlv_read_reg(DLV_REG_GCR1));
+void dump_dlv_regs(const char * str)
+{
+ unsigned int i;
+ unsigned char data;
+ printk("codec register dump, %s:\n", str);
+ for (i = 0; i < 32; i++) {
+ data = dlv_read_reg(i);
+ printk("address = 0x%02x, data = 0x%02x\n", i, data);
+ }
+}
- LEAVE();
+
+void board_set_record(void)
+{
+#ifdef Z800_CONFIG
+#endif
+
+#ifdef CONFIG_JZ4760_ALTAIR
+ dlv_enable_mic_1();
+#endif
+
+#ifdef CONFIG_JZ4760_PT701
+ dlv_enable_mic_1();
+#endif
+
+ dlv_enable_mic_1();
}
-/*
- * Base on set_record_mic_input_audio_without_playback()
- */
-static void dlv_set_record(void)
+/********************************************************************************
+ * Anti-pop *
+ ********************************************************************************/
+
+#ifdef ANTI_POP_WORK_STRUCT
+static struct work_struct dlv_anti_pop_work;
+#endif
+
+static void dlv_anti_pop_part(void)
{
- ENTER();
+ unsigned start_time = jiffies;
-// dump_dlv_regs("enter dlv_set_record");
+ __dlv_switch_sb(POWER_ON);
+ msleep(10);
- /* ADC path for MIC IN */
+ __dlv_switch_sb_sleep(POWER_ON);
+ msleep(10);
- dlv_write_reg_bit(DLV_REG_AGC1, 0, AGC1_AGCEN);//AGC1.AGC_EN->0
+ __dlv_switch_sb_dac(POWER_ON);
+ udelay(500);
- dlv_write_reg_bit(DLV_REG_PMR1, 0, PMR1_SB);
- dlv_write_reg_bit(DLV_REG_PMR1, 0, PMR1_SB_SLEEP);
+ __dlv_enable_hp_mute();
+ mdelay(1);
- switch_SB_ADC(POWER_ON);
+ turn_on_sb_hp();
+ mdelay(1);
+}
- /* MIC 1*/
- dlv_write_reg_bit(DLV_REG_PMR1, POWER_ON, PMR1_SB_MIC1);
+/**
+ * Work handler for dlv_anti_pop_work
+ *
+ * Perform an anti-pop startup sequence with msleep (block operation).
+ */
+static void dlv_anti_pop_work_handler(struct work_struct *work)
+{
+ dlv_anti_pop_part();
+ turn_on_dac();
+ __dlv_disable_hp_mute();
+
+#ifdef CONFIG_JZ4760_PT701
+ /* if headphone not attached */
+ if (!gstate_hp) {
+ if (gstate_dock == 1) {
+ printk("pt701 audio select external speaker!");
+ /* disable internal speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_clear_pin(GPIO_SPK_EN);
+ /* enable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_set_pin(GPIO_DOCK_SPK_EN);
+ } else {
+ printk("pt701 audio select internal speaker!");
+ /* enable internal speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_set_pin(GPIO_SPK_EN);
+ /* disable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_clear_pin(GPIO_DOCK_SPK_EN);
+ }
+ }
+#endif
+// up(&g_dlv_sem_lock);
- /* MIC 2 */
- //dlv_write_reg_bit(DLV_REG_PMR1, POWER_ON, PMR1_SB_MIC2);
+ DLV_UNLOCK();
+}
- dlv_write_reg_bit(DLV_REG_PMR1, POWER_ON, PMR1_SB_MICBIAS);
+#ifdef ANTI_POP_TIMER
- switch_SB_LINE_IN(POWER_OFF);
+#define ACTION_COUNT 6
+/* Time consuming (jiffie is 10ms) */
- schedule_timeout(2);
+#if 1
- // Record mono
- dlv_write_reg(DLV_REG_CR3, 0);
- dlv_write_reg_bit(DLV_REG_CR3, 1, CR3_MICDIFF);
+#define ACTION_0_DELAY_TIME 1
+#define ACTION_1_DELAY_TIME 1
+#define ACTION_2_DELAY_TIME 1
+#define ACTION_3_DELAY_TIME 1
+#define ACTION_4_DELAY_TIME 1
+#define ACTION_5_DELAY_TIME 50
- /* MIC 1 */
- dlv_write_reg_bit(DLV_REG_CR3, 0, CR3_INSEL1);
- dlv_write_reg_bit(DLV_REG_CR3, 0, CR3_INSEL0);
+#else
- /* MIC 2 */
- //dlv_write_reg_bit(DLV_REG_CR3, 0, CR3_INSEL1);
- //dlv_write_reg_bit(DLV_REG_CR3, 1, CR3_INSEL0);
+#define ACTION_0_DELAY_TIME 25
+#define ACTION_1_DELAY_TIME 2
+#define ACTION_2_DELAY_TIME 2
+#define ACTION_3_DELAY_TIME 2
+#define ACTION_4_DELAY_TIME 30
- dlv_write_reg_bit(DLV_REG_CR4, 0, 0);
+#endif
- dlv_write_reg_bit(DLV_REG_PMR1, 1, PMR1_SB_BYPASS);
+struct jz_anti_pop_timer_t {
+ struct timer_list timer;
+ int cur_startup_action;
+ void (*dlv_anti_pop_actions[ACTION_COUNT])(void);
+ int delay_time[ACTION_COUNT];
+};
- // GIM
-// dlv_write_reg(DLV_REG_GCR7, 0x3f);
- dlv_write_reg(DLV_REG_GCR7, 0x0);
+static inline int get_action_delay_time(struct jz_anti_pop_timer_t* apt)
+{
+ return apt->delay_time[apt->cur_startup_action];
+}
- // GIDR
-// dlv_write_reg(DLV_REG_GCR8, 0xff);
- dlv_write_reg(DLV_REG_GCR8, 0x0);
- // GID
-// dlv_write_reg(DLV_REG_GCR9, 0x1f);
- dlv_write_reg(DLV_REG_GCR9, 0x0);
+static inline void dlv_anti_pop_action_0(void)
+{
+// __dlv_set_irq_mask(ICR_COMMON_MASK);
+ __dlv_switch_sb(POWER_ON);
+}
+static inline void dlv_anti_pop_action_1(void)
+{
+ __dlv_switch_sb_sleep(POWER_ON);
+}
+static inline void dlv_anti_pop_action_2(void)
+{
+ __dlv_switch_sb_dac(POWER_ON);
+}
-// dump_dlv_regs("leave dlv_set_record");
+static inline void dlv_anti_pop_action_3(void)
+{
+ __dlv_enable_hp_mute();
+}
+static inline void dlv_anti_pop_action_4(void)
+{
+#if 1
+ if (__dlv_get_sb_hp() != POWER_ON){
+ __dlv_switch_sb_hp(POWER_ON);
+// dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ }
- LEAVE();
+#else
+ if (__dlv_get_sb_hp() != POWER_ON){
+ __dlv_switch_sb_hp(POWER_ON);
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ }
+ __dlv_reset_rup();
+
+ if(__dlv_get_dac_mute()){
+ __dlv_disable_dac_mute();
+ dlv_sleep_wait_bitset(0xb, IFR_GUP, 100,__LINE__);
+ }
+ __dlv_reset_gup();
+#endif
}
-static void dlv_set_replay_recode(int val)
+static inline void dlv_anti_pop_action_5(void)
{
- ENTER();
- if (val == USE_LINEIN) {
- /* Record LINE input audio with Audio data replay (full duplex for linein) */
- /* codec_test_line */
- printk("use line in ???\n");
-// set_record_line_input_audio_with_audio_data_replay();
+ while(!(dlv_read_reg(0x0b) & (1 << IFR_RUP))) {
+ printk("DLV delay waiting IFR_RUP \n");
+ mdelay(10);
}
- if (val == USE_MIC) {
- /* Record MIC input audio with Audio data replay (full duplex) */
- /* codec_test_mic */
-// set_record_mic_input_audio_with_audio_data_replay();
+}
+
+static struct jz_anti_pop_timer_t anti_pop_timer = {
+ .cur_startup_action = 0,
+ .dlv_anti_pop_actions = {
+ dlv_anti_pop_action_0,
+ dlv_anti_pop_action_1,
+ dlv_anti_pop_action_2,
+ dlv_anti_pop_action_3,
+ dlv_anti_pop_action_4,
+ dlv_anti_pop_action_5
+ },
+ .delay_time = {
+ ACTION_0_DELAY_TIME,
+ ACTION_1_DELAY_TIME,
+ ACTION_2_DELAY_TIME,
+ ACTION_3_DELAY_TIME,
+ ACTION_4_DELAY_TIME,
+ ACTION_5_DELAY_TIME
}
- LEAVE();
+};
+
+static void dlv_timer_callback(void)
+{
+ //printk("%s, startup action = %d\n", __FUNCTION__, anti_pop_timer.cur_startup_action);
+
+ int action_number = anti_pop_timer.cur_startup_action++;
+
+ if (action_number < ACTION_COUNT) {
+ anti_pop_timer.dlv_anti_pop_actions[action_number]();
+ mod_timer(&anti_pop_timer.timer, jiffies + anti_pop_timer.delay_time[action_number]);
+
+
+ } else if (action_number == ACTION_COUNT) {
+ del_timer_sync(&anti_pop_timer.timer);
+ anti_pop_timer.cur_startup_action = 0;
+
+ __dlv_disable_dac_mute();
+
+ __dlv_disable_hp_mute();
+ /*ulock*/
+ DLV_UNLOCK();
+ } else {
+ printk("JZ DLV: startup state error, cur_startup_action = %d\n", anti_pop_timer.cur_startup_action);
+ }
+
+}
+#endif
+
+/**
+ * Start startup anti-pop sequence.
+ *
+ * This is unblock operation that implement by using timer or work struct.
+ *
+ * Typically, for resuming from sleep.
+ */
+static void dlv_enable_hp_without_pop(void)
+{
+#ifdef ANTI_POP_TIMER
+ init_timer(&anti_pop_timer.timer);
+ anti_pop_timer.cur_startup_action = 0;
+ anti_pop_timer.timer.function = dlv_timer_callback;
+ dlv_timer_callback();
+#endif
+
+#ifdef ANTI_POP_WORK_STRUCT
+ schedule_work(&dlv_anti_pop_work);
+#endif
}
+/**
+ * DLV anti-pop "ioctl" routine.
+ * This function should only be called in device open function.
+ */
static void dlv_anti_pop(int mode)
{
-// dump_dlv_regs("++++++++++++++");
switch(mode) {
case CODEC_WRMODE:
- //set SB_ADC or SB_DAC
- //dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
- switch_SB_OUT(POWER_ON);
-
- //2010-01-31 Jason add
- //dlv_write_reg(22, 0x40);//mic 1
-
- //2010-01-31 Jason add
- //dlv_write_reg(1, 0x04);
-
- schedule_timeout(28); //280 ms
break;
case CODEC_RMODE:
- printk("dlv_anti_pop CODEC_WMODE\n");
- switch_SB_MIC1(POWER_ON);
break;
case CODEC_WMODE:
- //dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
- printk("dlv_anti_pop CODEC_WMODE\n");
- switch_SB_OUT(POWER_ON);
+ printk(">>>>>>>>>>>>>>>>1: dlv_anti_pop\n");
+ /* Call work handler directly to anti-pop at system start.
+ * Notice that this is block operation...
+ * We use this way to ensure the operation of device openning
+ * has already completed before any other operations like ioctl.
+ */
+ if (__dlv_get_sb_hp() != POWER_ON){
+ should_up = 1;
+ printk(">>>>>>>>>>>>>>>>2: dlv_anti_pop\n");
+ dlv_anti_pop_part();
+ }
+ break;
+ }
+}
- schedule_timeout(28); //280 ms
+/********************************************************************************
+ * Volume control *
+ ********************************************************************************/
- // 2010-01-31 Jason marked
- //dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+static void dlv_set_voice_volume(int vol)
+{
+ __dlv_set_line_in_bypass_volume(vol);
+}
- //2010-01-31 Jason add
- //dlv_write_reg(1, 0x04);
+static void dlv_set_replay_volume(int val)
+{
+ unsigned long fixed_vol;
- //dlv_write_reg_bit(5, 0, 7);//PMR1.SB_OUT->0
- switch_SB_DAC(POWER_ON);
+ ENTER();
- break;
- }
-// dump_dlv_regs("--------------");
+ /* Set it forcely
+ * val = 95;
+ */
+
+ fixed_vol = 30 * (100 - val) / 100;
+ __dlv_set_hp_volume(fixed_vol);
+
+ DPRINT_CODEC("$$$$$ val = %d, DLV_REG_CGR1 = 0x%02x\n",
+ val, dlv_read_reg(DLV_REG_GCR1));
+
+ LEAVE();
}
-static void dlv_turn_replay(int mode)
+static void dlv_set_mic_volume(int val)
{
+ int fixed_vol;
+
ENTER();
- if (mode == USE_LINEIN) {
- printk("use line in ?????????\n");
- //unset_record_line_input_audio_with_audio_data_replay();
+
+ fixed_vol = 31 * val / 100;
+ __dlv_set_gidr(fixed_vol | 0x80);
+ //__dlv_set_mic_1_volume(fixed_vol);
+
+ LEAVE();
+}
+
+/********************************************************************************
+ * ROUTE FUNCTIONS *
+ ********************************************************************************/
+
+/**
+ * Enable HP OUT replay mode
+ *
+ */
+static void dlv_enable_hp_out(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ __dlv_enable_nomad();
+ __dlv_disable_dac_right_only();
+ __dlv_set_outsel(DAC_OUTPUT);
+ __dlv_switch_sb_bypass(POWER_OFF);
+ __dlv_switch_sb_line_out(POWER_OFF);
+ __dlv_switch_sb_btl(POWER_OFF);
+
+ __dlv_switch_sb_aip(POWER_ON);
+ mdelay(1);
+ __dlv_switch_sb(POWER_ON);
+ // reference up time
+ mdelay(300);
+ __dlv_switch_sb_sleep(POWER_ON);
+ //sleep up time
+ mdelay(500);
+ __dlv_switch_sb_dac(POWER_ON);
+ //dac up time
+ udelay(500);
+ __dlv_disable_hp_mute();
+ mdelay(1);
+ turn_on_sb_hp();
+
+// mdelay(300);
+// __dlv_disable_dac_mute();
+}
+
+/**
+ * Disable HP OUT replay mode
+ *
+ */
+static void dlv_disable_hp_out(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ turn_off_sb_hp();
+ __dlv_enable_hp_mute();
+ turn_off_dac();
+ //__dlv_switch_sb_dac(POWER_ON);
+ mdelay(10);
+}
+
+/**
+ * Enable btl replay mode
+ *
+ */
+static void dlv_enable_btl(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ if (__dlv_get_sb_hp() != POWER_ON) {
+ __dlv_switch_sb_hp(POWER_ON);
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ }
+ __dlv_switch_sb_bypass(POWER_OFF);
+ __dlv_switch_sb_line_out(POWER_ON);
+ __dlv_switch_sb_btl(POWER_ON);
+ __dlv_disable_dac_mute();
+ __dlv_disable_hp_mute();
+ __dlv_disable_dac_right_only();
+ __dlv_disable_nomad();
+ __dlv_disable_lineout_mute();
+ __dlv_disable_btl_mute();
+
+ dlv_set_replay_volume(95);
+
+ DUMP_CODEC_REGS("after dlv_enable_btl\n");
+}
+
+/**
+ * Disable btl replay mode
+ *
+ */
+static void dlv_disable_btl(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ __dlv_switch_sb_btl(POWER_OFF);
+ __dlv_switch_sb_line_out(POWER_OFF);
+
+// DUMP_CODEC_REGS("after dlv_disable_speaker\n");
+}
+
+/**
+ * Enable SPERKER replay mode
+ *
+ */
+static void dlv_enable_speaker(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ dlv_enable_btl();
+}
+
+/**
+ * Disable SPERKER replay mode
+ *
+ */
+static void dlv_disable_speaker(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ dlv_disable_btl();
+
+}
+
+/**
+ * Enable RECEIVER replay mode
+ *
+ */
+static void dlv_enable_receiver(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+// __dlv_set_16ohm_load();
+// __dlv_set_10kohm_load();
+
+ dlv_enable_hp_out();
+}
+
+/**
+ * Disable RECEIVER replay mode
+ *
+ */
+static void dlv_disable_receiver(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ dlv_disable_hp_out();
+}
+
+/**
+ * Enable LINE OUT replay mode
+ *
+ */
+static void dlv_enable_line_out(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ __dlv_switch_sb_dac(POWER_ON);
+ if (__dlv_get_sb_hp() != POWER_ON) {
+ __dlv_switch_sb_hp(POWER_ON);
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
}
- if (mode == USE_MIC) {
- //unset_record_mic_input_audio_with_audio_data_replay();
+ __dlv_switch_sb_btl(POWER_OFF);
+ __dlv_switch_sb_line_out(POWER_ON);
+
+
+ __dlv_set_outsel(DAC_OUTPUT);
+
+ __dlv_disable_nomad();
+ __dlv_enable_dac_right_only();
+ dlv_set_replay_volume(70);
+ __dlv_disable_dac_mute();
+ __dlv_disable_hp_mute();
+ __dlv_disable_lineout_mute();
+}
+
+/**
+ * Disable LINE OUT replay mode
+ *
+ */
+static void dlv_disable_line_out(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ //DUMP_CODEC_REGS("after dlv_disable_line_out\n");
+}
+
+/**
+ * Enable LINE IN record mode
+ *
+ * insel: 1 line in left channel
+ * insel: 2 line in right channel
+ * insel: 3 line in left & right channels
+ */
+static void dlv_enable_line_in_record(int insel)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ dlv_write_reg_bit(DLV_REG_AGC1, 0, AGC1_AGCEN);//AGC1.AGC_EN->0
+
+ schedule_timeout(2);
+
+ __dlv_set_mic_stereo();
+ __dlv_enable_mic_diff();
+ __dlv_switch_sb_line_in(POWER_ON);
+ __dlv_set_insel(LINE_INPUT);
+ __dlv_set_gim(0x3f);
+ __dlv_set_gidr(0xf);
+ __dlv_set_gidl(0xf);
+ __dlv_switch_sb_adc(POWER_ON);
+
+ //DUMP_CODEC_REGS("after dlv_enable_line_in\n");
+}
+
+/**
+ * Disable LINE IN record mode
+ *
+ * Disable every channels independently ???
+ */
+static void dlv_disable_line_in_record(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ //DUMP_CODEC_REGS("after dlv_disable_line_in\n");
+}
+
+/**
+ * Enable LINE IN bypass to HP
+ *
+ * Depend: LINE IN was enabled, HP out was enabled
+ */
+static void dlv_enable_line_in_bypass_hp(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ // Yunfeng@Jul27'10 added for FM's audio path
+ __dlv_switch_sb(POWER_ON);
+ __dlv_switch_sb_sleep(POWER_ON);
+
+ __dlv_set_16ohm_load();
+
+ __dlv_switch_sb_line_out(POWER_OFF);
+ if (__dlv_get_sb_hp() != POWER_ON) {
+ __dlv_switch_sb_hp(POWER_ON);
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
}
+ __dlv_switch_sb_line_in(POWER_ON);
+ __dlv_switch_sb_btl(POWER_OFF);
+ __dlv_switch_sb_bypass(POWER_ON);
+
+ __dlv_set_outsel(BYPASS_PATH);
+
+ __dlv_disable_dac_mute();
+ __dlv_enable_lineout_mute();
+ __dlv_disable_hp_mute();
+ __dlv_enable_btl_mute();
+ __dlv_disable_dac_right_only();
+ __dlv_disable_nomad();
+}
+
+/**
+ * Disable LINE IN bypass to HP
+ *
+ */
+static void dlv_disable_line_in_bypass_hp(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+}
+
+/**
+ * Enable LINE IN bypass to BTL
+ *
+ * Depend: LINE IN was enabled, BTL was enabled
+ */
+static void dlv_enable_line_in_bypass_btl(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ __dlv_switch_sb(POWER_ON);
+ __dlv_switch_sb_sleep(POWER_ON);
+
+ __dlv_set_16ohm_load();
+
+ __dlv_switch_sb_line_out(POWER_ON);
+ if (__dlv_get_sb_hp() != POWER_ON) {
+ __dlv_switch_sb_hp(POWER_ON);
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ }
+ __dlv_switch_sb_line_in(POWER_ON);
+ __dlv_switch_sb_btl(POWER_ON);
+ __dlv_switch_sb_bypass(POWER_ON);
+
+ __dlv_set_outsel(BYPASS_PATH);
+
+ __dlv_disable_dac_mute();
+ __dlv_disable_lineout_mute();
+ __dlv_disable_hp_mute();
+ __dlv_disable_btl_mute();
+ __dlv_disable_dac_right_only();
+ __dlv_disable_nomad();
+
+
+ //dump_dlv_regs("after enable line in bypass btl\n");
+}
+
+/**
+ * Disable LINE IN bypass to BTL
+ *
+ */
+static void dlv_disable_line_in_bypass_btl(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ __dlv_set_outsel(DAC_OUTPUT);
+ __dlv_switch_sb_bypass(POWER_OFF);
+ __dlv_switch_sb_line_in(POWER_OFF);
+}
+
+/**
+ * Enable digital record mix into DA
+ *
+ */
+static void dlv_enable_rec_2_dac(void)
+{
+ __dlv_set_mix_rec_2_dac();
+}
+
+/**
+ * Disable ditital record mix into DA.
+ *
+ */
+static void dlv_disable_rec_2_dac(void)
+{
+ __dlv_set_mix_rec_only();
+}
+
+/**
+ * Enable MIC 2 record mode
+ *
+ * Caution: Please config regs according specific board
+ */
+static void dlv_enable_mic_2(void)
+{
+ ENTER();
+
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ dlv_write_reg(DLV_REG_CCR2, 0x29);
+
+ /* Ensure CODEC is opened */
+ __dlv_switch_sb_aip(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb_sleep(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb_adc(POWER_ON);
+ schedule_timeout(2);
+
+ //__dlv_enable_agc();
+ __dlv_disable_agc();
+
+ __dlv_switch_sb_micbias(POWER_ON);
+
+ /* For altair, ear_mic is single-ended input. */
+#ifdef CONFIG_JZ4760_ALTAIR
+ //__dlv_disable_mic_diff();
+ __dlv_enable_mic_diff();
+#endif
+ /* For z800, mic is differential input. */
+#ifdef CONFIG_JZ4760_Z800
+ __dlv_enable_mic_diff();
+#endif
+
+ /* For z800, main MIC is connected to MIC2 of JZ4760 */
+ __dlv_set_insel(MIC2_TO_LR);
+
+ __dlv_set_mic_mono();
+
+ __dlv_enable_adc_right_only();
+
+ /* Depend on board situation. For z800, we set max. */
+ __dlv_set_gim(0x3f);
+ __dlv_set_gidr(0x9f);
+
+ __dlv_switch_sb_mic2(POWER_ON);
+
+ __dlv_disable_agc();
+
+ dump_dlv_regs("enable mic2");
+
+ //DUMP_CODEC_REGS("leave dlv_enable_mic_2\n");
+ //dump_dlv_regs("leave dlv_enable_mic_2\n");
LEAVE();
}
-static void dlv_turn_off(int mode)
+/**
+ * Disable MIC 2 record mode
+ *
+ */
+static void dlv_disable_mic_2(void)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ __dlv_switch_sb_mic2(POWER_OFF);
+ //DUMP_CODEC_REGS("leave dlv_disable_mic_2\n");
+}
+
+/**
+ * Enable MIC 1 record mode
+ *
+ */
+static void dlv_enable_mic_1(void)
{
ENTER();
- if ((mode & REPLAY) && (mode & RECORD)) {
- printk("Close DLV !!!\n");
-// dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
- schedule_timeout(20);
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
- // 2010-01-31 Jason marked
- //dlv_write_reg_bit(5, 1, 6);//SB_OUT->1
+ dlv_write_reg(DLV_REG_CCR2, 0x29);
- dlv_write_reg(9, 0xff);
- dlv_write_reg(8, 0x2f);
- } else if (mode & REPLAY) {
- //nothing
- } else if (mode & RECORD) {
- printk("Close RECORD\n");
-// dlv_write_reg(4, 0x20);
- }
+ /* Ensure CODEC is opened */
+ __dlv_switch_sb_aip(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb_sleep(POWER_ON);
+ schedule_timeout(2);
+ __dlv_switch_sb_adc(POWER_ON);
+ schedule_timeout(2);
+
+// __dlv_enable_agc();
+ __dlv_disable_agc();
+
+ __dlv_switch_sb_micbias(POWER_ON);
+
+ /* For altair, ear_mic is single-ended input. */
+#ifdef CONFIG_JZ4760_ALTAIR
+ __dlv_disable_mic_diff();
+#endif
+ /* For z800, mic is differential input. */
+#ifdef CONFIG_JZ4760_Z800
+ __dlv_enable_mic_diff();
+#endif
+#ifdef CONFIG_JZ4760_LEPUS
+ __dlv_enable_mic_diff();
+#endif
+
+ /* For z800, main MIC is connected to MIC2 of JZ4760 */
+ __dlv_set_insel(MIC1_TO_LR);
+
+ __dlv_set_mic_mono();
+
+ __dlv_enable_adc_right_only();
+
+#if 0
+ /* Depend on board situation. For z800, we set max. */
+#if 0
+ /* max */
+ __dlv_set_gim(0x3f);
+ __dlv_set_gidr(0x9f);
+#endif
+
+#if 1
+ /* min */
+ __dlv_set_gim(0x0);
+ __dlv_set_gidr(0x8f);
+ //__dlv_set_gidl(0x0);
+#endif
+#endif
+
+ __dlv_switch_sb_mic1(POWER_ON);
+
+ __dlv_disable_agc();
+
+ dump_dlv_regs("enable mic1");
+
+ //DUMP_CODEC_REGS("leave dlv_enable_mic_2\n");
+ //dump_dlv_regs("leave dlv_enable_mic_2\n");
LEAVE();
}
-static int dlv_set_channel(int ch)
+/**
+ * Disable MIC 1 record mode
+ *
+ */
+static void dlv_disable_mic_1(void)
{
- if(ch > 2) ch = 2;
- if(ch < 1) ch = 1;
- switch (ch) {
- case 1:
- dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_MONO);// MONO->1 for Mono
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+ __dlv_switch_sb_mic1(POWER_OFF);
+ //DUMP_CODEC_REGS("leave dlv_disable_mic_1\n");
+}
+
+#ifdef CONFIG_JZ4760_PT701
+/**
+ * CODEC set device
+ *
+ * NEED TO FIX: do not enable device immediately, just set to g_current_out_dev (for output).
+ *
+ */
+static void dlv_set_device(struct snd_device_config *snd_dev_cfg)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
+
+ dlv_enable_hp_out();
+// __dlv_disable_hp_mute();
+
+ switch (snd_dev_cfg->device) {
+ case SND_DEVICE_HANDSET:
break;
- case 2:
- dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_MONO);// MONO->0 for Stereo
+ case SND_DEVICE_SPEAKER:
+ if (gstate_dock) {
+ printk("pt701 audio select external speaker!");
+ /* external speaker attached */
+ /* disable internal speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_clear_pin(GPIO_SPK_EN);
+ /* enable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_set_pin(GPIO_DOCK_SPK_EN);
+ } else {
+ printk("pt701 audio select internal speaker!");
+ /* external speaker not attached */
+ /* enable internal speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_set_pin(GPIO_SPK_EN);
+ /* disable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_clear_pin(GPIO_DOCK_SPK_EN);
+ }
+ __dlv_set_godr(0x00);
break;
- }
- return ch;
+ case SND_DEVICE_HEADSET:
+ __dlv_set_godr(0x93);
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ printk("pt701 audio select headphone!");
+ /* disable speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_clear_pin(GPIO_SPK_EN);
+ /* disable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_clear_pin(GPIO_DOCK_SPK_EN);
+ __dlv_set_godr(0x8f);
+ break;
+ case SND_DEVICE_BT:
+ break;
+ default:
+ printk("JZ DLV: Unkown ioctl argument in SND_SET_DEVICE\n");
+ };
+
+ g_current_out_dev = snd_dev_cfg->device;
}
+#else
+/**
+ * CODEC set device
+ *
+ * NEED TO FIX: do not enable device immediately, just set to g_current_out_dev (for output).
+ *
+ */
+#if 0
+static void dlv_set_device(struct snd_device_config *snd_dev_cfg)
+{
+ printk("[-- dlv route --] %s\n", __FUNCTION__);
-static int dlv_set_data_width(unsigned int mode, unsigned int width)
+ switch (snd_dev_cfg->device) {
+ case SND_DEVICE_HANDSET:
+ dlv_enable_receiver();
+ break;
+ case SND_DEVICE_HEADSET:
+
+ break;
+ case SND_DEVICE_SPEAKER:
+ dlv_enable_speaker();
+ break;
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ dlv_enable_speaker();
+ break;
+ case SND_DEVICE_BT:
+ break;
+ default:
+ printk("JZ DLV: Unkown ioctl argument in SND_SET_DEVICE\n");
+ };
+
+ g_current_out_dev = snd_dev_cfg->device;
+}
+#endif
+#endif
+
+static void dlv_set_standby(unsigned int sw)
{
- unsigned char cr2 = dlv_read_reg(DLV_REG_AICR);
- unsigned char savecr2 = cr2;
- int supported_width[4] = {16, 18, 20, 24};
- int i;
+ switch(g_current_out_dev) {
+ case SND_DEVICE_HANDSET:
- for (i = 0; i < (sizeof(supported_width) / sizeof(supported_width[0])); i++) {
- if (supported_width[i] <= width) {
- break;
+ if (sw == POWER_ON) {
+ //printk("%s:%d enable receiver\n", __FUNCTION__, __LINE__);
+ dlv_enable_receiver();
+ } else {
+ //printk("%s:%d disable btl\n", __FUNCTION__, __LINE__);
+ //dlv_disable_btl();
+ dlv_disable_receiver();
}
- }
- if (i == (sizeof(supported_width) / sizeof(supported_width[0]))) {
- // For 8 bit width mode, handle it as 16 bit
- if (width == 8) {
- i = 0;
+
+ case (SND_DEVICE_SPEAKER + SND_DEVICE_HEADSET):
+ case SND_DEVICE_HEADSET:
+
+ if (sw == POWER_ON) {
+ //printk("%s:%d enable hp out\n", __FUNCTION__, __LINE__);
+ dlv_enable_hp_out();
} else {
- return -1;
+ //printk("%s:%d disable btl\n", __FUNCTION__, __LINE__);
+ dlv_disable_btl();
}
- }
- //printk("mode = %d, width = %d, selected %d\n", mode, width, i);
+ case SND_DEVICE_SPEAKER:
- switch (mode) {
- case RECORD:
- cr2 &= ~(3 << 4);
- cr2 |= (i << 4);
- break;
- case REPLAY:
- cr2 &= ~(3 << 6);
- cr2 |= (i << 6);
- break;
- }
+ if (sw == POWER_ON) {
+ //printk("%s:%d enable speaker\n", __FUNCTION__, __LINE__);
- if (cr2 != savecr2) {
- dlv_write_reg(DLV_REG_AICR, cr2);
- }
+ /* 2010-06-28 Jason.
+ * To avoid noisy, do not open speaker after set device.
+ * The operation of openning speaker is at the beginning of write
+ */
- printk("set cr2 = %x, %x\n", cr2, savecr2);
+ //dlv_enable_speaker();
+ dlv_disable_btl();
+ } else {
+ //printk("%s:%d disable btl\n", __FUNCTION__, __LINE__);
+ dlv_disable_btl();
+ }
+ break;
+
+ default:
+ printk("JZ DLV: Unkown ioctl argument in SND_SET_STANDBY (%d)\n", g_current_out_dev);
- if (width == 8) {
- return 8;
- } else {
- return supported_width[i];
}
}
-static int dlv_mute(int val)
+static void dlv_debug(int arg)
{
- return dlv_write_reg_bit(DLV_REG_CR2, val ? 1 : 0, CR2_DAC_MUTE);
+ switch(arg) {
+ case 1:
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ printk("JZ DLV: Unknown debug number\n");
+ break;
+ };
}
-void dump_dlv_regs(const char * str)
+static void dlv_suspend(void)
{
- unsigned int i;
- unsigned char data;
- printk("codec register dump, %s:\n", str);
- for (i = 0; i < 32; i++) {
- data = dlv_read_reg(i);
- printk("address = 0x%02x, data = 0x%02x\n", i, data);
+ DPRINT_CODEC("CODEC suspend ...\n");
+ dlv_shutdown();
+}
+
+static void dlv_resume(void)
+{
+#ifdef CONFIG_JZ4760_PT701
+ /* if headphone out */
+ if (!gstate_hp) {
+ /* disable speaker output */
+ __gpio_as_output(GPIO_SPK_EN);
+ __gpio_clear_pin(GPIO_SPK_EN);
+ /* disable external speaker output */
+ __gpio_as_output(GPIO_DOCK_SPK_EN);
+ __gpio_clear_pin(GPIO_DOCK_SPK_EN);
}
+#endif
+
+ DPRINT_CODEC("CODEC resume ...\n");
+ dlv_enable_hp_without_pop();
}
+/**
+ * CODEC ioctl (simulated) routine
+ *
+ * Provide control interface for i2s driver
+ */
static int jzdlv_ioctl(void *context, unsigned int cmd, unsigned long arg)
{
+ int ret = 0;
ENTER();
DUMP_CODEC_REGS(__FUNCTION__);
DPRINT_CODEC("[dlv IOCTL]++++++++++++++++++++++++++++\n");
@@ -759,37 +1579,108 @@ static int jzdlv_ioctl(void *context, unsigned int cmd, unsigned long arg)
DPRINT_DLV_IOC_CMD(cmd);
DPRINT_CODEC("[dlv IOCTL]----------------------------\n");
+ should_up = 1;
+ DLV_LOCK();
switch (cmd) {
+ case CODEC_FIRST_OUTPUT:
+// dlv_set_replay_volume(greplay_volume);
+ __dlv_disable_dac_mute();
+ __dlv_disable_hp_mute();
+ break;
+
+ case CODEC_INIT:
+ dlv_init();
+ break;
+
case CODEC_SET_MODE:
- dlv_set_mode();
+ /* Add new mode to current mode. */
+ //dlv_set_mode(g_codec_mode | arg);
+ break;
+
+ case CODEC_CLEAR_MODE:
+ /* Remove dest mode from current mode. */
+ //dlv_set_mode(g_codec_mode & (~arg));
+ break;
+
+ case CODEC_SET_STANDBY:
+ dlv_set_standby(arg);
+ break;
+
+#if 0
+ case CODEC_SET_DEVICE:
+ dlv_set_device((struct snd_device_config *)arg);
+ break;
+#endif
+
+ case CODEC_SET_SPEAKER_POWER:
+ if (arg == 1) {
+ dlv_enable_speaker();
+ printk("speaker!!!!\n");
+ } else {
+ dlv_disable_speaker();
+ dlv_enable_hp_out();
+ }
+ break;
+
+ case CODEC_SET_LINEIN2BTL:
+ dlv_enable_line_in_bypass_btl();
+ break;
+
+ case CODEC_CLEAR_LINEIN2BTL:
+ dlv_disable_line_in_bypass_btl();
+ break;
+
+ case CODEC_SET_LINEIN2HP:
+ dlv_enable_line_in_bypass_hp();
+ break;
+
+ case CODEC_CLEAR_LINEIN2HP:
+ dlv_disable_line_in_bypass_hp();
break;
case CODEC_SET_STARTUP_PARAM:
- dlv_set_startup_param();
break;
case CODEC_SET_REPLAY:
- dlv_set_replay();
+ dlv_enable_receiver();
break;
case CODEC_SET_RECORD:
- dlv_set_record();
+ board_set_record();
+ break;
+
+ case CODEC_SET_REC_2_DAC:
+ if (arg) {
+ printk("JZ DLV: SET REC 2 ADC ---- %d\n", (int)arg);
+ dlv_enable_line_in_record(3);
+ dlv_enable_rec_2_dac();
+ } else {
+ printk("JZ DLV: SET REC 2 ADC ---- %d\n", (int)arg);
+ dlv_disable_line_in_record();
+ dlv_disable_rec_2_dac();
+ dlv_enable_line_in_bypass_btl();
+ }
break;
case CODEC_SET_REPLAY_RECORD:
- dlv_set_replay_recode(arg);
+ //dlv_set_replay_recode(arg);
+ printk("JZ DLV: should not run here -- CODEC_SET_REPLAY_RECORD");
+ BUG_ON(1);
break;
- case CODEC_SET_VOLUME:
- dlv_set_volume(arg);
+ case CODEC_SET_REPLAY_VOLUME:
+// greplay_volume = arg;
+ dlv_set_replay_volume(arg);
break;
- case CODEC_SET_MIC:
- dlv_set_mic(arg);
+ case CODEC_SET_MIC_VOLUME:
+ dlv_set_mic_volume(arg);
break;
case CODEC_SET_LINE:
- dlv_set_line(arg);
+ //dlv_set_line(arg);
+ printk("JZ DLV: should not run here -- CODEC_SET_LINE\n");
+ BUG_ON(1);
break;
case CODEC_EACH_TIME_INIT:
@@ -805,13 +1696,24 @@ static int jzdlv_ioctl(void *context, unsigned int cmd, unsigned long arg)
break;
case CODEC_TURN_REPLAY:
- dlv_turn_replay(arg);
+ //dlv_turn_replay(arg);
+ printk("JZ DLV: should not run here -- CODEC_TURN_REPLAY\n");
+ BUG_ON(1);
break;
case CODEC_TURN_OFF:
dlv_turn_off(arg);
break;
+ case CODEC_I2S_SUSPEND:
+ dlv_suspend();
+ break;
+
+ case CODEC_I2S_RESUME:
+ should_up = 0;
+ dlv_resume();
+ break;
+
case CODEC_GET_MIXER_INFO:
dlv_get_mixer_info((mixer_info *)arg);
break;
@@ -820,190 +1722,469 @@ static int jzdlv_ioctl(void *context, unsigned int cmd, unsigned long arg)
dlv_get_mixer_old_info((mixer_info *)arg);
break;
- case CODEC_SET_REPLAY_SPEED:
- return dlv_set_replay_speed(arg);
+ case CODEC_SET_REPLAY_RATE:
+ ret = dlv_set_replay_rate(arg);
+ break;
- case CODEC_SET_RECORD_SPEED:
- return dlv_set_record_speed(arg);
+ case CODEC_SET_RECORD_RATE:
+ ret = dlv_set_record_rate(arg);
+ break;
case CODEC_SET_RECORD_CHANNEL:
- return arg;
+ ret = arg;
+ break;
case CODEC_SET_REPLAY_CHANNEL:
- return dlv_set_channel(arg);
+ ret = dlv_set_channel(arg);
+ break;
case CODEC_SET_RECORD_DATA_WIDTH:
- return dlv_set_data_width(RECORD, arg);
+ ret = dlv_set_data_width(RECORD, arg);
+ break;
case CODEC_SET_REPLAY_DATA_WIDTH:
- return dlv_set_data_width(REPLAY, arg);
+ ret = dlv_set_data_width(REPLAY, arg);
+ break;
case CODEC_DAC_MUTE:
- return dlv_mute(arg);
+ ret = dlv_mute(arg);
+ break;
+
+ case CODEC_DEBUG_ROUTINE:
+ dlv_debug(arg);
+ break;
default:
- printk("%s:%d no support\n", __FUNCTION__, __LINE__);
- return -1;
+ printk("JZ DLV:%s:%d: Unkown IOC commond\n", __FUNCTION__, __LINE__);
+ ret = -1;
}
+ if (should_up)
+ {
+ DLV_UNLOCK();
+ }
LEAVE();
- return 0;
+ return ret;
+}
+
+/**
+ * CODEC restart routine
+ *
+ */
+static void dlv_restart(void)
+{
+
}
-static struct work_struct dlv_work;
+static struct work_struct dlv_irq_work;
+static spinlock_t dlv_irq_lock;
+//static int i = 0;
+static int handling_scmc = 0;
+
-/*
- * work handler
+/**
+ * CODEC short circut handler
*
- * Mission:
- * Restart CODEC after shut down by short circurt protection
+ * To protect CODEC, CODEC will be shutdown when short circut occured.
+ * Then we have to restart it.
*/
-static void dlv_work_handle(struct work_struct *work)
+static inline void dlv_short_circut_handler(void)
{
+ unsigned short curr_vol;
+ unsigned int dlv_ifr, delay;
- printk("CODEC: short circurt detected!\n");
+#define VOL_DELAY_BASE 22 //per VOL delay time in ms
-// dump_dlv_regs("IRQ ---------");
+ printk("JZ DLV: Short circut detected! restart CODEC hp out finish.\n");
- /* Renable SB OUT */
- switch_SB_OUT(POWER_OFF);
- mdelay(300);
+ curr_vol = dlv_read_reg(0x0C);
+ delay = VOL_DELAY_BASE * (0x20 - curr_vol & 0x1f);
+
+ dlv_write_reg(0x0c, 0x1f);
+ dlv_write_reg(0x0d, 0x1f);
+
+ printk("Short circut volume delay %d ms curr_vol=%x \n", delay,curr_vol);
+ msleep(delay);
- while (!(dlv_read_reg(DLV_REG_IFR) & (1 << IFR_RDO))) {
- ;/* nothing */
+ //clear rdo rup
+ __dlv_set_irq_flag((1 << IFR_RDO) | (1 << IFR_RUP));
+
+ __dlv_switch_sb_hp(POWER_OFF);
+
+ //wait rdo finish
+ dlv_sleep_wait_bitset(0xb, IFR_RDO, 100,__LINE__);
+
+ while (1) {
+ dlv_ifr = __dlv_get_irq_flag();
+ printk("waiting for SCMC recover finish ----- dlv_ifr = 0x%02x\n", dlv_ifr);
+ if ((dlv_ifr & (1 << IFR_SCMC)) == 0)
+ break;
+ __dlv_set_irq_flag((1 << IFR_SCMC));
+ msleep(10);
}
- while (dlv_read_reg(DLV_REG_IFR) & (1 << IFR_SCMC)) {
- dlv_write_reg(DLV_REG_IFR, 1 << IFR_SCMC);
+ __dlv_switch_sb_hp(POWER_ON);
+ // wait rup finish
+ dlv_sleep_wait_bitset(0xb, IFR_RUP, 100,__LINE__);
+ dlv_write_reg(0x0c, curr_vol);
+ dlv_write_reg(0x0d, curr_vol);
+ msleep(delay);
+ // do not clear RDO and RUP
+ //__dlv_set_irq_flag((1 << IFR_RDO) | (1 << IFR_RUP));
+}
+#ifdef HP_SENSE_DETECT
+static void dlv_jack_handler(int new_switch_status)
+{
+ //just set the state is enough,
+ if (g_switch_data) {
+ switch_set_state(&g_switch_data->sdev, new_switch_status);
+ }
+}
+#endif
+
+#ifdef HP_SENSE_DETECT
+
+/**
+ * CODEC work queue handler
+ *
+ * Handle bottom-half of SCMC & JACKE irq
+ *
+ */
+static void dlv_irq_work_handler(struct work_struct *work)
+{
+ unsigned int dlv_ifr;
+ unsigned long flags;
+
+ int old_status;
+ int new_status;
+ int i;
+ int j;
+ DLV_LOCK();
+ do {
+ dlv_ifr = __dlv_get_irq_flag();
+
+ if (dlv_ifr & (1 << IFR_SCMC)) {
+ dlv_short_circut_handler();
+ }
+
+ dlv_ifr = __dlv_get_irq_flag();
+#if 1
+ /* Updata SCMC */
+ __dlv_set_irq_flag((1 << IFR_SCMC));
+// gf_short_circuit_flow_run = 0;
+ /* Unmask SCMC */
+ __dlv_set_irq_mask(ICR_COMMON_MASK);
+#endif
+ printk("JZ DLV: Short circut detected! dlv_ifr = 0x%02x\n", dlv_ifr);
+
+ } while(dlv_ifr & (1 << IFR_SCMC));
+
+ handling_scmc = 0;
+
+ if (dlv_ifr & (1 << IFR_JACKE)) {
+_ensure_stable:
+ j = 0;
+ old_status = (__dlv_get_irq_flag() & (1 << IFR_JACK)) != 0;
+ /* Read status at least 3 times to make sure it is stable. */
+ for (i = 0; i < 3; ++i) {
+ new_status = (__dlv_get_irq_flag() & (1 << IFR_JACK)) != 0;
+
+ if (old_status != new_status) {
+ j += i + 1;
+ }
+ old_status = new_status;
+ msleep(50);
+ }
}
- switch_SB_OUT(POWER_ON);
- mdelay(300);
- while (!(dlv_read_reg(DLV_REG_IFR) & (1 << IFR_RUP))) {
- ;/* nothing */
+ spin_lock_irqsave(dlv_irq_lock, flags);
+
+ /* Clear current irq flag */
+ __dlv_set_irq_flag(dlv_ifr);
+
+ /* Unmask SCMC & JACK (ifdef HP_SENSE_DETECT) */
+ __dlv_set_irq_mask(ICR_COMMON_MASK);
+
+ spin_unlock_irqrestore(dlv_irq_lock, flags);
+
+ /* If the jack status has changed, we have to redo the process. */
+ if (dlv_ifr & (1 << IFR_JACKE)) {
+ msleep(50);
+ new_status = (__dlv_get_irq_flag() & (1 << IFR_JACK)) != 0;
+ if (new_status != old_status) {
+ goto _ensure_stable;
+ }
}
- /* Enable SCMC and JACK EVENT interrupt ... */
- dlv_write_reg(DLV_REG_ICR, 0x0f);
+ /* Report status */
+ dlv_jack_handler(new_status);
+ DLV_UNLOCK();
}
-static spinlock_t dlv_irq_lock;
-
+/**
+ * IRQ routine
+ *
+ * Now we are only interested in SCMC and JACKE.
+ */
static irqreturn_t dlv_codec_irq(int irq, void *dev_id)
{
-// unsigned char dlv_icr;
+ unsigned char dlv_icr;
unsigned char dlv_ifr;
- spin_lock(dlv_irq_lock);
+ unsigned int aic_reg;
+ unsigned long flags;
- /* Clear interrupt flag */
- dlv_ifr = dlv_read_reg(DLV_REG_IFR);
- dlv_write_reg(DLV_REG_IFR, dlv_ifr);
+ spin_lock_irqsave(dlv_irq_lock, flags);
- /* Mask SCMC and JACK EVENT temporarily */
- dlv_write_reg(DLV_REG_ICR, 0x3f);
+ dlv_ifr = __dlv_get_irq_flag();
+ dlv_icr = __dlv_get_irq_mask();
- REG_AIC_SR = 0x78; //???
+ /* Mask all irq temporarily */
+ __dlv_set_irq_mask(ICR_ALL_MASK);
+
+ aic_reg = REG_AIC_SR;
+
+ REG_AIC_SR = 0x78; // legacy ... need check
+
+ if (!(dlv_ifr & ((1 << IFR_SCMC) | (1 << IFR_JACKE)))) {
+ /* CODEC may generate irq with flag = 0xc0.
+ * We have to ingore it in this case as there is no mask for the reserve bit.
+ */
+ //printk("JZ DLV: Unkown irq detected, mask = 0x%08x, flag = 0x%08x\n", dlv_icr, dlv_ifr);
+
+ printk("AIC interrupt ??? AIC_SR = 0x%08x\n", aic_reg);
+
+ /* Unmask SCMC & JACK (ifdef HP_SENSE_DETECT) */
+// __dlv_set_irq_mask(ICR_COMMON_MASK);
+
+ spin_unlock_irqrestore(dlv_irq_lock, flags);
+ return IRQ_HANDLED;
- /*
- * Start handler when output short circuit has been detected
- */
- if (dlv_ifr & (1 << IFR_SCMC)) {
- schedule_work(&dlv_work);
} else {
- printk("Jack event ???\n");
-// dump_dlv_regs("irq -- maybe jack event");
+
+ spin_unlock_irqrestore(dlv_irq_lock, flags);
+
+ if (handling_scmc == 0) {
+ handling_scmc = 1;
+ /* Handle SCMC in work queue. */
+ schedule_work(&dlv_irq_work);
+ }
+
+ return IRQ_HANDLED;
}
+}
+
+#else
+
+/**
+ * CODEC work queue handler
+ *
+ * Handle bottom-half of SCMC & JACKE irq
+ *
+ */
+static void dlv_irq_work_handler(struct work_struct *work)
+{
+ unsigned int dlv_ifr;
+ unsigned long flags;
+ DLV_LOCK();
+ do {
+ dlv_ifr = __dlv_get_irq_flag();
+
+ if (dlv_ifr & (1 << IFR_SCMC)) {
+ dlv_short_circut_handler();
+ }
+
+ dlv_ifr = __dlv_get_irq_flag();
+#if 1
+ /* Updata SCMC */
+ __dlv_set_irq_flag((1 << IFR_SCMC));
+// gf_short_circuit_flow_run = 0;
+ /* Unmask SCMC */
+ __dlv_set_irq_mask(ICR_COMMON_MASK);
+#endif
+ printk("JZ DLV: Short circut detected! dlv_ifr = 0x%02x\n",dlv_ifr);
+
+ } while(dlv_ifr & (1 << IFR_SCMC));
+
+ handling_scmc = 0;
+ DLV_UNLOCK();
+}
+
+/**
+ * IRQ routine
+ *
+ * Now we are only interested in SCMC.
+ */
+static irqreturn_t dlv_codec_irq(int irq, void *dev_id)
+{
+ unsigned char dlv_icr;
+ unsigned char dlv_ifr;
+
+ unsigned int aic_reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(dlv_irq_lock, flags);
-#if HP_SENSE_DETECT
- /* Jack event detected */
- if (dlv_ifr & (1 << IFR_JACK_EVENT)) {
+ dlv_ifr = __dlv_get_irq_flag();
+ dlv_icr = __dlv_get_irq_mask();
- printk("Jack event ! dlv_ifr = 0x%08x\n", dlv_ifr);
+ /* Mask all irq temporarily */
+ __dlv_set_irq_mask(ICR_ALL_MASK);
- /* IFR_JACK indicate the status of jack:
- * 1. The jack is pluged: plug event
- * 2. The jack is not pluged: unplug event
+ aic_reg = REG_AIC_SR;
+
+ REG_AIC_SR = 0x78; // legacy ... need check
+
+ if (!(dlv_ifr & ((1 << IFR_SCMC) | (1 << IFR_JACKE)))) {
+ /* CODEC may generate irq with flag = 0xc0.
+ * We have to ingore it in this case as there is no mask for the reserve bit.
*/
- switch_set_state(&data->sdev, dlv_ifr & (1 << IFR_JACK));
+ //printk("JZ DLV: Unkown irq detected, mask = 0x%08x, flag = 0x%08x\n", dlv_icr, dlv_ifr);
+
+ printk("AIC interrupt ??? AIC_SR = 0x%08x\n", aic_reg);
+
+ /* Unmask SCMC & JACK (ifdef HP_SENSE_DETECT) */
+ __dlv_set_irq_mask(ICR_COMMON_MASK);
+
+ spin_unlock_irqrestore(dlv_irq_lock, flags);
+ return IRQ_HANDLED;
+
+ } else {
+ spin_unlock_irqrestore(dlv_irq_lock, flags);
+
+ /* Handle SCMC and JACK in work queue. */
+ schedule_work(&dlv_irq_work);
+
+ return IRQ_HANDLED;
}
-#endif
- spin_unlock(dlv_irq_lock);
- return IRQ_HANDLED;
}
-#if HP_SENSE_DETECT
+#endif // ifdef HP_SENSE_DETECT
+
+
+#ifdef HP_SENSE_DETECT
+
/*
- * HP_SENSE switch
+ * Headphone sense switch registration & initialization
*/
-#define gpio_to_irq(gpio) (IRQ_GPIO_0 + (gpio))
+static ssize_t jz_hp_switch_print_state(struct switch_dev *sdev, char *buf)
+{
+ jz_hp_switch_data_t *switch_data =
+ container_of(sdev, jz_hp_switch_data_t, sdev);
+ const char *state;
-struct hp_switch_data {
- struct switch_dev sdev;
- unsigned int gpio;
- const char *name_on;
- const char *name_off;
- const char *state_on;
- const char *state_off;
-};
+ if (switch_get_state(sdev))
+ state = switch_data->state_on;
+ else
+ state = switch_data->state_off;
+
+ if (state)
+ return sprintf(buf, "%s\n", state);
+ return -1;
+}
-static int __devexit hp_switch_remove(struct platform_device *pdev)
+static int jz_hp_switch_probe(struct platform_device *pdev)
{
- struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
+ jz_hp_switch_data_t *switch_data;
+ jz_hp_switch_platform_data_t *pdata = pdev->dev.platform_data;
+ int ret = 0;
+
+ switch_data = kzalloc(sizeof(jz_hp_switch_data_t), GFP_KERNEL);
+ if (!switch_data) {
+ printk("JZ HP Switch kzalloc failed (%s:%d)\n", __FUNCTION__, __LINE__);
+ return -ENOMEM;
+ }
+ g_switch_data = switch_data;
+
+ switch_data->sdev.name = pdata->name;
+ switch_data->name_on = pdata->name_on;
+ switch_data->name_off = pdata->name_off;
+ switch_data->state_on = pdata->state_on;
+ switch_data->state_off = pdata->state_off;
+ switch_data->sdev.print_state = jz_hp_switch_print_state;
+
+ if ((ret = switch_dev_register(&switch_data->sdev))) {
+ printk("JZ HP Switch: Could net register switch device\n");
+ return ret;
+ }
+
+ ret = __dlv_get_irq_flag();
+
+ switch_set_state(&switch_data->sdev, dlv_read_reg(DLV_REG_IFR) & (1 << IFR_JACK));
+
+ return 0;
+}
- switch_dev_unregister(&switch_data->sdev);
- kfree(switch_data);
+static int __devexit jz_hp_switch_remove(struct platform_device *pdev)
+{
+ switch_dev_unregister(&g_switch_data->sdev);
+ kfree(g_switch_data);
return 0;
}
-static struct platform_driver hp_switch_driver = {
- .probe = hp_switch_probe,
- .remove = __devexit_p(hp_switch_remove),
+static struct platform_driver jz_hp_switch_driver = {
+ .probe = jz_hp_switch_probe,
+ .remove = __devexit_p(jz_hp_switch_remove),
.driver = {
- .name = "switch-gpio",
+ .name = "hp-switch",
.owner = THIS_MODULE,
},
};
-/* HP_SENSE switch end */
-#endif
+#endif // ifdef HP_SENSE_DETECT
+/**
+ * Module init
+ */
static int __init init_dlv(void)
{
int retval;
+
cpm_start_clock(CGM_AIC);
spin_lock_init(&dlv_irq_lock);
- INIT_WORK(&dlv_work, dlv_work_handle);
- register_jz_codecs((void *)jzdlv_ioctl);
-#if HP_SENSE_DETECT
- retval = platform_driver_register(&hp_switch_driver);
- if (retval) {
- printk("Could net register headphone sense switch\n");
- return retval;
- }
+ spin_lock_init(&g_dlv_sem_lock);
+
+ INIT_WORK(&dlv_irq_work, dlv_irq_work_handler);
+
+#ifdef ANTI_POP_WORK_STRUCT
+ INIT_WORK(&dlv_anti_pop_work, dlv_anti_pop_work_handler);
#endif
- dlv_reset();
+ register_jz_codecs((void *)jzdlv_ioctl);
+ dlv_reset();
retval = request_irq(IRQ_AIC, dlv_codec_irq, IRQF_DISABLED, "dlv_codec_irq", NULL);
if (retval) {
- printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ printk("JZ DLV: Could not get AIC CODEC irq %d\n", IRQ_AIC);
return retval;
}
+#ifdef HP_SENSE_DETECT
+ retval = platform_driver_register(&jz_hp_switch_driver);
+ if (retval) {
+ printk("JZ HP Switch: Could net register headphone sense switch\n");
+ return retval;
+ }
+#endif
return 0;
}
+/**
+ * Module exit
+ */
static void __exit cleanup_dlv(void)
{
+
free_irq(IRQ_AIC, NULL);
-#if HP_SENSE_DETECT
- platform_driver_unregister(&hp_switch_driver);
+#ifdef HP_SENSE_DETECT
+ platform_driver_unregister(&jz_hp_switch_driver);
#endif
}
module_init(init_dlv);
module_exit(cleanup_dlv);
+
+
diff --git a/sound/oss/jz4760_dlv.h b/sound/oss/jz4760_dlv.h
index 99d0f0017de..eb0ea0df9ad 100644
--- a/sound/oss/jz4760_dlv.h
+++ b/sound/oss/jz4760_dlv.h
@@ -7,9 +7,48 @@
#ifndef __JZ4760_DLV_H__
#define __JZ4760_DLV_H__
-#define MAX_RATE_COUNT 10
+/* Enable headphone detection */
+//#define HP_SENSE_DETECT 1
+
+/* Power setting */
+#define POWER_ON 0
+#define POWER_OFF 1
+
+/* Have not been used. */
+#if 0
+
+/* CODEC mode
+ *
+ * unsigned int: I--- RL21 O--- -LSH
+ */
+#define CODEC_REPLAY 0x00008000
+ #define REPLAY_HP_OUT 1 << 0
+ #define REPLAY_SPEAKER 1 << 1
+ #define REPLAY_LINE_OUT 1 << 2
+
+#define CODEC_RECORD 0x80000000
+ #define RECORD_MIC1_IN 1 << 8
+ #define RECORD_MIC2_IN 1 << 9
+ #define RECORD_LINE_IN_L 1 << 10
+ #define RECORD_LINE_IN_R 1 << 11
+
+#endif
+
+/* File ops mode W & R */
+#define REPLAY 1
+#define RECORD 2
+
+/* Channels */
+#define LEFT_CHANNEL 1
+#define RIGHT_CHANNEL 2
+
+#define MAX_RATE_COUNT 10
+
+
+/*
+ * JZ4760 DLV CODEC registers
+ */
-/* JZ4760 DLV CODEC registers number */
#define DLV_REG_SR 0
#define DLV_REG_AICR 1
@@ -40,8 +79,12 @@
#define CR3_MICDIFF 0
#define DLV_REG_CR4 5
+ #define CR4_ADC_HPF 7
+ #define CR4_ADC_RIGHT_ONLY 0
#define DLV_REG_CCR1 6
+ #define CCR1_CRYSTAL_BIT 0
+ #define CCR1_CRYSTAL_MASK 0xf
#define DLV_REG_CCR2 7
@@ -63,16 +106,26 @@
#define PMR2_SB_DAC 0
#define DLV_REG_ICR 10
- #define ICR_JACK_MASK 5
- #define ICR_SCMC_MASK 4
- #define ICR_RUP_MASK 3
- #define ICR_RDO_MASK 2
- #define ICR_GUP_MASK 1
- #define ICR_GDO_MASK 0
+ #define ICR_INT_FORM_MASK 0xc0
+ #define ICR_INT_FORM_BIT 6
+ #define ICR_INT_HIGH 0x00
+ #define ICR_INT_LOW 0x01
+ #define ICR_INT_HIGH_8CYCLES 0x10
+ #define ICR_JACK_MASK (1 << 5)
+ #define ICR_SCMC_MASK (1 << 4)
+ #define ICR_RUP_MASK (1 << 3)
+ #define ICR_RDO_MASK (1 << 2)
+ #define ICR_GUP_MASK (1 << 1)
+ #define ICR_GDO_MASK (1 << 0)
+ #define ICR_ALL_MASK \
+ (ICR_GDO_MASK | ICR_GUP_MASK | ICR_RDO_MASK | ICR_RUP_MASK | ICR_SCMC_MASK | ICR_JACK_MASK)
+
+//#define ICR_COMMON_MASK (ICR_GDO_MASK | ICR_GUP_MASK | ICR_RDO_MASK | ICR_RUP_MASK)
+ #define ICR_COMMON_MASK (ICR_GDO_MASK | ICR_GUP_MASK | ICR_RDO_MASK | ICR_RUP_MASK | ICR_JACK_MASK)
#define DLV_REG_IFR 11
#define IFR_JACK 6
- #define IFR_JACK_EVENT 5
+ #define IFR_JACKE 5
#define IFR_SCMC 4
#define IFR_RUP 3
#define IFR_RDO 2
@@ -82,13 +135,25 @@
#define DLV_REG_GCR1 12
#define DLV_REG_GCR2 13
#define DLV_REG_GCR3 14
+ #define GCR3_RLGI 7
+ #define GCR3_GIR_BIT 0
+ #define GCR3_GIR_MASK 0x1f
+
#define DLV_REG_GCR4 15
+ #define GCR4_GIL_BIT 0
+ #define GCR3_GIR_MASK 0x1f
+
#define DLV_REG_GCR5 16
#define DLV_REG_GCR6 17
#define DLV_REG_GCR7 18
#define DLV_REG_GCR8 19
+ #define GCR8_GIDR_MASK 0x1f
+ #define GCR8_GIDR_BIT 0
+
#define DLV_REG_GCR9 20
+ #define GCR9_GIDL_MASK 0x1f
+ #define GCR9_GIDL_BIT 0
#define DLV_REG_AGC1 21
#define AGC1_AGCEN 7
@@ -98,29 +163,500 @@
#define DLV_REG_AGC4 24
#define DLV_REG_AGC5 25
#define DLV_REG_MIX1 26
+ #define MIX1_REC_BIT 6
+ #define MIX1_REC_MASK 0x3
+ #define MIX1_GIMIX_BIT 0
+ #define MIX1_GIMIX_MASK 0x1f
+
#define DLV_REG_MIX2 27
+//#define HP_SENSE_DETECT
+
+/*
+ * Ops
+ */
+
+/* SB switch */
+
+#define __dlv_get_sb_aip() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_AIP)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_aip(pwrstat) \
+do { \
+ if (__dlv_get_sb_aip() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_AIP); \
+ } \
+ \
+} while (0)
+
+
+#define __dlv_get_sb() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb(pwrstat) \
+do { \
+ if (__dlv_get_sb() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_sleep() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_SLEEP)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_sleep(pwrstat) \
+do { \
+ if (__dlv_get_sb_sleep() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_SLEEP);\
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_dac() ((dlv_read_reg(DLV_REG_PMR2) & (1 << PMR2_SB_DAC)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_dac(pwrstat) \
+do { \
+ if (__dlv_get_sb_dac() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_DAC); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_line_out() ((dlv_read_reg(DLV_REG_PMR2) & (1 << PMR2_SB_LOUT)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_line_out(pwrstat) \
+do { \
+ if (__dlv_get_sb_line_out() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_LOUT); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_hp() ((dlv_read_reg(DLV_REG_PMR2) & (1 << PMR2_SB_HP)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_hp(pwrstat) \
+do { \
+ if (__dlv_get_sb_hp() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_HP); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_btl() ((dlv_read_reg(DLV_REG_PMR2) & (1 << PMR2_SB_BTL)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_btl(pwrstat) \
+do { \
+ if (__dlv_get_sb_btl() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_BTL); \
+ } \
+ \
+} while (0)
+
+#define __dlv_switch_sb_out(pwrstat) \
+do { \
+ /*__dlv_switch_sb_btl(pwrstat);*/ \
+ __dlv_switch_sb_hp(pwrstat); \
+ /*__dlv_switch_sb_line_out(pwrstat);*/ \
+} while (0)
+
+#define __dlv_get_sb_adc() ((dlv_read_reg(DLV_REG_PMR2) & (1 << PMR2_SB_ADC)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_adc(pwrstat) \
+do { \
+ if (__dlv_get_sb_adc() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR2, pwrstat, PMR2_SB_ADC); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_mic1() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_MIC1)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_mic1(pwrstat) \
+do { \
+ if (__dlv_get_sb_mic1() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MIC1); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_mic2() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_MIC2)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_mic2(pwrstat) \
+do { \
+ if (__dlv_get_sb_mic2() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MIC2); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_micbias() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_MICBIAS)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_micbias(pwrstat) \
+do { \
+ if (__dlv_get_sb_micbias() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_MICBIAS);\
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_line_in() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_LINE)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_line_in(pwrstat) \
+do { \
+ if (__dlv_get_sb_line_in() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_LINE); \
+ } \
+ \
+} while (0)
+
+#define __dlv_get_sb_bypass() ((dlv_read_reg(DLV_REG_PMR1) & (1 << PMR1_SB_BYPASS)) ? POWER_OFF : POWER_ON)
+
+#define __dlv_switch_sb_bypass(pwrstat) \
+do { \
+ if (__dlv_get_sb_bypass() != pwrstat) { \
+ dlv_write_reg_bit(DLV_REG_PMR1, pwrstat, PMR1_SB_BYPASS);\
+ } \
+ \
+} while (0)
+
+#define __dlv_set_int_form(v) \
+do { \
+ dlv_write_reg_bit(DLV_REG_ICR, ((v) >> 1) & 1, 7); \
+ dlv_write_reg_bit(DLV_REG_ICR, (v) & 1, 6); \
+} while (0)
+
+#define __dlv_set_irq_mask(mask) \
+do { \
+ /*unsigned int int_form = dlv_read_reg(DLV_REG_ICR) & 0xc0;*/ \
+ /*dlv_write_reg(DLV_REG_ICR, ((mask) & 0x3f) | int_form);*/ \
+ dlv_write_reg(DLV_REG_ICR, mask); \
+ \
+} while (0)
+
+#define __dlv_set_irq_flag(flag) \
+do { \
+ dlv_write_reg(DLV_REG_IFR, flag); \
+ \
+} while (0)
+
+#define __dlv_get_irq_flag() (dlv_read_reg(DLV_REG_IFR))
+#define __dlv_get_irq_mask() (dlv_read_reg(DLV_REG_ICR) & 0x3f)
+
+#define __dlv_set_16ohm_load() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_LOAD); \
+ \
+} while (0)
+
+#define __dlv_set_10kohm_load() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_LOAD); \
+ \
+} while (0)
+
+#define __dlv_enable_hp_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_HP_MUTE); \
+ \
+} while (0)
+
+#define __dlv_disable_hp_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_HP_MUTE); \
+ \
+} while (0)
+
+#define __dlv_enable_lineout_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_LINEOUT_MUTE); \
+ \
+} while (0)
+
+#define __dlv_disable_lineout_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_LINEOUT_MUTE); \
+ \
+} while (0)
+
+#define __dlv_enable_btl_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 1, CR1_BTL_MUTE); \
+ \
+} while (0)
+
+#define __dlv_disable_btl_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, 0, CR1_BTL_MUTE); \
+ \
+} while (0)
+
+#define MIC1_TO_LR 0 //00b
+#define MIC2_TO_LR 1 //01b
+#define MIC1_TO_R_MIC2_TO_L 0 //00b
+#define MIC2_TO_R_MIC1_TO_L 1 //01b
+#define BYPASS_PATH 2 //10b
+#define DAC_OUTPUT 3 //11b
+
+#define __dlv_set_outsel(opt) \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR1, (opt) & 0x1, CR1_OUTSEL0); \
+ dlv_write_reg_bit(DLV_REG_CR1, (opt >> 1) & 0x1, CR1_OUTSEL1); \
+} while (0)
+
+#define __dlv_enable_dac_m2s() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_MONO); \
+ \
+} while (0)
+
+#define __dlv_disable_dac_m2s() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_MONO); \
+ \
+} while (0)
+
+#define __dlv_get_dac_mute() ((dlv_read_reg(DLV_REG_CR2) & (1 << CR2_DAC_MUTE)) ? 1 : 0)
+
+#define __dlv_enable_dac_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_DAC_MUTE); \
+ \
+} while (0)
+
+#define __dlv_disable_dac_mute() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_DAC_MUTE); \
+ \
+} while (0)
+
+#define __dlv_enable_nomad() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_NOMAD); \
+ \
+} while (0)
+
+#define __dlv_disable_nomad() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_NOMAD); \
+ \
+} while (0)
+
+
+#define __dlv_enable_dac_right_only() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 1, CR2_DAC_RIGHT_ONLY); \
+ \
+} while (0)
+
+#define __dlv_disable_dac_right_only() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR2, 0, CR2_DAC_RIGHT_ONLY); \
+ \
+} while (0)
+
+/* Following macros are the arguments for __dlv_set_insel.
+ * And they have already defined.
+ *
+#define MIC1_TO_LR 0 //00b
+#define MIC2_TO_LR 1 //01b
+#define MIC1_TO_R_MIC2_TO_L 0 //00b
+#define MIC2_TO_R_MIC1_TO_L 1 //01b
+ *
+ */
+#define LINE_INPUT 2 //10b
+
+#define __dlv_set_insel(opt) \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR3, (opt) & 1, CR3_INSEL0); \
+ dlv_write_reg_bit(DLV_REG_CR3, (opt >> 1) & 1, CR3_INSEL1); \
+} while (0)
+
+#define __dlv_set_mic_stereo() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR3, 1, CR3_MICSTEREO); \
+ \
+} while (0)
+
+#define __dlv_set_mic_mono() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR3, 0, CR3_MICSTEREO); \
+ \
+} while (0)
+
+#define __dlv_enable_mic_diff() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR3, 1, CR3_MICDIFF); \
+ \
+} while (0)
+
+#define __dlv_disable_mic_diff() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR3, 0, CR3_MICDIFF); \
+ \
+} while (0)
+
+#define __dlv_enable_adc_high_pass() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR4, 1, CR4_ADC_HPF); \
+ \
+} while (0)
+
+#define __dlv_disable_adc_high_pass() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR4, 0, CR4_ADC_HPF); \
+ \
+} while (0)
+
+#define __dlv_enable_adc_right_only() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR4, 1, CR4_ADC_RIGHT_ONLY); \
+ \
+} while (0)
+
+#define __dlv_disable_adc_right_only() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CR4, 0, CR4_ADC_RIGHT_ONLY); \
+ \
+} while (0)
+
+#define __dlv_set_hp_volume(vol) \
+do { \
+ dlv_write_reg(DLV_REG_GCR1, vol |= 0x80); \
+ \
+} while (0)
+
+#define __dlv_set_line_in_bypass_volume(vol) \
+do { \
+ vol = (vol & GCR3_GIR_MASK) | (1 << GCR3_RLGI); \
+ dlv_write_reg(DLV_REG_GCR3, vol); \
+ \
+} while (0)
+
+#define __dlv_set_line_in_bypass_volume_rl(lvol, rvol) \
+do { \
+ rvol = rvol & GCR3_GIR_MASK; \
+ dlv_write_reg(DLV_REG_GCR3, rvol); \
+ dlv_write_reg(DLV_REG_GCR4, lvol); \
+ \
+} while (0)
+
+#define __dlv_set_mic_1_volume(vol) \
+do { \
+ dlv_write_reg(DLV_REG_GCR8, vol | 0x80); \
+ \
+} while (0)
+
+#define __dlv_set_gim(value) \
+do { \
+ dlv_write_reg(DLV_REG_GCR7, (value)); \
+ \
+} while (0)
+
+#define __dlv_set_gidr(value) \
+do { \
+ unsigned int r = dlv_read_reg(DLV_REG_GCR8); \
+ r = (r & ~GCR8_GIDR_MASK) | ((value) << GCR8_GIDR_BIT); \
+ dlv_write_reg(DLV_REG_GCR8, r << GCR8_GIDR_BIT); \
+ \
+} while (0)
+
+#define __dlv_set_gidl(value) \
+do { \
+ unsigned int r = dlv_read_reg(DLV_REG_GCR9); \
+ r = (r & ~GCR9_GIDL_MASK) | ((value) << GCR9_GIDL_BIT); \
+ dlv_write_reg(DLV_REG_GCR9, r << GCR9_GIDL_BIT); \
+ \
+} while (0)
+
+#define __dlv_set_godr(value) \
+do { \
+ dlv_write_reg(DLV_REG_GCR5, value); \
+ \
+} while (0)
+
+#define __dlv_set_godl(value) \
+do { \
+ dlv_write_reg(DLV_REG_GCR6, value); \
+ \
+} while (0)
+
+#define __dlv_enable_agc() \
+do { \
+ dlv_write_reg_bit(DLV_REG_AGC1, 1, AGC1_AGCEN); \
+ \
+} while (0)
+
+#define __dlv_disable_agc() \
+do { \
+ dlv_write_reg_bit(DLV_REG_AGC1, 0, AGC1_AGCEN); \
+ \
+} while (0)
+
+#define __dlv_set_12m_crystal() \
+do { \
+ dlv_write_reg_bit(DLV_REG_CCR1, 0, 1); \
+ dlv_write_reg_bit(DLV_REG_CCR1, 0, 0); \
+ \
+} while (0)
+
+#define __dlv_set_mix_rec_2_dac() \
+do { \
+ dlv_write_reg_bit(DLV_REG_MIX1, 1, 6); \
+ dlv_write_reg_bit(DLV_REG_CCR1, 0, 7); \
+ \
+} while (0)
+
+#define __dlv_set_mix_rec_only() \
+do { \
+ dlv_write_reg_bit(DLV_REG_MIX1, 0, 6); \
+ dlv_write_reg_bit(DLV_REG_CCR1, 0, 7); \
+ \
+} while (0)
+
+#define __dlv_reset_rup() \
+do { \
+ dlv_write_reg_bit(DLV_REG_IFR, 1, IFR_RUP); \
+ \
+} while (0)
+
+#define __dlv_reset_gup() \
+do { \
+ dlv_write_reg_bit(DLV_REG_IFR, 1, IFR_GUP); \
+ \
+} while (0)
+
+#define __dlv_reset_gdo() \
+do { \
+ dlv_write_reg_bit(DLV_REG_IFR, 1, IFR_GDO); \
+ \
+} while (0)
+
+#define __dlv_reset_rdo() \
+do { \
+ dlv_write_reg_bit(DLV_REG_IFR, 1, IFR_RDO); \
+ \
+} while (0)
+
+#ifdef CONFIG_HP_SENSE_DETECT
/*
-void write_codec_file(int addr, int val);
-int read_codec_file(int addr);
-void printk_codec_files(int aaa);
-int write_codec_file_bit(int addr, int bitval, int mask_bit);
-void set_audio_data_replay(void);
-void unset_audio_data_replay(void);
-void set_record_mic_input_audio_without_playback(void);
-void unset_record_mic_input_audio_without_playback(void);
-void set_record_line_input_audio_without_playback(void);
-void unset_record_line_input_audio_without_playback(void);
-void set_playback_line_input_audio_direct_only(void);
-void unset_playback_line_input_audio_direct_only(void);
-void set_record_mic_input_audio_with_direct_playback(void);
-void unset_record_mic_input_audio_with_direct_playback(void);
-void set_record_playing_audio_mixed_with_mic_input_audio(void);
-void unset_record_playing_audio_mixed_with_mic_input_audio(void);
-void set_record_mic_input_audio_with_audio_data_replay(void);
-void unset_record_mic_input_audio_with_audio_data_replay(void);
-void set_record_line_input_audio_with_audio_data_replay(void);
-void unset_record_line_input_audio_with_audio_data_replay(void);
-*/
+ * HP_SENSE switch
+ */
+typedef struct {
+ struct switch_dev sdev;
+ const char *name;
+ const char *name_on;
+ const char *name_off;
+ const char *state_on;
+ const char *state_off;
+
+} jz_hp_switch_data_t ;
+
+typedef struct {
+ const char *name;
+ const char *name_on;
+ const char *name_off;
+ const char *state_on;
+ const char *state_off;
+
+} jz_hp_switch_platform_data_t ;
+
+#endif
#endif // __JZ4760_DLV_H__
diff --git a/sound/oss/jz4760_i2s.c b/sound/oss/jz4760_i2s.c
index c2a72a2532b..4da5607915e 100644
--- a/sound/oss/jz4760_i2s.c
+++ b/sound/oss/jz4760_i2s.c
@@ -33,9 +33,9 @@
#include "jz_codec.h"
#include "jz_i2s_dbg.h"
-#if defined CONFIG_PM
-#undef CONFIG_PM
-#endif
+//#if defined CONFIG_PM
+//#undef CONFIG_PM
+//#endif
#define DMA_ID_I2S_TX DMA_ID_AIC_TX
#define DMA_ID_I2S_RX DMA_ID_AIC_RX
@@ -180,6 +180,8 @@ static audio_pipe in_endpoint= {
static struct i2s_codec the_codecs[NR_I2S];
static struct jz_i2s_controller_info *the_i2s_controller = NULL;
static int audio_mix_modcnt = 0;
+static audio_node *last_read_node = NULL;
+static int g_play_first = 0;
/*
* Debug functions
@@ -577,10 +579,6 @@ static irqreturn_t jz_i2s_dma_irq (int irq, void *dev_id)
err = 1;
DPRINT_IRQ("!!!! DMA ADDR ERROR\n");
}
- if (dma_state & DMAC_DCCSR_INV) {
- err = 1;
- DPRINT_IRQ("!!!! DMA descriptor invalid\n");
- }
if (dma_state & DMAC_DCCSR_CT) {
DPRINT_IRQ("!!!! DMA descriptor finish\n");
}
@@ -1430,7 +1428,7 @@ static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned
DPRINT_IOC("SOUND_MIXER_WRITE_VOLUME <- %lu\n", val);
codec->audio_volume = val;
- codec_ioctrl(codec, CODEC_SET_VOLUME, val);
+ codec_ioctrl(codec, CODEC_SET_REPLAY_VOLUME, val);
return 0;
case SOUND_MIXER_READ_VOLUME:
@@ -1440,13 +1438,15 @@ static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned
return put_user(val, (long *) arg);
case SOUND_MIXER_WRITE_MIC:
+
+ printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>write mic\n");
ret = get_user(val, (long *) arg);
if ((val &= 0xff) >= 100) {
val = 100;
}
codec->mic_gain = val;
codec->use_mic_line_flag = USE_MIC;
- codec_ioctrl(codec, CODEC_SET_MIC, val);
+ codec_ioctrl(codec, CODEC_SET_MIC_VOLUME, val);
return 0;
case SOUND_MIXER_READ_MIC:
@@ -1601,7 +1601,7 @@ static int jz_codec_set_speed(struct i2s_codec *codec, int rate, int mode)
/* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
if (mode & CODEC_RMODE) {
- rate = codec_ioctrl(codec, CODEC_SET_RECORD_SPEED, rate);
+ rate = codec_ioctrl(codec, CODEC_SET_RECORD_RATE, rate);
if (rate > 0) {
codec->record_audio_rate = rate;
} else {
@@ -1609,7 +1609,7 @@ static int jz_codec_set_speed(struct i2s_codec *codec, int rate, int mode)
}
}
if (mode & CODEC_WMODE) {
- rate = codec_ioctrl(codec, CODEC_SET_REPLAY_SPEED, rate);
+ rate = codec_ioctrl(codec, CODEC_SET_REPLAY_RATE, rate);
if (rate > 0) {
codec->replay_audio_rate = rate;
} else {
@@ -1637,8 +1637,10 @@ static short jz_codec_set_channels(struct i2s_codec *codec, short channels, int
codec->replay_codec_channel = channels;
if (channels == 1) {
__aic_enable_mono2stereo();
+ __aic_out_channel_select(0);
} else {
__aic_disable_mono2stereo();
+ __aic_out_channel_select(1);
}
}
@@ -2053,6 +2055,8 @@ static int jz_audio_release(struct inode *inode, struct file *file)
__i2s_disable();
}
+ last_read_node = NULL;
+
jz_codec_close(controller->i2s_codec, mode);
LEAVE();
@@ -2097,6 +2101,9 @@ static int jz_audio_open(struct inode *inode, struct file *file)
}
file->private_data = controller;
+ /* we should turn codec and anti-pop first */
+ jz_codec_anti_pop(controller->i2s_codec, mode);
+
if (mode & CODEC_RMODE){
/*
jz_codec_set_channels(codec, 2, CODEC_RMODE);
@@ -2149,7 +2156,7 @@ static int jz_audio_open(struct inode *inode, struct file *file)
//DUMP_AIC_REGS();
DPRINT_TRC(".... jz_audio_open\n");
- jz_codec_anti_pop(controller->i2s_codec, mode);
+ g_play_first = 0;
LEAVE();
return 0;
@@ -2289,12 +2296,14 @@ static int jz_audio_ioctl(struct inode *inode, struct file *file, unsigned int c
//printk("\nSNDCTL_DSP_CHANNELS ... set to %d\n", val);
/* if mono, change to 2, and set 1 to codec->user_need_mono */
- if (val == 1) {
- val = 2;
- codec->user_need_mono = 1;
+ if (mode & CODEC_RMODE) {
+ if (val == 1) {
+ val = 2;
+ codec->user_need_mono = 1;
- } else {
- codec->user_need_mono = 0;
+ } else {
+ codec->user_need_mono = 0;
+ }
}
/* Following lines could be marked as nothing will be changed */
@@ -2562,10 +2571,17 @@ static ssize_t jz_audio_write(struct file *file, const char __user *buffer, size
{
struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *)file->private_data;
audio_pipe *pout_endpoint = controller->pout_endpoint;
+ struct i2s_codec *codec = (struct i2s_codec *)controller->i2s_codec;
size_t usecount = 0;
int bat_cnt = -1;
int rem_cnt = 0;
+ if (!g_play_first) {
+ // first play, trun on dac mute
+ codec_ioctrl(codec, CODEC_FIRST_OUTPUT, 0);
+ g_play_first = 1;
+ }
+
ENTER();
// dump_dlv_regs(__FUNCTION__);
@@ -2658,19 +2674,25 @@ static ssize_t jz_audio_write(struct file *file, const char __user *buffer, size
static inline int endpoint_get_userdata(audio_pipe *endpoint, const char __user *buffer, size_t count)
{
unsigned long flags;
- audio_node *node;
+ audio_node *node = last_read_node;
int ret;
/* counter for node buffer, raw data */
int node_buff_cnt = 0;
- /* counter for node buffer after filte, fixed data */
- int fixed_buff_cnt = 0;
ENTER();
- AUDIO_LOCK(endpoint->lock, flags);
- node = get_audio_usenode(endpoint->mem);
- AUDIO_UNLOCK(endpoint->lock, flags);
+ if (!node) {
+ AUDIO_LOCK(endpoint->lock, flags);
+ node = get_audio_usenode(endpoint->mem);
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ if (node && endpoint->filter) {
+ node_buff_cnt = node->end - node->start;
+ node_buff_cnt = endpoint->filter((void *)(node->pBuf + node->start), node_buff_cnt);
+ node->end = node->start + node_buff_cnt;
+ }
+ }
DPRINT(">>>> %s mode\n", endpoint->is_non_block ? "non block" : "block");
@@ -2701,60 +2723,40 @@ static inline int endpoint_get_userdata(audio_pipe *endpoint, const char __user
node = get_audio_usenode(endpoint->mem);
endpoint->avialable_couter = 0;
AUDIO_UNLOCK(endpoint->lock, flags);
+
+ if (node && endpoint->filter) {
+ node_buff_cnt = node->end - node->start;
+ node_buff_cnt = endpoint->filter((void *)(node->pBuf + node->start), node_buff_cnt);
+ node->end = node->start + node_buff_cnt;
+ }
}
if (node && (node_buff_cnt = node->end - node->start)) {
DPRINT("node_buff_cnt = %d, count = %d\n", node_buff_cnt, count);
- if (endpoint->filter) {
-/*
- printk("filter 3 ... %d\n", node_buff_cnt);
- {
- int i;
- for (i = 100; i < 112; i++) {
- printk("*(nod->pBuf + node_start + %d) = 0x%02x\n",
- i, *(char *)(node->pBuf + node->start + i));
- }
- }
-*/
- /* ret indicate that final data length when copy_to_user
- * (node->end - node->start) may not equals to ret !
- */
- fixed_buff_cnt = endpoint->filter((void *)(node->pBuf + node->start), node_buff_cnt);
-/*
- {
- int i;
- for (i = 100; i < 112; i++) {
- printk("*(nod->pBuf + node_start + %d) = 0x%02x\n",
- i, *(char *)(node->pBuf + node->start + i));
- }
- }
-*/
- } else {
- fixed_buff_cnt = node_buff_cnt;
- }
-
- if (count >= (size_t)fixed_buff_cnt) {
- DPRINT(">>>> count >= fixed_buff_cnt, copy_to_user, fixed_buff_cnt = %d\n", fixed_buff_cnt);
- ret = copy_to_user((void *)buffer, (void *)(node->pBuf + node->start), fixed_buff_cnt);
+ if (count >= (size_t)node_buff_cnt) {
+ DPRINT(">>>> count >= fixed_buff_cnt, copy_to_user count = %d\n", node_buff_cnt);
+ ret = copy_to_user((void *)buffer, (void *)(node->pBuf + node->start), node_buff_cnt);
if (ret) {
printk("JZ I2S: copy_to_user failed, return %d\n", ret);
return -EFAULT;
}
put_audio_freenode(endpoint->mem, node);
+ last_read_node = NULL;
} else {
- DPRINT(">>>> count < fixed_buff_cnt, copy_to_user, fixed_buff_cnt = %d\n", fixed_buff_cnt);
+ DPRINT(">>>> count < fixed_buff_cnt, copy_to_user count = %d\n", count);
ret = copy_to_user((void *)buffer,(void *)(node->pBuf + node->start), count);
if (ret) {
printk("JZ I2S: copy_to_user failed, return %d\n", ret);
return -EFAULT;
}
- node->start += node_buff_cnt;
+ node->start += count;
+ last_read_node = node;
}
}
LEAVE();
- return (fixed_buff_cnt < count ? fixed_buff_cnt : count);
+ return (node_buff_cnt < count ? node_buff_cnt : count);
}
static ssize_t jz_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
@@ -2886,49 +2888,40 @@ static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
//--------------------------------------------------------------------
#ifdef CONFIG_PM
-static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+static int jz_i2s_suspend(struct platform_device *pdev, pm_message_t state)
{
int i;
struct i2s_codec *codec;
for(i = 0;i < NR_I2S; i++){
codec = &the_codecs[i];
- codec->codes_ioctrl(codec, I2S_SUSPEND_CODEC, 0);
+ if (codec && codec->codecs_ioctrl) {
+ codec->codecs_ioctrl(codec, CODEC_I2S_SUSPEND, 0);
+ }
}
+
+#if 0
+ __i2s_disable();
+ mdelay(5);
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+#endif
printk("Aic and codec are suspended!\n");
return 0;
}
-static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+static int jz_i2s_resume(struct platform_device *pdev)
{
int i;
struct i2s_codec *codec;
for(i = 0;i < NR_I2S; i++){
codec = &the_codecs[i];
- codec->codes_ioctrl(codec, I2S_RESUME_CODEC,0);
+ if (codec && codec->codecs_ioctrl) {
+ codec->codecs_ioctrl(codec, CODEC_I2S_RESUME, 0);
+ }
}
return 0;
}
-
-static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
-{
- int ret;
- struct jz_i2s_controller_info *controller = pm_dev->data;
-
- if (!controller) return -EINVAL;
-
- switch (req) {
- case PM_SUSPEND:
- ret = jz_i2s_suspend(controller, (int)data);
- break;
- case PM_RESUME:
- ret = jz_i2s_resume(controller);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
#endif /* CONFIG_PM */
static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
@@ -2962,15 +2955,8 @@ void i2s_controller_init(void)
ENTER();
- REG_CPM_I2SCDR = 0;
-
- __cpm_select_i2sclk_exclk();
-// __cpm_exclk_div2();
- __cpm_enable_pll_change();
-
- /* ??? legacy ???
- printk("cpccr 0x%08x\n", *(unsigned int *)0xb0000000);
- */
+ /* Select exclk as i2s clock */
+ cpm_set_clock(CGU_I2SCLK, JZ_EXTAL);
aicfr = (8 << 12) | (8 << 8) | (AIC_FR_ICDC | AIC_FR_LSMP | AIC_FR_AUSEL);
REG_AIC_FR = aicfr;
@@ -2999,7 +2985,8 @@ static int __init init_jz_i2s(struct platform_device *pdev)
return -1;
}
- default_codec->codecs_ioctrl(default_codec, CODEC_SET_MODE, 0);
+ //default_codec->codecs_ioctrl(default_codec, CODEC_SET_MODE, 0);
+ default_codec->codecs_ioctrl(default_codec, CODEC_INIT, 0);
if ((errno = probe_jz_i2s(&the_i2s_controller)) < 0) {
return errno;
@@ -3024,13 +3011,6 @@ static int __init init_jz_i2s(struct platform_device *pdev)
audio_init_endpoint(&out_endpoint, fragsize, fragstotal);
audio_init_endpoint(&in_endpoint, fragsize, fragstotal);
-#ifdef CONFIG_PM
- the_i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
- jz_i2s_pm_callback);
- if (the_i2s_controller->pm) {
- the_i2s_controller->pm->data = i2s_controller;
- }
-#endif
printk("JZ I2S OSS audio driver initialized\n");
LEAVE();
@@ -3057,6 +3037,8 @@ static struct platform_driver snd_plat_driver = {
.name = "mixer",
.owner = THIS_MODULE,
},
+ .suspend = jz_i2s_suspend,
+ .resume = jz_i2s_resume,
};
static int __init snd_init(void)
diff --git a/sound/oss/jz_codec.h b/sound/oss/jz_codec.h
index a6e789f5fd1..680d8dac76c 100644
--- a/sound/oss/jz_codec.h
+++ b/sound/oss/jz_codec.h
@@ -3,6 +3,7 @@
#define _JZ_CODEC_H_
//-------------------------------------------------
+#define CODEC_INIT 0
#define CODEC_SET_MODE 1
#define CODEC_SET_STARTUP_PARAM 5
#define CODEC_SET_VOLUME_TABLE 6
@@ -15,8 +16,8 @@
#define CODEC_SET_REPLAY_RECORD 9
-#define CODEC_SET_REPLAY_SPEED 12
-#define CODEC_SET_RECORD_SPEED 37
+#define CODEC_SET_REPLAY_RATE 12
+#define CODEC_SET_RECORD_RATE 37
#define CODEC_SET_REPLAY_CHANNEL 33
#define CODEC_SET_REPLAY_DATA_WIDTH 34
@@ -26,8 +27,8 @@
#define CODEC_SET_GPIO_PIN 3
#define CODEC_SET_BASS 16
-#define CODEC_SET_VOLUME 17
-#define CODEC_SET_MIC 18
+#define CODEC_SET_REPLAY_VOLUME 17
+#define CODEC_SET_MIC_VOLUME 18
#define CODEC_SET_LINE 19
#define CODEC_SET_SOME_FUNC 23
@@ -49,7 +50,17 @@
#define CODEC_CLEAR_DIRECT_MODE 28
#define CODEC_SET_LINEIN2HP 29
#define CODEC_CLEAR_LINEIN2HP 30
+#define CODEC_SET_STANDBY 47
+#define CODEC_SET_LINEIN2BTL 39
+#define CODEC_CLEAR_LINEIN2BTL 40
+
+#define CODEC_SET_DEVICE 41
+#define CODEC_MUTE_DEVICE 42
+#define CODEC_SET_REPLAY_SPEED 43
+#define CODEC_SET_RECORD_SPEED 44
+#define CODEC_SET_MIC 45
+#define CODEC_SET_VOLUME 46
//------------------------------------------------
#define CODEC_ANTI_POP 31
@@ -57,19 +68,36 @@
#define CODEC_DAC_MUTE 38
+#define CODEC_SET_STANDBY 47
+#define CODEC_SET_REC_2_DAC 48
+#define CODEC_DEBUG_ROUTINE 49
+#define CODEC_SET_SPEAKER_POWER 50
+
+#define CODEC_FIRST_OUTPUT 66
+
+//-------------------------------------------------
+
+#define CODEC_DEBUG 100
+
//-------------------------------------------------
void register_jz_codecs(void *func);
void dump_dlv_regs(const char* str);
-void dlv_write_reg(int addr, int val);
+//void dlv_write_reg(int addr, int val);
+//-------------------------------------------------
+
+#define SND_SET_STANDBY _IOW(SND_IOCTL_MAGIC, 4, unsigned int *)
+
//-------------------------------------------------
-#define USE_NONE 1
-#define USE_MIC 2
-#define USE_LINEIN 3
+// Deprecate !!!
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
-#define CODEC_WMODE (1 << 0)
-#define CODEC_RMODE (1 << 1)
-#define CODEC_WRMODE (CODEC_WMODE | CODEC_RMODE)
+// For file ops
+#define CODEC_WMODE (1 << 0)
+#define CODEC_RMODE (1 << 1)
+#define CODEC_WRMODE (CODEC_WMODE | CODEC_RMODE)
#endif /* _JZ_CODEC_H_ */
diff --git a/sound/oss/jz_i2s.c b/sound/oss/jz_i2s.c
index f8fc5fce20d..7892a297d8b 100644
--- a/sound/oss/jz_i2s.c
+++ b/sound/oss/jz_i2s.c
@@ -1,19 +1,12 @@
/*
- * linux/drivers/sound/Jz_i2s.c
+ * Linux/sound/oss/jz_i2s.c
*
- * JzSOC On-Chip I2S audio driver.
+ * Sound driver for Ingenic Jz4750 MIPS processor
*
- * Copyright (C) 2005 by Junzheng Corp.
- * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
- * dma channel 4&3,noah is tested.
- *
- * 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.
- *
- * Because the normal application of AUDIO devices are focused on Little_endian,
- * then we only perform the little endian data format in driver.
+ * 2009-12-xx Steven <dsqiu@ingenic.cn>
+ * 2010-01-xx Jason <xwang@ingenic.cn>
*
+ * Copyright (c) Ingenic Semiconductor Co., Ltd.
*/
#include <linux/init.h>
@@ -21,7 +14,6 @@
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/delay.h>
-
#include <linux/sound.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -35,2902 +27,2962 @@
#include <asm/jzsoc.h>
#include "sound_config.h"
-#if defined(CONFIG_I2S_DLV)
-#include "jzdlv.h"
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+//#include <linux/msm_audio.h>
+#include "jz_codec.h"
+#include "jz_i2s_dbg.h"
+
+#if defined CONFIG_PM
+#undef CONFIG_PM
#endif
-#define DPRINTK(args...) printk(args)
-#define DMA_ID_I2S_TX DMA_ID_AIC_TX
-#define DMA_ID_I2S_RX DMA_ID_AIC_RX
-#define NR_I2S 2
-#define JZCODEC_RW_BUFFER_SIZE 5
-#define JZCODEC_RW_BUFFER_TOTAL 4
-
-#define USE_NONE 1
-#define USE_MIC 2
-#define USE_LINEIN 3
-#define USE_WAIT_EVENT
-
-typedef struct hpvol_shift_s
-{
- int hpvol;
- int shift;
-} hpvol_shift_t;
-
-mixer_info info;
-_old_mixer_info old_info;
-int codec_volue_shift;
-hpvol_shift_t hpvol_shift_table[72];
-int abnormal_data_count;
-unsigned long i2s_clk;
-
-void (*set_codec_mode)(void) = NULL;
-void (*clear_codec_mode)(void) = NULL;
-void (*set_codec_gpio_pin)(void) = NULL;
-void (*each_time_init_codec)(void) = NULL;
-int (*set_codec_startup_param)(void) = NULL;
-void (*set_codec_volume_table)(void) = NULL;
-void (*set_codec_record)(int mode) = NULL;
-void (*set_codec_replay)(void) = NULL;
-void (*set_codec_replay_record)(int mode) = NULL;
-void (*turn_on_codec)(void) = NULL;
-void (*turn_off_codec)(void) = NULL;
-void (*set_codec_speed)(int rate) = NULL;
-void (*reset_codec)(void) = NULL;
-void (*codec_mixer_old_info_id_name)(void) = NULL;
-void (*codec_mixer_info_id_name)(void) = NULL;
-void (*set_codec_bass)(int val) = NULL;
-void (*set_codec_volume)(int val) = NULL;
-void (*set_codec_mic)(int val) = NULL;
-void (*set_codec_line)(int val) = NULL;
-void (*i2s_resume_codec)(void) = NULL;
-void (*i2s_suspend_codec)(int wr,int rd) = NULL;
-void (*init_codec_pin)(void) = NULL;
-void (*set_codec_some_func)(void) = NULL;
-void (*clear_codec_record)(void) = NULL;
-void (*clear_codec_replay)(void) = NULL;
-void (*set_replay_hp_or_speaker)(void) = NULL;
-void (*set_codec_direct_mode)(void) = NULL;
-void (*clear_codec_direct_mode)(void) = NULL;
-void (*set_codec_linein2hp)(void) = NULL;
-void (*clear_codec_linein2hp)(void) = NULL;
-
-static int jz_audio_rate;
-static int jz_audio_format;
-static int jz_audio_volume;
-static int jz_audio_channels;
-static int jz_audio_b; /* bits expand multiple */
-static int jz_audio_fragments; /* unused fragment amount */
-static int jz_audio_fragstotal;
-static int jz_audio_fragsize;
-static int jz_audio_speed;
-
-static int codec_bass_gain;
-static int audio_mix_modcnt;
-static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */
-#if defined(CONFIG_I2S_DLV)
-int jz_dlv_vol_mute = 0; /* Added by River. */
-int jz_mic_only = 1;
-static int jz_codec_config = 0;
-static unsigned long ramp_up_start;
-static unsigned long ramp_up_end;
-static unsigned long gain_up_start;
-static unsigned long gain_up_end;
-static unsigned long ramp_down_start;
-static unsigned long ramp_down_end;
-static unsigned long gain_down_start;
-static unsigned long gain_down_end;
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+#define NR_I2S 2
+
+#define JZCODEC_RW_BUFFER_SIZE 1
+#define JZCODEC_RW_BUFFER_TOTAL 4
+
+#define AUDIOBUF_STATE_FREE 0
+
+#define NOMAL_STOP 0
+#define FORCE_STOP 1
+#define PIPE_TRANS 1
+
+#define AUDIO_LOCK(lock, flags) spin_lock_irqsave(lock, flags)
+#define AUDIO_UNLOCK(lock, flags) spin_unlock_irqrestore(lock, flags)
+
+#define THIS_AUDIO_NODE(p) list_entry(p, audio_node, list)
+#define ALIGN_PAGE_SIZE(x) (((x) + PAGE_SIZE) / PAGE_SIZE * PAGE_SIZE)
+
+typedef struct {
+ struct list_head list;
+ unsigned int pBuf;
+#ifdef Q_DEBUG
+ unsigned int pBufID;
#endif
+ unsigned int start;
+ unsigned int end;
+ unsigned int phyaddr;
+} audio_node;
+
+typedef struct {
+ unsigned int fact;
+ unsigned int datasize;
+ unsigned int listsize;
+ struct list_head free;
+ struct list_head use;
+} audio_head;
-static int codec_mic_gain;
-static int pop_dma_flag;
-static int last_dma_buffer_id;
-static int drain_flag;
-static int use_mic_line_flag;
-
-static void (*old_mksound)(unsigned int hz, unsigned int ticks);
-extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
-static void jz_update_filler(int bits, int channels);
-
-static int Init_In_Out_queue(int fragstotal,int fragsize);
-static int Free_In_Out_queue(int fragstotal,int fragsize);
-static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
-static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
-static void (*replay_filler)(signed long src_start, int count, int id);
-static int (*record_filler)(unsigned long dst_start, int count, int id);
-#if defined(CONFIG_I2S_ICODEC)
-static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample);
+typedef struct
+{
+ int ch;
+ int onetrans_bit;
+ int rw;
+ unsigned int *trans_addr;
+ unsigned int *trans_count;
+ unsigned int *trans_mode;
+ unsigned int *data_addr;
+} audio_dma_type;
+
+typedef struct __audio_pipe
+{
+ spinlock_t lock;
+ audio_dma_type dma;
+ unsigned int *mem;
+ audio_node *savenode;
+
+ int fragsize;
+ int fragstotal;
+ int trans_state;
+ int is_non_block;
+
+ wait_queue_head_t q_full;
+ int avialable_couter;
+
+#ifdef WORK_QUEUE_MODE
+ struct work_struct work;
#endif
-static void jz_audio_reset(void);
-static struct file_operations jz_i2s_audio_fops;
+ void (*handle)(struct __audio_pipe *endpoint);
+ int (*filter)(void *buff, int cnt);
+} audio_pipe;
+
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+
+ int use_mic_line_flag;
+ int audio_volume;
+ int mic_gain;
+ int bass_gain;
+
+ unsigned short record_audio_rate;
+ unsigned short replay_audio_rate;
+
+ short replay_codec_channel;
+ short record_codec_channel;
+
+ short replay_format;
+ short record_format;
-static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
-static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
-static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue);
-static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+ int audiomute;
+ int user_need_mono;
-static volatile int pop_wait_event;
+ struct semaphore i2s_sem;
+ int (*codecs_ioctrl)(void *context, unsigned int cmd, unsigned long arg);
+};
struct jz_i2s_controller_info
{
- int io_base;
- int dma1; /* for play */
- int dma2; /* for record */
- char *name;
- int dev_audio;
- struct i2s_codec *i2s_codec[NR_I2S];
- int opened1;
- int opened2;
- unsigned char *tmp1; /* tmp buffer for sample conversions */
- unsigned char *tmp2;
- spinlock_t lock;
- spinlock_t ioctllock;
-
- wait_queue_head_t dac_wait;
- wait_queue_head_t adc_wait;
- int nextIn; /* byte index to next-in to DMA buffer */
- int nextOut; /* byte index to next-out from DMA buffer */
- int count; /* current byte count in DMA buffer */
- int finish; /* current transfered byte count in DMA buffer */
- unsigned total_bytes; /* total bytes written or read */
- unsigned blocks;
- unsigned error; /* over/underrun */
+ char *name;
+ audio_pipe *pout_endpoint;
+ audio_pipe *pin_endpoint;
+ int dev_audio;
+ unsigned int error; /* over / underrun */
+
+ struct i2s_codec *i2s_codec;
+
#ifdef CONFIG_PM
- struct pm_dev *pm;
+ struct pm_dev *pm;
#endif
};
-static struct jz_i2s_controller_info *i2s_controller = NULL;
-struct i2s_codec
-{
- /* I2S controller connected with */
- void *private_data;
- char *name;
- int id;
- int dev_mixer;
- /* controller specific lower leverl i2s accessing routines */
- u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */
- void (*codec_write) (u8 reg, u16 val);
- /* Wait for codec-ready */
- void (*codec_wait) (struct i2s_codec *codec);
- /* OSS mixer masks */
- int modcnt;
- int supported_mixers;
- int stereo_mixers;
- int record_sources;
- int bit_resolution;
- /* OSS mixer interface */
- int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
- void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
- unsigned int left, unsigned int right);
- int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
- int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
- /* saved OSS mixer states */
- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+/*
+ * Global variates
+ */
+static audio_pipe out_endpoint = {
+ .mem = 0,
+ .savenode = 0,
+ .fragsize = 0,
+ .fragstotal = 0,
+ .trans_state = 0,
};
+static audio_pipe in_endpoint= {
+ .mem = 0,
+ .savenode = 0,
+ .fragsize = 0,
+ .fragstotal = 0,
+ .trans_state = 0,
+};
-typedef struct buffer_queue_s
-{
- int count;
- int *id;
- int lock;
-} buffer_queue_t;
+static struct i2s_codec the_codecs[NR_I2S];
+static struct jz_i2s_controller_info *the_i2s_controller = NULL;
+static int audio_mix_modcnt = 0;
-typedef struct left_right_sample_s
+/*
+ * Debug functions
+ */
+#ifdef DMA_DEBUG
+void dump_dma(unsigned int dmanr, const char *str)
{
- signed long left;
- signed long right;
-} left_right_sample_t;
+ printk("DMA%d Registers, %s:\n", dmanr, str);
+ printk("\tDMACR = 0x%08x\n", REG_DMAC_DMACR(dmanr/HALF_DMA_NUM));
+ printk("\tDSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk("\tDTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
+ printk("\tDTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk("\tDRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk("\tDCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+ printk("\tDCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
+ printk("\tDDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
+ printk("\tDMADBR= 0x%08x\n", REG_DMAC_DMADBR(dmanr/HALF_DMA_NUM));
+}
+#endif
-static unsigned long pop_turn_onoff_buf;
-static unsigned long pop_turn_onoff_pbuf;
+#ifdef IOC_DEBUG
+void dsp_print_ioc_cmd(int cmd)
+{
+ int i;
+ int cmd_arr[] = {
+ OSS_GETVERSION, SNDCTL_DSP_RESET, SNDCTL_DSP_SYNC,
+ SNDCTL_DSP_SPEED, SNDCTL_DSP_STEREO, SNDCTL_DSP_GETBLKSIZE,
+ SNDCTL_DSP_GETFMTS, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS,
+ SNDCTL_DSP_POST, SNDCTL_DSP_SUBDIVIDE, SNDCTL_DSP_SETFRAGMENT,
+ SNDCTL_DSP_GETCAPS, SNDCTL_DSP_NONBLOCK, SNDCTL_DSP_SETDUPLEX,
+ SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, SNDCTL_DSP_GETTRIGGER,
+ SNDCTL_DSP_SETTRIGGER, SNDCTL_DSP_GETIPTR, SNDCTL_DSP_GETOPTR,
+ SNDCTL_DSP_GETODELAY, SOUND_PCM_READ_RATE, SOUND_PCM_READ_CHANNELS,
+ SOUND_PCM_READ_BITS, SNDCTL_DSP_MAPINBUF, SNDCTL_DSP_MAPOUTBUF,
+ SNDCTL_DSP_SETSYNCRO, SOUND_PCM_READ_FILTER, SOUND_PCM_WRITE_FILTER
+// AUDIO_GET_CONFIG, AUDIO_SET_CONFIG
+ };
+ char *cmd_str[] = {
+ "OSS_GETVERSION", "SNDCTL_DSP_RESET", "SNDCTL_DSP_SYNC",
+ "SNDCTL_DSP_SPEED", "SNDCTL_DSP_STEREO", "SNDCTL_DSP_GETBLKSIZE",
+ "SNDCTL_DSP_GETFMTS", "SNDCTL_DSP_SETFMT", "SNDCTL_DSP_CHANNELS",
+ "SNDCTL_DSP_POST", "SNDCTL_DSP_SUBDIVIDE", "SNDCTL_DSP_SETFRAGMENT",
+ "SNDCTL_DSP_GETCAPS", "SNDCTL_DSP_NONBLOCK", "SNDCTL_DSP_SETDUPLEX",
+ "SNDCTL_DSP_GETOSPACE", "SNDCTL_DSP_GETISPACE", "SNDCTL_DSP_GETTRIGGER",
+ "SNDCTL_DSP_SETTRIGGER","SNDCTL_DSP_GETIPTR", "SNDCTL_DSP_GETOPTR",
+ "SNDCTL_DSP_GETODELAY", "SOUND_PCM_READ_RATE", "SOUND_PCM_READ_CHANNELS",
+ "SOUND_PCM_READ_BITS", "SNDCTL_DSP_MAPINBUF", "SNDCTL_DSP_MAPOUTBUF",
+ "SNDCTL_DSP_SETSYNCRO", "SOUND_PCM_READ_FILTER","SOUND_PCM_WRITE_FILTER"
+// "AUDIO_GET_CONFIG", "AUDIO_SET_CONFIG"
+ };
+
+ for ( i = 0; i < sizeof(cmd_arr) / sizeof(int); i++) {
+ if (cmd_arr[i] == cmd) {
+ printk("Command name : %s\n", cmd_str[i]);
+ return;
+ }
+ }
-static unsigned long *out_dma_buf = NULL;
-static unsigned long *out_dma_pbuf = NULL;
-static unsigned long *out_dma_buf_data_count = NULL;
-static unsigned long *in_dma_buf = NULL;
-static unsigned long *in_dma_pbuf = NULL;
-static unsigned long *in_dma_buf_data_count = NULL;
+ if (i == sizeof(cmd_arr) / sizeof(int)) {
+ printk("Unknown command\n");
+ }
+}
-static buffer_queue_t out_empty_queue;
-static buffer_queue_t out_full_queue;
-static buffer_queue_t out_busy_queue;
-static buffer_queue_t in_empty_queue;
-static buffer_queue_t in_full_queue;
-static buffer_queue_t in_busy_queue;
-static int first_record_call = 0;
+void mixer_print_ioc_cmd(int cmd)
+{
+ int i;
+ int cmd_arr[] = {
+ SOUND_MIXER_INFO, SOUND_OLD_MIXER_INFO, SOUND_MIXER_READ_STEREODEVS,
+ SOUND_MIXER_READ_CAPS, SOUND_MIXER_READ_DEVMASK, SOUND_MIXER_READ_RECMASK,
+ SOUND_MIXER_READ_RECSRC,SOUND_MIXER_WRITE_SPEAKER, SOUND_MIXER_WRITE_BASS,
+ SOUND_MIXER_READ_BASS, SOUND_MIXER_WRITE_VOLUME, SOUND_MIXER_READ_VOLUME,
+ SOUND_MIXER_WRITE_MIC, SOUND_MIXER_READ_MIC, SOUND_MIXER_WRITE_LINE,
+ SOUND_MIXER_READ_LINE, SOUND_MIXER_WRITE_MUTE, SOUND_MIXER_READ_MUTE
+// SND_SET_DEVICE, SND_SET_VOLUME,
+// SND_GET_NUM_ENDPOINTS, SND_GET_ENDPOINT
+ };
+
+ char *cmd_str[] = {
+ "SOUND_MIXER_INFO", "SOUND_OLD_MIXER_INFO", "SOUND_MIXER_READ_STEREODEVS",
+ "SOUND_MIXER_READ_CAPS", "SOUND_MIXER_READ_DEVMASK", "SOUND_MIXER_READ_RECMASK",
+ "SOUND_MIXER_READ_RECSRC", "SOUND_MIXER_WRITE_SPEAKER", "SOUND_MIXER_WRITE_BASS",
+ "SOUND_MIXER_READ_BASS", "SOUND_MIXER_WRITE_VOLUME", "SOUND_MIXER_READ_VOLUME",
+ "SOUND_MIXER_WRITE_MIC", "SOUND_MIXER_READ_MIC", "SOUND_MIXER_WRITE_LINE",
+ "SOUND_MIXER_READ_LINE", "SOUND_MIXER_WRITE_MUTE", "SOUND_MIXER_READ_MUTE"
+// "SND_SET_DEVICE", "SND_SET_VOLUME",
+// "SND_GET_NUM_ENDPOINTS", "SND_GET_ENDPOINT"
+ };
+
+ for (i = 0; i < sizeof(cmd_arr) / sizeof(int); i++) {
+ if (cmd_arr[i] == cmd) {
+ printk("Command name : %s\n", cmd_str[i]);
+ return;
+ }
+ }
-static left_right_sample_t save_last_samples[64];
+ printk("Unknown command\n");
+}
+#endif
-static inline int get_buffer_id(struct buffer_queue_s *q)
+#ifdef REG_DEBUG
+void dump_aic_regs(const char *str)
{
- int r;
- unsigned long flags;
+ char *regname[] = {"aicfr","aiccr","aiccr1","aiccr2","i2scr","aicsr","acsr","i2ssr"};
int i;
+ unsigned int addr;
- spin_lock_irqsave(&q->lock, flags);
- if (q->count == 0) {
- spin_unlock_irqrestore(&q->lock, flags);
- return -1;
+ printk("AIC regs dump, %s\n", str);
+ for (i = 0; i < 0x1c; i += 4) {
+ addr = 0xb0020000 + i;
+ printk("%s\t0x%08x -> 0x%08x\n", regname[i/4], addr, *(unsigned int *)addr);
}
- r = *(q->id + 0);
- for (i=0;i < q->count-1;i++)
- *(q->id + i) = *(q->id + (i+1));
- q->count --;
- spin_unlock_irqrestore(&q->lock, flags);
+}
+#endif
- return r;
+#ifdef BUF_DEBUG
+void dump_buf(char *buf, int dump_len, int bytes_in_line)
+{
+ int i;
+ printk("Buffer 0x%p:\n", buf);
+ for (i = 0; i < dump_len; i++) {
+ printk("%02x ", (unsigned char)buf[i]);
+ if ((i+1) % bytes_in_line == 0) {
+ printk("\n");
+ }
+ }
+ printk("\n");
}
+#endif
-static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+#ifdef Q_DEBUG
+void dump_node(audio_node *node, const char *str)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
- *(q->id + q->count) = id;
- q->count ++;
- spin_unlock_irqrestore(&q->lock, flags);
+ if (!node || !str) {
+ printk("DUMP_NODE: detected argument is NULL\n");
+ return;
+ }
+
+ printk("%s: addr(0x%08x) id=%d, pBuf=0x%08x, start=0x%08x, end=0x%08x, phyaddr=0x%08x\n",
+ str, (unsigned int)node, node->pBufID, node->pBuf, node->start, node->end, node->phyaddr);
}
-static inline int elements_in_queue(struct buffer_queue_s *q)
+void dump_list(audio_head *head)
{
- int r;
- unsigned long flags;
+ audio_node *tmp;
+ struct list_head *p, *n;
- spin_lock_irqsave(&q->lock, flags);
- r = q->count;
- spin_unlock_irqrestore(&q->lock, flags);
+ BUG_ON(!head);
- return r;
+ printk("--------\nAudio head info: fact = %d, datasize = %d, listsize = %d\n",
+ head->fact, head->datasize, head->listsize);
+
+ printk("free q:\n");
+ list_for_each_safe(p, n, &head->free) {
+ tmp = list_entry(p, audio_node, list);
+ DUMP_NODE(tmp, "fQ");
+ }
+ printk("use q:\n");
+ list_for_each_safe(p, n, &head->use) {
+ tmp = list_entry(p, audio_node, list);
+ DUMP_NODE(tmp, "uQ");
+ }
+ printk("--------\n");
}
+#endif
+
+//----------------------------------------------------------------
+// audio node operater
+// int init_audio_node(unsigned int **memory, unsigned int pagesize, unsigned int count)
+// void deinit_audio_node(unsigned int **memory)
+// static inline audio_node *get_audio_freenode(unsigned int *mem)
+// static inline void put_audio_usenode(unsigned int *mem, audio_node *node)
+// static inline audio_node *get_audio_usenode(unsigned int *mem)
+// static inline void put_audio_freenode(unsigned int *mem, audio_node *node)
+// static inline int get_audio_freenodecount(unsigned int *mem)
+//
+//----------------------------------------------------------------
-static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+void deinit_audio_node(unsigned int **memory)
{
- unsigned long flags;
- struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- jz_audio_dma_tran_count = count / jz_audio_b;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- flags = claim_dma_lock();
- disable_dma(chan);
- clear_dma_ff(chan);
-#if 1
- jz_set_oss_dma(chan, mode, jz_audio_format);
-#else
- set_dma_mode(chan, mode);
-#endif
- set_dma_addr(chan, phyaddr);
- if (count == 0) {
- count++;
- printk("JzSOC DMA controller can't set dma 0 count!\n");
- }
- set_dma_count(chan, count);
- enable_dma(chan);
- release_dma_lock(flags);
+ audio_head *phead;
+ unsigned int fact;
+
+ phead = (audio_head *)*memory;
+ fact = phead->fact;
+ free_pages((unsigned long)*memory, fact);
+ *memory = NULL;
}
-static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+int init_audio_node(unsigned int **memory, unsigned int pagesize, unsigned int count)
{
- int id1, id2;
- unsigned long flags;
- struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
- int dma = controller->dma2;
-
- disable_dma(dma);
- if (__dmac_channel_address_error_detected(dma)) {
- printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
- __dmac_channel_clear_address_error(dma);
+ unsigned int fact;
+ audio_node *pbuff;
+ audio_head *phead;
+ unsigned int *mem;
+ struct list_head *audio_wfree;
+ struct list_head *audio_wuse;
+ int memsize;
+ int datasize;
+ int headlistsize;
+ int i;
+
+ ENTER();
+
+ // Alloc memory first, to avail fail
+ datasize = ALIGN_PAGE_SIZE(pagesize * count);
+ headlistsize = ALIGN_PAGE_SIZE(count * sizeof(audio_node) + sizeof(audio_head));
+ memsize = headlistsize + datasize;
+ fact = get_order(memsize);
+
+ mem = (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA, fact);
+ if (mem == NULL) {
+ printk("JZ I2S: Memory allocation failed in function init_audio_node!\n");
+ return -1;
}
- if (__dmac_channel_transmit_end_detected(dma)) {
- __dmac_channel_clear_transmit_end(dma);
-
- if(drain_flag == 1)
- wake_up(&drain_wait_queue);
- /* for DSP_GETIPTR */
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes += jz_audio_dma_tran_count;
- controller->blocks ++;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- id1 = get_buffer_id(&in_busy_queue);
- put_buffer_id(&in_full_queue, id1);
-
- wake_up(&rx_wait_queue);
- wake_up(&controller->adc_wait);
- if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
- put_buffer_id(&in_busy_queue, id2);
- *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
- dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
- audio_start_dma(dma,dev_id,
- *(in_dma_pbuf + id2),
- *(in_dma_buf_data_count + id2),
- DMA_MODE_READ);
- } else
- in_busy_queue.count = 0;
+
+ DPRINT("Mem alloc finish! memsize = %x, fact = %d, mem = 0x%08x\n",
+ memsize, fact, (unsigned int)mem);
+
+ // Free old buffer
+ if (*memory) {
+ phead = (audio_head *)*memory;
+ fact = phead->fact;
+ free_pages((unsigned long)*memory, fact);
+ *memory = NULL;
}
+ *memory = mem;
- return IRQ_HANDLED;
-}
+/*
+ datasize = ALIGN_PAGE_SIZE(pagesize * count);
+ headlistsize = ALIGN_PAGE_SIZE(count * sizeof(audio_node) + sizeof(audio_head)); //8byte is save head data
+ memsize = headlistsize + datasize;
-static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
-{
- int id;
- unsigned long flags;
- struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
- int dma = controller->dma1;
-
- disable_dma(dma);
- if (__dmac_channel_address_error_detected(dma)) {
- printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
- __dmac_channel_clear_address_error(dma);
- }
- if (__dmac_channel_transmit_end_detected(dma)) {
- __dmac_channel_clear_transmit_end(dma);
-
- if(pop_dma_flag == 1) {
- pop_dma_flag = 0;
- wake_up(&pop_wait_queue);
- } else {
- if(drain_flag == 1) {
- /* Is replay dma buffer over ? */
- if(elements_in_queue(&out_full_queue) <= 0) {
- drain_flag = 0;
- wake_up(&drain_wait_queue);
- }
- }
+ fact = get_order(memsize);
+*/
- /* for DSP_GETOPTR */
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes += jz_audio_dma_tran_count;
- controller->blocks ++;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- if ((id = get_buffer_id(&out_busy_queue)) < 0)
- printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
- put_buffer_id(&out_empty_queue, id);
- if ((id = get_buffer_id(&out_full_queue)) >= 0) {
- put_buffer_id(&out_busy_queue, id);
- if(*(out_dma_buf_data_count + id) > 0) {
- audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
- *(out_dma_buf_data_count + id),
- DMA_MODE_WRITE);
- last_dma_buffer_id = id;
- }
- } else
- out_busy_queue.count = 0;
+ // Update list head
+ phead = (audio_head *)*memory;
+ phead->fact = fact;
+ phead->listsize = headlistsize;
+ phead->datasize = datasize;
- if (elements_in_queue(&out_empty_queue) > 0) {
- wake_up(&tx_wait_queue);
- wake_up(&controller->dac_wait);
- }
- }
+ audio_wuse = &(phead->use);
+ audio_wfree = &(phead->free);
+ INIT_LIST_HEAD(audio_wuse);
+ INIT_LIST_HEAD(audio_wfree);
+
+ pbuff = (audio_node *)((unsigned int)*memory + sizeof(audio_head));
+ for (i = 0; i < count; i++) {
+ pbuff->pBuf = (unsigned int)*memory + headlistsize + pagesize * i;
+ pbuff->phyaddr = (unsigned int)virt_to_phys((void *)pbuff->pBuf);
+ pbuff->start = 0;
+ pbuff->end = 0;
+#ifdef Q_DEBUG
+ pbuff->pBufID = i;
+#endif
+ DPRINT_Q("audio_note buffer[%d] = %x\n", i, (unsigned int)pbuff->pBuf);
+ list_add(&pbuff->list, audio_wfree);
+ pbuff++;
}
- return IRQ_HANDLED;
+ DUMP_LIST(phead);
+
+ LEAVE();
+ return 0;
}
-static void jz_i2s_initHw(int set)
+#define is_null_free_audio_node(mem) \
+({ \
+ audio_head *phead = (audio_head *)(mem); \
+ struct list_head *pfree = &(phead->pfree); \
+ (pfree->next == pfree); \
+})
+
+#define is_null_use_audio_node(mem) \
+({ \
+ audio_head *phead = (audio_head *)mem; \
+ struct list_head *puse = &(phead->use); \
+ (puse->next == puse); \
+})
+
+//static unsigned int putid = 0, getid = 0;
+
+static inline audio_node *get_audio_freenode(unsigned int *mem)
{
-#if defined(CONFIG_MIPS_JZ_URANUS)
- i2s_clk = 48000000;
-#else
- i2s_clk = __cpm_get_i2sclk();
-#endif
- __i2s_disable();
- if(set)
- __i2s_reset();
- schedule_timeout(5);
- if(each_time_init_codec)
- each_time_init_codec();
- __i2s_disable_record();
- __i2s_disable_replay();
- __i2s_disable_loopback();
- __i2s_set_transmit_trigger(12);
- __i2s_set_receive_trigger(4);
+ audio_head *phead;
+ audio_node *node = NULL;
+ struct list_head *pfree;
+ struct list_head *curnode;
+
+ phead = (audio_head *)mem;
+ pfree = &(phead->free);
+ curnode = pfree->next;
+
+ if (curnode != pfree) {
+ node = THIS_AUDIO_NODE(curnode);
+ node->start = 0;
+ node->end = 0;
+ list_del(curnode);
+ }
+ return node;
}
-static int Init_In_Out_queue(int fragstotal,int fragsize)
+static inline void put_audio_usenode(unsigned int *mem, audio_node *node)
{
- int i;
+ audio_head *phead = (audio_head *)mem;
+ struct list_head *puse = &(phead->use);
+ struct list_head *curnode = &(node->list);
- /* recording */
- in_empty_queue.count = fragstotal;
- in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
- if (!in_dma_buf)
- goto all_mem_err;
- in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
- if (!in_dma_pbuf)
- goto all_mem_err;
- in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
- if (!in_dma_buf_data_count)
- goto all_mem_err;
- in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!in_empty_queue.id)
- goto all_mem_err;
- in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!in_full_queue.id)
- goto all_mem_err;
- in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!in_busy_queue.id)
- goto all_mem_err;
-
- for (i=0;i < fragstotal;i++)
- *(in_empty_queue.id + i) = i;
- in_full_queue.count = 0;
- in_busy_queue.count = 0;
-
- for (i = 0; i < fragstotal; i++) {
- *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
- if (*(in_dma_buf + i) == 0)
- goto mem_failed_in;
- *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
- dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
- }
-
- /* playing */
- out_empty_queue.count = fragstotal;
- out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
- if (!out_dma_buf)
- goto all_mem_err;
- out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
- if (!out_dma_pbuf)
- goto all_mem_err;
- out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
-
- if (!out_dma_buf_data_count)
- goto all_mem_err;
- out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!out_empty_queue.id)
- goto all_mem_err;
- out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!out_full_queue.id)
- goto all_mem_err;
- out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
- if (!out_busy_queue.id)
- goto all_mem_err;
- for (i=0;i < fragstotal;i++)
- *(out_empty_queue.id + i) = i;
-
- out_busy_queue.count = 0;
- out_full_queue.count = 0;
- /* alloc DMA buffer */
- for (i = 0; i < fragstotal; i++) {
- *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
- if (*(out_dma_buf + i) == 0) {
- printk(" can't allocate required DMA(OUT) buffers.\n");
- goto mem_failed_out;
- }
- *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
- }
-
- return 1;
-all_mem_err:
- printk("error:allocate memory occur error 1!\n");
- return 0;
-mem_failed_out:
- printk("error:allocate memory occur error 2!\n");
- for (i = 0; i < fragstotal; i++) {
- if(*(out_dma_buf + i))
- free_pages(*(out_dma_buf + i), get_order(fragsize));
+ list_add_tail(curnode, puse);
+}
+
+static inline audio_node *get_audio_usenode(unsigned int *mem)
+{
+ audio_head *phead;
+ audio_node *node = NULL;
+ struct list_head *curnode;
+ struct list_head *puse;
+
+ phead = (audio_head *)mem;
+ puse = &(phead->use);
+ curnode = puse->next;
+
+ if (curnode != puse) {
+ node = THIS_AUDIO_NODE(curnode);
+ list_del(curnode);
}
+ return node;
+}
- return 0;
-mem_failed_in:
- printk("error:allocate memory occur error 3!\n");
- for (i = 0; i < fragstotal; i++) {
- if(*(in_dma_buf + i))
- free_pages(*(in_dma_buf + i), get_order(fragsize));
+static inline void put_audio_freenode(unsigned int *mem, audio_node *node)
+{
+ audio_head *phead = (audio_head *)mem;
+ struct list_head *pfree = &(phead->free);
+ struct list_head *curnode = &(node->list);
+
+ list_add_tail(curnode, pfree);
+}
+
+static inline int get_audio_freenodecount(unsigned int *mem)
+{
+ struct list_head *pfree;
+ struct list_head *plist;
+ audio_head *phead;
+ int count = 0;
+
+ phead = (audio_head *)mem;
+ pfree = &(phead->free);
+ plist = pfree;
+ while (plist->next != pfree) {
+ count++;
+ plist = plist->next;
}
- return 0;
+ return count;
}
-static int Free_In_Out_queue(int fragstotal,int fragsize)
+//--------------------------------------------------------------------
+// end audio node operater
+//--------------------------------------------------------------------
+
+//--------------------------------------------------------------------
+// static irqreturn_t jz_i2s_dma_irq (int irq, void *dev_id)
+// int init_audio_recorddma(audio_pipe *endpoint)
+// int init_audio_replaydma(audio_pipe *endpoint)
+// int init_audio_audiodma(audio_pipe *endpoint, int mode)
+// void config_dma_trans_mode(spinlock_t lock, audio_dma_type* dma, int mode)
+// static inline int audio_trystart_dma_node(audio_dma_type* dma, audio_node *node)
+// static inline int audio_trystart_dma_node(audio_dma_type* dma, audio_node *node)
+// static inline void audio_stop_dma_node(audio_dma_type* dma)
+
+static irqreturn_t jz_i2s_dma_irq (int irq, void *dev_id)
{
- int i;
- /* playing */
- if(out_dma_buf != NULL) {
- for (i = 0; i < fragstotal; i++) {
- if(*(out_dma_buf + i))
- free_pages(*(out_dma_buf + i), get_order(fragsize));
- *(out_dma_buf + i) = 0;
- }
- kfree(out_dma_buf);
- out_dma_buf = NULL;
- }
- if(out_dma_pbuf) {
- kfree(out_dma_pbuf);
- out_dma_pbuf = NULL;
- }
- if(out_dma_buf_data_count) {
- kfree(out_dma_buf_data_count);
- out_dma_buf_data_count = NULL;
- }
- if(out_empty_queue.id) {
- kfree(out_empty_queue.id);
- out_empty_queue.id = NULL;
- }
- if(out_full_queue.id) {
- kfree(out_full_queue.id);
- out_full_queue.id = NULL;
- }
- if(out_busy_queue.id) {
- kfree(out_busy_queue.id);
- out_busy_queue.id = NULL;
- }
- out_empty_queue.count = fragstotal;
- out_busy_queue.count = 0;
- out_full_queue.count = 0;
-
- /* recording */
- if(in_dma_buf) {
- for (i = 0; i < fragstotal; i++) {
- if(*(in_dma_buf + i)) {
- dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
- free_pages(*(in_dma_buf + i), get_order(fragsize));
- }
- *(in_dma_buf + i) = 0;
- }
- kfree(in_dma_buf);
- in_dma_buf = NULL;
+ audio_pipe * endpoint = (audio_pipe *) dev_id;
+ int dma_chan = endpoint->dma.ch;
+ int dma_state = REG_DMAC_DCCSR(dma_chan);
+ int err = 0;
+
+ ENTER();
+
+ REG_DMAC_DCCSR(dma_chan) = 0;
+
+ DPRINT_IRQ("!!!! endpoint direct = %s \n",(endpoint == &out_endpoint) ? "out" : "in");
+
+ if (dma_state & DMAC_DCCSR_HLT) {
+ err = 0;
+ DPRINT_IRQ("!!!! DMA HALT\n");
+ }
+ if (dma_state & DMAC_DCCSR_AR) {
+ err = 1;
+ DPRINT_IRQ("!!!! DMA ADDR ERROR\n");
+ }
+ if (dma_state & DMAC_DCCSR_INV) {
+ err = 1;
+ DPRINT_IRQ("!!!! DMA descriptor invalid\n");
+ }
+ if (dma_state & DMAC_DCCSR_CT) {
+ DPRINT_IRQ("!!!! DMA descriptor finish\n");
+ }
+ /*
+ if (dma_state & DMA_DCCSR_TT) {
+
}
- if(in_dma_pbuf) {
- kfree(in_dma_pbuf);
- in_dma_pbuf = NULL;
+ */
+ if (err == 0) {
+ //printk("schedule_work++++ %x %x\n", endpoint,&(endpoint->work));
+ //schedule_work(&(endpoint->work));
+ //printk("schedule_work----\n");
+ endpoint->handle(endpoint);
+ } else {
+ DPRINT_IRQ("!!!! ??? unknown !!!\n");
}
- if(in_dma_buf_data_count) {
- kfree(in_dma_buf_data_count);
- in_dma_buf_data_count = NULL;
+
+ LEAVE();
+
+ return IRQ_HANDLED;
+}
+
+int init_audio_recorddma(audio_pipe *endpoint)
+{
+ int ch = 0;
+
+ ENTER();
+ if ((ch = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_dma_irq, IRQF_DISABLED, endpoint)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", __FUNCTION__);
+ return -1;
}
- if(in_empty_queue.id) {
- kfree(in_empty_queue.id);
- in_empty_queue.id = NULL;
+ REG_DMAC_DMACR(ch / HALF_DMA_NUM) = 1;
+ REG_DMAC_DCMD(ch) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_TIE;
+ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AICIN;
+ REG_DMAC_DSAR(ch) = (unsigned int)CPHYSADDR(AIC_DR);
+
+ endpoint->dma.ch = ch;
+ endpoint->dma.trans_addr = (unsigned int *)DMAC_DTAR(ch);
+ endpoint->dma.trans_count = (unsigned int *)DMAC_DTCR(ch);
+ endpoint->dma.trans_mode = (unsigned int *)DMAC_DCMD(ch);
+ endpoint->dma.data_addr = (unsigned int *)DMAC_DSAR(ch);
+
+ endpoint->dma.rw = 0;
+
+ LEAVE();
+ return ch;
+}
+
+int init_audio_replaydma(audio_pipe *endpoint)
+{
+ int ch = 0;
+ if ((ch = jz_request_dma(DMA_ID_I2S_TX,"audio dac", jz_i2s_dma_irq, IRQF_DISABLED, endpoint)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", __FUNCTION__);
+ return -1;
}
- if(in_full_queue.id) {
- kfree(in_full_queue.id);
- in_full_queue.id = NULL;
+ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI | DMAC_DCMD_DWDH_32 | DMAC_DCMD_TIE;
+ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AICOUT;
+ REG_DMAC_DTAR(ch) = (unsigned int)CPHYSADDR(AIC_DR);
+
+ endpoint->dma.ch = ch;
+ endpoint->dma.trans_addr = (unsigned int *)DMAC_DSAR(ch);
+ endpoint->dma.trans_count = (unsigned int *)DMAC_DTCR(ch);
+ endpoint->dma.trans_mode = (unsigned int *)DMAC_DCMD(ch);
+ endpoint->dma.data_addr = (unsigned int *)DMAC_DTAR(ch);
+ endpoint->dma.rw = 1;
+ return ch;
+}
+
+int init_audio_audiodma(audio_pipe *endpoint, int mode)
+{
+ if (mode == CODEC_RMODE) {
+ return init_audio_recorddma(endpoint);
}
- if(in_busy_queue.id) {
- kfree(in_busy_queue.id);
- in_busy_queue.id = NULL;
+
+ if (mode == CODEC_WMODE) {
+ return init_audio_replaydma(endpoint);
}
- in_empty_queue.count = fragstotal;
- in_full_queue.count = 0;
- in_busy_queue.count = 0;
-
- return 1;
+ return -1;
}
-static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+void config_dma_trans_mode(spinlock_t lock, audio_dma_type* dma, int sound_data_width)
{
- jz_i2s_initHw(0);
-}
+ unsigned int curmode;
+ unsigned long flags;
-static int jz_audio_set_speed(int dev, int rate)
-{
- /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
- jz_audio_speed = rate;
-#if defined(CONFIG_I2S_DLV)
- if (rate > 96000)
- rate = 96000;
-#else
- if (rate > 48000)
- rate = 48000;
-#endif
- if (rate < 8000)
- rate = 8000;
- jz_audio_rate = rate;
+ ENTER();
+ AUDIO_LOCK(lock, flags);
+ curmode = *dma->trans_mode;
- if(set_codec_speed)
- set_codec_speed(rate);
+ if (dma->rw) {
+ curmode &= ~(DMAC_DCMD_DWDH_MASK | DMAC_DCMD_DS_MASK);
+ switch(sound_data_width) {
+ case 8:
+ *dma->trans_mode = (curmode | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE);
+ dma->onetrans_bit = 16 * 8;
+ break;
+ case 16:
+ *dma->trans_mode = (curmode | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE);
+ dma->onetrans_bit = 16 * 8;
+ break;
+ case 17 ... 32:
+ *dma->trans_mode = (curmode | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE);
+ dma->onetrans_bit = 32 * 8;
+ break;
+ default:
+ printk("JZ I2S: Unkown DMA mode(sound data width) %d\n", sound_data_width);
+ break;
+ }
+ } else {
+ curmode &= ~(DMAC_DCMD_SWDH_MASK | DMAC_DCMD_DS_MASK);
+ switch(sound_data_width) {
+ case 8:
+ *dma->trans_mode = (curmode | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DS_16BYTE);
+ dma->onetrans_bit = 16 * 8;
+ break;
+ case 16:
+ *dma->trans_mode = (curmode | DMAC_DCMD_SWDH_16 | DMAC_DCMD_DS_16BYTE);
+ dma->onetrans_bit = 16 * 8;
+ break;
+ case 17 ... 32:
+ *dma->trans_mode = (curmode | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BYTE);
+ dma->onetrans_bit = 32 * 8;
+ break;
+ default:
+ printk("JZ I2S: Unkown DMA mode(sound data width) %d\n", sound_data_width);
+ break;
+ }
+ }
- return jz_audio_rate;
+ AUDIO_UNLOCK(lock, flags);
+ DUMP_DMA(dma->ch, __FUNCTION__);
+ DPRINT_DMA("dma_trans = %d\n", dma->onetrans_bit);
+ LEAVE();
}
-
-static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+#define aic_enable_transmit() \
+do { \
+ int dat = REG_AIC_CR; \
+ dat |= (AIC_CR_TDMS | AIC_CR_ERPL); \
+ REG_AIC_CR = dat; \
+} while (0)
+
+#define aic_disable_transmit() \
+do { \
+ int dat = REG_AIC_CR; \
+ dat &= ~(AIC_CR_TDMS | AIC_CR_ERPL); \
+ REG_AIC_CR = dat; \
+} while (0)
+
+static inline int audio_trystart_dma_node(audio_dma_type* dma, audio_node *node)
{
- int cnt = 0;
- unsigned long data;
- volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
- volatile unsigned char *dp = (unsigned char*)dst_start;
+ int start = 0;
+
+ ENTER();
- while (count > 0) {
- count -= 2; /* count in dword */
- cnt++;
- data = *(s++);
- *(dp ++) = ((data << 16) >> 24) + 0x80;
- s++; /* skip the other channel */
+ if ((REG_DMAC_DCCSR(dma->ch) & DMAC_DCCSR_EN) == 0) {
+ int count = node->end - node->start;
+ *(dma->trans_addr) = node->phyaddr;
+ *(dma->data_addr) = (unsigned int)CPHYSADDR(AIC_DR);
+ *(dma->trans_count) = count * 8 / dma->onetrans_bit;
+ REG_DMAC_DCCSR(dma->ch) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ DUMP_DMA(dma->ch, __FUNCTION__);
+ DPRINT_DMA("virt = 0x%08x phy = 0x%08x, dma->onetrans_bit = 0x%x\n",
+ node->pBuf, node->phyaddr, dma->onetrans_bit);
+
+ DUMP_CODEC_REGS(__FUNCTION__);
+
+ DUMP_AIC_REGS(__FUNCTION__);
+ start = 1;
}
- return cnt;
+ LEAVE();
+ return start;
}
+static inline void audio_stop_dma_node(audio_dma_type* dma)
+{
+ REG_DMAC_DCCSR(dma->ch) = 0;
+}
-static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+/* Never be used, fix me ???
+static inline int recalculate_fifowidth(short channels, short fmt)
{
- int cnt = 0;
- unsigned long d1, d2;
- volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
- volatile unsigned char *dp = (unsigned char*)dst_start;
-
- while (count > 0) {
- count -= 2;
- cnt += 2;
- d1 = *(s++);
- *(dp ++) = ((d1 << 16) >> 24) + 0x80;
- d2 = *(s++);
- *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ int bit = 16;
+
+ if (fmt <= 8) {
+ bit = 8;
+ } else if (fmt > 16) {
+ bit = 32;
+ } else {
+ bit = 16;
}
-
- return cnt;
-}
+ return bit *= channels;
+}
+*/
+#define I2S_FIFO_DEPTH 32
-static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+static inline void set_controller_triger(struct jz_i2s_controller_info *controller,
+ audio_pipe *endpoint, short channels, short format)
{
- int cnt = 0;
- unsigned long d1;
- unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
- unsigned short *dp = (unsigned short *)dst_start;
-
- while (count > 0) {
- count -= 2; /* count in dword */
- cnt += 2; /* count in byte */
- d1 = *(s++);
- *(dp ++) = (d1 << 16) >> 16;
- s++; /* skip the other channel */
- }
+ int sound_data_width = 0;
- return cnt;
-}
+ ENTER();
+// printk("%%%% format = %d\n", format);
-static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
-{
- int cnt = 0;
- unsigned long d1, d2;
- unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
- unsigned short *dp = (unsigned short *)dst_start;
- while (count > 0) {
- count -= 2; /* count in dword */
- cnt += 4; /* count in byte */
- d1 = *(s++);
- d2 = *(s++);
- if(abnormal_data_count > 0) {
- d1 = d2 = 0;
- abnormal_data_count --;
+ switch (format) {
+ case AFMT_U8:
+ case AFMT_S8:
+ sound_data_width = 8;
+ break;
+ case AFMT_S16_LE:
+ case AFMT_S16_BE:
+ sound_data_width = 16;
+ break;
+ default:
+ printk("JZ I2S: Unkown sound format %d\n", format);
+ return ;
}
- *(dp ++) = (d1 << 16) >> 16;
- *(dp ++) = (d2 << 16) >> 16;
- }
- return cnt;
+ config_dma_trans_mode(endpoint->lock,&(endpoint->dma), sound_data_width);
+ if (endpoint == &out_endpoint) {
+ if ((I2S_FIFO_DEPTH - endpoint->dma.onetrans_bit / sound_data_width) >= 30) {
+ __i2s_set_transmit_trigger(14);
+ } else {
+ __i2s_set_transmit_trigger((I2S_FIFO_DEPTH - endpoint->dma.onetrans_bit / sound_data_width) / 2);
+ }
+ }
+ if (endpoint == &in_endpoint) {
+ __i2s_set_receive_trigger((endpoint->dma.onetrans_bit / sound_data_width) / 2);
+ }
+
+ LEAVE();
}
-static void replay_fill_1x8_u(signed long src_start, int count, int id)
+//-------------------------------------------------------------------
+/*
+ int trystart_endpoint_out(audio_pipe *endpoint, audio_node *node);
+ int trystart_endpoint_in(audio_pipe *endpoint, audio_node *node);
+ note: this two function isn't protected;
+ */
+static inline int trystart_endpoint_out(struct jz_i2s_controller_info *controller, audio_node *node)
{
- int cnt = 0;
- unsigned char data;
- unsigned long ddata;
- volatile unsigned char *s = (unsigned char *)src_start;
- volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+ audio_pipe *endpoint = controller->pout_endpoint;
+ int start = 0;
+
+ ENTER();
+ start = audio_trystart_dma_node(&(endpoint->dma), node);
+ if (start) {
+ endpoint->trans_state |= PIPE_TRANS;
+ endpoint->savenode = node;
+ aic_enable_transmit();
+ DUMP_AIC_REGS(__FUNCTION__);
+ DUMP_CODEC_REGS(__FUNCTION__);
+ }
- while (count > 0) {
- count--;
- cnt += 1;
- data = *(s++) - 0x80;
- ddata = (unsigned long) data << 8;
- *(dp ++) = ddata;
- *(dp ++) = ddata;
+ LEAVE();
+ return start;
+}
- /* save last left and right */
- if(count == 1) {
- save_last_samples[id].left = ddata;
- save_last_samples[id].right = ddata;
- }
+static inline int trystart_endpoint_in(struct jz_i2s_controller_info *controller, audio_node *node)
+{
+ audio_pipe *endpoint = controller->pin_endpoint;
+ int start = 0;
+
+ ENTER();
+ dma_cache_wback_inv((unsigned long)node->pBuf, endpoint->fragsize);
+ start = audio_trystart_dma_node(&(endpoint->dma), node);
+ if (start) {
+ endpoint->trans_state |= PIPE_TRANS;
+ endpoint->savenode = node;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ DUMP_AIC_REGS(__FUNCTION__);
+ DUMP_CODEC_REGS(__FUNCTION__);
}
- cnt = cnt * 2 * jz_audio_b;
- *(out_dma_buf_data_count + id) = cnt;
+ LEAVE();
+ return start;
}
+int audio_get_endpoint_freesize(audio_pipe *endpoint, audio_buf_info *info)
+{
+ int count;
+ unsigned long flags;
-static void replay_fill_2x8_u(signed long src_start, int count, int id)
+ AUDIO_LOCK(endpoint->lock, flags);
+ count = get_audio_freenodecount(endpoint->mem);
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ info->fragments = count;
+ info->fragstotal = endpoint->fragstotal;
+ info->fragsize = endpoint->fragsize;
+ info->bytes = count * endpoint->fragsize;
+ return info->bytes;
+}
+
+void audio_clear_endpoint(audio_pipe *endpoint)
{
- int cnt = 0;
- unsigned char d1;
- unsigned long dd1;
- volatile unsigned char *s = (unsigned char *)src_start;
- volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+ audio_node *pusenode;
+ unsigned long flags;
- while (count > 0) {
- count -= 1;
- cnt += 1 ;
- d1 = *(s++) - 0x80;
- dd1 = (unsigned long) d1 << 8;
- *(dp ++) = dd1;
- /* save last left */
- if(count == 2)
- save_last_samples[id].left = dd1;
- /* save last right */
- if(count == 1)
- save_last_samples[id].right = dd1;
+ ENTER();
+ AUDIO_LOCK(endpoint->lock, flags);
+ while (!is_null_use_audio_node(endpoint->mem)) {
+ pusenode = get_audio_usenode(endpoint->mem);
+ if (pusenode) {
+ put_audio_freenode(endpoint->mem, pusenode);
+ }
}
- cnt *= jz_audio_b;
- *(out_dma_buf_data_count + id) = cnt;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ LEAVE();
}
-
-static void replay_fill_1x16_s(signed long src_start, int count, int id)
+void audio_sync_endpoint(audio_pipe *endpoint)
{
- int cnt = 0;
- signed short d1;
- signed long l1;
- volatile signed short *s = (signed short *)src_start;
- volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
-
- while (count > 0) {
- count -= 2;
- cnt += 2 ;
- d1 = *(s++);
- l1 = (signed long)d1;
-#if defined(CONFIG_I2S_ICODEC)
- l1 >>= codec_volue_shift;
-#endif
- *(dp ++) = l1;
- *(dp ++) = l1;
+ int isnull = 1;
+ unsigned long flags;
+
+ ENTER();
- /* save last left and right */
- if(count == 1) {
- save_last_samples[id].left = l1;
- save_last_samples[id].right = l1;
+ do {
+ AUDIO_LOCK(endpoint->lock, flags);
+ isnull = is_null_use_audio_node(endpoint->mem);
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ if (!isnull) {
+ //printk("&&&& audio_sync_endpoint\n");
+ schedule_timeout(1);
}
- }
- cnt = cnt * 2 * jz_audio_b;
- *(out_dma_buf_data_count + id) = cnt;
+ } while (!isnull);
+
+ LEAVE();
}
-static void replay_fill_2x16_s(signed long src_start, int count, int id)
+void audio_close_endpoint(audio_pipe *endpoint, int mode)
{
- int cnt = 0;
- signed short d1;
- signed long l1;
- volatile signed short *s = (signed short *)src_start;
- volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
-#if defined(CONFIG_I2S_ICODEC)
- int mute_cnt = 0;
- signed long tmp1,tmp2;
- volatile signed long *before_dp;
- int sam_rate = jz_audio_rate / 20;
+ int is_use_list_null = 1, trans = 0;
+ unsigned long flags;
- tmp1 = tmp2 = 0;
- while (count > 0) {
- count -= 2;
- cnt += 2;
- d1 = *(s++);
-
- l1 = (signed long)d1;
- l1 >>= codec_volue_shift;
-
- if(l1 == 0) {
- mute_cnt ++;
- if(mute_cnt >= sam_rate) {
- before_dp = dp - 10;
- *(before_dp) = (signed long)1;
- before_dp = dp - 11;
- *(before_dp) = (signed long)1;
- mute_cnt = 0;
+ ENTER();
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ is_use_list_null = is_null_use_audio_node(endpoint->mem);
+ trans = endpoint->trans_state & PIPE_TRANS;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ if (is_use_list_null) {
+ // Wait savenode trans complete
+ while (trans) {
+ AUDIO_LOCK(endpoint->lock, flags);
+ trans = endpoint->trans_state & PIPE_TRANS;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ DPRINT("waiting savenode\n");
+ if (trans) {
+ schedule_timeout(10);
}
- } else
- mute_cnt = 0;
+ }
- *(dp ++) = l1;
-
- tmp1 = tmp2;
- tmp2 = l1;
- }
-
- /* save last left */
- save_last_samples[id].left = tmp1;
- /* save last right */
- save_last_samples[id].right = tmp2;
-#endif
-#if defined(CONFIG_I2S_DLV)
- while (count > 0) {
- count -= 2;
- cnt += 2;
- d1 = *(s++);
-
- l1 = (signed long)d1;
-
- *(dp ++) = l1;
+ /* In replay mode, savenode must been put into free list after trans completed,
+ * so we don't care it in this condition.
+ * But in record mode, savenode must been put into use list after trans completed,
+ * so we have to ignore the incomming data and move it to free list forcely.
+ */
+ if (endpoint == &out_endpoint) {
+ goto _L_AUDIO_CLOSE_EP_RET;
+ }
}
-#endif
- cnt *= jz_audio_b;
- *(out_dma_buf_data_count + id) = cnt;
+
+ // NOMAL_STOP routine of replay mode
+ if (mode == NOMAL_STOP) {
+ BUG_ON(endpoint != &out_endpoint);
+
+ // Wait use list free
+ audio_sync_endpoint(endpoint);
+ // wait savenode trans finish
+ while (trans) {
+ AUDIO_LOCK(endpoint->lock, flags);
+ trans = endpoint->trans_state & PIPE_TRANS;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ //printk("waiting savenode\n");
+ if (trans) {
+ schedule_timeout(10);
+ }
+ }
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ } else {
+ // FORCE_STOP routine, both replay and record mode could run
+ audio_node *pusenode;
+
+ // Shutdown DMA immediately and clear lists forcely.
+ AUDIO_LOCK(endpoint->lock, flags);
+
+ endpoint->trans_state &= ~PIPE_TRANS;
+ audio_stop_dma_node(&endpoint->dma);
+
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ DPRINT_Q("---------------------------------\n");
+
+ while (!is_null_use_audio_node(endpoint->mem)) {
+ pusenode = get_audio_usenode(endpoint->mem);
+ if (pusenode) {
+ put_audio_freenode(endpoint->mem, pusenode);
+ }
+ }
+
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ DPRINT_Q("---------------------------------\n");
+
+ if (endpoint->savenode) {
+ DPRINT_Q("handle savenode : 0x%08x\n", (unsigned int)endpoint->savenode);
+ DUMP_NODE(endpoint->savenode, "SN");
+ put_audio_freenode(endpoint->mem, endpoint->savenode);
+
+ DPRINT_Q("savenode->list->next = 0x%08x, savenode->list->prev = 0x%08x\n",
+ (unsigned int)endpoint->savenode->list.next,
+ (unsigned int)endpoint->savenode->list.prev);
+
+ endpoint->savenode = NULL;
+ }
+
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ }
+
+_L_AUDIO_CLOSE_EP_RET:
+ LEAVE();
}
-static void replay_fill_2x18_s(signed long src_start, int count, int id)
+int audio_resizemem_endpoint(audio_pipe *endpoint, unsigned int pagesize, unsigned int count)
{
- int cnt = 0;
- signed long d1;
- signed long l1;
- volatile signed long *s = (signed long *)src_start;
- volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
- while (count > 0) {
- count -= 4;
- cnt += 4;
- d1 = *(s++);
- l1 = (signed long)d1;
- *(dp ++) = l1;
+ int ret = init_audio_node(&endpoint->mem, pagesize, count);
+ if (!ret) {
+ endpoint->fragsize = pagesize;
+ endpoint->fragstotal = count;
}
-
- cnt *= jz_audio_b;
- *(out_dma_buf_data_count + id) = cnt;
+ return ret;
}
-static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+static void handle_in_endpoint_work(audio_pipe *endpoint)
{
- switch (fmt) {
- case AFMT_U8:
- __i2s_set_oss_sample_size(8);
- __i2s_set_iss_sample_size(8);
- jz_audio_format = fmt;
- jz_update_filler(jz_audio_format,jz_audio_channels);
- break;
- case AFMT_S16_LE:
-#if defined(CONFIG_I2S_DLV)
- /* DAC path and ADC path */
- write_codec_file(2, 0x00);
- //write_codec_file(2, 0x60);
-#endif
- jz_audio_format = fmt;
- jz_update_filler(jz_audio_format,jz_audio_channels);
- __i2s_set_oss_sample_size(16);
- __i2s_set_iss_sample_size(16);
- break;
- case 18:
- __i2s_set_oss_sample_size(18);
- jz_audio_format = fmt;
- jz_update_filler(jz_audio_format,jz_audio_channels);
- break;
- case AFMT_QUERY:
- break;
+ audio_node *node;
+ unsigned long flags;
+
+ ENTER();
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ if (endpoint->savenode) {
+ DPRINT_Q("\nIIII RRRR QQQQ >>>>\n");
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "IRQSN");
+ DPRINT_Q("IIII RRRR QQQQ <<<<\n\n");
+
+ DPRINT_IRQ("%s endpoint->savenode = 0x%p\n", __FUNCTION__, endpoint->savenode);
+ put_audio_usenode(endpoint->mem, endpoint->savenode);
+
+ endpoint->savenode = NULL;
+ DUMP_BUF((char *)(endpoint->savenode->pBuf + endpoint->savenode->start), 64, 32);
+
+ if (!(endpoint->is_non_block)) {
+ endpoint->avialable_couter++;
+ wake_up_interruptible(&endpoint->q_full);
+ }
+ }
+
+ node = get_audio_freenode(endpoint->mem);
+ if (node) {
+ int start;
+ node->end = endpoint->fragsize;
+ dma_cache_wback_inv((unsigned long)node->pBuf, endpoint->fragsize);
+ start = audio_trystart_dma_node(&(endpoint->dma), node);
+ if (start == 0) {
+ put_audio_freenode(endpoint->mem, node);
+ } else {
+ endpoint->savenode = node;
+ }
+ } else {
+ endpoint->trans_state &= ~PIPE_TRANS;
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ DPRINT_IRQ("!!!! Stop AIC record !\n");
}
- return jz_audio_format;
+ DPRINT_Q("\nIIII RRRR QQQQ >>>>\n");
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ DPRINT_Q("IIII RRRR QQQQ <<<<\n\n");
+
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ LEAVE();
}
+/*
+static void audio_in_endpoint_work(struct work_struct *work)
+{
+ audio_pipe *endpoint = &in_endpoint;
+ handle_in_endpoint_work(endpoint);
+}
+*/
-static short jz_audio_set_channels(int dev, short channels)
+static void handle_out_endpoint_work(audio_pipe *endpoint)
{
- switch (channels) {
- case 1:
- if(set_codec_some_func)
- set_codec_some_func();
- jz_audio_channels = channels;
- jz_update_filler(jz_audio_format, jz_audio_channels);
-#if defined(CONFIG_I2S_DLV)
- write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
-#endif
- break;
- case 2:
- jz_audio_channels = channels;
- jz_update_filler(jz_audio_format, jz_audio_channels);
-#if defined(CONFIG_I2S_DLV)
- write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
-#endif
- break;
- case 0:
- break;
+ audio_node *node;
+ unsigned long flags;
+
+ ENTER();
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ DPRINT_IRQ("%s endpoint->savenode = 0x%08x\n", __FUNCTION__, (unsigned int)endpoint->savenode);
+
+ if (endpoint->savenode) {
+ put_audio_freenode(endpoint->mem, endpoint->savenode);
+ DPRINT_IRQ("put_audio_freenode\n");
+ endpoint->savenode = NULL;
+
+ if (!(endpoint->is_non_block)) {
+ wake_up_interruptible(&endpoint->q_full);
+ endpoint->avialable_couter++;
+ }
+ }
+
+ node = get_audio_usenode(endpoint->mem);
+ if (node) {
+ int start;
+ start = audio_trystart_dma_node(&(endpoint->dma), node);
+ if (start == 0) {
+ printk("audio_out_endpoint_work audio_trystart_dma_node error!\n");
+ } else {
+ endpoint->savenode = node;
+ DPRINT_DMA("restart dma!\n");
+ }
+ } else {
+ endpoint->trans_state &= ~PIPE_TRANS;
+ aic_disable_transmit();
+ DPRINT_IRQ("!!!! Stop AIC !\n");
}
- return jz_audio_channels;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ LEAVE();
}
-static void init_codec(void)
+/*
+static void audio_out_endpoint_work(struct work_struct *work)
{
- /* inititalize internal I2S codec */
- if(init_codec_pin)
- init_codec_pin();
+ audio_pipe *endpoint = &out_endpoint;
+ handle_out_endpoint_work(endpoint);
+}
+*/
-#if defined(CONFIG_I2S_ICDC)
- /* initialize AIC but not reset it */
- jz_i2s_initHw(0);
-#endif
- if(reset_codec)
- reset_codec();
+void audio_init_endpoint(audio_pipe *endpoint, unsigned int pagesize, unsigned int count)
+{
+ audio_resizemem_endpoint(endpoint, pagesize, count);
+ spin_lock_init(&endpoint->lock);
+ init_waitqueue_head(&endpoint->q_full);
+ endpoint->avialable_couter = 0;
+ endpoint->filter = NULL;
+
+ if (endpoint == &in_endpoint) {
+ init_audio_audiodma(endpoint, CODEC_RMODE);
+ // INIT_WORK(&endpoint->work, audio_in_endpoint_work);
+ endpoint->handle = handle_in_endpoint_work;
+ }
+ if (endpoint == &out_endpoint) {
+ init_audio_audiodma(endpoint, CODEC_WMODE);
+ // INIT_WORK(&endpoint->work, audio_out_endpoint_work);
+ endpoint->handle = handle_out_endpoint_work;
+ }
}
-static void jz_audio_reset(void)
+void audio_deinit_endpoint(audio_pipe *endpoint)
{
- __i2s_disable_replay();
- __i2s_disable_receive_dma();
- __i2s_disable_record();
- __i2s_disable_transmit_dma();
-#if defined(CONFIG_I2S_DLV)
- REG_AIC_I2SCR = 0x10;
-#endif
- init_codec();
+ audio_close_endpoint(endpoint, FORCE_STOP);
+ deinit_audio_node(&endpoint->mem);
}
-static int jz_audio_release(struct inode *inode, struct file *file);
-static int jz_audio_open(struct inode *inode, struct file *file);
-static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
-static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
-static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
-static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+void register_jz_codecs(void *func)
+{
+ int i;
-/* static struct file_operations jz_i2s_audio_fops */
-static struct file_operations jz_i2s_audio_fops =
-{
- owner: THIS_MODULE,
- open: jz_audio_open,
- release: jz_audio_release,
- write: jz_audio_write,
- read: jz_audio_read,
- poll: jz_audio_poll,
- ioctl: jz_audio_ioctl
-};
+ ENTER();
+
+ for (i = 0; i < NR_I2S; i++) {
+ if (the_codecs[i].codecs_ioctrl == 0) {
+ printk("register codec %x\n",(unsigned int)func);
+ the_codecs[i].id = i;
+ the_codecs[i].codecs_ioctrl = func;
+ init_MUTEX(&(the_codecs[i].i2s_sem));
+ break;
+ }
+ }
+
+ LEAVE();
+}
+
+#define codec_ioctrl(codec, cmd, args) ({ \
+ int result; \
+ down(&(codec)->i2s_sem); \
+ result = (codec)->codecs_ioctrl((codec), (cmd), (args));\
+ up(&(codec)->i2s_sem); \
+ result; \
+})
static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
{
int i;
int minor = MINOR(inode->i_rdev);
- struct jz_i2s_controller_info *controller = i2s_controller;
- for (i = 0; i < NR_I2S; i++)
- if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ ENTER();
+
+ for (i = 0; i < NR_I2S; i++) {
+ if (the_codecs[i].dev_mixer == minor) {
goto match;
-
- if (!controller)
- return -ENODEV;
+ }
+ }
match:
- file->private_data = controller->i2s_codec[i];
+ file->private_data = &the_codecs[i];
+ LEAVE();
return 0;
}
-static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+/*
+ * Debug entry for Android
+ */
+static int jz_i2s_write_mixdev(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
- return codec->mixer_ioctl(codec, cmd, arg);
-}
+ char buf_byte = 0;
+ char argument[16];
+ int val;
+
-static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
+ if (copy_from_user((void *)&buf_byte, buffer, 1)) {
+ printk("JZ MIX: copy_from_user failed !\n");
+ return -EFAULT;
+ }
+
+ switch (buf_byte) {
+ case '1':
+ dump_dlv_regs("jz_i2s_write_mixdev --- debug routine");
+ break;
+ case '2':
+ printk("dlv_set_replay\n");
+ codec_ioctrl(codec, CODEC_SET_REPLAY, 0);
+ break;
+ case '3':
+ printk("dlv_set_record\n");
+ codec_ioctrl(codec, CODEC_SET_RECORD, 0);
+ break;
+ case '4':
+ if (codec_ioctrl(codec, CODEC_SET_RECORD_DATA_WIDTH, 16) >= 0) {
+ printk("Set data width : 16\n");
+ } else {
+ printk("Could not set data width\n");
+ }
+ break;
+ case '5':
+ if (copy_from_user((void *)&argument, buffer + 1, 3)) {
+ printk("JZ MIX: copy_from_user failed !\n");
+ return -EFAULT;
+ }
+ if (argument[0] >= '0' && argument[0] <= '9'
+ && argument [1] >= '0' && argument[1] <= '9'
+ && argument [2] >= '0' && argument[2] <= '9') {
+
+ val = (argument[0] - '0') * 100 + (argument[1] - '0') * 10 + argument[2] - '0';
+
+ printk("JZ MIX: set volume (%d)\n", val);
+ codec_ioctrl(codec, CODEC_SET_VOLUME, val);
+ } else {
+ printk("JZ MIX: invalid argument for set volume\n");
+ }
+ break;
+ }
+
+ return count;
}
-static struct file_operations jz_i2s_mixer_fops =
+/*
+ * Handle IOCTL request on /dev/mixer
+ *
+ * Support OSS IOCTL interfaces for /dev/mixer
+ * Support IOCTL interfaces for /dev/mixer defined in include/msm_audio.h
+ */
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- owner: THIS_MODULE,
- llseek: jz_i2s_llseek,
- ioctl: jz_i2s_ioctl_mixdev,
- open: jz_i2s_open_mixdev,
-};
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ long val = 0;
+ int ret, rc = 0;
+
+ ENTER();
+
+ DPRINT_IOC("[mixer IOCTL]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ DPRINT_IOC(" mixer IOCTL %s cmd = 0x%08x, arg = %lu\n", __FUNCTION__, cmd, arg);
+ DPRINT_MIXER_IOC_CMD(cmd);
+ DPRINT_IOC("[mixer IOCTL]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+ // struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
-static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
-{
- int ret;
- long val = 0;
switch (cmd) {
- case SOUND_MIXER_INFO:
- if(codec_mixer_info_id_name)
- codec_mixer_info_id_name();
+ /*
+ * OSS IOCTL commands for /dev/mixer
+ */
+ case SOUND_MIXER_INFO:
+ {
+ mixer_info info;
+ codec_ioctrl(codec, CODEC_GET_MIXER_INFO, (unsigned int)&info);
info.modify_counter = audio_mix_modcnt;
-
return copy_to_user((void *)arg, &info, sizeof(info));
+ }
case SOUND_OLD_MIXER_INFO:
+ {
+ _old_mixer_info info;
+ codec_ioctrl(codec, CODEC_GET_MIXER_OLD_INFO, (unsigned int)&info);
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ }
- if(codec_mixer_old_info_id_name)
- codec_mixer_old_info_id_name();
-
- return copy_to_user((void *)arg, &old_info, sizeof(info));
case SOUND_MIXER_READ_STEREODEVS:
-
return put_user(0, (long *) arg);
case SOUND_MIXER_READ_CAPS:
+ return put_user(SOUND_CAP_EXCL_INPUT, (long *) arg);
- val = SOUND_CAP_EXCL_INPUT;
- return put_user(val, (long *) arg);
case SOUND_MIXER_READ_DEVMASK:
break;
case SOUND_MIXER_READ_RECMASK:
break;
case SOUND_MIXER_READ_RECSRC:
break;
+
case SOUND_MIXER_WRITE_SPEAKER:
-
ret = get_user(val, (long *) arg);
- if (ret)
- return ret;
- val = val & 0xff;
- if(val < 0)
- val = 0;
- if(val > 100)
+ if ((val &= 0xff) >= 100) {
val = 100;
- switch(val) {
- case 100:
- if(set_codec_direct_mode)
- set_codec_direct_mode();
- break;
- case 0:
- if(clear_codec_direct_mode)
- clear_codec_direct_mode();
- break;
}
+ codec_ioctrl(codec, CODEC_SET_DIRECT_MODE, val);
break;
- case SOUND_MIXER_WRITE_BASS:
+ case SOUND_MIXER_WRITE_BASS:
ret = get_user(val, (long *) arg);
- if (ret)
- return ret;
-
- val = val & 0xff;
- if(val < 0)
- val = 0;
- if(val > 100)
+ if ((val &= 0xff) >= 100) {
val = 100;
- codec_bass_gain = val;
- if(set_codec_bass)
- set_codec_bass(val);
-
+ }
+ codec->bass_gain = val;
+ codec_ioctrl(codec, CODEC_SET_BASS, val);
return 0;
- case SOUND_MIXER_READ_BASS:
-
- val = codec_bass_gain;
+
+ case SOUND_MIXER_READ_BASS:
+ val = codec->bass_gain;
ret = val << 8;
- val = val | ret;
-
+ val = val | ret;
return put_user(val, (long *) arg);
+
case SOUND_MIXER_WRITE_VOLUME:
ret = get_user(val, (long *) arg);
- if (ret)
- return ret;
- val = val & 0xff;
- if(val < 0)
- val = 0;
- if(val > 100)
+ if ((val &= 0xff) >= 100) {
val = 100;
-
- jz_audio_volume = val;
- if(set_codec_volume)
- set_codec_volume(val);
-
+ }
+
+ DPRINT_IOC("SOUND_MIXER_WRITE_VOLUME <- %lu\n", val);
+
+ codec->audio_volume = val;
+ codec_ioctrl(codec, CODEC_SET_VOLUME, val);
return 0;
+
case SOUND_MIXER_READ_VOLUME:
-
- val = jz_audio_volume;
+ val = codec->audio_volume;
ret = val << 8;
val = val | ret;
-
return put_user(val, (long *) arg);
- case SOUND_MIXER_WRITE_MIC:
-
- ret = get_user(val, (long *) arg);
- if (ret)
- return ret;
-
- val = val & 0xff;
- if(val < 0)
- val = 0;
- if(val > 100)
- val = 100;
- codec_mic_gain = val;
- use_mic_line_flag = USE_MIC;
- if(set_codec_mic)
- set_codec_mic(val);
+ case SOUND_MIXER_WRITE_MIC:
+ ret = get_user(val, (long *) arg);
+ if ((val &= 0xff) >= 100) {
+ val = 100;
+ }
+ codec->mic_gain = val;
+ codec->use_mic_line_flag = USE_MIC;
+ codec_ioctrl(codec, CODEC_SET_MIC, val);
+ return 0;
- return 0;
- case SOUND_MIXER_READ_MIC:
-
- val = codec_mic_gain;
+ case SOUND_MIXER_READ_MIC:
+ val = codec->mic_gain;
ret = val << 8;
val = val | ret;
-
return put_user(val, (long *) arg);
-
+
case SOUND_MIXER_WRITE_LINE:
+ ret = get_user(val, (long *) arg);
+ if (ret) {
+ return ret;
+ }
+ if ((val &= 0xff) >= 100) {
+ val = 100;
+ }
+ codec->use_mic_line_flag = USE_LINEIN;
+ codec->mic_gain = val;
+ codec_ioctrl(codec, CODEC_SET_LINE, val);
+ return 0;
- ret = get_user(val, (long *) arg);
- if (ret)
- return ret;
-
- val = val & 0xff;
- if(val < 0)
- val = 0;
- if(val > 100)
- val = 100;
- use_mic_line_flag = USE_LINEIN;
- codec_mic_gain = val;
- if(set_codec_line)
- set_codec_line(val);
-
- return 0;
- case SOUND_MIXER_READ_LINE:
-
- val = codec_mic_gain;
+ case SOUND_MIXER_READ_LINE:
+ val = codec->mic_gain;
ret = val << 8;
val = val | ret;
-
return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_MUTE:
+ get_user(codec->audiomute, (long *)arg);
+ //codec_ioctrl(codec, CODEC_DAC_MUTE, codec->audiomute);
+ break;
+
+ case SOUND_MIXER_READ_MUTE:
+ put_user(codec->audiomute, (long *) arg);
+ break;
+
+#if 0
+ /*
+ * MSM IOCTL commands for /dev/mixer
+ */
+ case SND_SET_DEVICE:
+ {
+ struct snd_device_config dev;
+ if (copy_from_user(&dev, (void *) arg, sizeof(dev))) {
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case SND_SET_VOLUME:
+ {
+ struct snd_volume_config vol;
+ if (copy_from_user(&vol, (void *) arg, sizeof(vol))) {
+ return -EFAULT;
+ }
+ val = vol.volume;
+ if ((val &= 0xff) >= 100) {
+ val = 100;
+ }
+ DPRINT_IOC("snd_set_volume %d %d %d\n", vol.device, vol.method, vol.volume);
+ codec->audio_volume = val;
+ codec_ioctrl(codec, CODEC_SET_MIC, (unsigned int)&val); ///??????????????????????????
+ //error
+ break;
+ }
+
+ case SND_GET_NUM_ENDPOINTS:
+ if (copy_to_user((void __user*) arg, &snd->snd_epts->num, sizeof(unsigned))) {
+ printk("%s: error get endpoint\n",__FUNCTION__);
+ rc = -EFAULT;
+ }
+ val = 2;
+ if (copy_to_user((void __user*) arg, &val, sizeof(unsigned))) {
+ printk("%s: error get endpoint\n",__FUNCTION__);
+ rc = -EFAULT;
+ }
+
+ break;
+ case SND_GET_ENDPOINT:
+ //rc = get_endpoint(snd, arg);
+ break;
+#endif
+
default:
+ printk("Mixer IOCTL error: %s:%d: known command: 0x%08x\n", __FUNCTION__, __LINE__, cmd);
return -ENOSYS;
}
- audio_mix_modcnt ++;
- return 0;
+ audio_mix_modcnt++;
+
+ LEAVE();
+ return rc;
}
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+ write: jz_i2s_write_mixdev,
+};
int i2s_probe_codec(struct i2s_codec *codec)
{
/* generic OSS to I2S wrapper */
- codec->mixer_ioctl = i2s_mixer_ioctl;
- return 1;
+ return (codec->codecs_ioctrl) ? 1 : 0;
}
-
/* I2S codec initialisation. */
static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
{
- int num_i2s = 0;
- struct i2s_codec *codec;
-
- for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
- if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
- return -ENOMEM;
- memset(codec, 0, sizeof(struct i2s_codec));
- codec->private_data = controller;
- codec->id = num_i2s;
-
- if (i2s_probe_codec(codec) == 0)
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < NR_I2S; i++) {
+ the_codecs[i].private_data = controller;
+ if (i2s_probe_codec(&the_codecs[i]) == 0) {
break;
- if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
- kfree(codec);
+ }
+ if ((the_codecs[i].dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, the_codecs[i].id)) < 0) {
+ printk(KERN_ERR "JZ I2S: couldn't register mixer!\n");
break;
}
- controller->i2s_codec[num_i2s] = codec;
+
}
- return num_i2s;
-}
+ controller->i2s_codec = &the_codecs[0];
+ LEAVE();
+ return i;
+}
-static void jz_update_filler(int format, int channels)
+static void jz_i2s_reinit_hw(struct i2s_codec *codec, int mode)
{
-#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
-
- switch (TYPE(format, channels))
- {
-
- case TYPE(AFMT_U8, 1):
- jz_audio_b = 4; /* 4bytes * 8bits =32bits */
- replay_filler = replay_fill_1x8_u;
- record_filler = record_fill_1x8_u;
- break;
- case TYPE(AFMT_U8, 2):
- jz_audio_b = 4;
- replay_filler = replay_fill_2x8_u;
- record_filler = record_fill_2x8_u;
- break;
- case TYPE(AFMT_S16_LE, 1):
- jz_audio_b = 2; /* 2bytes * 16bits =32bits */
- replay_filler = replay_fill_1x16_s;
- record_filler = record_fill_1x16_s;
- break;
- case TYPE(AFMT_S16_LE, 2):
- jz_audio_b = 2;
- replay_filler = replay_fill_2x16_s;
- record_filler = record_fill_2x16_s;
- break;
- case TYPE(18, 2):
- jz_audio_b = 1;
- replay_filler = replay_fill_2x18_s;
- record_filler = record_fill_2x16_s;
- break;
- default:
- ;
- }
-}
+ ENTER();
+ __i2s_disable();
+ schedule_timeout(5);
+ codec_ioctrl(codec, CODEC_EACH_TIME_INIT, 0);
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_jz_root;
-int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- return 0;
+ LEAVE();
}
-static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+static int jz_codec_set_speed(struct i2s_codec *codec, int rate, int mode)
{
- if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
- return -EIO;
- return 0;
-}
+ ENTER();
-static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
-{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ if (mode & CODEC_RMODE) {
+ rate = codec_ioctrl(codec, CODEC_SET_RECORD_SPEED, rate);
+ if (rate > 0) {
+ codec->record_audio_rate = rate;
+ } else {
+ rate = codec->record_audio_rate;
+ }
+ }
+ if (mode & CODEC_WMODE) {
+ rate = codec_ioctrl(codec, CODEC_SET_REPLAY_SPEED, rate);
+ if (rate > 0) {
+ codec->replay_audio_rate = rate;
+ } else {
+ rate = codec->replay_audio_rate;
+ }
+ }
+
+ LEAVE();
+ return rate;
}
-#endif
-static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+static short jz_codec_set_channels(struct i2s_codec *codec, short channels, int mode)
{
- char *name;
- int adev; /* No of Audio device. */
-
- name = controller->name;
- /* initialize AIC controller and reset it */
- jz_i2s_initHw(1);
- adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
- if (adev < 0)
- goto audio_failed;
- /* initialize I2S codec and register /dev/mixer */
- if (jz_i2s_codec_init(controller) <= 0)
- goto mixer_failed;
+ ENTER();
-#ifdef CONFIG_PROC_FS
- if (jz_i2s_init_proc(controller) < 0) {
- printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
- goto proc_failed;
- }
-#endif
+ DPRINT_IOC("%s mode = %x channels = %d\n", __FUNCTION__, mode, channels);
+ DPRINT_IOC("mode & CODEC_RMODE == %x", mode & CODEC_RMODE);
- controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);
- if (!controller->tmp1) {
- printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
- goto tmp1_failed;
- }
- controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);
- if (!controller->tmp2) {
- printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
- goto tmp2_failed;
+ if (mode & CODEC_RMODE) {
+ channels = codec_ioctrl(codec, CODEC_SET_RECORD_CHANNEL, channels);
+ codec->record_codec_channel = channels;
}
- if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
- printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
- goto dma2_failed;
- }
- if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
- printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
- goto dma1_failed;
+ if (mode & CODEC_WMODE) {
+ channels = codec_ioctrl(codec, CODEC_SET_REPLAY_CHANNEL, channels);
+ codec->replay_codec_channel = channels;
+ if (channels == 1) {
+ __aic_enable_mono2stereo();
+ } else {
+ __aic_disable_mono2stereo();
+ }
}
- printk(JZ_SOC_NAME": On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
- controller->dev_audio = adev;
- pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8);
- if(!pop_turn_onoff_buf)
- printk("pop_turn_onoff_buf alloc is wrong!\n");
- pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf);
+ LEAVE();
- return;
-dma2_failed:
- jz_free_dma(controller->dma1);
-dma1_failed:
- free_pages((unsigned long)controller->tmp2, 8);
-tmp2_failed:
- free_pages((unsigned long)controller->tmp1, 8);
-tmp1_failed:
-
-#ifdef CONFIG_PROC_FS
- jz_i2s_cleanup_proc(controller);
-#endif
-proc_failed:
- /* unregister mixer dev */
-mixer_failed:
- unregister_sound_dsp(adev);
-audio_failed:
- return;
+ return channels;
}
-static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+static void jz_codec_select_mode(struct i2s_codec *codec, int mode)
{
- if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
- GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
- return -ENOMEM;
- }
+ ENTER();
- (*controller)->name = "Jz I2S controller";
- (*controller)->opened1 = 0;
- (*controller)->opened2 = 0;
- init_waitqueue_head(&(*controller)->adc_wait);
- init_waitqueue_head(&(*controller)->dac_wait);
- spin_lock_init(&(*controller)->lock);
- init_waitqueue_head(&rx_wait_queue);
- init_waitqueue_head(&tx_wait_queue);
- init_waitqueue_head(&pop_wait_queue);
- init_waitqueue_head(&drain_wait_queue);
- pop_wait_event = 0;
+ switch (mode) {
+ case CODEC_WRMODE:
+ if (codec->use_mic_line_flag == USE_NONE) {
+ codec->use_mic_line_flag = USE_MIC;
+ }
+ codec_ioctrl(codec, CODEC_SET_REPLAY_RECORD, codec->use_mic_line_flag);
+ break;
+ case CODEC_RMODE:
+ if (codec->use_mic_line_flag == USE_NONE) {
+ codec->use_mic_line_flag = USE_MIC;
+ }
+ codec_ioctrl(codec, CODEC_SET_RECORD, codec->use_mic_line_flag);
+ break;
+ case CODEC_WMODE:
+ codec_ioctrl(codec, CODEC_SET_REPLAY, mode);
+ break;
+ }
- return 0;
+ LEAVE();
}
-static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+void jz_codec_anti_pop(struct i2s_codec *codec, int mode)
{
- int adev = controller->dev_audio;
-
- jz_i2s_full_reset(controller);
- controller->dev_audio = -1;
- if (old_mksound)
- kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */
-
-#ifdef CONFIG_PROC_FS
- jz_i2s_cleanup_proc(controller);
-#endif
-
- jz_free_dma(controller->dma1);
- jz_free_dma(controller->dma2);
- free_pages((unsigned long)controller->tmp1, 8);
- free_pages((unsigned long)controller->tmp2, 8);
- free_pages((unsigned long)pop_turn_onoff_buf, 8);
-
- if (adev >= 0) {
- /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */
- unregister_sound_dsp(controller->dev_audio);
- }
+ ENTER();
+ codec_ioctrl(codec, CODEC_ANTI_POP, mode);
+ LEAVE();
}
-#if 0 /* Deprecated PM API */
-//#if CONFIG_PM
-static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
-{
- if(i2s_suspend_codec)
- i2s_suspend_codec(controller->opened1,controller->opened2);
- printk("Aic and codec are suspended!\n");
- return 0;
+void jz_codec_close(struct i2s_codec *codec, int mode)
+{
+ ENTER();
+ down(&codec->i2s_sem);
+ codec->codecs_ioctrl(codec, CODEC_TURN_OFF, mode);
+ up(&codec->i2s_sem);
+ LEAVE();
}
-static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+/***************************************************************
+ filter functions
+ ***************************************************************/
+
+/*
+ * Convert signed byte to unsiged byte
+ *
+ * Mapping:
+ * signed unsigned
+ * 0x00 (0) 0x80 (128)
+ * 0x01 (1) 0x81 (129)
+ * ...... ......
+ * 0x7f (127) 0xff (255)
+ * 0x80 (-128) 0x00 (0)
+ * 0x81 (-127) 0x01 (1)
+ * ...... ......
+ * 0xff (-1) 0x7f (127)
+ */
+static int convert_8bits_signed2unsigned(void *buffer, int counter)
{
- if(i2s_resume_codec)
- i2s_resume_codec();
-
-#if defined(CONFIG_I2S_AK4642EN)
- jz_i2s_initHw(0);
- jz_audio_reset();
- __i2s_enable();
- jz_audio_set_speed(controller->dev_audio,jz_audio_speed);
- /* playing */
- if(controller->opened1) {
- if(set_codec_replay)
- set_codec_replay();
- int dma = controller->dma1;
- int id;
- unsigned long flags;
- disable_dma(dma);
- if(__dmac_channel_address_error_detected(dma)) {
- printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
- __dmac_channel_clear_address_error(dma);
- }
- if(__dmac_channel_transmit_end_detected(dma))
- __dmac_channel_clear_transmit_end(dma);
-
- /* for DSP_GETOPTR */
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes += jz_audio_dma_tran_count;
- controller->blocks ++;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- while((id = get_buffer_id(&out_busy_queue)) >= 0)
- put_buffer_id(&out_empty_queue, id);
-
- out_busy_queue.count=0;
- if((id = get_buffer_id(&out_full_queue)) >= 0) {
- put_buffer_id(&out_empty_queue, id);
- }
- if (elements_in_queue(&out_empty_queue) > 0) {
- wake_up(&tx_wait_queue);
- wake_up(&controller->dac_wait);
- } else
- printk("pm out_empty_queue empty");
- }
-
- /* recording */
- if(controller->opened2) {
- if(set_codec_record)
- set_codec_record(use_mic_line_flag);
- int dma = controller->dma2;
- int id1, id2;
- unsigned long flags;
- disable_dma(dma);
- if (__dmac_channel_address_error_detected(dma)) {
- printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
- __dmac_channel_clear_address_error(dma);
- }
- if (__dmac_channel_transmit_end_detected(dma)) {
- __dmac_channel_clear_transmit_end(dma);
- }
- /* for DSP_GETIPTR */
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes += jz_audio_dma_tran_count;
- controller->blocks ++;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- id1 = get_buffer_id(&in_busy_queue);
- put_buffer_id(&in_full_queue, id1);
- wake_up(&rx_wait_queue);
- wake_up(&controller->adc_wait);
- if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
- put_buffer_id(&in_full_queue, id2);
- }
- in_busy_queue.count = 0;
- }
-#endif
+ int i;
+ int counter_8align = counter & ~0x7;
+ unsigned char *ucsrc = buffer;
+ unsigned char *ucdst = buffer;
- return 0;
-}
+ ENTER();
-static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
-{
- int ret;
- struct jz_i2s_controller_info *controller = pm_dev->data;
+ for (i = 0; i < counter_8align; i+=8) {
+ *(ucdst + i + 0) = *(ucsrc + i + 0) + 0x80;
+ *(ucdst + i + 1) = *(ucsrc + i + 1) + 0x80;
+ *(ucdst + i + 2) = *(ucsrc + i + 2) + 0x80;
+ *(ucdst + i + 3) = *(ucsrc + i + 3) + 0x80;
+ *(ucdst + i + 4) = *(ucsrc + i + 4) + 0x80;
+ *(ucdst + i + 5) = *(ucsrc + i + 5) + 0x80;
+ *(ucdst + i + 6) = *(ucsrc + i + 6) + 0x80;
+ *(ucdst + i + 7) = *(ucsrc + i + 7) + 0x80;
+ //printk("csrc + %d + 7 = %d, ucdst + %d + 7 = %d\n",
+ // i, *(csrc + i + 7), i, *(ucdst + i + 7));
+ }
- if (!controller) return -EINVAL;
+ BUG_ON(i != counter_8align);
- switch (req) {
- case PM_SUSPEND:
- ret = jz_i2s_suspend(controller, (int)data);
- break;
- case PM_RESUME:
- ret = jz_i2s_resume(controller);
- break;
- default:
- ret = -EINVAL;
- break;
+ for (i = counter_8align; i < counter; i++) {
+ *(ucdst + i) = *(ucsrc + i) + 0x80;
}
- return ret;
-}
-#endif /* CONFIG_PM */
-#if defined(CONFIG_I2S_DLV)
-static irqreturn_t aic_codec_irq(int irq, void *dev_id)
-{
- u8 file_9 = read_codec_file(9);
- u8 file_8 = read_codec_file(8);
-
- //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
- if ((file_9 & 0x1f) == 0x10) {
-
- write_codec_file(8, 0x3f);
- write_codec_file_bit(5, 1, 6);//SB_OUT->1
- mdelay(300);
- while ((read_codec_file(9) & 0x4) != 0x4);
- while ((read_codec_file(9) & 0x10) == 0x10) {
- write_codec_file(9, 0x10);
- }
- write_codec_file_bit(5, 0, 6);//SB_OUT->0
- mdelay(300);
- while ((read_codec_file(9) & 0x8) != 0x8);
- write_codec_file(9, file_9);
- write_codec_file(8, file_8);
-
- return IRQ_HANDLED;
- }
-
- if (file_9 & 0x8)
- ramp_up_end = jiffies;
- else if (file_9 & 0x4)
- ramp_down_end = jiffies;
- else if (file_9 & 0x2)
- gain_up_end = jiffies;
- else if (file_9 & 0x1)
- gain_down_end = jiffies;
-
- write_codec_file(9, file_9);
- if (file_9 & 0xf) {
- pop_wait_event = 1;
- wake_up(&pop_wait_queue);
- }
- while (REG_ICDC_RGDATA & 0x100);
-
- return IRQ_HANDLED;
+ //printk("[dbg] src = 0x%02x (%d) --- dst = 0x%02x (%d), cnt = %d, cnt8a = %d\n",
+ // *csrc, *csrc, *ucdst, *ucdst, counter, counter_8align);
+ LEAVE();
+ return counter;
}
-#endif
-static int __init init_jz_i2s(void)
+/*
+ * Convert stereo data to mono data, data width: 8 bits/channel
+ *
+ * buff: buffer address
+ * data_len: data length in kernel space, the length of stereo data
+ * calculated by "node->end - node->start"
+ */
+int convert_8bits_stereo2mono(void *buff, int data_len)
{
- int errno;
-#if defined(CONFIG_I2S_DLV)
- int retval;
- ramp_up_start = 0;
- ramp_up_end = 0;
- gain_up_start = 0;
- gain_up_end = 0;
- ramp_down_start = 0;
- ramp_down_end = 0;
- gain_down_start = 0;
- gain_down_end = 0;
-#endif
- use_mic_line_flag = USE_NONE;
- abnormal_data_count = 0;
- if(set_codec_mode)
- set_codec_mode();
+ /* stride = 16 bytes = 2 channels * 1 byte * 8 pipelines */
+ int data_len_16aligned = data_len & ~0xf;
+ int mono_cur, stereo_cur;
+ unsigned char *uc_buff = buff;
- drain_flag = 0;
- if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
- return errno;
- if(set_codec_gpio_pin)
- set_codec_gpio_pin();
-
- attach_jz_i2s(i2s_controller);
- if(set_codec_startup_param)
- set_codec_startup_param();
- if(set_codec_volume_table)
- set_codec_volume_table();
+ /* copy 8 times each loop */
+ for (stereo_cur = mono_cur = 0;
+ stereo_cur < data_len_16aligned;
+ stereo_cur += 16, mono_cur += 8) {
-#if defined(CONFIG_I2S_DLV)
- jz_codec_config = 0;
- retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
- if (retval) {
- printk("Could not get aic codec irq %d\n", IRQ_AIC);
- return retval;
+ uc_buff[mono_cur + 0] = uc_buff[stereo_cur + 0];
+ uc_buff[mono_cur + 1] = uc_buff[stereo_cur + 2];
+ uc_buff[mono_cur + 2] = uc_buff[stereo_cur + 4];
+ uc_buff[mono_cur + 3] = uc_buff[stereo_cur + 6];
+ uc_buff[mono_cur + 4] = uc_buff[stereo_cur + 8];
+ uc_buff[mono_cur + 5] = uc_buff[stereo_cur + 10];
+ uc_buff[mono_cur + 6] = uc_buff[stereo_cur + 12];
+ uc_buff[mono_cur + 7] = uc_buff[stereo_cur + 14];
}
-#endif
-
- out_empty_queue.id = NULL;
- out_full_queue.id = NULL;
- out_busy_queue.id = NULL;
- in_empty_queue.id = NULL;
- in_full_queue.id = NULL;
- in_busy_queue.id = NULL;
- jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
- jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
- Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ BUG_ON(stereo_cur != data_len_16aligned);
-#if 0 /* Deprecated PM API */
-//#ifdef CONFIG_PM
- i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
- jz_i2s_pm_callback);
- if (i2s_controller->pm)
- i2s_controller->pm->data = i2s_controller;
-#endif
+ /* remaining data */
+ for (; stereo_cur < data_len; stereo_cur += 2, mono_cur++) {
+ uc_buff[mono_cur] = uc_buff[stereo_cur];
+ }
- printk(JZ_SOC_NAME ": I2S OSS audio driver initialized.\n");
-
- return 0;
+ LEAVE();
+ return (data_len / 2);
}
-static void __exit cleanup_jz_i2s(void)
+/*
+ * Convert stereo data to mono data, and convert signed byte to unsigned byte.
+ *
+ * data width: 8 bits/channel
+ *
+ * buff: buffer address
+ * data_len: data length in kernel space, the length of stereo data
+ * calculated by "node->end - node->start"
+ */
+int convert_8bits_stereo2mono_signed2unsigned(void *buff, int data_len)
{
-#ifdef CONFIG_PM
- /* pm_unregister(i2s_controller->pm); */
-#endif
-#if defined(CONFIG_I2S_DLV)
- free_irq(IRQ_AIC, NULL);
-#endif
- unload_jz_i2s(i2s_controller);
- Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
- if(clear_codec_mode)
- clear_codec_mode();
-}
+ /* stride = 16 bytes = 2 channels * 1 byte * 8 pipelines */
+ int data_len_16aligned = data_len & ~0xf;
+ int mono_cur, stereo_cur;
+ unsigned char *uc_buff = buff;
-module_init(init_jz_i2s);
-module_exit(cleanup_jz_i2s);
+ /* copy 8 times each loop */
+ for (stereo_cur = mono_cur = 0;
+ stereo_cur < data_len_16aligned;
+ stereo_cur += 16, mono_cur += 8) {
-#if defined(CONFIG_SOC_JZ4730)
-static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count,con;
-
- if(elements_in_queue(&in_busy_queue) > 0) {
- if (nonblock)
- return -EBUSY;
- drain_flag = 1;
- sleep_on(&drain_wait_queue);
- drain_flag = 0;
- } else {
- add_wait_queue(&ctrl->adc_wait, &wait);
- for (con = 0; con < 1000; con ++) {
- udelay(1);
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&ctrl->lock, flags);
- count = get_dma_residue(ctrl->dma2);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- if (count <= 0)
- break;
- if (nonblock) {
- remove_wait_queue(&ctrl->adc_wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- }
- remove_wait_queue(&ctrl->adc_wait, &wait);
- current->state = TASK_RUNNING;
+ uc_buff[mono_cur + 0] = uc_buff[stereo_cur + 0] + 0x80;
+ uc_buff[mono_cur + 1] = uc_buff[stereo_cur + 2] + 0x80;
+ uc_buff[mono_cur + 2] = uc_buff[stereo_cur + 4] + 0x80;
+ uc_buff[mono_cur + 3] = uc_buff[stereo_cur + 6] + 0x80;
+ uc_buff[mono_cur + 4] = uc_buff[stereo_cur + 8] + 0x80;
+ uc_buff[mono_cur + 5] = uc_buff[stereo_cur + 10] + 0x80;
+ uc_buff[mono_cur + 6] = uc_buff[stereo_cur + 12] + 0x80;
+ uc_buff[mono_cur + 7] = uc_buff[stereo_cur + 14] + 0x80;
}
- return 0;
+
+ BUG_ON(stereo_cur != data_len_16aligned);
+
+ /* remaining data */
+ for (; stereo_cur < data_len; stereo_cur += 2, mono_cur++) {
+ uc_buff[mono_cur] = uc_buff[stereo_cur] + 0x80;
+ }
+
+ LEAVE();
+ return (data_len / 2);
}
-static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+/*
+ * Convert stereo data to mono data, data width: 16 bits/channel
+ *
+ * buff: buffer address
+ * data_len: data length in kernel space, the length of stereo data
+ * calculated by "node->end - node->start"
+ */
+int convert_16bits_stereo2mono(void *buff, int data_len)
{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
-
- if(elements_in_queue(&out_full_queue) > 0) {
- if (nonblock)
- return -EBUSY;
-
- drain_flag = 1;
- sleep_on(&drain_wait_queue);
- drain_flag = 0;
- } else {
- add_wait_queue(&(ctrl->dac_wait), &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if(elements_in_queue(&out_full_queue) <= 0) {
- spin_lock_irqsave(&ctrl->lock, flags);
- count = get_dma_residue(ctrl->dma1);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- if(count <= 0)
- break;
- }
- if (nonblock) {
- remove_wait_queue(&ctrl->dac_wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- }
- remove_wait_queue(&ctrl->dac_wait, &wait);
- current->state = TASK_RUNNING;
+ /* stride = 32 bytes = 2 channels * 2 byte * 8 pipelines */
+ int data_len_32aligned = data_len & ~0x1f;
+ int data_cnt_ushort = data_len_32aligned / 2;
+ int mono_cur, stereo_cur;
+ unsigned short *ushort_buff = (unsigned short *)buff;
+
+ /* copy 8 times each loop */
+ for (stereo_cur = mono_cur = 0;
+ stereo_cur < data_cnt_ushort;
+ stereo_cur += 16, mono_cur += 8) {
+
+ ushort_buff[mono_cur + 0] = ushort_buff[stereo_cur + 0];
+ ushort_buff[mono_cur + 1] = ushort_buff[stereo_cur + 2];
+ ushort_buff[mono_cur + 2] = ushort_buff[stereo_cur + 4];
+ ushort_buff[mono_cur + 3] = ushort_buff[stereo_cur + 6];
+ ushort_buff[mono_cur + 4] = ushort_buff[stereo_cur + 8];
+ ushort_buff[mono_cur + 5] = ushort_buff[stereo_cur + 10];
+ ushort_buff[mono_cur + 6] = ushort_buff[stereo_cur + 12];
+ ushort_buff[mono_cur + 7] = ushort_buff[stereo_cur + 14];
}
-
- return 0;
+
+ BUG_ON(stereo_cur != data_cnt_ushort);
+
+ /* remaining data */
+ for (; stereo_cur < data_cnt_ushort; stereo_cur += 2, mono_cur++) {
+ ushort_buff[mono_cur] = ushort_buff[stereo_cur];
+ }
+
+ LEAVE();
+ return (data_len / 2);
}
-#endif
-#if defined(CONFIG_SOC_JZ4740)
-#define MAXDELAY 50000
-static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+/*
+ * Set convert function for audio_pipe
+ *
+ * In AIC, we just use signed data for all ops as it is shared by
+ * replay and record. So, converting data for every non-compatible
+ * format is neccessary.
+ */
+static inline int endpoint_set_filter(audio_pipe *endpoint, int format, int channels)
{
- int count,ele,i=0;
- int tfl;
+ ENTER();
- for (;;) {
- if(!nonblock) {//blocked
- if ( i < MAXDELAY ) {
- udelay(10);
- i++;
- } else
- break;
-
- ele = elements_in_queue(&out_full_queue);
- if(ele <= 0) {
- udelay(10);
- spin_lock(&ctrl->lock);
- count = get_dma_residue(ctrl->dma1);
- spin_unlock(&ctrl->lock);
- if (count <= 0)
- break;
+ DPRINT("%s %d, endpoint = 0x%08x, format = %d, channels = %d\n",
+ __FUNCTION__, __LINE__, (unsigned int)endpoint, format, channels);
+
+ endpoint->filter = NULL;
+
+ switch (format) {
+ case AFMT_U8:
+ if (endpoint == &in_endpoint) {
+ if (channels == 2) {
+ endpoint->filter = convert_8bits_stereo2mono_signed2unsigned;
+ DPRINT("$$$$ set pin_endpoint->filter = convert_8bits_stereo_2_mono\n");
+ } else {
+ endpoint->filter = convert_8bits_signed2unsigned;
+ DPRINT("$$$$ set pin_endpoint->filter = convert_8bits_signed2unsigned\n");
}
- } else {//non-blocked
- mdelay(100);
- ele = elements_in_queue(&out_full_queue);
-
- if(ele <= 0) {
- mdelay(100);
-
- spin_lock(&ctrl->lock);
- count = get_dma_residue(ctrl->dma1);
- spin_unlock(&ctrl->lock);
- if (count <= 0)
- break;
+ }
+ break;
+ case AFMT_S16_LE:
+ if (endpoint == &in_endpoint) {
+ if (channels == 1) {
+ endpoint->filter = convert_16bits_stereo2mono;
+ DPRINT("$$$$ set pin_endpoint->filter = convert_16bits_stereo2mono\n");
+ } else {
+ endpoint->filter = NULL;
+ DPRINT("$$$$ record channels = %d\n", channels);
}
}
- }
-
- /* wait for TX fifo */
- while (1) {
- tfl = __aic_get_transmit_resident();
- if (tfl == 0)
- break;
- udelay(2);
+ break;
+ default:
+ printk("JZ I2S endpoint_set_filter: unknown format\n");
+ endpoint->filter = NULL;
}
+ LEAVE();
return 0;
}
-static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+/*
+ * The "format" contains data width, signed/unsigned and LE/BE
+ *
+ * The AIC registers will not be modified !
+ *
+ * For CODEC set data_width
+ */
+static int jz_codec_set_format(struct i2s_codec *codec, unsigned int format, int mode)
{
- int count,i=0;
-
- for (;;) {
- if ( i < MAXDELAY )
- {
- udelay(10);
- i++;
- }
- else
- break;
- spin_lock(&ctrl->lock);
- count = get_dma_residue(ctrl->dma2);
- spin_unlock(&ctrl->lock);
- if (count <= 0)
- break;
-
- if (nonblock) {
- return -EBUSY;
+ /* The value of format reference to soundcard.h:
+ *
+ * AFMT_MU_LAW 0x00000001
+ * AFMT_A_LAW 0x00000002
+ * AFMT_IMA_ADPCM 0x00000004
+ * AFMT_U8 0x00000008
+ * AFMT_S16_LE 0x00000010
+ * AFMT_S16_BE 0x00000020
+ * AFMT_S8 0x00000040
+ */
+ int data_width = 0;
+
+ ENTER();
+
+ DPRINT("$$$$ %s %d, format = %u, mode = %d\n", __FUNCTION__, __LINE__, format, mode);
+
+ down(&codec->i2s_sem);
+
+ /*
+ * It is dangerous to modify settings about signed bit, endian and M2S
+ * as record and replay shared the settings.
+ *
+ * Now we don't support unsigned format (AFMT_U8) and BE format (AFMT_S16_BE)
+ * To support such format, corresponding filter function must be implemented.
+ */
+ switch (format) {
+ case AFMT_U8:
+ data_width = 8;
+ __aic_enable_unsignadj();
+ if (mode & CODEC_RMODE) {
+ __i2s_set_iss_sample_size(8);
+ }
+ if (mode & CODEC_WMODE) {
+ __i2s_set_oss_sample_size(8);
+ }
+ break;
+ case AFMT_S8:
+ data_width = 8;
+ __aic_disable_unsignadj();
+ if (mode & CODEC_RMODE) {
+ __i2s_set_iss_sample_size(8);
+ }
+ if (mode & CODEC_WMODE) {
+ __i2s_set_oss_sample_size(8);
+ }
+ break;
+ case AFMT_S16_LE:
+ data_width = 16;
+ __aic_disable_unsignadj();
+ if (mode & CODEC_RMODE) {
+ __i2s_set_iss_sample_size(16);
+ }
+ if (mode & CODEC_WMODE) {
+ __i2s_set_oss_sample_size(16);
+ }
+ break;
+ case AFMT_S16_BE:
+ data_width = 16;
+ __aic_disable_unsignadj();
+ if (mode & CODEC_RMODE) {
+ __i2s_set_iss_sample_size(16);
+ }
+ if (mode & CODEC_WMODE) {
+ __i2s_set_oss_sample_size(16);
}
+ break;
+ default:
+ printk("JZ I2S: Unkown sound format %d\n", format);
+ goto _ERROR_SET_FORMAT;
}
-
- return 0;
-}
-#endif
-#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) || defined(CONFIG_SOC_JZ4750L)
-#define MAXDELAY 50000
-static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
-{
- //DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count,i=0;
-
- //add_wait_queue(&ctrl->adc_wait, &wait);
- for (;;) {
- if (i < MAXDELAY) {
- udelay(10);
- i++;
- } else
- break;
- //set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&ctrl->lock, flags);
- //spin_lock(&ctrl->lock);
- count = get_dma_residue(ctrl->dma2);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- //spin_unlock(&ctrl->lock);
- if (count <= 0)
- break;
-
- /*if (signal_pending(current))
- break;*/
- if (nonblock) {
- //remove_wait_queue(&ctrl->adc_wait, &wait);
- //current->state = TASK_RUNNING;
- return -EBUSY;
- }
- }
- //remove_wait_queue(&ctrl->adc_wait, &wait);
- //current->state = TASK_RUNNING;
- /*if (signal_pending(current))
- return -ERESTARTSYS;*/
- return 0;
-}
-static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
-{
- unsigned long flags;
- int count,ele,busyele,emptyele,i=0;
-
- for (;;) {
- if(!nonblock) {//blocked
- if (i < MAXDELAY) {
- udelay(10);
- i++;
- } else
- break;
-
- ele = elements_in_queue(&out_full_queue);
- if(ele <= 0) {
- udelay(200);
-
- busyele = elements_in_queue(&out_busy_queue);
- emptyele = elements_in_queue(&out_empty_queue);
- if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
- spin_lock_irqsave(&ctrl->lock, flags);
- count = get_dma_residue(ctrl->dma1);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- if (count <= 0)
- break;
- }
- }
- } else {//non-blocked
- //mdelay(100);
- ele = elements_in_queue(&out_full_queue);
-
- if(ele <= 0) {
- //mdelay(100);
- busyele = elements_in_queue(&out_busy_queue);
- emptyele = elements_in_queue(&out_empty_queue);
-
- if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
- spin_lock_irqsave(&ctrl->lock, flags);
- count = get_dma_residue(ctrl->dma1);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- if (count <= 0)
- break;
- }
- }
+ if (mode & CODEC_RMODE) {
+ if (codec->codecs_ioctrl(codec, CODEC_SET_RECORD_DATA_WIDTH, data_width) < 0) {
+ printk("JZ I2S: CODEC ioctl error, command: CODEC_SET_RECORD_FORMAT");
+ goto _ERROR_SET_FORMAT;
}
+ codec->record_format = format;
}
-
- return 0;
+
+ if (mode & CODEC_WMODE) {
+ if (codec->codecs_ioctrl(codec, CODEC_SET_REPLAY_DATA_WIDTH, data_width) < 0) {
+ printk("JZ I2S: CODEC ioctl error, command: CODEC_SET_REPLAY_FORMAT");
+ goto _ERROR_SET_FORMAT;
+ }
+ codec->replay_format = format;
+ }
+
+ up(&codec->i2s_sem);
+ LEAVE();
+ return format;
+
+_ERROR_SET_FORMAT:
+ up(&codec->i2s_sem);
+ LEAVE();
+ return -1;
}
-#endif
static int jz_audio_release(struct inode *inode, struct file *file)
{
- unsigned long flags;
- unsigned int dacflag;
- unsigned int timeout = 0xfff;
-#if defined(CONFIG_I2S_DLV)
- unsigned long tfl;
-#endif
struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
-#if defined(CONFIG_I2S_DLV)
- jz_codec_config = 0;
-#endif
- if (controller == NULL)
- return -ENODEV;
+ int mode = 0;
- pop_dma_flag = 0;
- pop_wait_event = 0;
+ ENTER();
+
+ if (controller == NULL) {
+ printk("\nAudio device not ready!\n");
+ return -ENODEV;
+ }
+ if ((controller->pin_endpoint == NULL) && (controller->pout_endpoint == NULL) ) {
+ printk("\nAudio endpoint not open!\n");
+ return -ENODEV;
+ }
+ if ((file->f_mode & FMODE_READ) && controller->pin_endpoint) {
+ mode |= CODEC_RMODE;
+ audio_close_endpoint(controller->pin_endpoint, FORCE_STOP);
+ controller->pin_endpoint = NULL;
- if (controller->opened1 == 1 && controller->opened2 == 1) {
- controller->opened1 = 0;
- __i2s_enable_transmit_dma();
- __i2s_enable_replay();
- drain_dac(controller, file->f_flags & O_NONBLOCK);
-#if defined(CONFIG_I2S_DLV)
-#if 0
- /* wait for fifo empty */
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- gain_down_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
-#endif
- //gain_down_end = jiffies;
- /*while (1) {
- tfl = REG_AIC_SR & 0x00003f00;
- if (tfl == 0) {
- udelay(500);
- break;
- }
- mdelay(2);
- }*/
- mdelay(100);
-#endif
- disable_dma(controller->dma1);
- set_dma_count(controller->dma1, 0);
- __i2s_disable_transmit_dma();
- __i2s_disable_replay();
-
-#if defined(CONFIG_I2S_ICODEC)
- if(clear_codec_replay)
- clear_codec_replay();
-#endif
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes = 0;
- controller->count = 0;
- controller->finish = 0;
- jz_audio_dma_tran_count = 0;
- controller->blocks = 0;
- controller->nextOut = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-
- controller->opened2 = 0;
- first_record_call = 1;
- __i2s_enable_receive_dma();
- __i2s_enable_record();
- drain_adc(controller, file->f_flags & O_NONBLOCK);
- disable_dma(controller->dma2);
- set_dma_count(controller->dma2, 0);
__i2s_disable_receive_dma();
__i2s_disable_record();
-#if defined(CONFIG_I2S_ICODEC)
- if(clear_codec_record)
- clear_codec_record();
-#endif
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextIn = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-#if defined(CONFIG_I2S_DLV)
- write_codec_file_bit(5, 1, 6);//SB_OUT->1
- ramp_down_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
+ }
- //ramp_down_end = jiffies;
- if (use_mic_line_flag == USE_LINEIN) {
- unset_record_line_input_audio_with_audio_data_replay();
- //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag);
- }
- if (use_mic_line_flag == USE_MIC) {
- unset_record_mic_input_audio_with_audio_data_replay();
- //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag);
- }
+ if ((file->f_mode & FMODE_WRITE) && controller->pout_endpoint) {
+ mode |= CODEC_WMODE;
+ audio_close_endpoint(controller->pout_endpoint, NOMAL_STOP);
+ controller->pout_endpoint = NULL;
-#if 0
- unset_record_playing_audio_mixed_with_mic_input_audio();
-#endif
-#endif
- __i2s_disable();
- if(turn_off_codec)
- turn_off_codec();
- abnormal_data_count = 0;
- } else if (controller->opened1 == 1) {
- //controller->opened1 = 0;
- __i2s_enable_transmit_dma();
- __i2s_enable_replay();
- drain_dac(controller, file->f_flags & O_NONBLOCK);
- /* add some mute to anti-pop */
-#if defined(CONFIG_I2S_ICODEC)
- //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right);
-#endif
-#if defined(CONFIG_I2S_DLV)
-#if 0
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- gain_down_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
-#endif
- if (!jz_dlv_vol_mute) {
- dacflag = read_codec_file(1);
- if (!(dacflag & 0x20)) {
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- gain_down_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
- }
- }else
- mdelay(280);
-
- //gain_down_end = jiffies;
- while (1) {
- timeout --;
- tfl = REG_AIC_SR & 0x00003f00;
- if (tfl == 0) {
- break;
- udelay(500);
- } else if (!timeout){
- break;
- }
- mdelay(2);
- }
-#endif
- disable_dma(controller->dma1);
- set_dma_count(controller->dma1, 0);
__i2s_disable_transmit_dma();
__i2s_disable_replay();
-#if defined(CONFIG_I2S_ICODEC)
- if(clear_codec_replay)
- clear_codec_replay();
-#endif
- __aic_flush_fifo();
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes = 0;
- controller->count = 0;
- controller->finish = 0;
- jz_audio_dma_tran_count = 0;
- controller->blocks = 0;
- controller->nextOut = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-#if defined(CONFIG_I2S_DLV)
- write_codec_file_bit(5, 1, 6);//SB_OUT->1
- ramp_down_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
- unset_audio_data_replay();
-#endif
- __i2s_disable();
-#if defined(CONFIG_I2S_ICODEC)
- if(turn_off_codec)
- turn_off_codec();
-#endif
- } else if (controller->opened2 == 1) {
- controller->opened2 = 0;
- first_record_call = 1;
- __i2s_enable_receive_dma();
- __i2s_enable_record();
- drain_adc(controller, file->f_flags & O_NONBLOCK);
- disable_dma(controller->dma2);
- set_dma_count(controller->dma2, 0);
- __i2s_disable_receive_dma();
- __i2s_disable_record();
-#if defined(CONFIG_I2S_ICODEC)
- if(clear_codec_record)
- clear_codec_record();
-#endif
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextIn = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-#if defined(CONFIG_I2S_DLV)
-#if 0
- /* unset Record MIC input audio with direct playback */
- unset_record_mic_input_audio_with_direct_playback();
-#endif
-#if 1
- /* unset Record MIC input audio without playback */
- unset_record_mic_input_audio_without_playback();
-#endif
-#if 0
- unset_playback_line_input_audio_direct_only();
-#endif
-#if 0
- /* tested */
- /* unset Record LINE input audio without playback */
- unset_record_line_input_audio_without_playback();
-#endif
-#endif
- __i2s_disable();
-#if defined(CONFIG_I2S_ICODEC)
- if(turn_off_codec)
- turn_off_codec();
-#endif
- abnormal_data_count = 0;
}
-#if defined(CONFIG_I2S_DLV)
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
-/* __cpm_stop_idct();
- __cpm_stop_db();
- __cpm_stop_me();
- __cpm_stop_mc();
- __cpm_stop_ipu();*/
-#endif
-
- if (controller->opened1 == 1 && controller->opened2 == 1) {
- controller->opened1 = 0;
- controller->opened2 = 0;
- //print_pop_duration();
- //__dmac_disable_module(0);
- } else if ( controller->opened1 == 1 ) {
- controller->opened1 = 0;
- //print_pop_duration();
- } else if ( controller->opened2 == 1 ) {
- controller->opened2 = 0;
+
+ if ((controller->pin_endpoint == NULL) && (controller->pout_endpoint == NULL) ) {
+ __i2s_disable();
}
+ jz_codec_close(controller->i2s_codec, mode);
+
+ LEAVE();
return 0;
}
static int jz_audio_open(struct inode *inode, struct file *file)
-{
- int i;
- struct jz_i2s_controller_info *controller = i2s_controller;
-#if defined(CONFIG_I2S_DLV)
- jz_codec_config = 0;
-#endif
- if (controller == NULL)
- return -ENODEV;
-
- mdelay(2);
-#if defined(CONFIG_I2S_DLV)
- REG_DMAC_DMACKE(0) = 0x3f;
-#endif
- pop_dma_flag = 0;
- pop_wait_event = 0;
+{
+ struct jz_i2s_controller_info *controller = the_i2s_controller;
+ struct i2s_codec *codec = controller->i2s_codec;
+ int mode = 0;
+ int reset = 1;
- if (controller->opened1 == 1 || controller->opened2 == 1 ) {
- printk("\naudio is busy!\n");
- return -EBUSY;
- }
-
- if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
- if (controller->opened1 == 1)
- return -EBUSY;
- controller->opened1 = 1;
- /* for ioctl */
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextOut = 0;
-
- for(i=0;i < 64;i++) {
- save_last_samples[i].left = 0;
- save_last_samples[i].right = 0;
- }
-
- out_empty_queue.count = jz_audio_fragstotal;
- for (i=0;i < jz_audio_fragstotal;i++)
- *(out_empty_queue.id + i) = i;
- out_busy_queue.count = 0;
- out_full_queue.count = 0;
- last_dma_buffer_id = 0;
-
- if (controller->opened2 == 1)
- return -EBUSY;
-
- controller->opened2 = 1;
- first_record_call = 1;
- /* for ioctl */
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextIn = 0;
-
- in_empty_queue.count = jz_audio_fragstotal;
- for (i=0;i < jz_audio_fragstotal;i++)
- *(in_empty_queue.id + i) = i;
-
- in_full_queue.count = 0;
- in_busy_queue.count = 0;
- } else if (file->f_mode & FMODE_WRITE) {
- if (controller->opened1 == 1)
- return -EBUSY;
-
- controller->opened1 = 1;
- /* for ioctl */
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextOut = 0;
-
- for(i=0;i < 64;i++) {
- save_last_samples[i].left = 0;
- save_last_samples[i].right = 0;
- }
-
- out_empty_queue.count = jz_audio_fragstotal;
- for (i=0;i < jz_audio_fragstotal;i++)
- *(out_empty_queue.id + i) = i;
- out_busy_queue.count = 0;
- out_full_queue.count = 0;
- last_dma_buffer_id = 0;
- } else if (file->f_mode & FMODE_READ) {
- if (controller->opened2 == 1)
- return -EBUSY;
-
- controller->opened2 = 1;
- first_record_call = 1;
- /* for ioctl */
- controller->total_bytes = 0;
- jz_audio_dma_tran_count = 0;
- controller->count = 0;
- controller->finish = 0;
- controller->blocks = 0;
- controller->nextIn = 0;
-
- in_empty_queue.count = jz_audio_fragstotal;
- for (i=0;i < jz_audio_fragstotal;i++)
- *(in_empty_queue.id + i) = i;
-
- in_full_queue.count = 0;
- in_busy_queue.count = 0;
- }
-
- file->private_data = controller;
- jz_audio_reset();
- REG_AIC_FR |= (1 << 6);
- if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
-#if defined(CONFIG_I2S_ICODEC)
- if (set_codec_replay_record)
- set_codec_replay_record(use_mic_line_flag);
-#endif
-#if defined(CONFIG_I2S_DLV)
- if (use_mic_line_flag == USE_NONE) {
- printk("you select mic or line recording please.or use mic recording!\n");
- use_mic_line_flag = USE_MIC;
- }
- if (use_mic_line_flag == USE_LINEIN) {
- /* Record LINE input audio with Audio data replay (full duplex for linein) */
- /* codec_test_line */
- set_record_line_input_audio_with_audio_data_replay();
-
- }
- if (use_mic_line_flag == USE_MIC) {
- /* Record MIC input audio with Audio data replay (full duplex) */
- /* codec_test_mic */
- set_record_mic_input_audio_with_audio_data_replay();
- }
-#if 0
- /* Record playing audio mixed with MIC input audio */
- set_record_playing_audio_mixed_with_mic_input_audio();
-#endif
+ ENTER();
-#endif
- } else if (file->f_mode & FMODE_WRITE) {
-#if defined(CONFIG_I2S_ICODEC)
- if(set_codec_replay)
- set_codec_replay();
-#endif
-#if defined(CONFIG_I2S_DLV)
- //mdelay(10);
- /* Audio data replay */
- set_audio_data_replay();
-#endif
- } else if (file->f_mode & FMODE_READ) {
-#if defined(CONFIG_I2S_ICODEC)
- abnormal_data_count = 0;
- if(set_codec_record)
- set_codec_record(use_mic_line_flag);
-#endif
+ if (controller == NULL) {
+ return -ENODEV;
+ }
#if defined(CONFIG_I2S_DLV)
-#if 0
- /* Record MIC input audio with direct playback */
- set_record_mic_input_audio_with_direct_playback();
+ REG_DMAC_DMACKE(1) = 0x3f;
#endif
-#if 1
- /* set Record MIC input audio without playback */
- set_record_mic_input_audio_without_playback();
-#endif
-#if 0
- /* set Playback LINE input audio direct only */
- set_playback_line_input_audio_direct_only();
-#endif
-#if 0
- /* tested */
- /* set Record LINE input audio without playback */
- set_record_line_input_audio_without_playback();
-#endif
- mdelay(1);
-#endif
+ if (controller->pin_endpoint || controller->pout_endpoint) {
+ reset = 0;
}
-#if defined(CONFIG_I2S_DLV)
- __aic_reset();
-
- mdelay(10);
- REG_AIC_I2SCR = 0x10;
- mdelay(20);
- __aic_flush_fifo();
-#endif
-
- __i2s_enable();
+ if ((file->f_mode & FMODE_READ) && (controller->pin_endpoint)) {
+ printk("\nAudio read device is busy!\n");
+ return -EBUSY;
+ }
+ if ((file->f_mode & FMODE_WRITE) && (controller->pout_endpoint)) {
+ printk("\nAudio write device is busy!\n");
+ return -EBUSY;
+ }
-#if defined(CONFIG_I2S_DLV)
- ndelay(100);
-
- if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
-#if defined(CONFIG_I2S_DLV)
- //set SB_ADC or SB_DAC
- __dmac_enable_module(0);
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- ramp_up_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
-#endif
- } else if (file->f_mode & FMODE_WRITE) {
-#if defined(CONFIG_I2S_DLV)
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- ramp_up_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
-#endif
- } else if (file->f_mode & FMODE_READ) {
-#if defined(CONFIG_I2S_DLV)
- if (jz_mic_only)
- write_codec_file_bit(5, 1, 7);//SB_DAC->1
- else
- write_codec_file_bit(5, 0, 7);//SB_DAC->0
- mdelay(500);
-#endif
+ if (file->f_mode & FMODE_WRITE) {
+ controller->pout_endpoint = &out_endpoint;
+ mode |= CODEC_WMODE;
}
-#endif
+ if (file->f_mode & FMODE_READ) {
+ controller->pin_endpoint = &in_endpoint;
+ mode |= CODEC_RMODE;
+ }
+ file->private_data = controller;
+
+ if (mode & CODEC_RMODE){
+/*
+ jz_codec_set_channels(codec, 2, CODEC_RMODE);
+ jz_codec_set_format(codec, 8, CODEC_RMODE);
+ jz_codec_set_speed(codec, 8000, CODEC_RMODE);
+*/
+ jz_codec_set_channels(codec, 2, CODEC_RMODE);
+ jz_codec_set_format(codec, 16, CODEC_RMODE);
+ jz_codec_set_speed(codec, 44100, CODEC_RMODE);
+ codec->user_need_mono = 0;
+
+ set_controller_triger(controller, &in_endpoint, codec->record_codec_channel, codec->record_format);
+ }
+ if (mode & CODEC_WMODE) {
+ jz_codec_set_channels(codec, 2, CODEC_WMODE);
+ jz_codec_set_format(codec, 16, CODEC_WMODE);
+ jz_codec_set_speed(codec, 44100, CODEC_WMODE);
+ set_controller_triger(controller, &out_endpoint, codec->replay_codec_channel, codec->replay_format);
+ }
+
+ DPRINT_IOC("============ default_codec record ===============\n"
+ "format = %d\n"
+ "channels = %d\n"
+ "rate = %d\n"
+ "dma one tran bit = %d\n",
+ codec->record_format, codec->record_codec_channel,
+ codec->record_audio_rate, in_endpoint.dma.onetrans_bit);
+
+ DPRINT_IOC("============ default_codec replay ===============\n"
+ "format = %d\n"
+ "channels = %d\n"
+ "rate = %d\n"
+ "dma one tran bit = %d\n",
+ codec->replay_format, codec->replay_codec_channel,
+ codec->replay_audio_rate, out_endpoint.dma.onetrans_bit);
+
+ jz_codec_select_mode(controller->i2s_codec, mode);
+
+ /* note: reset AIC protected REG_AIC_I2SCR.ECCLK is setting */
+ if (reset) {
+ down(&controller->i2s_codec->i2s_sem);
+ //__i2s_enable_transmit_dma();
+ //__i2s_enable_receive_dma();
+ //__i2s_enable_replay();
+ __i2s_enable();
+ up(&controller->i2s_codec->i2s_sem);
+ }
+ //reinit codec option
+
+ //DUMP_AIC_REGS();
+ DPRINT_TRC(".... jz_audio_open\n");
+
+ if(mode != 1)
+ jz_codec_anti_pop(controller->i2s_codec, mode);
+
+ LEAVE();
return 0;
}
-
-static int jz_audio_ioctl(struct inode *inode, struct file *file,
-unsigned int cmd, unsigned long arg)
+static int jz_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
- unsigned long flags;
+ long rc = -EINVAL;
+ int val = 0;
+ int mode = 0;
+
struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
- count_info cinfo;
- audio_buf_info abinfo;
- int id, i;
+ struct i2s_codec *codec = controller->i2s_codec;
+ audio_pipe *pin_endpoint = controller->pin_endpoint;
+ audio_pipe *pout_endpoint = controller->pout_endpoint;
+
+ ENTER();
+
+ DPRINT_IOC("[dsp IOCTL] --------------------------------\n");
+ DPRINT_IOC(" dsp IOCTL %s cmd = (0x%08x), arg = %lu\n", __FUNCTION__, cmd, arg);
+ DPRINT_DSP_IOC_CMD(cmd);
+ DPRINT_IOC("[dsp IOCTL] --------------------------------\n");
+
+ if (file->f_mode & FMODE_READ) {
+ mode |= CODEC_RMODE;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ mode |= CODEC_WMODE;
+ }
- val = 0;
switch (cmd) {
+
case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
+ rc = put_user(SOUND_VERSION, (int *)arg);
+ break;
case SNDCTL_DSP_RESET:
-#if 0
- jz_audio_reset();
- __i2s_disable_replay();
- __i2s_disable_receive_dma();
- __i2s_disable_record();
- __i2s_disable_transmit_dma();
-#endif
- return 0;
+ break;
+
case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(controller, file->f_flags & O_NONBLOCK);
- return 0;
+ if (mode & CODEC_WMODE) {
+ if (pout_endpoint) {
+ audio_sync_endpoint(pout_endpoint);
+ }
+ }
+ rc = 1;
+ break;
+
case SNDCTL_DSP_SPEED:
/* set smaple rate */
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val >= 0)
- jz_audio_set_speed(controller->dev_audio, val);
-
- return put_user(val, (int *)arg);
+ if (get_user(val, (int *)arg)) {
+ rc = -EFAULT;
+ }
+ //printk("SNDCTL_DSP_SPEED ... set to %d\n", val);
+ val = jz_codec_set_speed(codec, val, mode);
+ rc = put_user(val, (int *)arg);
+ break;
+
case SNDCTL_DSP_STEREO:
/* set stereo or mono channel */
- if (get_user(val, (int *)arg))
- return -EFAULT;
- jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
-
- return 0;
+ if (get_user(val, (int *)arg)) {
+ rc = -EFAULT;
+ }
+
+ jz_codec_set_channels(controller->i2s_codec, val ? 2 : 1, mode);
+
+ if (mode & CODEC_RMODE) {
+ set_controller_triger(controller, pin_endpoint,
+ codec->record_codec_channel, codec->record_format);
+ }
+
+ if (mode & CODEC_WMODE) {
+ set_controller_triger(controller, pout_endpoint,
+ codec->replay_codec_channel, codec->replay_format);
+ }
+
+ rc = 0;
+ break;
+
case SNDCTL_DSP_GETBLKSIZE:
- //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg);
- return put_user(jz_audio_fragsize, (int *)arg);
+ {
+ // It seems that device could only be open with one mode (R or W)
+ int fragsize = 0;
+ if (mode & CODEC_RMODE) {
+ fragsize = pin_endpoint->fragsize;
+ }
+ if (mode & CODEC_WMODE) {
+ fragsize = pout_endpoint->fragsize;
+ }
+ rc = put_user(fragsize, (int *)arg);
+ break;
+ }
+
case SNDCTL_DSP_GETFMTS:
/* Returns a mask of supported sample format*/
- return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ rc = put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ break;
+
case SNDCTL_DSP_SETFMT:
/* Select sample format */
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != AFMT_QUERY)
- jz_audio_set_format(controller->dev_audio,val);
- else {
- if (file->f_mode & FMODE_READ)
- val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
- else
- val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ if (get_user(val, (int *)arg)) {
+ rc = -EFAULT;
+ }
+
+ //printk("\nSNDCTL_DSP_SETFMT ... set to %d\n", val);
+
+ if (val == AFMT_QUERY) {
+ if (mode & CODEC_RMODE) {
+ val = codec->record_format;
+ } else {
+ val = codec->replay_format;
+ }
+ } else {
+ val = jz_codec_set_format(codec, val, mode);
+ if (mode & CODEC_RMODE) {
+ if (codec->user_need_mono) {
+ endpoint_set_filter(pin_endpoint, val, 1);
+ } else {
+ endpoint_set_filter(pin_endpoint, val, 2);
+ }
+
+ set_controller_triger(controller, pin_endpoint,
+ codec->record_codec_channel, codec->record_format);
+ }
+ if (mode & CODEC_WMODE) {
+ set_controller_triger(controller, pout_endpoint,
+ codec->replay_codec_channel, codec->replay_format);
+ }
}
- return put_user(val, (int *)arg);
+ rc = put_user(val, (int *)arg);
+ break;
+
case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- jz_audio_set_channels(controller->dev_audio, val);
-
- return put_user(val, (int *)arg);
+ if (get_user(val, (int *)arg)) {
+ rc = -EFAULT;
+ }
+ //printk("\nSNDCTL_DSP_CHANNELS ... set to %d\n", val);
+
+ /* if mono, change to 2, and set 1 to codec->user_need_mono */
+ if (val == 1) {
+ val = 2;
+ codec->user_need_mono = 1;
+
+ } else {
+ codec->user_need_mono = 0;
+ }
+
+ /* Following lines could be marked as nothing will be changed */
+ jz_codec_set_channels(codec, val, mode);
+
+ if (mode & CODEC_RMODE) {
+ /* Set filter according to channel count */
+ if (codec->user_need_mono) {
+ endpoint_set_filter(pin_endpoint, codec->record_format, 1);
+ } else {
+ endpoint_set_filter(pin_endpoint, codec->record_format, 2);
+ }
+
+ set_controller_triger(controller, pin_endpoint,
+ codec->record_codec_channel, codec->record_format);
+ }
+ if (mode & CODEC_WMODE) {
+ set_controller_triger(controller, pout_endpoint,
+ codec->replay_codec_channel, codec->replay_format);
+ }
+
+ /* Restore for return value */
+ if (codec->user_need_mono) {
+ val = 1;
+ }
+
+ rc = put_user(val, (int *)arg);
+ break;
+
case SNDCTL_DSP_POST:
/* FIXME: the same as RESET ?? */
- return 0;
+ break;
+
case SNDCTL_DSP_SUBDIVIDE:
- return 0;
+ break;
+
case SNDCTL_DSP_SETFRAGMENT:
- get_user(val, (long *) arg);
- newfragsize = 1 << (val & 0xFFFF);
- if (newfragsize < 4 * PAGE_SIZE)
- newfragsize = 4 * PAGE_SIZE;
- if (newfragsize > (16 * PAGE_SIZE))
- newfragsize = 16 * PAGE_SIZE;
-
- newfragstotal = (val >> 16) & 0x7FFF;
- if (newfragstotal < 2)
- newfragstotal = 2;
- if (newfragstotal > 32)
- newfragstotal = 32;
- if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
- return 0;
- Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
- mdelay(500);
- jz_audio_fragstotal = newfragstotal;
- jz_audio_fragsize = newfragsize;
-
- Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
- mdelay(10);
+ rc = get_user(val, (long *) arg);
+ if (rc != -EINVAL) {
+ int newfragsize, newfragstotal;
+ newfragsize = 1 << (val & 0xFFFF);
+ if (newfragsize < 4 * PAGE_SIZE) {
+ newfragsize = 4 * PAGE_SIZE;
+ }
+ if (newfragsize > (16 * PAGE_SIZE)) {
+ newfragsize = 16 * PAGE_SIZE;
+ }
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2) {
+ newfragstotal = 2;
+ }
+ if (newfragstotal > 32) {
+ newfragstotal = 32;
+ }
+
+ if (mode & CODEC_RMODE) {
+ rc = audio_resizemem_endpoint(controller->pin_endpoint, newfragsize, newfragstotal);
+ if (!rc) {
+ rc = -EINVAL;
+ }
+ }
+ if (mode & CODEC_WMODE) {
+ rc = audio_resizemem_endpoint(controller->pout_endpoint, newfragsize, newfragstotal);
+ if (!rc) {
+ rc = -EINVAL;
+ }
+ }
+ }
+ break;
- return 0;
case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ rc = put_user(DSP_CAP_REALTIME | DSP_CAP_BATCH, (int *)arg);
+ break;
+
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
- return 0;
+ rc = 0;
+ break;
+
case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
+ rc = -EINVAL;
+ break;
+
case SNDCTL_DSP_GETOSPACE:
{
- int i;
- unsigned long bytes = 0;
- if (!(file->f_mode & FMODE_WRITE))
+ audio_buf_info abinfo;
+ if (!(mode & CODEC_WMODE)) {
return -EINVAL;
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- jz_audio_fragments = elements_in_queue(&out_empty_queue);
- for (i = 0; i < jz_audio_fragments; i++)
- bytes += jz_audio_fragsize;
-
- if (jz_audio_channels == 2)
- bytes /= jz_audio_b;
- else if (jz_audio_channels == 1)
- bytes /= 4;
- else
- printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n");
-
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- /* unused fragment amount */
- abinfo.fragments = jz_audio_fragments;
- /* amount of fragments */
- abinfo.fragstotal = jz_audio_fragstotal;
- /* fragment size in bytes */
- if (jz_audio_channels == 2)
- abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
- else if (jz_audio_channels == 1)
- abinfo.fragsize = jz_audio_fragsize / 4;
- else
- printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n");
-
- /* write size count without blocking in bytes */
- abinfo.bytes = (int)bytes;
-
- return copy_to_user((void *)arg, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ audio_get_endpoint_freesize(pout_endpoint, &abinfo);
+ rc = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ break;
}
+
case SNDCTL_DSP_GETISPACE:
{
- int i;
- unsigned long bytes = 0;
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- jz_audio_fragments = elements_in_queue(&in_empty_queue);
- for (i = 0; i < jz_audio_fragments; i++)
- bytes += jz_audio_fragsize;
-
- if (jz_audio_channels == 2)
- bytes /= jz_audio_b;
- else if (jz_audio_channels == 1)
- bytes /= 4;
- else
- printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n");
-
- abinfo.fragments = jz_audio_fragments;
- abinfo.fragstotal = jz_audio_fragstotal;
-
- if (jz_audio_channels == 2)
- abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
- else if (jz_audio_channels == 1)
- abinfo.fragsize = jz_audio_fragsize / 4;
- else
- printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n");
-
- abinfo.bytes = (int)bytes;
-
- return copy_to_user((void *)arg, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
+ audio_buf_info abinfo;
+ if (!(mode & CODEC_RMODE)) {
+ return -EINVAL;
+ }
+ audio_get_endpoint_freesize(controller->pin_endpoint, &abinfo);
+ rc = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ break;
}
+
case SNDCTL_DSP_GETTRIGGER:
val = 0;
- if (file->f_mode & FMODE_READ && in_dma_buf)
+ if ((mode & CODEC_RMODE) && controller->pin_endpoint) {
val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ }
+ if ((mode & CODEC_WMODE) && controller->pout_endpoint) {
val |= PCM_ENABLE_OUTPUT;
+ }
+ rc = put_user(val, (int *)arg);
+
+ break;
- return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- return 0;
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
+ if (get_user(val, (int *)arg)) {
+ rc = -EFAULT;
+ }
+ break;
- spin_lock_irqsave(&controller->ioctllock, flags);
- cinfo.bytes = controller->total_bytes;
- cinfo.blocks = controller->blocks;
- cinfo.ptr = controller->nextIn;
- controller->blocks = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info cinfo;
+ if (!(mode & CODEC_RMODE)) {
+ rc = -EINVAL;
+ }
+ rc = copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ break;
+ }
- return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
+ {
+ count_info cinfo;
+ if (!(mode & CODEC_WMODE)) {
+ rc = -EINVAL;
+ }
+ rc = copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ break;
+ }
- spin_lock_irqsave(&controller->ioctllock, flags);
- cinfo.bytes = controller->total_bytes;
- cinfo.blocks = controller->blocks;
- cinfo.ptr = controller->nextOut;
- controller->blocks = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-
- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- unfinish = 0;
- fullc = elements_in_queue(&out_full_queue);
- busyc = elements_in_queue(&out_busy_queue);
- for(i = 0;i < fullc ;i ++) {
- id = *(out_full_queue.id + i);
- unfinish += *(out_dma_buf_data_count + id);
- }
- for(i = 0;i < busyc ;i ++) {
- id = *(out_busy_queue.id + i);
- unfinish += get_dma_residue(controller->dma1);
- }
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-
- if (jz_audio_channels == 2)
- unfinish /= jz_audio_b;
- else if (jz_audio_channels == 1)
- unfinish /= 4;
- else
- printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n");
-
- return put_user(unfinish, (int *) arg);
+ {
+ // fix me !!!
+ int unfinish = 0;
+ if (!(mode & CODEC_WMODE)) {
+ rc = -EINVAL;
+ }
+ rc = put_user(unfinish, (int *) arg);
+ break;
+ }
+
case SOUND_PCM_READ_RATE:
- return put_user(jz_audio_rate, (int *)arg);
+ if (mode & CODEC_RMODE) {
+ //printk("\nSOUND_PCM_READ_RATE = %d\n", codec->record_audio_rate);
+ rc = put_user(codec->record_audio_rate, (int *)arg);
+ }
+ if (mode & CODEC_WMODE) {
+ //printk("\nSOUND_PCM_READ_RATE = %d\n", codec->replay_audio_rate);
+ rc = put_user(codec->replay_audio_rate, (int *)arg);
+ }
+ break;
+
case SOUND_PCM_READ_CHANNELS:
- return put_user(jz_audio_channels, (int *)arg);
+ if (mode & CODEC_RMODE) {
+ //printk("\nSOUND_PCM_READ_RATE = %d\n", codec->record_codec_channel);
+ rc = put_user(codec->record_codec_channel, (int *)arg);
+ }
+ if (mode & CODEC_WMODE) {
+ //printk("\nSOUND_PCM_READ_RATE = %d\n", codec->replay_codec_channel);
+ rc = put_user(codec->replay_codec_channel, (int *)arg);
+ }
+ break;
+
case SOUND_PCM_READ_BITS:
- return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ if (mode & CODEC_RMODE) {
+ rc = put_user((codec->record_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ }
+ if (mode & CODEC_WMODE) {
+ rc = put_user((codec->record_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ }
+ break;
+
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
- return -EINVAL;
+ rc = -EINVAL;
+ break;
+
+// may be for msm only
+#if 0
+ case AUDIO_GET_CONFIG:
+ break;
+
+ case AUDIO_SET_CONFIG:
+ break;
+#endif
+ default:
+ printk("%s[%s]:%d---no cmd\n",__FILE__,__FUNCTION__,__LINE__);
+ break;
}
- return -EINVAL;
-}
+ LEAVE();
+
+ return rc;
+}
-static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+static inline int endpoint_put_userdata(audio_pipe *endpoint, const char __user *buffer, size_t count)
{
- struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
+ unsigned long flags;
+ audio_node *node;
+ int err;
- if (file->f_mode & FMODE_WRITE) {
- if (elements_in_queue(&out_empty_queue) > 0)
- return POLLOUT | POLLWRNORM;
+ ENTER();
+ DPRINT("<<<< put_userdata\n");
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ node = get_audio_freenode(endpoint->mem);
+ AUDIO_UNLOCK(endpoint->lock, flags);
- poll_wait(file, &controller->dac_wait, wait);
+ // For non-block mode
+ if (endpoint->is_non_block && !node) {
+ LEAVE();
+ return 0;
}
- if (file->f_mode & FMODE_READ) {
- if (elements_in_queue(&in_full_queue) > 0)
- return POLLIN | POLLRDNORM;
+ // For block mode, wait free node
+ while (!node) {
+ DPRINT("wait ----------\n");
- poll_wait(file, &controller->adc_wait, wait);
- }
+ AUDIO_LOCK(endpoint->lock, flags);
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ AUDIO_UNLOCK(endpoint->lock, flags);
- spin_lock_irqsave(&controller->lock, flags);
- if (file->f_mode & FMODE_WRITE) {
- if (elements_in_queue(&out_empty_queue) > 0)
- mask |= POLLOUT | POLLWRNORM;
- } else if (file->f_mode & FMODE_READ) {
- if (elements_in_queue(&in_full_queue) > 0)
- mask |= POLLIN | POLLRDNORM;
+ // wait available node
+ do {
+ err = wait_event_interruptible(endpoint->q_full, (endpoint->avialable_couter >= 1));
+ if (err == -ERESTARTSYS)
+ printk("There is no available node???\n");
+ }while(err == -ERESTARTSYS);
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ node = get_audio_freenode(endpoint->mem);
+ endpoint->avialable_couter = 0;
+ AUDIO_UNLOCK(endpoint->lock, flags);
}
- spin_unlock_irqrestore(&controller->lock, flags);
- return mask;
+ if (copy_from_user((void *)node->pBuf, buffer, count)) {
+ printk("JZ I2S: copy_from_user failed !\n");
+ return -EFAULT;
+ }
+ dma_cache_wback_inv((unsigned long)node->pBuf,(unsigned long)count);
+ node->start = 0;
+ node->end = count;
+ AUDIO_LOCK(endpoint->lock, flags);
+ put_audio_usenode(endpoint->mem, node);
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ LEAVE();
+
+ return count;
}
-static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t jz_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
- int id, ret = 0, left_count, copy_count, cnt = 0;
- unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *)file->private_data;
+ audio_pipe *pout_endpoint = controller->pout_endpoint;
+ size_t usecount = 0;
+ int bat_cnt = -1;
+ int rem_cnt = 0;
- if (count < 0)
- return -EINVAL;
-
- __i2s_enable_receive_dma();
- __i2s_enable_record();
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->nextIn = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-
- copy_count = jz_audio_fragsize / 4;
-
- left_count = count;
- if (first_record_call) {
- first_record_call = 0;
- audio_read_back_first:
- if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
- put_buffer_id(&in_busy_queue, id);
- spin_lock(&controller->lock);
- *(in_dma_buf_data_count + id) = copy_count * 4;
-
- spin_unlock(&controller->lock);
- __i2s_enable_receive_dma();
- __i2s_enable_record();
- dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
- audio_start_dma(controller->dma2,file->private_data,
- *(in_dma_pbuf + id),
- *(in_dma_buf_data_count + id),
- DMA_MODE_READ);
- sleep_on(&rx_wait_queue);
- } else
- goto audio_read_back_first;
- }
-
- while (left_count > 0) {
- audio_read_back_second:
- if (elements_in_queue(&in_full_queue) <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- else
- sleep_on(&rx_wait_queue);
- }
-
- if ((id = get_buffer_id(&in_full_queue)) >= 0) {
- spin_lock(&controller->lock);
- cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
- spin_unlock(&controller->lock);
- put_buffer_id(&in_empty_queue, id);
- } else
- goto audio_read_back_second;
-
- if (elements_in_queue(&in_busy_queue) == 0) {
- if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
- put_buffer_id(&in_busy_queue, id);
- spin_lock(&controller->lock);
- *(in_dma_buf_data_count + id) = copy_count * 4;
- spin_unlock(&controller->lock);
-
- dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
- audio_start_dma(controller->dma2,file->private_data,
- *(in_dma_pbuf + id),
- *(in_dma_buf_data_count + id),
- DMA_MODE_READ);
+ ENTER();
+
+ // dump_dlv_regs(__FUNCTION__);
+
+ pout_endpoint->is_non_block = file->f_flags & O_NONBLOCK;
+
+ DPRINT("write data count = %d\n", count);
+
+ while (count >= pout_endpoint->fragsize) {
+
+ bat_cnt = endpoint_put_userdata(pout_endpoint,
+ &(buffer[usecount]),
+ pout_endpoint->fragsize);
+ // Prepare data success.
+ if (bat_cnt > 0) {
+ usecount += bat_cnt;
+ count -= bat_cnt;
+ DPRINT("bat_cnt = %d\n", bat_cnt);
+ }
+ // Perhaps non node is avialable.
+ else if (bat_cnt == 0) {
+ DPRINT("bat_cnt == 0\n");
+ break;
+ }
+ // Error occured.
+ else {
+ // break and handle prepared data.
+ if (usecount > 0) {
+ DPRINT("bat_cnt < 0, usecount > 0\n");
+ break;
+ }
+ // Has not prepared any data and return error when prepared data.
+ else {
+ DPRINT("bat_cnt < 0, usecount == 0\n");
+ return bat_cnt;
}
}
- if (ret + cnt > count) {
- spin_lock(&controller->lock);
- cnt = count - ret;
- spin_unlock(&controller->lock);
+ }
+
+ DPRINT("count = %d\n", count);
+
+ // Prepare few data or remain data after below code.
+ if (bat_cnt != 0 && count >= 32) {
+ DPRINT("check point 2 ... count = %d\n", count);
+ rem_cnt = endpoint_put_userdata(pout_endpoint, &buffer[usecount], count);
+ if (rem_cnt > 0) {
+ usecount += rem_cnt;
+ count -= rem_cnt;
+ DPRINT("check point 3 ... rem_cnt = %d\n", rem_cnt);
+ } else if (rem_cnt <= 0) {
+ // Not success... return Error.
+ if (usecount == 0) {
+ DPRINT("rem_cnt <= 0, usecount == 0\n");
+ return rem_cnt;
+ }
+ // Go on handle prepared data, ignore the error.
+ else {
+ DPRINT("rem_cnt <= 0, usecount != 0, usecount = %d\n", usecount);
+ }
}
- if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
- return ret ? ret : -EFAULT;
+ }
- spin_lock(&controller->lock);
- ret += cnt;
- spin_unlock(&controller->lock);
+ // Handle prepared data.
+ if (usecount > 0) {
+ unsigned long flags;
+ audio_node *node;
+ AUDIO_LOCK(pout_endpoint->lock, flags);
+ if ((pout_endpoint->trans_state & PIPE_TRANS) == 0) {
+ node = get_audio_usenode(pout_endpoint->mem);
+ if (node) {
+ unsigned int start;
+ start = trystart_endpoint_out(controller, node);
+ if (start == 0) {
+ printk("JZ I2S: trystart_endpoint_out error\n");
+ }
+ }
+ }
+ AUDIO_UNLOCK(pout_endpoint->lock, flags);
+ }
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->nextIn += ret;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
+ DPRINT("----write data usecount = %d, count = %d\n", usecount, count);
+ BUG_ON(count < 0);
+ LEAVE();
- spin_lock(&controller->lock);
- left_count -= cnt;
- spin_unlock(&controller->lock);
- }
- return ret;
+ return usecount + (count < 32 ? count : 0);
}
-static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+/**
+ * Copy recorded sound data from 'use' link list to userspace
+ */
+static inline int endpoint_get_userdata(audio_pipe *endpoint, const char __user *buffer, size_t count)
{
- int id, ret = 0, left_count, copy_count = 0;
- unsigned long flags;
- struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
-
- if (count <= 0)
- return -EINVAL;
-
- if(set_replay_hp_or_speaker)
- set_replay_hp_or_speaker();
-
- __i2s_enable_transmit_dma();
- __i2s_enable_replay();
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->nextOut = 0;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
- if (jz_audio_channels == 2)
- copy_count = jz_audio_fragsize / jz_audio_b;
- else if(jz_audio_channels == 1)
- copy_count = jz_audio_fragsize / 4;
- left_count = count;
- if (copy_from_user(controller->tmp1, buffer, count)) {
- printk("copy_from_user failed:%d",ret);
- return ret ? ret : -EFAULT;
- }
-
- while (left_count > 0) {
- audio_write_back:
- if (file->f_flags & O_NONBLOCK)
- udelay(2);
- if (elements_in_queue(&out_empty_queue) == 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret;
- else
- sleep_on(&tx_wait_queue);
- }
- /* the end fragment size in this write */
- if (ret + copy_count > count)
- copy_count = count - ret;
- if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
- replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
- if(*(out_dma_buf_data_count + id) > 0) {
- put_buffer_id(&out_full_queue, id);
- dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id));
- } else
- put_buffer_id(&out_empty_queue, id);
- } else
- goto audio_write_back;
-
- left_count = left_count - copy_count;
- ret += copy_count;
-
- spin_lock_irqsave(&controller->ioctllock, flags);
- controller->nextOut += ret;
- spin_unlock_irqrestore(&controller->ioctllock, flags);
-
- if (elements_in_queue(&out_busy_queue) == 0) {
- if ((id=get_buffer_id(&out_full_queue)) >= 0) {
- put_buffer_id(&out_busy_queue, id);
- if(*(out_dma_buf_data_count + id) > 0) {
- audio_start_dma(controller->dma1,
- file->private_data,
- *(out_dma_pbuf + id),
- *(out_dma_buf_data_count + id),
- DMA_MODE_WRITE);
- last_dma_buffer_id = id;
-#if defined(CONFIG_I2S_DLV)
- if (jz_codec_config == 0) {
-#if 0
- write_codec_file_bit(1, 0, 5);
- gain_up_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
-#endif
- if (!jz_dlv_vol_mute) {
- write_codec_file_bit(1, 0, 5);
- gain_up_start = jiffies;
- wait_event(pop_wait_queue, pop_wait_event);
- pop_wait_event = 0;
- }
-
- //gain_up_end = jiffies;
- jz_codec_config = 1;
- //SB_ADC->1
- //write_codec_file_bit(5, 1, 4);
- //while(1);
- }
-#endif
+ unsigned long flags;
+ audio_node *node;
+ int ret,err;
+
+ /* counter for node buffer, raw data */
+ int node_buff_cnt = 0;
+ /* counter for node buffer after filte, fixed data */
+ int fixed_buff_cnt = 0;
+
+ ENTER();
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ node = get_audio_usenode(endpoint->mem);
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ DPRINT(">>>> %s mode\n", endpoint->is_non_block ? "non block" : "block");
+
+ // For non-block mode
+ if (endpoint->is_non_block && !node) {
+ return 0;
+ }
+
+ // For block mode, wait node which full filled data
+ while (!node) {
+ if ((endpoint->trans_state & PIPE_TRANS) == 0 ) {
+ DPRINT("DMA trans has not been started !\n");
+ return -1;
+ }
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ DUMP_LIST((audio_head *)endpoint->mem);
+ DUMP_NODE(endpoint->savenode, "SN");
+ AUDIO_UNLOCK(endpoint->lock, flags);
+
+ DPRINT("record stereo ... wait pipe_sem ----------\n");
+
+ // wait available node
+// interruptible_sleep_on(&endpoint->q_full);
+// wait_event_interruptible(endpoint->q_full, endpoint->avialable_couter >= 1);
+ do {
+ err = wait_event_interruptible(endpoint->q_full, endpoint->avialable_couter >= 1);
+ if (err == -ERESTARTSYS)
+ printk("There is no available node\n");
+ }while(err == -ERESTARTSYS);
+
+ AUDIO_LOCK(endpoint->lock, flags);
+ node = get_audio_usenode(endpoint->mem);
+ endpoint->avialable_couter = 0;
+ AUDIO_UNLOCK(endpoint->lock, flags);
+ }
+
+ if (node && (node_buff_cnt = node->end - node->start)) {
+ DPRINT("node_buff_cnt = %d, count = %d\n", node_buff_cnt, count);
+
+ if (endpoint->filter) {
+
+/*
+ printk("filter 3 ... %d\n", node_buff_cnt);
+ {
+ int i;
+ for (i = 100; i < 112; i++) {
+ printk("*(nod->pBuf + node_start + %d) = 0x%02x\n",
+ i, *(char *)(node->pBuf + node->start + i));
}
}
+*/
+ /* ret indicate that final data length when copy_to_user
+ * (node->end - node->start) may not equals to ret !
+ */
+ fixed_buff_cnt = endpoint->filter((void *)(node->pBuf + node->start), node_buff_cnt);
+/*
+ {
+ int i;
+ for (i = 100; i < 112; i++) {
+ printk("*(nod->pBuf + node_start + %d) = 0x%02x\n",
+ i, *(char *)(node->pBuf + node->start + i));
+ }
+ }
+*/
+ } else {
+ fixed_buff_cnt = node_buff_cnt;
+ }
+
+ if (count >= (size_t)fixed_buff_cnt) {
+ DPRINT(">>>> count >= fixed_buff_cnt, copy_to_user, fixed_buff_cnt = %d\n", fixed_buff_cnt);
+ ret = copy_to_user((void *)buffer, (void *)(node->pBuf + node->start), fixed_buff_cnt);
+ if (ret) {
+ printk("JZ I2S: copy_to_user failed, return %d\n", ret);
+ return -EFAULT;
+ }
+ put_audio_freenode(endpoint->mem, node);
+ } else {
+ DPRINT(">>>> count < fixed_buff_cnt, copy_to_user, fixed_buff_cnt = %d\n", fixed_buff_cnt);
+ ret = copy_to_user((void *)buffer,(void *)(node->pBuf + node->start), count);
+ if (ret) {
+ printk("JZ I2S: copy_to_user failed, return %d\n", ret);
+ return -EFAULT;
+ }
+ node->start += node_buff_cnt;
}
}
- return ret;
+ LEAVE();
+
+ return (fixed_buff_cnt < count ? fixed_buff_cnt : count);
}
-#if defined(CONFIG_I2S_ICODEC)
-static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample)
+static ssize_t jz_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- int i,step_len;
- unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf;
- unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
- unsigned long l_sample_count,r_sample_count,sample_count;
- struct jz_i2s_controller_info *controller = i2s_controller;
- signed int left_sam=0,right_sam=0,l_val,r_val;
-
- switch (sample_oss) {
- case 0x0:
- break;
- case 0x1:
- left_sam = (signed int)l_sample;
- right_sam = (signed int)r_sample;
- break;
- case 0x2:
- break;
- case 0x3:
- break;
- case 0x4:
- break;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *)file->private_data;
+ audio_pipe *pin_endpoint = controller->pin_endpoint;
+ audio_node *node;
+ unsigned long flags;
+ int mcount, usecount = 0;
+
+ ENTER();
+
+ if (count == 0) {
+ DPRINT("@@@@ jz_audio_read count == 0\n");
+ return 0;
}
- if(left_sam == 0 && right_sam == 0)
- return;
-
- switch (sample_oss) {
- case 0x0:
- break;
- case 0x1:
- step_len = jz_audio_speed / 10 * 3;
- step_len = step_len / 2;
- step_len = 0x7fff / step_len + 1;
-
- l_sample_count = 0;
- l_val = left_sam;
-
- while(1) {
- if(l_val > 0) {
- if(l_val >= step_len) {
- l_val -= step_len;
- l_sample_count ++;
- } else
- break;
- }
-
- if(l_val < 0) {
- if(l_val <= -step_len) {
- l_val += step_len;
- l_sample_count ++;
- } else
- break;
+ pin_endpoint->is_non_block = file->f_flags & O_NONBLOCK;
+
+ AUDIO_LOCK(pin_endpoint->lock, flags);
+
+ DUMP_LIST((audio_head *)pin_endpoint->mem);
+ DUMP_NODE(pin_endpoint->savenode, "SN");
+
+ DPRINT("@@@@ jz_audio_read, pin_endpoint->trans_state = 0x%08x\n",
+ pin_endpoint->trans_state);
+
+ if ((pin_endpoint->trans_state & PIPE_TRANS) == 0) {
+ DPRINT("@@@@ jz_audio_read, PIPE_TRANS\n");
+ node = get_audio_freenode(pin_endpoint->mem);
+ if (node) {
+ unsigned int start;
+ DPRINT("@@@@ jz_audio_read, trystart_endpoint_in\n");
+// pin_endpoint->fragsize = count;
+ node->end = pin_endpoint->fragsize;
+
+ start = trystart_endpoint_in(controller, node);
+ if (start == 0) {
+ DPRINT("@@@@ Error ! jz_audio_read, start == 0\n");
+ put_audio_freenode(pin_endpoint->mem, node);
}
-
- if(l_val == 0)
- break;
}
-
- r_sample_count = 0;
- r_val = right_sam;
- while(1) {
- if(r_val > 0) {
- if(r_val >= step_len) {
- r_val -= step_len;
- r_sample_count ++;
- } else
- break;
- }
-
- if(r_val < 0) {
- if(r_val <= -step_len) {
- r_val += step_len;
- r_sample_count ++;
- } else
- break;
- }
-
- if(r_val == 0)
+ }
+ AUDIO_UNLOCK(pin_endpoint->lock, flags);
+
+ DUMP_AIC_REGS(__FUNCTION__);
+ DUMP_CODEC_REGS(__FUNCTION__);
+ //dump_dlv_regs(__FUNCTION__);
+ DPRINT("@@@@ count = %d\n", count);
+
+ do{
+ mcount = endpoint_get_userdata(pin_endpoint, &buffer[usecount], count);
+
+ DPRINT("@@@@ jz_audio_read, mcount = %d, usecount = %d\n", mcount, usecount);
+
+ if (mcount < 0) {
+ DPRINT("@@@@ jz_audio_read, mcount < 0, %d\n", mcount);
+ if (usecount > 0) {
break;
+ } else {
+ return mcount;
+ }
+ } else if (mcount == 0) {
+ DPRINT("@@@@ jz_audio_read, mcount == 0\n");
+ break;
+ } else {
+ usecount += mcount;
+ count -= mcount;
+ DPRINT("@@@@ jz_audio_read, mcount > 0, %d\n", mcount);
}
- /* fill up */
- if(l_sample_count > r_sample_count)
- sample_count = l_sample_count;
- else
- sample_count = r_sample_count;
-
- l_val = left_sam;
- r_val = right_sam;
- for(i=0;i <= sample_count;i++) {
-
- *pop_buf = (unsigned long)l_val;
- pop_buf ++;
-
- if(l_val > step_len)
- l_val -= step_len;
- else if(l_val < -step_len)
- l_val += step_len;
- else if(l_val >= -step_len && l_val <= step_len)
- l_val = 0;
-
- *pop_buf = (unsigned long)r_val;
- pop_buf ++;
- if(r_val > step_len)
- r_val -= step_len;
- else if(r_val < -step_len)
- r_val += step_len;
- else if(r_val >= -step_len && r_val <= step_len)
- r_val = 0;
- }
-
- *pop_buf = 0;
- pop_buf ++;
- *pop_buf = 0;
-
- pop_buf ++;
- sample_count += 2;
- dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8);
-
- pop_dma_flag = 1;
- audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE);
- sleep_on(&pop_wait_queue);
- pop_dma_flag = 0;
- break;
- case 0x2:
+ } while (count > 0);
+
+ DPRINT("@@@@ jz_audio_read, usecount = %d\n", usecount);
+
+ LEAVE();
+ return usecount;
+}
+
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops = {
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ ioctl: jz_audio_ioctl
+};
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name = NULL;
+ int adev = 0; /* No of Audio device. */
+
+ ENTER();
+
+ name = controller->name;
+
+ /* Initialize I2S CODEC and register /dev/mixer. */
+ if (jz_i2s_codec_init(controller) <= 0) {
+ goto mixer_failed;
+ }
+
+ /* Initialize AIC controller and reset it. */
+ jz_i2s_reinit_hw(controller->i2s_codec,1);
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0) {
+ goto audio_failed;
+ }
+
+ controller->dev_audio = adev;
+ jz_codec_anti_pop(controller->i2s_codec, 1); //CODEC_WMODE
+
+ LEAVE();
+
+ return;
+mixer_failed:
+
+audio_failed:
+ unregister_sound_dsp(adev);
+
+ LEAVE();
+ return;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_reinit_hw(controller->i2s_codec,0);
+}
+
+//--------------------------------------------------------------------
+#ifdef CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ int i;
+ struct i2s_codec *codec;
+ for(i = 0;i < 1; i++){
+ codec = &the_codecs[i];
+ codec->codes_ioctrl(codec, CODEC_I2S_SUSPEND, 0);
+ }
+ printk("Aic and codec are suspended!\n");
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ int i;
+ struct i2s_codec *codec;
+ for(i = 0;i < 1; i++){
+ codec = &the_codecs[i];
+ codec->codes_ioctrl(codec, CODEC_I2S_RESUME,0);
+ }
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
break;
- case 0x3:
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
break;
- case 0x4:
+ default:
+ ret = -EINVAL;
break;
}
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ struct jz_i2s_controller_info *ctrl;
+
+ ENTER();
+ ctrl = kmalloc(sizeof(struct jz_i2s_controller_info), GFP_KERNEL);
+ if (ctrl == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ ctrl->name = "Jz I2S controller";
+ ctrl->pout_endpoint = 0;
+ ctrl->pin_endpoint = 0;
+ ctrl->error = 0;
+ //ctrl->i2s_codec->use_mic_line_flag = USE_NONE;
+
+ *controller = ctrl;
+
+ LEAVE();
+
+ return 0;
+}
+
+void i2s_controller_init(void)
+{
+ unsigned int aicfr;
+ unsigned int aiccr;
+ //init cpm clock, use ext clock;
+
+ ENTER();
+
+ REG_CPM_I2SCDR = 0;
+ __cpm_select_i2sclk_exclk();
+ __cpm_exclk_div2();
+ __cpm_enable_pll_change();
+
+ aicfr = (8 << 12) | (8 << 8) | (AIC_FR_ICDC | AIC_FR_LSMP | AIC_FR_AUSEL);
+ REG_AIC_FR = aicfr;
+
+ aiccr = REG_AIC_CR;
+ aiccr &= (~(AIC_CR_EREC | AIC_CR_ERPL | AIC_CR_TDMS | AIC_CR_RDMS));
+ REG_AIC_CR = aiccr;
+
+ LEAVE();
}
+
+static int __init init_jz_i2s(struct platform_device *pdev)
+{
+ struct i2s_codec *default_codec = &(the_codecs[0]);
+ int errno;
+ int fragsize;
+ int fragstotal;
+
+ i2s_controller_init();
+ if (default_codec->codecs_ioctrl == NULL) {
+ printk("default_codec: not ready!");
+ return -1;
+ }
+
+ default_codec->codecs_ioctrl(default_codec, CODEC_SET_MODE, 0);
+
+ if ((errno = probe_jz_i2s(&the_i2s_controller)) < 0) {
+ return errno;
+ }
+
+ /* May be external CODEC need it ...
+ * default_codec->codecs_ioctrl(default_codec, CODEC_SET_GPIO_PIN, 0);
+ */
+
+ attach_jz_i2s(the_i2s_controller);
+
+ /* Actually, the handler function of the command do nothing ...
+ * default_codec->codecs_ioctrl(default_codec, CODEC_SET_STARTUP_PARAM, 0);
+ * default_codec->codecs_ioctrl(default_codec, CODEC_SET_STARTUP_PARAM, 0);
+ */
+
+ /* Now the command is not supported by DLV CODEC ...
+ * default_codec->codecs_ioctrl(default_codec, CODEC_SET_VOLUME_TABLE, 0);
+ */
+ fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ fragstotal = JZCODEC_RW_BUFFER_TOTAL;
+
+ audio_init_endpoint(&out_endpoint, fragsize, fragstotal);
+ audio_init_endpoint(&in_endpoint, fragsize, fragstotal);
+
+#ifdef CONFIG_PM
+ the_i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (the_i2s_controller->pm) {
+ the_i2s_controller->pm->data = i2s_controller;
+ }
#endif
+
+ printk("JZ I2S OSS audio driver initialized\n");
+
+ LEAVE();
+
+ return 0;
+}
+
+static void __exit cleanup_jz_i2s(void)
+{
+#ifdef CONFIG_PM
+ /* pm_unregister(i2s_controller->pm); */
+#endif
+ struct i2s_codec *default_codec = &the_codecs[0];
+ unload_jz_i2s(the_i2s_controller);
+ the_i2s_controller = NULL;
+ audio_deinit_endpoint(&out_endpoint);
+ audio_deinit_endpoint(&in_endpoint);
+ default_codec->codecs_ioctrl(default_codec, CODEC_CLEAR_MODE, 0);
+}
+
+static struct platform_driver snd_plat_driver = {
+ .probe = init_jz_i2s,
+ .driver = {
+ .name = "mixer",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init snd_init(void)
+{
+ return platform_driver_register(&snd_plat_driver);
+}
+
+module_init(snd_init);
+module_exit(cleanup_jz_i2s);
diff --git a/sound/oss/jzdlv.c b/sound/oss/jzdlv.c
index 8061c36f508..91229d98ef2 100644
--- a/sound/oss/jzdlv.c
+++ b/sound/oss/jzdlv.c
@@ -1,14 +1,19 @@
/*
- * linux/drivers/sound/jzcodec.c
+ * Linux/sound/oss/jz_dlv.c
*
- * JzSOC internal audio driver.
+ * DLV CODEC driver for Ingenic Jz4750 MIPS processor
*
+ * 2009-12-xx Steven <dsqiu@ingenic.cn>
+ * 2010-01-xx Jason <xwang@ingenic.cn>
+ *
+ * Copyright (c) Ingenic Semiconductor Co., Ltd.
*/
+
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/delay.h>
-
+#include <linux/workqueue.h>
#include <linux/sound.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -22,641 +27,1134 @@
#include <asm/jzsoc.h>
#include "sound_config.h"
-#include "jzdlv.h"
-
-#define USE_NONE 1
-#define USE_MIC 2
-#define USE_LINEIN 3
-
-/* For volume control mute - Added by River. */
-extern int jz_dlv_vol_mute;
-
-extern mixer_info info;
-extern _old_mixer_info old_info;
-extern int codec_volue_shift;
-
-extern void (*set_codec_mode)(void);
-extern void (*each_time_init_codec)(void);
-extern int (*set_codec_startup_param)(void);
-extern void (*set_codec_record)(void);
-extern void (*set_codec_replay)(void);
-extern void (*set_codec_replay_record)(void);
-extern void (*turn_on_codec)(void);
-extern void (*turn_off_codec)(void);
-extern void (*set_codec_speed)(int rate);
-extern void (*reset_codec)(void);
-extern void (*codec_mixer_old_info_id_name)(void);
-extern void (*codec_mixer_info_id_name)(void);
-extern void (*set_codec_bass)(int val);
-extern void (*set_codec_volume)(int val);
-extern void (*set_codec_mic)(int val);
-extern void (*set_codec_line)(int val);
-extern void (*i2s_resume_codec)(void);
-extern void (*i2s_suspend_codec)(void);
-extern void (*set_codec_direct_mode)(void);
-extern void (*clear_codec_direct_mode)(void);
-
-
-void set_dlv_mode(void);
-void each_time_init_jzcodec(void);
-int set_dlv_startup_param(void);
-void set_dlvjzcodec_volume_table(void);
-void set_dlv_replay(void);
-void set_dlv_record(void);
-void set_dlv_speed(int rate);
-void reset_dlv(void);
-void jzcodec_mixer_old_info_id_name(void);
-void jzcodec_mixer_info_id_name(void);
-void set_dlv_volume(int val);
-void set_dlv_mic(int val);
-
-extern int jz_mic_only;
-int read_codec_file(int addr)
-{
- while (__icdc_rgwr_ready());
- __icdc_set_addr(addr);
- mdelay(1);
- return(__icdc_get_value());
-}
-#if 0
-void printk_codec_files(void)
-{
- int cnt;
+#include "jz_audio.h"
+#include "jz_codec.h"
+#include "jz4750_dlv.h"
+#include "jz_i2s_dbg.h"
- printk("\n");
-
- printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
- printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
- printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
- printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
- printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
- printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
- printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
- printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+#define REPLAY 1
+#define RECORD 2
- for (cnt = 0; cnt <= 27 ; cnt++) {
- printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt));
+#define POWER_ON 0
+#define POWER_OFF 1
+
+#define switch_SB_DAC(pwrstat) \
+do { \
+ dlv_write_reg_bit(5, pwrstat, 7); \
+} while (0) \
+
+#define switch_SB_OUT(pwrstat) \
+do { \
+ dlv_write_reg_bit(5, pwrstat, 6); \
+} while (0) \
+
+#define switch_SB_MIX(pwrstat) \
+do { \
+ dlv_write_reg_bit(5, pwrstat, 5); \
+} while (0) \
+
+#define switch_SB_ADC(pwrstat) \
+do { \
+ dlv_write_reg_bit(5, pwrstat, 4); \
+} while (0) \
+
+/*
+#define ENTER() printk("Enter: %s, %s:%i\n", __FUNCTION__, __FILE__, __LINE__)
+#define LEAVE() printk("Leave: %s, %s:%i\n", __FUNCTION__, __FILE__, __LINE__)
+*/
+
+#ifdef IOC_DEBUG
+static dlv_print_ioc_cmd(int cmd)
+{
+ char *dlv_ioc_cmd[] = {
+ "CODEC_SET_MODE", "CODEC_CLEAR_MODE", "CODEC_SET_GPIO_PIN",
+ "CODEC_EACH_TIME_INIT", "CODEC_SET_STARTUP_PARAM", "CODEC_SET_VOLUME_TABLE",
+ "CODEC_SET_RECORD", "CODEC_SET_REPLAY", "CODEC_SET_REPLAY_RECORD",
+ "CODEC_TURN_ON", "CODEC_TURN_OFF", "CODEC_SET_REPLAY_SPEED",
+ "CODEC_RESET", "CODEC_GET_MIXER_OLD_INFO", "CODEC_GET_MIXER_INFO",
+ "CODEC_SET_BASS", "CODEC_SET_VOLUME", "CODEC_SET_MIC",
+ "CODEC_SET_LINE", "CODEC_I2S_RESUME", "CODEC_I2S_SUSPEND",
+ "CODEC_PIN_INIT", "CODEC_SET_SOME_FUNC", "CODEC_CLEAR_RECORD",
+ "CODEC_CLEAR_REPLAY", "CODEC_SET_REPLAY_HP_OR_SPKR", "CODEC_SET_DIRECT_MODE",
+ "CODEC_CLEAR_DIRECT_MODE", "CODEC_SET_LINEIN2HP", "CODEC_CLEAR_LINEIN2HP",
+ "CODEC_ANTI_POP", "CODEC_TURN_REPLAY", "CODEC_SET_REPLAY_CHANNEL",
+ "CODEC_SET_REPLAY_FORMAT", "CODEC_SET_RECORD_CHANNEL", "CODEC_SET_RECORD_FORMAT",
+ "CODEC_SET_RECORD_SPEED", "CODEC_DAC_MUTE"
+ };
+
+ if (cmd >= (sizeof(dlv_ioc_cmd) / sizeof(dlv_ioc_cmd[0]))) {
+ printk("%s: Unkown command !\n", __FUNCTION__);
+ } else {
+ printk("IOC CMD NAME = %s\n", dlv_ioc_cmd[cmd - 1]);
}
- printk("\n");
}
#endif
-void write_codec_file(int addr, int val)
+static inline int dlv_read_reg(int addr)
{
- while (__icdc_rgwr_ready());
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
__icdc_set_addr(addr);
- __icdc_set_cmd(val); /* write */
- mdelay(1);
+ return __icdc_get_value();
+}
+
+void dlv_write_reg(int addr, int val)
+{
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
+ REG_ICDC_RGADW = ((addr << ICDC_RGADW_RGADDR_BIT) | val);
__icdc_set_rgwr();
- mdelay(1);
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
}
-int write_codec_file_bit(int addr, int bitval, int mask_bit)
+static int dlv_write_reg_bit(int addr, int bitval, int mask_bit)
{
int val;
- while (__icdc_rgwr_ready());
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
__icdc_set_addr(addr);
mdelay(1);
- val = __icdc_get_value(); /* read */
+ /* read */
+ val = __icdc_get_value();
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
- while (__icdc_rgwr_ready());
__icdc_set_addr(addr);
val &= ~(1 << mask_bit);
- if (bitval == 1)
+ if (bitval == 1) {
val |= 1 << mask_bit;
+ }
__icdc_set_cmd(val); /* write */
mdelay(1);
__icdc_set_rgwr();
mdelay(1);
- while (__icdc_rgwr_ready());
+ while (__icdc_rgwr_ready()) {
+ ;//nothing...
+ }
__icdc_set_addr(addr);
val = __icdc_get_value(); /* read */
- if (((val >> mask_bit) & bitval) == bitval)
+ if (((val >> mask_bit) & bitval) == bitval) {
return 1;
- else
+ } else {
return 0;
+ }
}
-void set_dlv_mode(void)
-{
- /*REG_CPM_CPCCR &= ~(1 << 31);
- REG_CPM_CPCCR &= ~(1 << 30);*/
- write_codec_file(0, 0xf);
- REG_AIC_I2SCR = 0x10;
- __i2s_internal_codec();
- __i2s_as_slave();
- __i2s_select_i2s();
- __aic_select_i2s();
- __aic_reset();
- mdelay(10);
- REG_AIC_I2SCR = 0x10;
- mdelay(20);
+/*
+ * DLV CODEC operations routines
+ */
- /* power on DLV */
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
- mdelay(10);
-}
-void reset_dlv_codec(void)
+static void dlv_each_time_init(void)
{
- /* reset DLV codec. from hibernate mode to sleep mode */
- write_codec_file(0, 0xf);
- write_codec_file_bit(6, 0, 0);
- write_codec_file_bit(6, 0, 1);
- mdelay(200);
- //write_codec_file(0, 0xf);
- write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
- write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
- mdelay(10);//wait for stability
+ ENTER();
+ __i2s_disable();
+ __i2s_as_slave();
+ __aic_internal_codec();
+ //__i2s_set_oss_sample_size(16);
+ //__i2s_set_iss_sample_size(16);
+ LEAVE();
}
-void each_time_init_dlv(void)
+static void dlv_set_mode(void)
{
- __i2s_disable();
- __i2s_as_slave();
- __aic_internal_codec();
- __i2s_set_oss_sample_size(16);
- __i2s_set_iss_sample_size(16);
+ ENTER();
+ /*REG_CPM_CPCCR &= ~(1 << 31);
+ REG_CPM_CPCCR &= ~(1 << 30);*/
+ dlv_write_reg(0, 0xf);
+ dlv_write_reg(8, 0x2f);
+ dlv_write_reg(9, 0xff);
+ schedule_timeout(2);
+
+ dlv_write_reg_bit(6, 0, 1);//PMR2.SB->0
+ msleep(10);
+ dlv_write_reg_bit(6, 0, 0);//PMR2.SB->0
+ msleep(10);
+ DPRINT_CODEC("##### cleared codec reg6\n");
+ dlv_write_reg_bit(1, 0, 3);//PMR2.SB->0
+
+ dlv_write_reg_bit(5, 0, 4);//SB_ADC->1
+// set_record_mic_input_audio_with_audio_data_replay();
+// reset_dlv_codec();
+ LEAVE();
}
-int set_dlv_startup_param(void)
+static void dlv_reset(void)
{
- __i2s_disable_transmit_intr();
- __i2s_disable_receive_intr();
+ ENTER();
+ /* reset DLV codec. from hibernate mode to sleep mode */
+ dlv_write_reg(0, 0xf);
+ dlv_write_reg_bit(6, 0, 0);
+ dlv_write_reg_bit(6, 0, 1);
+
+ //2010-01-31 Jason add
+ dlv_write_reg(22, 0x40);//mic 1
+
+ schedule_timeout(20);
+ //dlv_write_reg(0, 0xf);
+ dlv_write_reg_bit(5, 0, 7);//PMR1.SB_DAC->0
+ dlv_write_reg_bit(5, 0, 4);//PMR1.SB_ADC->0
+ schedule_timeout(2); ;//wait for stability
+ LEAVE();
+}
+static int dlv_set_startup_param(void)
+{
+ ENTER();
+ LEAVE();
+// __i2s_disable_transmit_intr();
+// __i2s_disable_receive_intr();
return 1;
}
+
+//@@@@@@@@@@@@@@@@@@@@
/* set Audio data replay */
-void set_audio_data_replay(void)
+static void dlv_set_replay(void)
{
+ ENTER();
+
+ //dump_dlv_regs("enter dlv_set_replay");
+
/* DAC path */
- write_codec_file(9, 0xff);
- //write_codec_file(8, 0x30);
- write_codec_file(8, 0x20);
- mdelay(10);
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
-
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
-
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ dlv_write_reg(9, 0xff);
+ //dlv_write_reg(8, 0x30);
+ //dlv_write_reg(8, 0x20);
+
+ schedule_timeout(2);
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
+
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ //2010-01-31 Jason marked
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
+
+ dlv_write_reg_bit(1, 0, 5);//MUTE
+
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
//mdelay(100);
- //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+
+ //2010-01-31 Jason marked
+ //dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+
//mdelay(300);
+ //dump_dlv_regs("leave dlv_set_replay");
+ LEAVE();
}
-#if 1 /* mask warning */
+#if 0
+// @@@@@@@@@@@@@@@@@@@@@@@@
/* set Record MIC input audio without playback */
-void set_record_mic_input_audio_without_playback(void)
+static void set_record_mic_input_audio_without_playback(void)
{
+ ENTER();
+ // 2010-01-20 Jason added
+/*
+ dlv_write_reg_bit(6, 0, 0);//SB_SLEEP->0
+ dlv_write_reg_bit(6, 0, 1);//SB->0
+ dlv_write_reg_bit(5, 0, 4);//SB_ADC->0
+*/
/* ADC path for MIC IN */
- jz_mic_only = 1;
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- mdelay(10);
- write_codec_file_bit(1, 1, 2);
- //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x3f);
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ schedule_timeout(2);
+ dlv_write_reg_bit(1, 1, 2);
+ //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
- write_codec_file(22, 0x40);//mic 1
- write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg(22, 0x40);//mic 1
+ dlv_write_reg_bit(3, 1, 7);//CR1.HP_DIS->1
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
- //write_codec_file_bit(6, 1, 3);// gain set
-
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
- mdelay(100);
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- write_codec_file(1, 0x4);
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(1, 0, 3);//CR1.DACSEL->0
+ //dlv_write_reg_bit(6, 1, 3);// gain set
+
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+ schedule_timeout(10);
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+ dlv_write_reg(1, 0x4);
+
+ dlv_write_reg(19, (80 * 32 / 100) | ((80 * 32 / 100) << 4));
+
+ // 2010-01-19 Jason added
+
+ dlv_write_reg_bit(6, 0, 0);//SB_SLEEP->0
+ dlv_write_reg_bit(6, 0, 1);//SB->0
+ dlv_write_reg_bit(5, 0, 4);//SB_ADC->0
+
+ LEAVE();
}
-#endif
-#if 1 /* mask warning */
/* unset Record MIC input audio without playback */
-void unset_record_mic_input_audio_without_playback(void)
+static void unset_record_mic_input_audio_without_playback(void)
{
+ ENTER();
/* ADC path for MIC IN */
- jz_mic_only = 0;
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- write_codec_file(22, 0xc0);//CR3.SB_MIC1
- write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ // 2010-01-20 Jason modified
+// dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1
+ dlv_write_reg_bit(5, 1, 6);//PMR1.SB_OUT->1
+ dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+// dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+// dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* set Record LINE input audio without playback */
-void set_record_line_input_audio_without_playback(void)
+static void set_record_line_input_audio_without_playback(void)
{
+ ENTER();
/* ADC path for LINE IN */
- jz_mic_only = 1;
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x3f);
mdelay(10);
- write_codec_file(22, 0xf6);//line in 1
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
- write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg(22, 0xf6);//line in 1
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg_bit(3, 1, 7);//CR1.HP_DIS->1
+ dlv_write_reg_bit(5, 0, 3);//PMR1.SB_LIN->0
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(1, 0, 3);//CR1.DACSEL->0
mdelay(10);
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
mdelay(100);
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- write_codec_file(1, 0x4);
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+ dlv_write_reg(1, 0x4);
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* unset Record LINE input audio without playback */
-void unset_record_line_input_audio_without_playback(void)
+static void unset_record_line_input_audio_without_playback(void)
{
+ ENTER();
/* ADC path for LINE IN */
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1
-
- write_codec_file(22, 0xc0);//CR3.SB_MIC1
- write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(5, 1, 3);//ONR1.SB_LIN->1
+
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1
+ dlv_write_reg_bit(5, 1, 6);//PMR1.SB_OUT->1
+ dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+ dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+ dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-#if 1 /* mask warning */
+#if 0
/* set Playback LINE input audio direct only */
-void set_playback_line_input_audio_direct_only(void)
+static void set_playback_line_input_audio_direct_only(void)
{
- jz_mic_only = 0;
-
+ ENTER();
+// need fix !!!
// jz_audio_reset();//or init_codec()
REG_AIC_I2SCR = 0x10;
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x3f);
mdelay(10);
- write_codec_file(22, 0xf6);//line in 1
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg(22, 0xf6);//line in 1
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
mdelay(10);
- write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ dlv_write_reg_bit(1, 1, 2);//CR1.HP_BYPASS->1
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
+ dlv_write_reg_bit(1, 0, 3);//CR1.DACSEL->0
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg_bit(5, 0, 3);//PMR1.SB_LIN->0
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
mdelay(100);
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1
- //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //dlv_write_reg_bit(5, 1, 7);//PMR1.SB_DAC->1
+ //dlv_write_reg_bit(5, 1, 4);//PMR1.SB_ADC->1
+ LEAVE();
}
#endif
-#if 1 /* mask warning */
+#if 0
/* unset Playback LINE input audio direct only */
-void unset_playback_line_input_audio_direct_only(void)
+static void unset_playback_line_input_audio_direct_only(void)
{
- write_codec_file_bit(6, 0, 3);//GIM->0
- write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1
- write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ ENTER();
+ dlv_write_reg_bit(6, 0, 3);//GIM->0
+ dlv_write_reg_bit(1, 0, 2);//PMR1.BYPASS->0
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LINE->1
+ dlv_write_reg_bit(5, 1, 6);//PMR1.SB_OUT->1
mdelay(100);
- write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ dlv_write_reg_bit(5, 1, 5);//PMR1.SB_MIX->1
+ dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+ dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* set Record MIC input audio with direct playback */
-void set_record_mic_input_audio_with_direct_playback(void)
-{
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- jz_mic_only = 0;
- write_codec_file(9, 0xff);
- write_codec_file(8, 0x3f);
+static void set_record_mic_input_audio_with_direct_playback(void)
+{
+ ENTER();
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x3f);
mdelay(10);
- write_codec_file(22, 0x60);//mic 1
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ dlv_write_reg(22, 0x60);//mic 1
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
- write_codec_file_bit(6, 1, 3);// gain set
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(1, 0, 3);//CR1.DACSEL->0
+ dlv_write_reg_bit(6, 1, 3);// gain set
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
mdelay(100);
- write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
- //write_codec_file(1, 0x4);
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //dlv_write_reg(1, 0x4);
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* unset Record MIC input audio with direct playback */
-void unset_record_mic_input_audio_with_direct_playback(void)
+static void unset_record_mic_input_audio_with_direct_playback(void)
{
+ ENTER();
/* ADC path for MIC IN */
- jz_mic_only = 0;
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- write_codec_file(22, 0xc0);//CR3.SB_MIC1
- write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
- write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1
+ dlv_write_reg_bit(5, 1, 6);//PMR1.SB_OUT->1
+ dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+ dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+ dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* set Record playing audio mixed with MIC input audio */
-void set_record_playing_audio_mixed_with_mic_input_audio(void)
+static void set_record_playing_audio_mixed_with_mic_input_audio(void)
{
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- write_codec_file(9, 0xff);
- //write_codec_file(8, 0x30);
- write_codec_file(8, 0x20);
- mdelay(10);
+ ENTER();
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg(9, 0xff);
+ //dlv_write_reg(8, 0x30);
+ dlv_write_reg(8, 0x20);
- write_codec_file(22, 0x63);//mic 1
+ schedule_timeout(2);
+ dlv_write_reg(22, 0x63);//mic 1
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(6, 1, 3);// gain set
-
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
- write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
- write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
- write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(6, 1, 3);// gain set
+
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ dlv_write_reg_bit(22, 0, 7);//CR3.SB_MIC->0
+ dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+ dlv_write_reg_bit(5, 0, 4);//PMR1.SB_MIX->0
+ LEAVE();
}
#endif
-#if 0 /* mask warning */
+#if 0
/* unset Record playing audio mixed with MIC input audio */
-void unset_record_playing_audio_mixed_with_mic_input_audio(void)
+static void unset_record_playing_audio_mixed_with_mic_input_audio(void)
{
+ ENTER();
/* ADC path */
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
- write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
- //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
- //write_codec_file_bit(5, 1, 6);//SB_OUT->1
- write_codec_file_bit(5, 1, 7);//SB_DAC->1
- write_codec_file_bit(5, 1, 5);//SB_MIX->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1->1
+ //dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+ //dlv_write_reg_bit(5, 1, 6);//SB_OUT->1
+// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
+ dlv_write_reg_bit(5, 1, 5);//SB_MIX->1
+ dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+ dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-#if 1 /* mask warning */
+
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/* set Record MIC input audio with Audio data replay (full duplex) */
-void set_record_mic_input_audio_with_audio_data_replay(void)
-{
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- write_codec_file(9, 0xff);
- //write_codec_file(8, 0x30);
- write_codec_file(8, 0x20);
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
-
- write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
- write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
-
- write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+static void set_record_mic_input_audio_with_audio_data_replay(void)
+{
+ ENTER();
+ printk("when run here ?????\n");
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg(9, 0xff);
+ //dlv_write_reg(8, 0x30);
+ dlv_write_reg(8, 0x20);
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ dlv_write_reg_bit(22, 0, 7);//CR3.SB_MIC->0
+
+ dlv_write_reg_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+
+ dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+ LEAVE();
}
-#endif
-#if 1 /* mask warning */
/* unset Record MIC input audio with Audio data replay (full duplex) */
-void unset_record_mic_input_audio_with_audio_data_replay(void)
+static void unset_record_mic_input_audio_with_audio_data_replay(void)
{
+ ENTER();
/* ADC path */
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
- write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
- write_codec_file_bit(5, 1, 7);//SB_DAC->1
- write_codec_file_bit(5, 1, 5);//SB_MIX->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ printk("@@@ %s", __FUNCTION__);
+ dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1->1
+// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
+ dlv_write_reg_bit(5, 1, 5);//SB_MIX->1
+
+ // 2009-01-20 Jason marked
+// dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+// dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
-#endif
-#if 1 /* mask warning */
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/* set Record LINE input audio with Audio data replay (full duplex for linein) */
-void set_record_line_input_audio_with_audio_data_replay(void)
-{
- write_codec_file(9, 0xff);
- //write_codec_file(8, 0x30);
- write_codec_file(8, 0x20);
- write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
- write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
- write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1
- write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
-
-
- //jz_mic_only = 1;
- write_codec_file(22, 0xc6);//line in 1
- write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
- write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
- write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+static void set_record_line_input_audio_with_audio_data_replay(void)
+{
+ ENTER();
+ dlv_write_reg(9, 0xff);
+ //dlv_write_reg(8, 0x30);
+ dlv_write_reg(8, 0x20);
+ dlv_write_reg_bit(1, 0, 4);//CR1.HP_DIS->0
+ dlv_write_reg_bit(5, 0, 3);//PMR1.SB_LIN->0
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //dlv_write_reg_bit(22, 1, 7);//CR3.SB_MIC->1
+ dlv_write_reg_bit(1, 1, 3);//CR1.DACSEL->1
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+
+ dlv_write_reg(22, 0xc6);//line in 1
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+ LEAVE();
}
-#endif
-#if 1 /* mask warning */
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
-void unset_record_line_input_audio_with_audio_data_replay(void)
+static void unset_record_line_input_audio_with_audio_data_replay(void)
{
+ ENTER();
/* ADC path */
- write_codec_file_bit(5, 1, 4);//SB_ADC->1
- write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
- //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
- write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
- write_codec_file_bit(5, 1, 7);//SB_DAC->1
- write_codec_file_bit(5, 1, 5);//SB_MIX->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+ printk("@@@ %s", __FUNCTION__);
+
+ dlv_write_reg_bit(5, 1, 4);//SB_ADC->1
+ dlv_write_reg_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
+ dlv_write_reg(22, 0xc0);//CR3.SB_MIC1->1
+// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
+ dlv_write_reg_bit(5, 1, 5);//SB_MIX->1
+
+ // 2010-01-20 Jason masked
+// dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+// dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
-#endif
-#if 1
+#if 0
/* unset Audio data replay */
-void unset_audio_data_replay(void)
+static void unset_audio_data_replay(void)
{
- //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ ENTER();
+ //dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
//mdelay(800);
- //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ //dlv_write_reg_bit(5, 1, 6);//SB_OUT->1
//mdelay(800);
- write_codec_file_bit(5, 1, 7);//SB_DAC->1
- write_codec_file_bit(5, 1, 4);//SB_MIX->1
- write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
- write_codec_file_bit(6, 1, 1);//SB->1
+// dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
+ dlv_write_reg_bit(5, 1, 4);//SB_MIX->1
+ dlv_write_reg_bit(6, 1, 0);//SB_SLEEP->1
+ dlv_write_reg_bit(6, 1, 1);//SB->1
+ LEAVE();
}
#endif
-void set_dlv_replay(void)
+static int dlv_set_replay_speed(int rate)
{
- set_audio_data_replay();
+ int speed = 0, val;
+#define MAX_RATE_COUNT 11
+ int mrate[MAX_RATE_COUNT] = {
+ 96000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000,
+ 11025, 9600 , 8000};
+
+ for (val = 0; val < MAX_RATE_COUNT; val++) {
+ if (rate >= mrate[val]) {
+ speed = val;
+ break;
+ }
+ }
+ if (rate < mrate[MAX_RATE_COUNT - 1]) {
+ speed = MAX_RATE_COUNT - 1;
+ }
+ val = dlv_read_reg(4);
+ val &= 0xf;
+ val = (speed << 4) | val;
+ dlv_write_reg(4, val);
+ return mrate[speed];
}
-void set_dlv_speed(int rate)
+static int dlv_set_record_speed(int rate)
{
int speed = 0, val;
- speed = 0;
- switch (rate) {
- case 8000:
- speed = 10;
- break;
- case 9600:
- speed = 9;
- break;
- case 11025:
- speed = 8;
- break;
- case 12000:
- speed = 7;
- break;
- case 16000:
- speed = 6;
- break;
- case 22050:
- speed = 5;
- break;
- case 24000:
- speed = 4;
- break;
- case 32000:
- speed = 3;
- break;
- case 44100:
- speed = 2;
- break;
- case 48000:
- speed = 1;
- break;
- case 96000:
- speed = 0;
- break;
- default:
- break;
+#define MAX_RATE_COUNT 11
+ int mrate[MAX_RATE_COUNT] = {
+ 96000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000,
+ 11025, 9600 , 8000};
+ for (val = 0; val < MAX_RATE_COUNT; val++) {
+ if (rate >= mrate[val]) {
+ speed = val;
+ break;
+ }
}
-
- val = read_codec_file(4);
- val = (speed << 4) | speed;
- write_codec_file(4, val);
+ if (rate < mrate[MAX_RATE_COUNT - 1]) {
+ speed = MAX_RATE_COUNT - 1;
+ }
+ val = dlv_read_reg(4);
+ val &= 0xf0;
+ val = (speed) | val;
+ dlv_write_reg(4, val);
+ return mrate[speed];
}
-void reset_jzcodec(void)
+static void dlv_get_mixer_old_info(mixer_info *info)
{
-
+ strncpy(info->id, "JZDLV", sizeof(info->id));
+ strncpy(info->name, "Jz internal codec dlv on jz4750", sizeof(info->name));
}
-void dlv_mixer_old_info_id_name(void)
+static void dlv_get_mixer_info(mixer_info *old_info)
{
- strncpy(info.id, "JZDLV", sizeof(info.id));
- strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name));
+ strncpy(old_info->id, "JZDLV", sizeof(old_info->id));
+ strncpy(old_info->name, "Jz internal codec dlv on jz4750", sizeof(old_info->name));
}
-void dlv_mixer_info_id_name(void)
+static void dlv_set_mic(int val)
{
- strncpy(old_info.id, "JZDLV", sizeof(old_info.id));
- strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name));
-}
+ int cur_vol;
+
+ ENTER();
-void set_dlv_mic(int val)
-{
- int cur_vol ;
/* set gain */
- //write_codec_file_bit(6, 1, 3);//GIM
- cur_vol = 31 * val / 100;
+ dlv_write_reg_bit(6, 1, 3);//GIM
+ cur_vol = 31 * val / 100;
cur_vol |= cur_vol << 4;
- write_codec_file(19, cur_vol);//GIL,GIR
+ dlv_write_reg(19, cur_vol);//GIL,GIR
+
+ LEAVE();
}
-void set_dlv_line(int val)
+static void dlv_set_line(int val)
{
int cur_vol;
+
+ ENTER();
/* set gain */
- cur_vol = 31 * val / 100;
+ cur_vol = 31 * val / 100;
cur_vol &= 0x1f;
- write_codec_file(11, cur_vol);//GO1L
- write_codec_file(12, cur_vol);//GO1R
+ dlv_write_reg(11, cur_vol);//GO1L
+ dlv_write_reg(12, cur_vol);//GO1R
+
+ LEAVE();
}
-void set_dlv_volume(int val)
+static void dlv_set_volume(int val)
{
unsigned long cur_vol;
+
+ ENTER();
+
+ /* To protect circut and to avoid shutting down CODEC,
+ * valume must less then 60% of the max
+ */
+ if (val > 60) {
+ val = 60;
+ }
+ cur_vol = 31 * (100 - val) / 100;
+
+ dlv_write_reg(17, cur_vol | 0x80);
+
+ DPRINT_CODEC("$$$$$ val = %d, REG_17 = 0x%02x, REG_18 = 0x%02x\n",
+ val, dlv_read_reg(17), dlv_read_reg(18));
+
+ LEAVE();
+}
+
+/*
+ * Base on set_record_mic_input_audio_without_playback()
+ */
+static void dlv_set_record(void)
+{
+ ENTER();
+
+ //dump_dlv_regs("enter dlv_set_record");
+
+ /* ADC path for MIC IN */
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x2f);
+ dlv_write_reg_bit(23, 0, 7);//AGC1.AGC_EN->0
+ schedule_timeout(2);
+ dlv_write_reg_bit(1, 1, 2);
+ //dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1
- /* 0 -> DAC Soft Mute - Modified by River. */
- if (!val) {
- if (!jz_dlv_vol_mute) {
- write_codec_file_bit(1, 1, 5); /* DAC soft mute -> ON. */
- jz_dlv_vol_mute = 1;
- }
- }else {
- cur_vol = 31 * (100 - val) / 100;
+ dlv_write_reg(22, 0x40);//mic 1
+ dlv_write_reg_bit(3, 1, 7);//CR1.HP_DIS->1
+ dlv_write_reg_bit(5, 1, 3);//PMR1.SB_LIN->1
+ dlv_write_reg_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ dlv_write_reg_bit(1, 0, 2);//CR1.BYPASS->0
+
+ //2010-02-01 Jason marked
+ //dlv_write_reg_bit(1, 0, 3);//CR1.DACSEL->0
+
+ // 2010-01-31 Jason added
+ //dlv_write_reg_bit(1, 0, 7);
+
+ dlv_write_reg_bit(5, 0, 5);//PMR1.SB_MIX->0
+ schedule_timeout(10);
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+ dlv_write_reg(1, 0x8);
+
+ //2010-02-01 Jason masked
+ //dlv_write_reg(19, (80 * 32 / 100) | ((80 * 32 / 100) << 4));
+
+ // 2010-01-19 Jason added
+ dlv_write_reg_bit(6, 0, 0);//SB_SLEEP->0
+ dlv_write_reg_bit(6, 0, 1);//SB->0
+ dlv_write_reg_bit(5, 0, 4);//SB_ADC->0
+
+ //dump_dlv_regs("leave dlv_set_record");
+
+ LEAVE();
+}
+
+static void dlv_set_replay_recode(int val)
+{
+ ENTER();
+ if (val == USE_LINEIN) {
+ /* Record LINE input audio with Audio data replay (full duplex for linein) */
+ /* codec_test_line */
+ printk("use line in ???\n");
+ set_record_line_input_audio_with_audio_data_replay();
+ }
+ if (val == USE_MIC) {
+ /* Record MIC input audio with Audio data replay (full duplex) */
+ /* codec_test_mic */
+ set_record_mic_input_audio_with_audio_data_replay();
+ }
+ LEAVE();
+}
+
+static void dlv_anti_pop(int mode)
+{
+ switch(mode) {
+ case CODEC_WRMODE:
+ //set SB_ADC or SB_DAC
+ dlv_write_reg_bit(5, 0, 6);//PMR1.SB_OUT->0
+
+ //2010-01-31 Jason add
+ dlv_write_reg(22, 0x40);//mic 1
+
+ //2010-01-31 Jason add
+ //dlv_write_reg(1, 0x04);
+
+ schedule_timeout(28); //280 ms
+ break;
+ case CODEC_RMODE:
+ // 2010-01-31 Jason marked
+ //dlv_write_reg_bit(5, 1, 7);//SB_DAC->1
+
+ //2010-01-31 Jason add
+ dlv_write_reg(22, 0x40);//mic 1
+
+ break;
+ case CODEC_WMODE:
+ dlv_write_reg_bit(6, 0, 2); //codec_reg_clear(A_CODEC_PMR2, SB_MC);
+ mdelay(5);
+ dlv_write_reg_bit(6, 0, 1); //codec_reg_clear(A_CODEC_PMR2, SB);
+ mdelay(30);
+ dlv_write_reg_bit(6, 0, 0); //codec_reg_clear(A_CODEC_PMR2, SB_SLEEP);
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 7); //codec_reg_clear(A_CODEC_PMR1, SB_DAC);
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 6); //codec_reg_clear(A_CODEC_PMR1, SB_OUT);
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 5); //codec_reg_clear(A_CODEC_PMR1, SB_MIX);
- if (jz_dlv_vol_mute) {
- jz_dlv_vol_mute = 0;
- write_codec_file_bit(1, 0, 5); /* DAC soft mute -> OFF. */
+ msleep(350);
+ break;
+ }
+}
+
+static void dlv_turn_replay(int mode)
+{
+ ENTER();
+ if (mode == USE_LINEIN) {
+ unset_record_line_input_audio_with_audio_data_replay();
+ }
+ if (mode == USE_MIC) {
+ unset_record_mic_input_audio_with_audio_data_replay();
+ }
+ LEAVE();
+}
+
+static void dlv_turn_off(int mode)
+{
+ ENTER();
+
+ if ((mode & REPLAY) && (mode & RECORD)) {
+ printk("Close DLV !!!\n");
+ dlv_write_reg_bit(1, 1, 5);//DAC_MUTE->1
+ schedule_timeout(20);
+
+ // 2010-01-31 Jason marked
+ //dlv_write_reg_bit(5, 1, 6);//SB_OUT->1
+
+ dlv_write_reg(9, 0xff);
+ dlv_write_reg(8, 0x2f);
+ } else if (mode & REPLAY) {
+ //nothing
+ } else if (mode & RECORD) {
+ printk("Close RECORD\n");
+ dlv_write_reg(4, 0x20);
+ }
+
+ LEAVE();
+}
+
+static int dlv_set_channel(int ch)
+{
+ if(ch > 2) ch = 2;
+ if(ch < 1) ch = 1;
+ switch (ch) {
+ case 1:
+ dlv_write_reg_bit(1, 1, 6);//CR1.MONO->1 for Mono
+ break;
+ case 2:
+ dlv_write_reg_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+ break;
+ }
+ return ch;
+}
+
+static int dlv_set_data_width(unsigned int mode, unsigned int width)
+{
+ unsigned char cr2 = dlv_read_reg(2);
+ unsigned char savecr2 = cr2;
+ int supported_width[4] = {16, 18, 20, 24};
+ int i;
+
+ for (i = 0; i < (sizeof(supported_width) / sizeof(supported_width[0])); i++) {
+ if (supported_width[i] <= width) {
+ break;
+ }
+ }
+
+ if (i == (sizeof(supported_width) / sizeof(supported_width[0]))) {
+ // For 8 bit width mode, handle it as 16 bit
+ if (width == 8) {
+ i = 0;
+ } else {
+ return -1;
}
+ }
- write_codec_file(17, cur_vol | 0xc0);
- write_codec_file(18, cur_vol);
+ //printk("mode = %d, width = %d, selected %d\n", mode, width, i);
+
+ switch (mode) {
+ case RECORD:
+ cr2 &= ~(3 << 3);
+ cr2 |= (i << 3);
+ break;
+ case REPLAY:
+ cr2 &= ~(3 << 5);
+ cr2 |= (i << 5);
+ break;
+ }
+
+ if (cr2 != savecr2) {
+ dlv_write_reg(2, cr2);
+ }
+
+ //printk("set cr2 = %x, %x\n", cr2, savecr2);
+
+ if (width == 8) {
+ return 8;
+ } else {
+ return supported_width[i];
}
}
-static int __init init_dlv(void)
+static int dlv_mute(int val)
{
- set_codec_mode = set_dlv_mode;
- each_time_init_codec = each_time_init_dlv;
- reset_codec = reset_dlv_codec;
- set_codec_startup_param = set_dlv_startup_param;
+ return dlv_write_reg_bit(1, val ? 1 : 0, 5);
+}
+static void dlv_suspend(void)
+{
+ printk("suspend\n");
+ dlv_write_reg_bit(5, 1, 6); //codec_reg_set(A_CODEC_PMR1, SB_OUT);
+ mdelay(40);
+ dlv_write_reg_bit(6, 1, 1); //codec_reg_set(A_CODEC_PMR2, SB);
+ dlv_write_reg_bit(6, 1, 0); //codec_reg_set(A_CODEC_PMR2, SB_SLEEP);
+ mdelay(30);
+ dlv_write_reg_bit(5, 1, 5); //codec_reg_set(A_CODEC_PMR1, SB_MIX);
+ dlv_write_reg_bit(5, 1, 7); //codec_reg_set(A_CODEC_PMR1, SB_DAC);
+ dlv_write_reg_bit(5, 1, 4); //codec_reg_set(A_CODEC_PMR1, SB_ADC);
+}
+
+static void dlv_resume(void)
+{
+ dlv_write_reg_bit(6, 0, 2); //codec_reg_clear(A_CODEC_PMR2, SB_MC);
+ mdelay(5);
+ dlv_write_reg_bit(6, 0, 1); //codec_reg_clear(A_CODEC_PMR2, SB);
+ mdelay(30);
+ dlv_write_reg_bit(6, 0, 0); //codec_reg_clear(A_CODEC_PMR2, SB_SLEEP);
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 7); //codec_reg_clear(A_CODEC_PMR1, SB_DAC); p380
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 6); //codec_reg_clear(A_CODEC_PMR1, SB_OUT);
+ mdelay(1);
+ dlv_write_reg_bit(5, 0, 5); //codec_reg_clear(A_CODEC_PMR1, SB_MIX);
+ msleep(350);
+ }
+
+
+void dump_dlv_regs(const char * str)
+{
+ unsigned int i;
+ unsigned char dat;
+ printk("codec register, %s:\n", str);
+ for (i = 0; i < 27; i++) {
+ dat = dlv_read_reg(i);
+ printk("addr = %2d data = 0x%02x\n", i, dat);
+ }
+}
+
+static int jzdlv_ioctl(void *context, unsigned int cmd, unsigned long arg)
+{
+ ENTER();
+ DUMP_CODEC_REGS(__FUNCTION__);
+ DPRINT_CODEC("[dlv IOCTL]++++++++++++++++++++++++++++\n");
+ DPRINT_CODEC("%s cmd = %d, arg = %lu\n", __FUNCTION__, cmd, arg);
+ DPRINT_DLV_IOC_CMD(cmd);
+ DPRINT_CODEC("[dlv IOCTL]----------------------------\n");
+
+ switch (cmd) {
+ case CODEC_SET_MODE:
+ dlv_set_mode();
+ break;
- set_codec_replay = set_dlv_replay;
+ case CODEC_SET_STARTUP_PARAM:
+ dlv_set_startup_param();
+ break;
+
+ case CODEC_SET_REPLAY:
+ dlv_set_replay();
+ break;
+
+ case CODEC_SET_RECORD:
+ dlv_set_record();
+ break;
+
+ case CODEC_SET_REPLAY_RECORD:
+ dlv_set_replay_recode(arg);
+ break;
+
+ case CODEC_SET_VOLUME:
+ dlv_set_volume(arg);
+ break;
- set_codec_speed = set_dlv_speed;
+ case CODEC_SET_MIC:
+ dlv_set_mic(arg);
+ break;
+
+ case CODEC_SET_LINE:
+ dlv_set_line(arg);
+ break;
+
+ case CODEC_EACH_TIME_INIT:
+ dlv_each_time_init();
+ break;
+
+ case CODEC_RESET:
+ dlv_reset();
+ break;
+
+ case CODEC_ANTI_POP:
+ dlv_anti_pop(arg);
+ break;
- codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name;
- codec_mixer_info_id_name = dlv_mixer_info_id_name;
+ case CODEC_TURN_REPLAY:
+ dlv_turn_replay(arg);
+ break;
+
+ case CODEC_TURN_OFF:
+ dlv_turn_off(arg);
+ break;
+
+ case CODEC_GET_MIXER_INFO:
+ dlv_get_mixer_info((mixer_info *)arg);
+ break;
+
+ case CODEC_GET_MIXER_OLD_INFO:
+ dlv_get_mixer_old_info((mixer_info *)arg);
+ break;
+
+ case CODEC_SET_REPLAY_SPEED:
+ return dlv_set_replay_speed(arg);
+
+ case CODEC_SET_RECORD_SPEED:
+ return dlv_set_record_speed(arg);
+
+ case CODEC_SET_RECORD_CHANNEL:
+ return arg;
+
+ case CODEC_SET_REPLAY_CHANNEL:
+ return dlv_set_channel(arg);
+
+ case CODEC_SET_RECORD_DATA_WIDTH:
+ return dlv_set_data_width(RECORD, arg);
+
+ case CODEC_SET_REPLAY_DATA_WIDTH:
+ return dlv_set_data_width(REPLAY, arg);
+
+ case CODEC_DAC_MUTE:
+ return dlv_mute(arg);
+
+ case CODEC_I2S_SUSPEND:
+ dlv_suspend();
+ break;
+ case CODEC_I2S_RESUME:
+ dlv_resume();
+ break;
- set_codec_volume = set_dlv_volume;
- set_codec_mic = set_dlv_mic;
- set_codec_line = set_dlv_line;
+ default:
+ printk("%s:%d no support\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ LEAVE();
return 0;
}
+static struct work_struct dlv_work;
-static void __exit cleanup_dlv(void)
+/*
+ * work handler
+ *
+ * Mission:
+ * Restart CODEC after shut down by short circurt protection
+ */
+static void dlv_work_handle(struct work_struct *work)
+{
+ printk("CODEC: short circurt detected!\n");
+
+ /* Renable SB OUT */
+ switch_SB_OUT(POWER_OFF);
+ mdelay(300);
+ while ((dlv_read_reg(9) & 0x4) != 0x4) {
+ ;/* nothing */
+ }
+ while ((dlv_read_reg(9) & 0x10) == 0x10) {
+ dlv_write_reg(9, 0x10);
+ }
+ switch_SB_OUT(POWER_ON);
+ mdelay(300);
+ while ((dlv_read_reg(9) & 0x8) != 0x8) {
+ ;/* nothing */
+ }
+
+ /* Enable CCMC interrupt ... clear bit 4*/
+ dlv_write_reg(8, 0x2f);
+}
+
+static spinlock_t dlv_irq_lock;
+
+static irqreturn_t dlv_codec_irq(int irq, void *dev_id)
{
+ unsigned char reg_9;
+
+ spin_lock(dlv_irq_lock);
+
+ /* Clear interrupt flag */
+ reg_9 = dlv_read_reg(9);
+ dlv_write_reg(9, reg_9);
+
+ /* Mask CCMC temporarily */
+ dlv_write_reg(8, 0x3f);
+ REG_AIC_SR = 0x78; //???
+
+ /* Start work when output short circuit has been detected */
+ if ((reg_9 & 0x10) == 0x10) {
+ schedule_work(&dlv_work);
+ }
+
+/*
+ reg_9 = dlv_read_reg(9);
+ reg_8 = dlv_read_reg(8);
+ printk("reg_8 = %x, reg_9 = %x\n", reg_8, reg_9);
+*/
+ spin_unlock(dlv_irq_lock);
+ return IRQ_HANDLED;
+}
+
+static int __init init_dlv(void)
+{
+ int retval;
+
+ spin_lock_init(&dlv_irq_lock);
+ INIT_WORK(&dlv_work, dlv_work_handle);
+ register_jz_codecs((void *)jzdlv_ioctl);
+ dlv_reset();
+
+ retval = request_irq(IRQ_AIC, dlv_codec_irq, IRQF_DISABLED, "dlv_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+
+ return 0;
+}
+
+static void __exit cleanup_dlv(void)
+{
+ free_irq(IRQ_AIC, NULL);
}
module_init(init_dlv);