diff options
author | Ingenic <ftp.ingenic.cn/3sw/01linux/02kernel/linux-2.6.31> | 2020-10-30 01:37:18 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2020-10-30 01:46:31 +0100 |
commit | b0bfe4f4fe557c1f16c30f35cb3fd678314e9aa7 (patch) | |
tree | 76e729bf3a9fb594fcca19f78545575d3a9b2d16 | |
parent | 8155bc8f16a1f2e61f51a5bdc0918109383de34d (diff) | |
download | linux-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
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(¶m); - 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(¶m); - 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);
|