From 03c65aadf0d141033e348d01713a4fd688d949b7 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Thu, 11 Oct 2012 12:03:18 +0530 Subject: arm: tegra: cardhu: add support for PM315 Add support for PM315 Bug 1171138 Change-Id: I2e5461c656c41d4172aca60525655cb780eaa17e Original-author: Mike Thompson Signed-off-by: Mike Thompson Signed-off-by: Bibek Basu Signed-off-by: Syed Rafiuddin Reviewed-on: http://git-master/r/143506 (cherry picked from commit 4e66142b6990ca586e085aa88ae0bd6b819da0c4) Reviewed-on: http://git-master/r/166814 GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/board-cardhu-kbc.c | 3 +- arch/arm/mach-tegra/board-cardhu-memory.c | 607 ++++++++++++++++++++++++++++- arch/arm/mach-tegra/board-cardhu-pinmux.c | 67 +++- arch/arm/mach-tegra/board-cardhu-power.c | 39 +- arch/arm/mach-tegra/board-cardhu-sensors.c | 48 ++- arch/arm/mach-tegra/board-cardhu.c | 81 +++- arch/arm/mach-tegra/board-cardhu.h | 7 + 7 files changed, 819 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c index ce9b22cc1170..5bbb27176159 100644 --- a/arch/arm/mach-tegra/board-cardhu-kbc.c +++ b/arch/arm/mach-tegra/board-cardhu-kbc.c @@ -86,7 +86,8 @@ int __init cardhu_kbc_init(void) tegra_get_board_info(&board_info); if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) return 0; pr_info("Registering tegra-kbc\n"); diff --git a/arch/arm/mach-tegra/board-cardhu-memory.c b/arch/arm/mach-tegra/board-cardhu-memory.c index 4ec8839c44f6..1ea30fe74a6d 100644 --- a/arch/arm/mach-tegra/board-cardhu-memory.c +++ b/arch/arm/mach-tegra/board-cardhu-memory.c @@ -24,6 +24,608 @@ #include "tegra3_emc.h" #include "fuse.h" +static const struct tegra_emc_table cardhu_emc_tables_h5tc4g83mfr[] = { + { + 0x32, /* Rev 3.2 */ + 51000, /* SDRAM frequency */ + { + 0x00000002, /* EMC_RC */ + 0x0000000d, /* EMC_RFC */ + 0x00000001, /* EMC_RAS */ + 0x00000000, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000000, /* EMC_RD_RCD */ + 0x00000000, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000009, /* EMC_QSAFE */ + 0x0000000b, /* EMC_RDV */ + 0x00000181, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x0000000e, /* EMC_TXSR */ + 0x0000000e, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000002, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x0000018e, /* EMC_TREFBW */ + 0x00000006, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00004288, /* EMC_FBIO_CFG5 */ + 0x007800a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x000fc000, /* EMC_DLL_XFORM_DQS0 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS1 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS2 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS3 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS4 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS5 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS6 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ0 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ1 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ2 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00010003, /* MC_EMEM_ARB_CFG */ + 0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x74630303, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 102000, /* SDRAM frequency */ + { + 0x00000004, /* EMC_RC */ + 0x0000001a, /* EMC_RFC */ + 0x00000003, /* EMC_RAS */ + 0x00000001, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000001, /* EMC_RD_RCD */ + 0x00000001, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000009, /* EMC_QSAFE */ + 0x0000000b, /* EMC_RDV */ + 0x00000303, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x0000001c, /* EMC_TXSR */ + 0x0000001c, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000004, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x0000031c, /* EMC_TREFBW */ + 0x00000006, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00004288, /* EMC_FBIO_CFG5 */ + 0x007800a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x000fc000, /* EMC_DLL_XFORM_DQS0 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS1 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS2 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS3 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS4 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS5 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS6 */ + 0x000fc000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ0 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ1 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ2 */ + 0x000fc000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80000713, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000001, /* MC_EMEM_ARB_CFG */ + 0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0403, /* MC_EMEM_ARB_DA_COVERS */ + 0x73c30504, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 204000, /* SDRAM frequency */ + { + 0x00000009, /* EMC_RC */ + 0x00000035, /* EMC_RFC */ + 0x00000007, /* EMC_RAS */ + 0x00000002, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000002, /* EMC_RD_RCD */ + 0x00000002, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000009, /* EMC_QSAFE */ + 0x0000000b, /* EMC_RDV */ + 0x00000607, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000181, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000038, /* EMC_TXSR */ + 0x00000038, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000007, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000638, /* EMC_TREFBW */ + 0x00000006, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00004288, /* EMC_FBIO_CFG5 */ + 0x004400a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQ0 */ + 0x00080000, /* EMC_DLL_XFORM_DQ1 */ + 0x00080000, /* EMC_DLL_XFORM_DQ2 */ + 0x00080000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000003, /* MC_EMEM_ARB_CFG */ + 0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0405, /* MC_EMEM_ARB_DA_COVERS */ + 0x73840a06, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 400000, /* SDRAM frequency */ + { + 0x00000012, /* EMC_RC */ + 0x00000066, /* EMC_RFC */ + 0x0000000c, /* EMC_RAS */ + 0x00000004, /* EMC_RP */ + 0x00000003, /* EMC_R2W */ + 0x00000008, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000a, /* EMC_W2P */ + 0x00000004, /* EMC_RD_RCD */ + 0x00000004, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000004, /* EMC_WDV */ + 0x00000006, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x0000000a, /* EMC_QSAFE */ + 0x0000000d, /* EMC_RDV */ + 0x00000bf0, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000002fc, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000001, /* EMC_PDEX2WR */ + 0x00000008, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000008, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x0000006c, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x0000000c, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000c30, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x001d0084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00038000, /* EMC_DLL_XFORM_DQS0 */ + 0x00038000, /* EMC_DLL_XFORM_DQS1 */ + 0x00038000, /* EMC_DLL_XFORM_DQS2 */ + 0x00038000, /* EMC_DLL_XFORM_DQS3 */ + 0x00038000, /* EMC_DLL_XFORM_DQS4 */ + 0x00038000, /* EMC_DLL_XFORM_DQS5 */ + 0x00038000, /* EMC_DLL_XFORM_DQS6 */ + 0x00038000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00030000, /* EMC_DLL_XFORM_DQ0 */ + 0x00030000, /* EMC_DLL_XFORM_DQ1 */ + 0x00030000, /* EMC_DLL_XFORM_DQ2 */ + 0x00030000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0158000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x800018c8, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000006, /* MC_EMEM_ARB_CFG */ + 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000009, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */ + 0x7086120a, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff89, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000521, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200000, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 800000, /* SDRAM frequency */ + { + 0x00000025, /* EMC_RC */ + 0x000000ee, /* EMC_RFC */ + 0x0000001a, /* EMC_RAS */ + 0x00000009, /* EMC_RP */ + 0x00000005, /* EMC_R2W */ + 0x0000000d, /* EMC_W2R */ + 0x00000004, /* EMC_R2P */ + 0x00000013, /* EMC_W2P */ + 0x00000009, /* EMC_RD_RCD */ + 0x00000009, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000007, /* EMC_WDV */ + 0x0000000b, /* EMC_QUSE */ + 0x00000009, /* EMC_QRST */ + 0x0000000b, /* EMC_QSAFE */ + 0x00000012, /* EMC_RDV */ + 0x00001820, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000003, /* EMC_PDEX2WR */ + 0x00000012, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000f, /* EMC_AR2PDEN */ + 0x00000018, /* EMC_RW2PDEN */ + 0x000000f8, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000005, /* EMC_TCKE */ + 0x00000018, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000007, /* EMC_TCLKSTABLE */ + 0x00000008, /* EMC_TCLKSTOP */ + 0x00001860, /* EMC_TREFBW */ + 0x0000000c, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0xf0070191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x0000c00a, /* EMC_DLL_XFORM_DQS0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS1 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS3 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS4 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS5 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS6 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ1 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x22220000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f501, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x06000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x00d0000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000c, /* MC_EMEM_ARB_CFG */ + 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000013, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */ + 0x08040202, /* MC_EMEM_ARB_DA_TURNS */ + 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */ + 0x712c2414, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff49, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000d71, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200018, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + } +}; static const struct tegra_emc_table cardhu_emc_tables_h5tc2g[] = { { @@ -6798,7 +7400,6 @@ int cardhu_emc_init(void) struct board_info board; tegra_get_board_info(&board); - switch (board.board_id) { case BOARD_PM269: tegra_init_dram_bit_map(pm269_bit_swap_map, @@ -6819,6 +7420,10 @@ int cardhu_emc_init(void) tegra_init_emc(cardhu_emc_tables_h5tc2g_pm311, ARRAY_SIZE(cardhu_emc_tables_h5tc2g_pm311)); break; + case BOARD_PM315: + tegra_init_emc(cardhu_emc_tables_h5tc4g83mfr, + ARRAY_SIZE(cardhu_emc_tables_h5tc4g83mfr)); + break; default: if (tegra_get_revision() == TEGRA_REVISION_A01) tegra_init_emc(cardhu_emc_tables_h5tc2g, diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c index 346dccfd715b..c416d453e960 100644 --- a/arch/arm/mach-tegra/board-cardhu-pinmux.c +++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c @@ -497,6 +497,20 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_e1291_a04[] = { DEFAULT_PINMUX(GPIO_PU4, RSVD1, PULL_UP, NORMAL, INPUT), }; +static __initdata struct tegra_pingroup_config cardhu_pinmux_pm315[] = { + DEFAULT_PINMUX(GMI_AD15, NAND, PULL_DOWN, NORMAL, OUTPUT), + DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(SPI2_MOSI, SPI6, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP3_SCLK, RSVD1, NORMAL, NORMAL, OUTPUT), + /* PCIE dock detect */ + DEFAULT_PINMUX(GPIO_PU4, RSVD1, PULL_UP, NORMAL, INPUT), + /* CDC enable for realtek RTL5640 */ + DEFAULT_PINMUX(SPI2_SCK, SPI2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, NORMAL, INPUT), + /* Power up for USB1, USB3 */ + DEFAULT_PINMUX(GMI_AD13, NAND, PULL_UP, NORMAL, INPUT), +}; + static __initdata struct tegra_pingroup_config cardhu_pinmux_e1198[] = { DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, NORMAL, NORMAL, INPUT), DEFAULT_PINMUX(LCD_SCK, DISPLAYA, NORMAL, NORMAL, INPUT), @@ -606,10 +620,33 @@ static __initdata struct tegra_pingroup_config gmi_pins_269[] = { DEFAULT_PINMUX(GMI_WP_N, NAND, NORMAL, NORMAL, INPUT), }; -static void __init cardhu_pinmux_audio_init(void) +static void __init cardhu_wm8903_audio_init(void) +{ + int ret = gpio_request(TEGRA_GPIO_CDC_IRQ, "wm8903"); + if (ret < 0) + pr_err("%s() Error in gpio_request() for gpio %d\n", + __func__, ret); + ret = gpio_direction_input(TEGRA_GPIO_CDC_IRQ); + if (ret < 0) { + pr_err("%s() Error in setting gpio %d to in/out\n", + __func__, ret); + gpio_free(TEGRA_GPIO_CDC_IRQ); + } +} + +static void __init beaver_rt5640_audio_init(void) { - gpio_request(TEGRA_GPIO_CDC_IRQ, "wm8903"); - gpio_direction_input(TEGRA_GPIO_CDC_IRQ); + int ret = gpio_request(TEGRA_GPIO_RTL_CDC_IRQ, "rt5640"); + if (ret < 0) + pr_err("%s() Error in gpio_request() for gpio %d\n", + __func__, ret); + ret = gpio_direction_input(TEGRA_GPIO_RTL_CDC_IRQ); + if (ret < 0) { + pr_err("%s() Error in setting gpio %d to in/out\n", + __func__, ret); + gpio_free(TEGRA_GPIO_RTL_CDC_IRQ); + } + } #define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ @@ -639,6 +676,13 @@ static struct gpio_init_pin_info init_gpio_mode_e1291_a04[] = { GPIO_INIT_PIN_MODE(TEGRA_GPIO_PR2, false, 0), }; +static struct gpio_init_pin_info init_gpio_mode_pm315[] = { + GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD6, false, 0), + GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD4, false, 0), + GPIO_INIT_PIN_MODE(TEGRA_GPIO_PH5, false, 1), + GPIO_INIT_PIN_MODE(TEGRA_GPIO_PR2, false, 0), +}; + static void __init cardhu_gpio_init_configure(void) { struct board_info board_info; @@ -670,6 +714,10 @@ static void __init cardhu_gpio_init_configure(void) pins_info = init_gpio_mode_e1291_a04; } break; + case BOARD_PM315: + len = ARRAY_SIZE(init_gpio_mode_pm315); + pins_info = init_gpio_mode_pm315; + break; default: return; } @@ -718,7 +766,12 @@ int __init cardhu_pinmux_init(void) tegra_pinmux_config_table(cardhu_pinmux_e1291_a04, ARRAY_SIZE(cardhu_pinmux_e1291_a04)); break; - + case BOARD_PM315: + tegra_pinmux_config_table(cardhu_pinmux_cardhu_a03, + ARRAY_SIZE(cardhu_pinmux_cardhu_a03)); + tegra_pinmux_config_table(cardhu_pinmux_pm315, + ARRAY_SIZE(cardhu_pinmux_pm315)); + break; case BOARD_PM269: case BOARD_PM305: case BOARD_PM311: @@ -749,7 +802,11 @@ int __init cardhu_pinmux_init(void) break; } - cardhu_pinmux_audio_init(); + if (board_info.board_id == BOARD_PM315) + beaver_rt5640_audio_init(); + else + cardhu_wm8903_audio_init(); + return 0; } diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c index 677b38347514..db86a07778b4 100644 --- a/arch/arm/mach-tegra/board-cardhu-power.c +++ b/arch/arm/mach-tegra/board-cardhu-power.c @@ -455,12 +455,14 @@ int __init cardhu_regulator_init(void) tps62361_pdata.vsel0_def_state); } - if ((board_info.board_id == BOARD_E1291) && + if (((board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) && (board_info.sku & SKU_DCDC_TPS62361_SUPPORT)) ext_core_regulator = true; if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { if (ext_core_regulator) { tps_platform.num_subdevs = ARRAY_SIZE(tps_devs_e1198_skubit0_1); @@ -485,7 +487,8 @@ int __init cardhu_regulator_init(void) } /* E1291-A04/A05: Enable DEV_SLP and enable sleep on GPIO2 */ - if ((board_info.board_id == BOARD_E1291) && + if (((board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) && ((board_info.fab == BOARD_FAB_A04) || (board_info.fab == BOARD_FAB_A05) || (board_info.fab == BOARD_FAB_A07))) { @@ -660,6 +663,13 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = { REGULATOR_SUPPLY("vdd_i2c", "2-0033"), }; +/* Enable realtek Codec for PM315 */ +static struct regulator_consumer_supply fixed_reg_cdc_en_supply[] = { + REGULATOR_SUPPLY("cdc_en", NULL), +}; + + + static struct regulator_consumer_supply fixed_reg_en_vbrtr_supply[] = { REGULATOR_SUPPLY("vdd_vbrtr", NULL), }; @@ -748,6 +758,10 @@ FIXED_REG(1, en_5v0_a04, en_5v0, NULL, 0, 0, TPS6591X_GPIO_8, true FIXED_REG(2, en_ddr_a04, en_ddr, NULL, 1, 0, TPS6591X_GPIO_7, true, 1, 1500); FIXED_REG(3, en_3v3_sys_a04, en_3v3_sys, NULL, 0, 0, TPS6591X_GPIO_6, true, 1, 3300); +/* PM315 Rev C realtek alc5640 codec */ +FIXED_REG(23, en_cdc, cdc_en, FIXED_SUPPLY(en_3v3_sys), 0, 1, TEGRA_GPIO_PX2, true, 0, 1200); + + /* Specific to pm269 */ FIXED_REG(4, en_vdd_bl_pm269, en_vdd_bl, NULL, 0, 0, TEGRA_GPIO_PH3, true, 1, 5000); FIXED_REG(6, en_vdd_pnl1_pm269, en_vdd_pnl1, FIXED_SUPPLY(en_3v3_sys), 0, 0, TEGRA_GPIO_PW1, true, 1, 3300); @@ -962,6 +976,11 @@ static struct platform_device *fixed_reg_devs_e1198_a02[] = { ADD_FIXED_REG(en_vddio_vid_oc), }; +#define PM315_FIXED_REG \ + ADD_FIXED_REG(en_cdc), + + + /* Fixed regulator devices for PM269 */ static struct platform_device *fixed_reg_devs_pm269[] = { PM269_FIXED_REG @@ -1010,6 +1029,15 @@ static struct platform_device *fixed_reg_devs_e1291_a04[] = { E1198_FIXED_REG }; +/* Fixed regulator devices for PM315 */ +static struct platform_device *fixed_reg_devs_pm315[] = { + COMMON_FIXED_REG_E1291_A04 + E1291_A03_FIXED_REG + E1198_FIXED_REG + PM315_FIXED_REG +}; + + static bool is_display_board_dsi(u16 display_board_id) { return ((display_board_id == BOARD_DISPLAY_E1213) || @@ -1063,7 +1091,10 @@ int __init cardhu_fixed_regulator_init(void) fixed_reg_devs = fixed_reg_devs_e1198_base; } break; - + case BOARD_PM315: + nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm315); + fixed_reg_devs = fixed_reg_devs_pm315; + break; case BOARD_PM311: case BOARD_PM305: nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm311); diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c index 7e9774f290eb..365da60fa9ec 100644 --- a/arch/arm/mach-tegra/board-cardhu-sensors.c +++ b/arch/arm/mach-tegra/board-cardhu-sensors.c @@ -88,7 +88,8 @@ static int cardhu_camera_init(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { ret = gpio_request(CAM1_POWER_DWN_GPIO, "camera_power_en"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", @@ -137,7 +138,8 @@ static int cardhu_left_ov5650_power_on(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { if (cardhu_vdd_2v8_cam1 == NULL) { cardhu_vdd_2v8_cam1 = regulator_get(NULL, "vdd_2v8_cam1"); @@ -164,7 +166,8 @@ static int cardhu_left_ov5650_power_on(void) mdelay(5); if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 0); mdelay(20); gpio_direction_output(OV5650_RESETN_GPIO, 0); @@ -199,7 +202,8 @@ static int cardhu_left_ov5650_power_off(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 1); gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); gpio_direction_output(CAM3_POWER_DWN_GPIO, 1); @@ -281,7 +285,8 @@ static int cardhu_right_ov5650_power_on(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 0); gpio_direction_output(CAM2_POWER_DWN_GPIO, 0); @@ -342,7 +347,8 @@ static int cardhu_right_ov5650_power_off(void) /* Boards E1198 and E1291 are of Cardhu personality * and do not have TCA6416 for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 1); gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); gpio_direction_output(CAM3_POWER_DWN_GPIO, 1); @@ -363,8 +369,8 @@ static void cardhu_ov5650_synchronize_sensors(void) mdelay(50); gpio_direction_output(CAM1_POWER_DWN_GPIO, 0); mdelay(50); - } - else if (board_info.board_id == BOARD_E1291) { + } else if ((board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 1); gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); mdelay(50); @@ -401,7 +407,8 @@ static int cardhu_ov2710_power_on(void) /* Boards E1198 and E1291 are of Cardhu personality * and do not have TCA6416 for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { if (cardhu_vdd_cam3 == NULL) { cardhu_vdd_cam3 = regulator_get(NULL, "vdd_cam3"); if (WARN_ON(IS_ERR(cardhu_vdd_cam3))) { @@ -446,7 +453,8 @@ static int cardhu_ov2710_power_off(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 1); gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); gpio_direction_output(CAM3_POWER_DWN_GPIO, 1); @@ -473,7 +481,8 @@ static int cardhu_ov5640_power_on(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 0); gpio_direction_output(CAM2_POWER_DWN_GPIO, 0); @@ -526,7 +535,8 @@ static int cardhu_ov5640_power_off(void) /* Boards E1198 and E1291 are of Cardhu personality * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { gpio_direction_output(CAM1_POWER_DWN_GPIO, 1); gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); gpio_direction_output(CAM3_POWER_DWN_GPIO, 1); @@ -858,7 +868,8 @@ static int cardhu_nct1008_init(void) (board_info.board_id == BOARD_E1257) || (board_info.board_id == BOARD_PM269) || (board_info.board_id == BOARD_PM305) || - (board_info.board_id == BOARD_PM311)) { + (board_info.board_id == BOARD_PM311) || + (board_info.board_id == BOARD_PM315)) { nct1008_port = TEGRA_GPIO_PCC2; } else if ((board_info.board_id == BOARD_E1186) || (board_info.board_id == BOARD_E1187) || @@ -1109,7 +1120,7 @@ int __init cardhu_sensors_init(void) if (board_info.sku == BOARD_SKU_B11) i2c_register_board_info(2, cardhu_i2c2_ltr_board_info, ARRAY_SIZE(cardhu_i2c2_ltr_board_info)); - else + else if (board_info.board_id != BOARD_PM315) i2c_register_board_info(2, cardhu_i2c2_isl_board_info, ARRAY_SIZE(cardhu_i2c2_isl_board_info)); @@ -1165,19 +1176,20 @@ int __init cardhu_ov5650_late_init(void) return 0; if ((board_info.board_id == BOARD_E1198) || - (board_info.board_id == BOARD_E1291)) + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) return 0; - printk("%s: \n", __func__); + printk(KERN_INFO "%s:\n", __func__); for (i = 0; i < ARRAY_SIZE(ov5650_gpio_keys); i++) { ret = gpio_request(ov5650_gpio_keys[i].gpio, ov5650_gpio_keys[i].name); if (ret < 0) { - printk("%s: gpio_request failed for gpio #%d\n", + printk(KERN_INFO "%s: gpio_request failed for gpio #%d\n", __func__, i); goto fail; } - printk("%s: enable - %d\n", __func__, i); + printk(KERN_INFO "%s: enable - %d\n", __func__, i); gpio_direction_output(ov5650_gpio_keys[i].gpio, ov5650_gpio_keys[i].enabled); gpio_export(ov5650_gpio_keys[i].gpio, false); diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c index e14e6b25d644..af6b128ab429 100644 --- a/arch/arm/mach-tegra/board-cardhu.c +++ b/arch/arm/mach-tegra/board-cardhu.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -432,8 +433,16 @@ static struct i2c_board_info __initdata cardhu_codec_max98095_info = { .platform_data = &cardhu_max98095_pdata, }; +static struct i2c_board_info __initdata rt5640_board_info = { + I2C_BOARD_INFO("rt5640", 0x1c), +}; + + static void cardhu_i2c_init(void) { + struct board_info board_info; + + tegra_get_board_info(&board_info); tegra_i2c_device1.dev.platform_data = &cardhu_i2c1_platform_data; tegra_i2c_device2.dev.platform_data = &cardhu_i2c2_platform_data; tegra_i2c_device3.dev.platform_data = &cardhu_i2c3_platform_data; @@ -446,7 +455,10 @@ static void cardhu_i2c_init(void) platform_device_register(&tegra_i2c_device2); platform_device_register(&tegra_i2c_device1); - i2c_register_board_info(4, &cardhu_codec_wm8903_info, 1); + if (board_info.board_id == BOARD_PM315) + i2c_register_board_info(4, &rt5640_board_info, 1); + else + i2c_register_board_info(4, &cardhu_codec_wm8903_info, 1); i2c_register_board_info(4, &cardhu_codec_max98095_info, 1); i2c_register_board_info(4, &cardhu_codec_aic326x_info, 1); @@ -830,6 +842,38 @@ static struct platform_device cardhu_audio_aic326x_device = { }, }; +static struct tegra_asoc_platform_data beaver_audio_rt5640_pdata = { + .codec_name = "rt5640.4-001c", + .codec_dai_name = "rt5640-aif1", + .gpio_spkr_en = TEGRA_GPIO_RTL_SPKR_EN, + .gpio_hp_det = TEGRA_GPIO_RTL_HP_DET, + .gpio_hp_mute = -1, + .gpio_int_mic_en = TEGRA_GPIO_RTL_INT_MIC_EN, + .gpio_ext_mic_en = -1, /* TEGRA_GPIO_EXT_MIC_EN,*/ + .i2s_param[HIFI_CODEC] = { + .audio_port_id = 0, + .is_i2s_master = 1, + .i2s_mode = TEGRA_DAIFMT_I2S, + }, + .i2s_param[BASEBAND] = { + .audio_port_id = -1, + }, + .i2s_param[BT_SCO] = { + .audio_port_id = 3, + .is_i2s_master = 1, + .i2s_mode = TEGRA_DAIFMT_DSP_A, + }, +}; + +static struct platform_device beaver_audio_rt5640_device = { + .name = "tegra-snd-rt5640", + .id = 0, + .dev = { + .platform_data = &beaver_audio_rt5640_pdata, + }, +}; + + static struct platform_device *cardhu_devices[] __initdata = { &tegra_pmu_device, &tegra_rtc_device, @@ -860,7 +904,6 @@ static struct platform_device *cardhu_devices[] __initdata = { &baseband_dit_device, &cardhu_bt_rfkill_device, &tegra_pcm_device, - &cardhu_audio_wm8903_device, &cardhu_audio_max98095_device, &cardhu_audio_aic326x_device, &tegra_hda_device, @@ -943,6 +986,15 @@ static const u8 config_sku2000[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static struct platform_device *cardhu_audio_devices[] __initdata = { + &cardhu_audio_wm8903_device, + +}; + +static struct platform_device *beaver_audio_devices[] __initdata = { + &beaver_audio_rt5640_device, + +}; static struct mxt_platform_data atmel_mxt_info = { .x_line = 27, @@ -1359,10 +1411,17 @@ static void cardhu_pci_init(void) cardhu_pci_platform_data.port_status[2] = 1; cardhu_pci_platform_data.use_dock_detect = 1; cardhu_pci_platform_data.gpio = DOCK_DETECT_GPIO; + } else if (board_info.board_id == BOARD_PM315) { + cardhu_pci_platform_data.port_status[0] = 1; + cardhu_pci_platform_data.port_status[1] = 0; + cardhu_pci_platform_data.port_status[2] = 1; + cardhu_pci_platform_data.use_dock_detect = 0; + cardhu_pci_platform_data.gpio = 0; } if ((board_info.board_id == BOARD_E1186) || - (board_info.board_id == BOARD_E1187) || - (board_info.board_id == BOARD_E1291)) { + (board_info.board_id == BOARD_E1187) || + (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315)) { tegra_pci_device.dev.platform_data = &cardhu_pci_platform_data; platform_device_register(&tegra_pci_device); } @@ -1428,6 +1487,9 @@ static void cardhu_sata_init(void) { } static void __init tegra_cardhu_init(void) { + struct board_info board_info; + + tegra_get_board_info(&board_info); tegra_thermal_init(&thermal_data, throttle_list, ARRAY_SIZE(throttle_list)); @@ -1442,6 +1504,17 @@ static void __init tegra_cardhu_init(void) cardhu_uart_init(); tegra_camera_init(); platform_add_devices(cardhu_devices, ARRAY_SIZE(cardhu_devices)); + switch (board_info.board_id) { + case BOARD_PM315: + platform_add_devices(beaver_audio_devices, + ARRAY_SIZE(beaver_audio_devices)); + break; + default: + platform_add_devices(cardhu_audio_devices, + ARRAY_SIZE(cardhu_audio_devices)); + + break; + } tegra_ram_console_debug_init(); tegra_io_dpd_init(); cardhu_sdhci_init(); diff --git a/arch/arm/mach-tegra/board-cardhu.h b/arch/arm/mach-tegra/board-cardhu.h index 3dd3d23d9414..2f8e21a6492d 100644 --- a/arch/arm/mach-tegra/board-cardhu.h +++ b/arch/arm/mach-tegra/board-cardhu.h @@ -38,6 +38,7 @@ #define BOARD_E1208 0x0C08 #define BOARD_PM305 0x0305 #define BOARD_PM311 0x030B +#define BOARD_PM315 0x030F #define BOARD_PMU_PM298 0x0262 #define BOARD_PMU_PM299 0x0263 @@ -162,6 +163,12 @@ #define TEGRA_GPIO_SPKR_EN CARDHU_GPIO_WM8903(2) #define TEGRA_GPIO_HP_DET TEGRA_GPIO_PW2 +/* PM315 Realtek audio related GPIOs */ +#define TEGRA_GPIO_RTL_CDC_IRQ TEGRA_GPIO_PX3 +#define TEGRA_GPIO_RTL_SPKR_EN -1 +#define TEGRA_GPIO_RTL_HP_DET TEGRA_GPIO_PW2 +#define TEGRA_GPIO_RTL_INT_MIC_EN TEGRA_GPIO_PK3 + /* CAMERA RELATED GPIOs on CARDHU */ #define OV5650_RESETN_GPIO TEGRA_GPIO_PBB0 #define CAM1_POWER_DWN_GPIO TEGRA_GPIO_PBB5 -- cgit v1.2.3 From 272fb5df134a30f72a1acf6d5d2b06e290865af7 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Thu, 11 Oct 2012 15:34:04 +0530 Subject: arm: tegra: ahci/sata: check sata against board id If the board has sata support, then only add platform device Also move slumber code to Idle powergate section to avoid build failure. Bug 1171138 Change-Id: I6128f451f348a7fad41fc52579b18939c8a2efcd Original-author: Mike Thompson Signed-off-by: Mike Thompson Signed-off-by: Bibek Basu Signed-off-by: Syed Rafiuddin Reviewed-on: http://git-master/r/143984 Tested-by: Simone Willett (cherry picked from commit 6e6a0ec500a3113272a593e4466f04d940bc637f) Signed-off-by: Bibek Basu Reviewed-on: http://git-master/r/166837 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/board-cardhu.c | 8 +++++++- drivers/ata/ahci-tegra.c | 32 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c index af6b128ab429..4b03ddc03b7b 100644 --- a/arch/arm/mach-tegra/board-cardhu.c +++ b/arch/arm/mach-tegra/board-cardhu.c @@ -1530,7 +1530,13 @@ static void __init tegra_cardhu_init(void) cardhu_pmon_init(); cardhu_sensors_init(); cardhu_setup_bluesleep(); - cardhu_sata_init(); + /* + * if you want to add support for SATA in your board + * then add your board check here like + * board_info.board_id == BOARD_E1186 + */ + if (board_info.board_id == BOARD_PM315) + cardhu_sata_init(); //audio_wired_jack_init(); cardhu_pins_state_init(); cardhu_emc_init(); diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c index 5c58da143c5a..39cf4acf0ae6 100644 --- a/drivers/ata/ahci-tegra.c +++ b/drivers/ata/ahci-tegra.c @@ -258,10 +258,10 @@ static int tegra_ahci_controller_resume(struct platform_device *pdev); static int tegra_ahci_suspend(struct platform_device *pdev, pm_message_t mesg); static int tegra_ahci_resume(struct platform_device *pdev); static enum port_idle_status tegra_ahci_is_port_idle(struct ata_port *ap); -static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap); static bool tegra_ahci_are_all_ports_idle(struct ata_host *host); -static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host); #ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE +static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap); +static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host); static unsigned int tegra_ahci_qc_issue(struct ata_queued_cmd *qc); static int tegra_ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); @@ -1623,6 +1623,20 @@ static enum port_idle_status tegra_ahci_is_port_idle(struct ata_port *ap) return PORT_IS_IDLE; } +/* check if all supported ports are idle (no outstanding commands) */ +static bool tegra_ahci_are_all_ports_idle(struct ata_host *host) +{ int i; + struct ata_port *ap; + + for (i = 0; i < host->n_ports; i++) { + ap = host->ports[i]; + if (ap && (tegra_ahci_is_port_idle(ap) == PORT_IS_NOT_IDLE)) + return false; + } + return true; +} + +#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); @@ -1638,19 +1652,6 @@ static enum port_idle_status tegra_ahci_is_port_slumber(struct ata_port *ap) return PORT_IS_IDLE_NOT_SLUMBER; } -/* check if all supported ports are idle (no outstanding commands) */ -static bool tegra_ahci_are_all_ports_idle(struct ata_host *host) -{ int i; - struct ata_port *ap; - - for (i = 0; i < host->n_ports; i++) { - ap = host->ports[i]; - if (ap && (tegra_ahci_is_port_idle(ap) == PORT_IS_NOT_IDLE)) - return false; - } - return true; -} - /* check if all supported ports are in slumber */ static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host) { int i; @@ -1664,7 +1665,6 @@ static bool tegra_ahci_are_all_ports_slumber(struct ata_host *host) return true; } -#ifdef CONFIG_TEGRA_SATA_IDLE_POWERGATE static void tegra_ahci_to_add_idle_timer(struct ata_host *host) { struct tegra_ahci_host_priv *tegra_hpriv; -- cgit v1.2.3 From 1ce45b6495c2e780ccca1fe2df179a2cb3096279 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Fri, 12 Oct 2012 10:31:45 +0530 Subject: arm: tegra: config: enable SATA for L4T Enable CONFIG_SATA_AHCI_TEGRA Bug 1171138 Change-Id: Id0cf3679a0fb0b85e20cd83c94135bf2aab2dd71 Original-author: Mike Thompson Signed-off-by: Mike Thompson Signed-off-by: Bibek Basu Signed-off-by: Syed Rafiuddin Reviewed-on: http://git-master/r/143985 Tested-by: Simone Willett (cherry picked from commit 6830e27f86e0f3a2f1e3bad51ee2bf6855dc99b7) Signed-off-by: Bibek Basu Reviewed-on: http://git-master/r/166838 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro --- arch/arm/configs/tegra3_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index 41c39818ee70..71068f33031b 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -210,12 +210,13 @@ CONFIG_MPU_SENSORS_AK8975=m CONFIG_TEGRA_BB_SUPPORT=y CONFIG_TEGRA_BB_POWER=y CONFIG_TEGRA_BB_M7400=y -CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_SCSI_MULTI_LUN=y +CONFIG_ATA=y +CONFIG_SATA_AHCI_TEGRA=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -- cgit v1.2.3 From 4c7f1b3304a4effbccd7ba6d4c12c0275fbf73d1 Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Mon, 26 Nov 2012 16:10:52 -0800 Subject: config: tegra3: enable RFKILL_GPIO required for bluetooth Bug 1033671 Change-Id: Ibc45eaf344ef7a5eea88e7df5747f8dcdcbf202d Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/166347 Reviewed-by: Matthew Pedro --- arch/arm/configs/tegra3_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index 71068f33031b..79ddcf267f42 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -187,6 +187,7 @@ CONFIG_CFG80211=y CONFIG_LIB80211=m CONFIG_MAC80211=m CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y CONFIG_CAIF=y CONFIG_NFC=y CONFIG_PN544_NFC=y -- cgit v1.2.3 From 8024dfe1ac9035050c3402ceef52475dd59f3237 Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Thu, 29 Nov 2012 14:33:57 -0800 Subject: bluetooth: hid: make Android code conditional Commit 7c786ce33a1b4194cb95aa1e68bc38d552eda932 introduced couple of fields, which are not used in standard bluez user space stack. However, Android bluez use them. This CL, conditionally builds the part of the code introduced in the above commit. Bug 1178960 Change-Id: I7254fe83c7fb4bbfd14e00dda3ec3a14afc1b234 Signed-off-by: Mursalin Akon (cherry picked from commit e3375fd96fa5e0d7cfcda848d797cd512c12b7a6) Reviewed-on: http://git-master/r/167540 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Eric Brower Reviewed-by: Matthew Pedro --- include/net/bluetooth/hci.h | 2 ++ net/bluetooth/hci_conn.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 915d7ae527b3..14bee5ade7c7 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1264,9 +1264,11 @@ struct hci_conn_info { __u8 out; __u16 state; __u32 link_mode; +#ifdef CONFIG_ANDROID __u32 mtu; __u32 cnt; __u32 pkts; +#endif }; struct hci_dev_req { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 33c4e0cd83b1..46f2c18a4cb8 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -907,6 +907,7 @@ int hci_get_conn_list(void __user *arg) (ci + n)->out = c->out; (ci + n)->state = c->state; (ci + n)->link_mode = c->link_mode; +#ifdef CONFIG_ANDROID if (c->type == SCO_LINK) { (ci + n)->mtu = hdev->sco_mtu; (ci + n)->cnt = hdev->sco_cnt; @@ -916,6 +917,7 @@ int hci_get_conn_list(void __user *arg) (ci + n)->cnt = hdev->acl_cnt; (ci + n)->pkts = hdev->acl_pkts; } +#endif if (++n >= req.conn_num) break; } @@ -952,6 +954,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.out = conn->out; ci.state = conn->state; ci.link_mode = conn->link_mode; +#ifdef CONFIG_ANDROID if (req.type == SCO_LINK) { ci.mtu = hdev->sco_mtu; ci.cnt = hdev->sco_cnt; @@ -961,6 +964,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.cnt = hdev->acl_cnt; ci.pkts = hdev->acl_pkts; } +#endif } hci_dev_unlock_bh(hdev); -- cgit v1.2.3 From 9a04e36ab05bfe16b9c1fdeec48195462ce09d2e Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Thu, 29 Nov 2012 15:07:46 -0800 Subject: config: tegra3: BT and HID options - enable couple of HID devices - modify couple of BT options Bug 1178960 Change-Id: Id9377edff2189d8a63f624d5d4e388e54658482f Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/167541 Reviewed-by: Matthew Pedro Tested-by: Matthew Pedro Reviewed-by: Automatic_Commit_Validation_User --- arch/arm/configs/tegra3_defconfig | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index 79ddcf267f42..26889bd74d5f 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -175,11 +175,11 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_HIDP=y -CONFIG_BT_HCIUART=y +CONFIG_BT_BNEP=m +CONFIG_BT_HIDP=m +CONFIG_BT_HCIUART=m CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_LL=y CONFIG_BT_BLUESLEEP=y @@ -356,7 +356,27 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_TEGRA=y CONFIG_SND_SOC_TEGRA_WM8903=y CONFIG_SND_SOC_TEGRA_MAX98088=y +CONFIG_HID_A4TECH=m +CONFIG_HID_APPLE=m +CONFIG_HID_BELKIN=m +CONFIG_HID_ELECOM=m +CONFIG_HID_EZKEY=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_LOGITECH=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=m +CONFIG_HID_TIVO=m +CONFIG_HID_WACOM=m +CONFIG_HID_WACOM_POWER_SUPPLY=y +CONFIG_HID_WIIMOTE=m CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_DEVICEFS=y CONFIG_USB_SUSPEND=y -- cgit v1.2.3 From 7da5cecd4eb9a7771a75e754c87e21cad2d4e26d Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Wed, 31 Oct 2012 16:59:30 -0700 Subject: ARM: tegra: p852: Fix misbracketed cond clause This misbracketing can potentially result in an invalid pointer dereference. Signed-off-by: Andrew Chew Change-Id: Iaed185dd2141f1aa332747eeba10d22b850caa37 Reviewed-on: http://git-master/r/168475 Reviewed-by: Peng Wu Tested-by: Peng Wu Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Allen Martin Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/p852/board-p852-power.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/p852/board-p852-power.c b/arch/arm/mach-tegra/p852/board-p852-power.c index 949537ed5d94..e69f98c8cba9 100644 --- a/arch/arm/mach-tegra/p852/board-p852-power.c +++ b/arch/arm/mach-tegra/p852/board-p852-power.c @@ -173,11 +173,12 @@ static void __init tps6586x_rtc_preinit(void) system_rev == P852_SKU5_C01) { for (i = 0; i < tps_platform.num_subdevs; ++i) if (!strcmp(tps_platform.subdevs[i].name, - "tps6586x-rtc")) + "tps6586x-rtc")) { rtc_pdata = (struct tps6586x_rtc_platform_data *) (tps_platform.subdevs[i].platform_data); rtc_pdata->cl_sel = TPS6586X_RTC_CL_SEL_1_5PF; + } } } -- cgit v1.2.3 From 3c3574a139f9093d6841b2483c0015060f88ee55 Mon Sep 17 00:00:00 2001 From: Preetham Chandru R Date: Thu, 29 Nov 2012 17:08:50 +0530 Subject: usb: tegra: conditionally set wake enable Set wake enable only if remote wakeup is supported by the platform Bug 1039143 Signed-off-by: Preetham Chandru R Change-Id: I805dd773cdbb5639f59b2f5ba4bcb2e14be74d5b Reviewed-on: http://git-master/r/147462 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Suresh Mangipudi Reviewed-by: Krishna Yarlagadda Reviewed-by: Bitan Biswas Reviewed-by: Matthew Pedro --- drivers/usb/gadget/tegra_udc.c | 16 ++++++++++------ drivers/usb/host/ehci-tegra.c | 20 ++++++++++++-------- drivers/usb/otg/tegra-otg.c | 14 ++++++++------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index ddf9c602dc89..9af22ebe8b58 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -2565,6 +2566,7 @@ static int __init tegra_udc_probe(struct platform_device *pdev) { struct tegra_udc *udc; struct resource *res; + struct tegra_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); int err = -ENODEV; DBG("%s(%d) BEGIN\n", __func__, __LINE__); @@ -2615,12 +2617,14 @@ static int __init tegra_udc_probe(struct platform_device *pdev) goto err_iounmap; } - err = enable_irq_wake(udc->irq); - if (err < 0) { - dev_warn(&pdev->dev, - "Couldn't enable USB udc mode wakeup, irq=%d, error=%d\n", - udc->irq, err); - err = 0; + if (pdata->u_data.dev.remote_wakeup_supported) { + err = enable_irq_wake(udc->irq); + if (err < 0) { + dev_warn(&pdev->dev, + "Couldn't enable USB udc mode wakeup, irq=%d," + " error=%d\n", udc->irq, err); + err = 0; + } } udc->phy = tegra_usb_phy_open(pdev); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index af6fa87fb645..4ddb279cfb35 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -407,6 +407,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; struct tegra_ehci_hcd *tegra; + struct tegra_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); int err = 0; int irq; @@ -477,13 +478,15 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_phy; } - err = enable_irq_wake(tegra->irq); - if (err < 0) { - dev_warn(&pdev->dev, - "Couldn't enable USB host mode wakeup, irq=%d, " - "error=%d\n", irq, err); - err = 0; - tegra->irq = 0; + if (pdata->u_data.host.remote_wakeup_supported) { + err = enable_irq_wake(tegra->irq); + if (err < 0) { + dev_warn(&pdev->dev, + "Couldn't enable USB host mode wakeup," + " irq=%d error=%d\n", irq, err); + err = 0; + tegra->irq = 0; + } } tegra->ehci = hcd_to_ehci(hcd); @@ -531,6 +534,7 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) static int tegra_ehci_remove(struct platform_device *pdev) { struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); + struct tegra_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); if (tegra == NULL || hcd == NULL) @@ -543,7 +547,7 @@ static int tegra_ehci_remove(struct platform_device *pdev) } #endif - if (tegra->irq) + if (tegra->irq && pdata->u_data.host.remote_wakeup_supported) disable_irq_wake(tegra->irq); /* Make sure phy is powered ON to access USB register */ diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 22e303ede24e..ce19f77433fc 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -472,12 +472,14 @@ static int tegra_otg_probe(struct platform_device *pdev) goto err_irq; } - err = enable_irq_wake(tegra->irq); - if (err < 0) { - dev_warn(&pdev->dev, - "Couldn't enable USB otg mode wakeup, irq=%d, error=%d\n", - tegra->irq, err); - err = 0; + if (pdata->ehci_pdata->u_data.host.remote_wakeup_supported) { + err = enable_irq_wake(tegra->irq); + if (err < 0) { + dev_warn(&pdev->dev, + "Couldn't enable USB otg mode wakeup," + " irq=%d, error=%d\n", tegra->irq, err); + err = 0; + } } INIT_WORK(&tegra->work, irq_work); -- cgit v1.2.3 From 48105b8d2b4ae39660655fb26fc7d6459643d3d4 Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Wed, 12 Dec 2012 12:06:04 -0800 Subject: media: video: tegra: nvavp: Fix nvmap handle issue In open call we were assigning the driver's nvmap handle to the nvavp's client context which would get released in release call to driver. This will cause driver's nvmap handle to be invalid if a parallel client context is running and driver does any nvmap operation. Bug 1013063 Bug 1192772 Change-Id: Id02520ae8ec511bb8c50bc4d3908ea3e75e1ea6b Reviewed-on: http://git-master/r/170585 Signed-off-by: Gajanan Bhat Reviewed-on: http://git-master/r/171097 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro Tested-by: Matthew Pedro Reviewed-by: Winnie Hsu --- drivers/media/video/tegra/nvavp/nvavp_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index 4501abb9a735..d5edcbe685bf 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -1355,7 +1355,6 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_ if (!ret) nvavp->refcount++; - clientctx->nvmap = nvavp->nvmap; clientctx->nvavp = nvavp; filp->private_data = clientctx; -- cgit v1.2.3 From 4d667a6aff6ce8089973b73a5e6645e750045356 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 29 Nov 2012 16:01:28 -0800 Subject: tegra_camera: fix building error when disable CONFIG_TEGRA_CAMERA LD vmlinux.o drivers/built-in.o: In function `is_tegra_camera_on': /home/roc/Work/bug_vip/source_vibrante/kernel/include/media/ tegra_camera.h:59: multiple definition of `is_tegra_camera_on' arch/arm/mach-tegra/built-in.o:/home/roc/Work/bug_vip/source_vibrante /kernel/include/media/tegra_camera.h:59: first defined here make: *** [vmlinux.o] Error 1 Commit '678708d WAR: gr3d: limit 3d clock when camera is on' introduced a function is_tegra_camera_on(), which is dummy when CONFIG_TEGRA_CAMERA is disabled. But it will be multiple defined when includ this header file in multiple C files. So marking it as static will kill this error. Change-Id: I9dbcf1231f744c23e761d70da0bfc874fb286e4a Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/167510 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- include/media/tegra_camera.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/tegra_camera.h b/include/media/tegra_camera.h index 3c41864cc71f..d47839282382 100644 --- a/include/media/tegra_camera.h +++ b/include/media/tegra_camera.h @@ -56,7 +56,7 @@ struct tegra_camera_platform_data { #if defined(CONFIG_TEGRA_CAMERA) int is_tegra_camera_on(void); #else -int is_tegra_camera_on(void) { return 0; } +static inline int is_tegra_camera_on(void) { return 0; } #endif #define TEGRA_CAMERA_IOCTL_ENABLE _IOWR('i', 1, uint) -- cgit v1.2.3 From bce66df644851d87a7ba8c54eae9fc51d0614b3f Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Mon, 6 Aug 2012 14:43:09 -0700 Subject: media: tegra: Add docs for Tegra V4L2 camera This readme describes theory of operations of the Tegra camera host driver. Signed-off-by: Andrew Chew Change-Id: I9e6f761cd60f5b8a537174290df21fb85f016dca Reviewed-on: http://git-master/r/145347 (cherry picked from commit 7dd02775470d2b243f96b7d1f4e8b9c4e3b3ada6) Signed-off-by: Bryan Wu Change-Id: I10fd56ea6e3e83db6e09b75126a2048552ef052c Reviewed-on: http://git-master/r/170822 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew Reviewed-by: Winnie Hsu GVS: Gerrit_Virtual_Submit --- Documentation/video4linux/README.tegra | 180 +++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 Documentation/video4linux/README.tegra diff --git a/Documentation/video4linux/README.tegra b/Documentation/video4linux/README.tegra new file mode 100644 index 000000000000..610eeded2ae9 --- /dev/null +++ b/Documentation/video4linux/README.tegra @@ -0,0 +1,180 @@ +Theory of Operations +==================== + +There are three separate drivers within the V4L2 framework that are interesting +to Tegra-based platforms. They are as follows: + +Image Sensor driver +=================== +This driver communicates only with the image sensor hardware (typically via +I2C transactions), and is intentionally PLATFORM-AGNOSTIC. Existing image +sensor drivers can be found in drivers/media/video. For example, the ov9740 +driver communicates with the Omnivision OV9740 image sensor with built-in ISP. + +Some of the things that this driver is responsible for are: + +Setting up the proper output format of the image sensor, + +Setting up image output extents + +Setting up capture and crop regions + +Camera Host driver +================== +This driver communicates only with the camera controller on a given platform, +and is intentionally IMAGE-SENSOR-AGNOSTIC. Existing camera host drivers +can be found in drivers/media/video, of which tegra_v4l2_camera.c is the +example that is interesting to us. This camera host driver knows how to +program the CSI/VI block on Tegra2 and Tegra3 platforms. + +Some of the things that this driver is responsible for are: + +Setting up the proper input format (image frame data flowing from the image +sensor to the camera host), + +Setting up the proper output format (image frame data flowing from the +camera host to system memory), + +Programming the DMA destination to receive the image frame data, + +Starting and stopping the reception of image frame data. + +Videobuf driver +=============== +This driver is responsible for the allocation and deallocation of buffers that +are used to hold image frame data. Different camera hosts have different +DMA requirements, which makes it necessary to allow for different methods of +buffer allocation. For example, the Tegra2 and Tegra3 camera host cannot +DMA via a scatter-gather list, so the image frame buffers must be physically +contiguous. The videobuf-dma-contig.c videobuf driver can be found in +drivers/media/video, and contains a videobuf implementation that allocates +physically contiguous regions. One can also have a videobuf driver that +uses a different allocator like nvmap. + +The nvhost driver and Syncpts +============================= + +The camera host driver (tegra_v4l2_camera) has a dependency on the nvhost +driver/subsystem in order to make use of syncpts. In other words, the camera +host driver is a client of nvhost. + +A syncpt is essentially an incrementing hardware counter that triggers an +interrupt when a certain number (or threshold) is reached. The interrupt, +however, is hidden from clients of nvhost. Instead, asynchronous completion +notification is done via calling an nvhost routine that goes to sleep, and +wakes up upon completion. + +Tegra has a number of syncpts that serve various purposes. The two syncpts +that are used by the camera host driver are the VI and CSI syncpts. Other +syncpts are used in display, etc. + +A syncpt increments when a certain hardware condition is met. + +The public operations available for a syncpt are: + +nvhost_syncpt_read_ext(syncpt_id) - Read the current syncpt counter value. +nvhost_syncpt_wait_timeout_ext(syncpt_id, threshold, timeout) - Go to sleep + until the syncpt value reaches the threshold, or until the timeout + expires. +nvhost_syncpt_cpu_incr_ext(syncpt_id) - Manually increment a syncpt. + +Syncpts are used in the camera host driver in order to signify the completion +of an operation. The typical usage case can be illustrated by summarizing +the steps that the camera host driver takes in capturing a single frame +(this is called one-shot mode, where we program up each frame transfer +separately): + +0) At the very start, read the current syncpt values and remember them. See + tegra_camera_activate() -> tegra_camera_save_syncpts(), where we read + the current values and store them in pcdev->syncpt_csi and pcdev->syncpt_vi. + +1) Program the camera host registers to prepare to receive frames from the + image sensor using the proper input format. Note that we are at this + point NOT telling the camera host to DMA a frame. That comes later. See + tegra_camera_capture_setup(), where we do a whole bunch of magical + register writes depending on our input format, output format, image extents, + etc. + +2) Increment our remembered copies of the current syncpt values according to + how many syncpt increments we are expecting for the given operation we + want to perform. For capturing a single frame, we are expecting a single + increment on the CSI syncpt when the reception of the frame is complete, and + a single increment on the VI syncpt when the DMA of the frame is complete. + See tegra_camera_capture_start(), where we increment pcdev->syncpt_csi + and pcdev->syncpt_vi. + +3) Program the DMA destination registers, and toggle the bit in + TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND to do the DMA on the next available + frame. See tegra_camera_capture_start() for this. + +4) Call nvhost_syncpt_wait_timeout_ext() to wait on the CSI syncpt threshold. + Remember that we incremented our local syncpt values in step 2. Those + new values become the threshold to wait for. See + tegra_camera_capture_start(). + +5) When the frame finishes its transfer from the image sensor to the camera + host, the CSI syncpt hardware counter will be incremented by hardware. + Since the hardware syncpt value will now match the threshold, our call to + nvhost_syncpt_wait_timeout_ext() in step 4 wakes up. + +6) We now tell the camera host to get ready for the DMA to complete. We do + this by writing again to TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND. See + tegra_camera_capture_stop(). + +7) When the camera host finishes its DMA, we expect the hardware to increment + the VI syncpt. Therefore, we call nvhost_syncpt_wait_timeout_ext() on + the VI syncpt with our new threshold that we got by the incrementing in + step 2. See tegra_camera_capture_stop(). + +8) When the camera host finally finishes its DMA, the VI syncpt hardware + counter increments. Since our VI syncpt threshold is met, the call to + nvhost_syncpt_wait_timeout_ext() wakes up, and we are done. See + tegra_camera_capture_stop(). + +9) To capture the next frame, go back to step 2. The tegra_v4l2_camera driver + calls tegra_camera_capture_setup at the beginning, and then a worker thread + repeatedly calls tegra_camera_capture_start() and + tegra_camera_capture_stop(). See tegra_camera_work() -> + tegra_camera_capture_frame(). + +Note for VIP: Only a single syncpt is used for the VIP path. We use the +continuous VIP VSYNC syncpt to determine the completion of a frame transfer. +In addition, to start and finish the capture of a frame, the +VI_CAMERA_CONTROL register is used. See tegra_camera_capture_start() and +tegra_camera_capture_stop() to see how that register is used for the VIP path. +Essentially, steps 4, 5, and 6 are eliminated, and instead of writing to +TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND or TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, +we write to VI_CAMERA_CONTROL to achieve the same purpose for VIP. + +VIP versus CSI +============== +VI_VI_CORE_CONTROL bits 26:24 (INPUT_TO_CORE_EXT) should be set to 0 +(use INPUT_TO_CORE). + +VI_VI_INPUT_CONTROL bit 1 (VIP_INPUT_ENABLE) should be set to 1 (ENABLED), +bit 26:25 (SYNC_FORMAT) should be set to 1 (ITU656), and bit 27 (FIELD_DETECT) +should be set to 1 (ENABLED). + +VI_H_DOWNSCALE_CONTROL bit 0 (INPUT_H_SIZE_SEL) should be set to 0 (VIP), +and bits 3:2 (INPUT_H_SIZE_SEL_EXT) should be set to 0 (USE INPUT_H_SIZE_SEL). + +Rather than placing the image width and height into VI_CSI_PPA_H_ACTIVE and +VI_CSI_PPA_V_ACTIVE, respectively (or the CSI B counterparts), use +VI_VIP_H_ACTIVE and VI_VIP_V_ACTIVE bits 31:16. Bits 15:0 of VI_VIP_H_ACTIVE +and VI_VIP_V_ACTIVE are the number of clock cycles to wait after receiving +HSYNC or VSYNC before starting. This can be used to adjust the vertical and +horizontal back porches. + +VI_PIN_INPUT_ENABLE should be set to 0x00006fff, which enables input pins +VHS, VVS, and VD11..VD0. + +VI_PIN_INVERSION bits 1 and 2 can be used to invert input pins VHS and VVS, +respectively. + +VI_CONT_SYNCPT_VIP_VSYNC bit 8 (enable VIP_VSYNC) should be set to 1, and +bits 7:0 should hold the index of the syncpt to be used. When this syncpt +is enabled, the syncpt specified by the index will increment by 1 every +time a VSYNC occurs. We use this syncpt to signal frame completion. + +VI_CAMERA_CONTROL bit 0 should be set to 1 to start capturing. Writing a 0 +to this bit is ignored, so to stop capturing, write 1 to bit 2. -- cgit v1.2.3 From 792af1fd4fd216852b51266ccdef8f770648e922 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Mon, 28 Mar 2011 18:38:39 -0700 Subject: media: tegra: Tegra V4L2 camera This is the Tegra V4L2 camera host driver, for Tegra2/Tegra3's VI/CSI controller. Signed-off-by: Andrew Chew Change-Id: If2d9eefe53c2119c1a6ae518216e1a3c3ed216ef Reviewed-on: http://git-master/r/145346 (cherry picked from commit 5a9bfd588b755f354ae21471a3a2a3e559ca6fae) Signed-off-by: Bryan Wu Change-Id: I4db33b17efdb401938603cb2153d73bf3421ba61 Reviewed-on: http://git-master/r/170823 Reviewed-by: Andrew Chew GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 2 + drivers/media/video/tegra_v4l2_camera.c | 1752 +++++++++++++++++++++++++++++++ include/media/tegra_v4l2_camera.h | 40 + 4 files changed, 1801 insertions(+) create mode 100644 drivers/media/video/tegra_v4l2_camera.c create mode 100644 include/media/tegra_v4l2_camera.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 38719599a476..18c9805a8140 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -921,6 +921,13 @@ config VIDEO_SH_MOBILE_CEU ---help--- This is a v4l2 driver for the SuperH Mobile CEU Interface +config VIDEO_TEGRA + tristate "Tegra soc_camera host driver" + depends on VIDEO_DEV && ARCH_TEGRA && SOC_CAMERA && HAS_DMA && HAVE_CLK + select VIDEOBUF2_DMA_NVMAP + ---help--- + This is a v4l2 driver for the Tegra camera interface + config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 225f8823de2b..21ec2c37da23 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -168,6 +168,7 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o +obj-$(CONFIG_VIDEO_TEGRA) += tegra_v4l2_camera.o obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o @@ -194,3 +195,4 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/video/tegra/host diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c new file mode 100644 index 000000000000..22e3f5b73cbb --- /dev/null +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -0,0 +1,1752 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dev.h" +#include "bus_client.h" +#include "host1x/host1x_syncpt.h" + +#define TEGRA_CAM_DRV_NAME "vi" +#define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) + +#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200 +#define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200 + +#define TEGRA_SYNCPT_RETRY_COUNT 10 + +#define TEGRA_VIP_H_ACTIVE_START 0x98 +#define TEGRA_VIP_V_ACTIVE_START 0x10 + +/* SYNCPTs 12-17 are reserved for VI. */ +#define TEGRA_VI_SYNCPT_VI NVSYNCPT_VI_ISP_2 +#define TEGRA_VI_SYNCPT_CSI NVSYNCPT_VI_ISP_3 + +/* Tegra CSI-MIPI registers. */ +#define TEGRA_VI_OUT_1_INCR_SYNCPT 0x0000 +#define TEGRA_VI_OUT_1_INCR_SYNCPT_CNTRL 0x0004 +#define TEGRA_VI_OUT_1_INCR_SYNCPT_ERROR 0x0008 +#define TEGRA_VI_OUT_2_INCR_SYNCPT 0x0020 +#define TEGRA_VI_OUT_2_INCR_SYNCPT_CNTRL 0x0024 +#define TEGRA_VI_OUT_2_INCR_SYNCPT_ERROR 0x0028 +#define TEGRA_VI_MISC_INCR_SYNCPT 0x0040 +#define TEGRA_VI_MISC_INCR_SYNCPT_CNTRL 0x0044 +#define TEGRA_VI_MISC_INCR_SYNCPT_ERROR 0x0048 +#define TEGRA_VI_CONT_SYNCPT_OUT_1 0x0060 +#define TEGRA_VI_CONT_SYNCPT_OUT_2 0x0064 +#define TEGRA_VI_CONT_SYNCPT_VIP_VSYNC 0x0068 +#define TEGRA_VI_CONT_SYNCPT_VI2EPP 0x006c +#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_START 0x0070 +#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END 0x0074 +#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_START 0x0078 +#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END 0x007c +#define TEGRA_VI_CTXSW 0x0080 +#define TEGRA_VI_INTSTATUS 0x0084 +#define TEGRA_VI_VI_INPUT_CONTROL 0x0088 +#define TEGRA_VI_VI_CORE_CONTROL 0x008c +#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x0090 +#define TEGRA_VI_VI_SECOND_OUTPUT_CONTROL 0x0094 +#define TEGRA_VI_HOST_INPUT_FRAME_SIZE 0x0098 +#define TEGRA_VI_HOST_H_ACTIVE 0x009c +#define TEGRA_VI_HOST_V_ACTIVE 0x00a0 +#define TEGRA_VI_VIP_H_ACTIVE 0x00a4 +#define TEGRA_VI_VIP_V_ACTIVE 0x00a8 +#define TEGRA_VI_VI_PEER_CONTROL 0x00ac +#define TEGRA_VI_VI_DMA_SELECT 0x00b0 +#define TEGRA_VI_HOST_DMA_WRITE_BUFFER 0x00b4 +#define TEGRA_VI_HOST_DMA_BASE_ADDRESS 0x00b8 +#define TEGRA_VI_HOST_DMA_WRITE_BUFFER_STATUS 0x00bc +#define TEGRA_VI_HOST_DMA_WRITE_PEND_BUFCOUNT 0x00c0 +#define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x00c4 +#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x00c8 +#define TEGRA_VI_VB0_START_ADDRESS_U 0x00cc +#define TEGRA_VI_VB0_BASE_ADDRESS_U 0x00d0 +#define TEGRA_VI_VB0_START_ADDRESS_V 0x00d4 +#define TEGRA_VI_VB0_BASE_ADDRESS_V 0x00d8 +#define TEGRA_VI_VB_SCRATCH_ADDRESS_UV 0x00dc +#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x00e0 +#define TEGRA_VI_VB0_COUNT_FIRST 0x00e4 +#define TEGRA_VI_VB0_SIZE_FIRST 0x00e8 +#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x00ec +#define TEGRA_VI_VB0_START_ADDRESS_SECOND 0x00f0 +#define TEGRA_VI_VB0_BASE_ADDRESS_SECOND 0x00f4 +#define TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE 0x00f8 +#define TEGRA_VI_VB0_COUNT_SECOND 0x00fc +#define TEGRA_VI_VB0_SIZE_SECOND 0x0100 +#define TEGRA_VI_VB0_BUFFER_STRIDE_SECOND 0x0104 +#define TEGRA_VI_H_LPF_CONTROL 0x0108 +#define TEGRA_VI_H_DOWNSCALE_CONTROL 0x010c +#define TEGRA_VI_V_DOWNSCALE_CONTROL 0x0110 +#define TEGRA_VI_CSC_Y 0x0114 +#define TEGRA_VI_CSC_UV_R 0x0118 +#define TEGRA_VI_CSC_UV_G 0x011c +#define TEGRA_VI_CSC_UV_B 0x0120 +#define TEGRA_VI_CSC_ALPHA 0x0124 +#define TEGRA_VI_HOST_VSYNC 0x0128 +#define TEGRA_VI_COMMAND 0x012c +#define TEGRA_VI_HOST_FIFO_STATUS 0x0130 +#define TEGRA_VI_INTERRUPT_MASK 0x0134 +#define TEGRA_VI_INTERRUPT_TYPE_SELECT 0x0138 +#define TEGRA_VI_INTERRUPT_POLARITY_SELECT 0x013c +#define TEGRA_VI_INTERRUPT_STATUS 0x0140 +#define TEGRA_VI_VIP_INPUT_STATUS 0x0144 +#define TEGRA_VI_VIDEO_BUFFER_STATUS 0x0148 +#define TEGRA_VI_SYNC_OUTPUT 0x014c +#define TEGRA_VI_VVS_OUTPUT_DELAY 0x0150 +#define TEGRA_VI_PWM_CONTROL 0x0154 +#define TEGRA_VI_PWM_SELECT_PULSE_A 0x0158 +#define TEGRA_VI_PWM_SELECT_PULSE_B 0x015c +#define TEGRA_VI_PWM_SELECT_PULSE_C 0x0160 +#define TEGRA_VI_PWM_SELECT_PULSE_D 0x0164 +#define TEGRA_VI_VI_DATA_INPUT_CONTROL 0x0168 +#define TEGRA_VI_PIN_INPUT_ENABLE 0x016c +#define TEGRA_VI_PIN_OUTPUT_ENABLE 0x0170 +#define TEGRA_VI_PIN_INVERSION 0x0174 +#define TEGRA_VI_PIN_INPUT_DATA 0x0178 +#define TEGRA_VI_PIN_OUTPUT_DATA 0x017c +#define TEGRA_VI_PIN_OUTPUT_SELECT 0x0180 +#define TEGRA_VI_RAISE_VIP_BUFFER_FIRST_OUTPUT 0x0184 +#define TEGRA_VI_RAISE_VIP_FRAME_FIRST_OUTPUT 0x0188 +#define TEGRA_VI_RAISE_VIP_BUFFER_SECOND_OUTPUT 0x018c +#define TEGRA_VI_RAISE_VIP_FRAME_SECOND_OUTPUT 0x0190 +#define TEGRA_VI_RAISE_HOST_FIRST_OUTPUT 0x0194 +#define TEGRA_VI_RAISE_HOST_SECOND_OUTPUT 0x0198 +#define TEGRA_VI_RAISE_EPP 0x019c +#define TEGRA_VI_CAMERA_CONTROL 0x01a0 +#define TEGRA_VI_VI_ENABLE 0x01a4 +#define TEGRA_VI_VI_ENABLE_2 0x01a8 +#define TEGRA_VI_VI_RAISE 0x01ac +#define TEGRA_VI_Y_FIFO_WRITE 0x01b0 +#define TEGRA_VI_U_FIFO_WRITE 0x01b4 +#define TEGRA_VI_V_FIFO_WRITE 0x01b8 +#define TEGRA_VI_VI_MCCIF_FIFOCTRL 0x01bc +#define TEGRA_VI_TIMEOUT_WCOAL_VI 0x01c0 +#define TEGRA_VI_MCCIF_VIRUV_HP 0x01c4 +#define TEGRA_VI_MCCIF_VIWSB_HP 0x01c8 +#define TEGRA_VI_MCCIF_VIWU_HP 0x01cc +#define TEGRA_VI_MCCIF_VIWV_HP 0x01d0 +#define TEGRA_VI_MCCIF_VIWY_HP 0x01d4 +#define TEGRA_VI_CSI_PPA_RAISE_FRAME_START 0x01d8 +#define TEGRA_VI_CSI_PPA_RAISE_FRAME_END 0x01dc +#define TEGRA_VI_CSI_PPB_RAISE_FRAME_START 0x01e0 +#define TEGRA_VI_CSI_PBB_RAISE_FRAME_END 0x01e4 +#define TEGRA_VI_CSI_PPA_H_ACTIVE 0x01e8 +#define TEGRA_VI_CSI_PPA_V_ACTIVE 0x01ec +#define TEGRA_VI_CSI_PPB_H_ACTIVE 0x01f0 +#define TEGRA_VI_CSI_PPB_V_ACTIVE 0x01f4 +#define TEGRA_VI_ISP_H_ACTIVE 0x01f8 +#define TEGRA_VI_ISP_V_ACTIVE 0x01fc +#define TEGRA_VI_STREAM_1_RESOURCE_DEFINE 0x0200 +#define TEGRA_VI_STREAM_2_RESOURCE_DEFINE 0x0204 +#define TEGRA_VI_RAISE_STREAM_1_DONE 0x0208 +#define TEGRA_VI_RAISE_STREAM_2_DONE 0x020c +#define TEGRA_VI_TS_MODE 0x0210 +#define TEGRA_VI_TS_CONTROL 0x0214 +#define TEGRA_VI_TS_PACKET_COUNT 0x0218 +#define TEGRA_VI_TS_ERROR_COUNT 0x021c +#define TEGRA_VI_TS_CPU_FLOW_CTL 0x0220 +#define TEGRA_VI_VB0_CHROMA_BUFFER_STRIDE_FIRST 0x0224 +#define TEGRA_VI_VB0_CHROMA_LINE_STRIDE_FIRST 0x0228 +#define TEGRA_VI_EPP_LINES_PER_BUFFER 0x022c +#define TEGRA_VI_BUFFER_RELEASE_OUTPUT1 0x0230 +#define TEGRA_VI_BUFFER_RELEASE_OUTPUT2 0x0234 +#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT1 0x0238 +#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT2 0x023c +#define TEGRA_VI_TERMINATE_BW_FIRST 0x0240 +#define TEGRA_VI_TERMINATE_BW_SECOND 0x0244 +#define TEGRA_VI_VB0_FIRST_BUFFER_ADDR_MODE 0x0248 +#define TEGRA_VI_VB0_SECOND_BUFFER_ADDR_MODE 0x024c +#define TEGRA_VI_RESERVE_0 0x0250 +#define TEGRA_VI_RESERVE_1 0x0254 +#define TEGRA_VI_RESERVE_2 0x0258 +#define TEGRA_VI_RESERVE_3 0x025c +#define TEGRA_VI_RESERVE_4 0x0260 +#define TEGRA_VI_MCCIF_VIRUV_HYST 0x0264 +#define TEGRA_VI_MCCIF_VIWSB_HYST 0x0268 +#define TEGRA_VI_MCCIF_VIWU_HYST 0x026c +#define TEGRA_VI_MCCIF_VIWV_HYST 0x0270 +#define TEGRA_VI_MCCIF_VIWY_HYST 0x0274 + +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0800 +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0808 +#define TEGRA_CSI_INPUT_STREAM_A_CONTROL 0x0810 +#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL0 0x0818 +#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL1 0x081c +#define TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT 0x0820 +#define TEGRA_CSI_PIXEL_STREAM_A_GAP 0x0824 +#define TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND 0x0828 +#define TEGRA_CSI_INPUT_STREAM_B_CONTROL 0x083c +#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL0 0x0844 +#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL1 0x0848 +#define TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT 0x084c +#define TEGRA_CSI_PIXEL_STREAM_B_GAP 0x0850 +#define TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND 0x0854 +#define TEGRA_CSI_PHY_CIL_COMMAND 0x0868 +#define TEGRA_CSI_PHY_CILA_CONTROL0 0x086c +#define TEGRA_CSI_PHY_CILB_CONTROL0 0x0870 +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0878 +#define TEGRA_CSI_CSI_CIL_STATUS 0x087c +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0880 +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0884 +#define TEGRA_CSI_CSI_READONLY_STATUS 0x0888 +#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x088c +#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0890 +#define TEGRA_CSI_CILA_PAD_CONFIG0 0x0894 +#define TEGRA_CSI_CILA_PAD_CONFIG1 0x0898 +#define TEGRA_CSI_CILB_PAD_CONFIG0 0x089c +#define TEGRA_CSI_CILB_PAD_CONFIG1 0x08a0 +#define TEGRA_CSI_CIL_PAD_CONFIG 0x08a4 +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x08a8 +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x08ac +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x08b0 +#define TEGRA_CSI_CLKEN_OVERRIDE 0x08b4 +#define TEGRA_CSI_DEBUG_CONTROL 0x08b8 +#define TEGRA_CSI_DEBUG_COUNTER_0 0x08bc +#define TEGRA_CSI_DEBUG_COUNTER_1 0x08c0 +#define TEGRA_CSI_DEBUG_COUNTER_2 0x08c4 +#define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x08c8 +#define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x08cc +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x08d0 + +#define TC_VI_REG_RD(DEV, REG) readl(DEV->vi_base + REG) +#define TC_VI_REG_WT(DEV, REG, VAL) writel(VAL, DEV->vi_base + REG) + +#define tegra_camera_port_is_valid(port) \ + (((port) >= TEGRA_CAMERA_PORT_CSI_A) && \ + ((port) <= TEGRA_CAMERA_PORT_VIP)) + +#define tegra_camera_port_is_csi(port) \ + (((port) == TEGRA_CAMERA_PORT_CSI_A) || \ + ((port) == TEGRA_CAMERA_PORT_CSI_B)) + +/* + * Structures + */ + +/* buffer for one video frame */ +struct tegra_buffer { + struct vb2_buffer vb; /* v4l buffer must be first */ + struct list_head queue; + + /* + * Various buffer addresses shadowed so we don't have to recalculate + * per frame. These are calculated during videobuf_prepare. + */ + dma_addr_t buffer_addr; + dma_addr_t buffer_addr_u; + dma_addr_t buffer_addr_v; + dma_addr_t start_addr; + dma_addr_t start_addr_u; + dma_addr_t start_addr_v; +}; + +struct tegra_camera_dev { + struct soc_camera_host ici; + struct soc_camera_device *icd; + struct nvhost_device *ndev; + struct tegra_camera_platform_data *pdata; + + struct clk *clk_vi; + struct clk *clk_vi_sensor; + struct clk *clk_csi; + struct clk *clk_isp; + struct clk *clk_csus; + + void __iomem *vi_base; + spinlock_t videobuf_queue_lock; + struct list_head capture; + struct vb2_buffer *active; + struct vb2_alloc_ctx *alloc_ctx; + enum v4l2_field field; + int sequence; + + struct work_struct work; + struct mutex work_mutex; + + u32 syncpt_vi; + u32 syncpt_csi; + + /* Debug */ + int num_frames; +}; + +static const struct soc_mbus_pixelfmt tegra_camera_formats[] = { + { + .fourcc = V4L2_PIX_FMT_UYVY, + .name = "YUV422 (UYVY) packed", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, + { + .fourcc = V4L2_PIX_FMT_VYUY, + .name = "YUV422 (VYUY) packed", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .name = "YUV422 (YUYV) packed", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .name = "YUV422 (YVYU) packed", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .name = "YUV420 (YU12) planar", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, + .name = "YVU420 (YV12) planar", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, +}; + +static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb) +{ + return container_of(vb, struct tegra_buffer, vb); +} + +static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev) +{ + pcdev->syncpt_csi = + nvhost_syncpt_read_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_CSI); + + pcdev->syncpt_vi = + nvhost_syncpt_read_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_VI); +} + +static void tegra_camera_incr_syncpts(struct tegra_camera_dev *pcdev) +{ + nvhost_syncpt_cpu_incr_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_CSI); + + nvhost_syncpt_cpu_incr_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_VI); +} + +static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev, + int input_format, + int yuv_input_format) +{ + struct soc_camera_device *icd = pcdev->icd; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, + (yuv_input_format << 8) | + (input_format << 2)); + + TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000004); + TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000004); + + /* CSI-A H_ACTIVE and V_ACTIVE */ + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE, + (icd->user_width << 16)); + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE, + (icd->user_height << 16)); + + /* CSI A */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); + + /* pad1s enabled, virtual channel ID 00 */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, + (0x1 << 16) | /* Output 1 pixel per clock */ + (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */ + (0x1 << 7) | /* Check header CRC */ + (0x1 << 6) | /* Use word count field in the header */ + (0x1 << 5) | /* Look at data identifier byte in hdr */ + (0x1 << 4)); /* Expect packet header */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, + 0x1); /* Frame # for top field detect for interlaced */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, + bytes_per_line); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00140000); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, + (icd->user_height << 16) | + (0x100 << 4) | /* Wait 0x100 vi clks for timeout */ + 0x1); /* Enable line timeout */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, + (0x3f << 16) | /* Skip packet threshold */ + (pcdev->pdata->lanes - 1)); + + /* Use 0x00000022 for continuous clock mode. */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0, + (pcdev->pdata->continuous_clk << 5) | + 0x5); /* Clock settle time */ + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_CSI); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_VI); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x0000f002); +} + +static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev, + int input_format, + int yuv_input_format) +{ + struct soc_camera_device *icd = pcdev->icd; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, + (yuv_input_format << 8) | + (input_format << 2)); + + TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000008); + TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000008); + + /* CSI-B H_ACTIVE and V_ACTIVE */ + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE, + (icd->user_width << 16)); + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE, + (icd->user_height << 16)); + + /* CSI B */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); + + /* pad1s enabled, virtual channel ID 00 */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, + (0x1 << 16) | /* Output 1 pixel per clock */ + (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */ + (0x1 << 7) | /* Check header CRC */ + (0x1 << 6) | /* Use word count field in the header */ + (0x1 << 5) | /* Look at data identifier byte in hdr */ + (0x1 << 4) | /* Expect packet header */ + 0x1); /* Set PPB stream source to CSI B */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, + 0x1); /* Frame # for top field detect for interlaced */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, + bytes_per_line); + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00140000); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, + (icd->user_height << 16) | + (0x100 << 4) | /* Wait 0x100 vi clks for timeout */ + 0x1); /* Enable line timeout */ + + TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, + (0x3f << 16) | /* Skip packet threshold */ + (pcdev->pdata->lanes - 1)); + + /* Use 0x00000022 for continuous clock mode. */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0, + (pcdev->pdata->continuous_clk << 5) | + 0x5); /* Clock settle time */ + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_CSI); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_VI); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f002); +} + +static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev, + int input_format, + int yuv_input_format) +{ + struct soc_camera_device *icd = pcdev->icd; + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x00000000); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, + (1 << 27) | /* field detect */ + (1 << 25) | /* hsync/vsync decoded from data (BT.656) */ + (yuv_input_format << 8) | + (1 << 1) | /* VIP_INPUT_ENABLE */ + (input_format << 2)); + + TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000); + + /* VIP H_ACTIVE and V_ACTIVE */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_H_ACTIVE, + (icd->user_width << 16) | + TEGRA_VIP_H_ACTIVE_START); + TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_V_ACTIVE, + (icd->user_height << 16) | + TEGRA_VIP_V_ACTIVE_START); + + /* + * For VIP, D9..D2 is mapped to the video decoder's P7..P0. + * Disable/mask out the other Dn wires. + */ + TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc); + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc); + TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INVERSION, 0x00000000); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_VI); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004); +} + +static void tegra_camera_capture_setup(struct tegra_camera_dev *pcdev) +{ + struct soc_camera_device *icd = pcdev->icd; + const struct soc_camera_format_xlate *current_fmt = icd->current_fmt; + enum v4l2_mbus_pixelcode input_code = current_fmt->code; + u32 output_fourcc = current_fmt->host_fmt->fourcc; + int yuv_input_format = 0x0; + int input_format = 0x0; /* Default to YUV422 */ + int yuv_output_format = 0x0; + int output_format = 0x3; /* Default to YUV422 */ + int port = pcdev->pdata->port; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + switch (input_code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + yuv_input_format = 0x2; + break; + case V4L2_MBUS_FMT_VYUY8_2X8: + yuv_input_format = 0x3; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + yuv_input_format = 0x0; + break; + case V4L2_MBUS_FMT_YVYU8_2X8: + yuv_input_format = 0x1; + break; + default: + BUG_ON(1); + } + + switch (output_fourcc) { + case V4L2_PIX_FMT_UYVY: + yuv_output_format = 0x0; + break; + case V4L2_PIX_FMT_VYUY: + yuv_output_format = 0x1; + break; + case V4L2_PIX_FMT_YUYV: + yuv_output_format = 0x2; + break; + case V4L2_PIX_FMT_YVYU: + yuv_output_format = 0x3; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + output_format = 0x6; /* YUV420 planar */ + break; + default: + BUG_ON(1); + } + + BUG_ON(!tegra_camera_port_is_valid(port)); + + /* + * Set up low pass filter. Use 0x240 for chromaticity and 0x240 + * for luminance, which is the default and means not to touch + * anything. + */ + TC_VI_REG_WT(pcdev, TEGRA_VI_H_LPF_CONTROL, 0x02400240); + + /* Set up raise-on-edge, so we get an interrupt on end of frame. */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_RAISE, 0x00000001); + + if (port == TEGRA_CAMERA_PORT_CSI_A) + tegra_camera_capture_setup_csi_a(pcdev, input_format, + yuv_input_format); + else if (port == TEGRA_CAMERA_PORT_CSI_B) + tegra_camera_capture_setup_csi_b(pcdev, input_format, + yuv_input_format); + else + tegra_camera_capture_setup_vip(pcdev, input_format, + yuv_input_format); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL, + (pcdev->pdata->flip_v ? (0x1 << 20) : 0) | + (pcdev->pdata->flip_h ? (0x1 << 19) : 0) | + (yuv_output_format << 17) | + output_format); + + /* + * Set up frame size. Bits 31:16 are the number of lines, and + * bits 15:0 are the number of pixels per line. + */ + TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE, + (icd->user_height << 16) | icd->user_width); + + /* First output memory enabled */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000); + + /* Set the number of frames in the buffer. */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001); + + /* Set up buffer frame size. */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST, + (icd->user_height << 16) | icd->user_width); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST, + (icd->user_height * bytes_per_line)); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000); +} + +static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, + struct tegra_buffer *buf) +{ + struct soc_camera_device *icd = pcdev->icd; + int port = pcdev->pdata->port; + int err; + + pcdev->syncpt_csi++; + pcdev->syncpt_vi++; + + switch (icd->current_fmt->host_fmt->fourcc) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_U, + buf->buffer_addr_u); + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_U, + buf->start_addr_u); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_V, + buf->buffer_addr_v); + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_V, + buf->start_addr_v); + + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST, + buf->buffer_addr); + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST, + buf->start_addr); + + break; + + default: + BUG_ON(1); + } + + BUG_ON(!tegra_camera_port_is_valid(port)); + + if (port == TEGRA_CAMERA_PORT_CSI_A) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, + 0x0000f005); + else if (port == TEGRA_CAMERA_PORT_CSI_B) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, + 0x0000f005); + else + TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, + 0x00000001); + + /* + * Only wait on CSI frame end syncpt if we're using CSI. Otherwise, + * wait on VIP VSYNC syncpt. + */ + if (tegra_camera_port_is_csi(port)) + err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_CSI, + pcdev->syncpt_csi, + TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, + NULL); + else + err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_VI, + pcdev->syncpt_csi, + TEGRA_SYNCPT_VI_WAIT_TIMEOUT, + NULL); + + if (!err) + return 0; + + if (tegra_camera_port_is_csi(port)) { + u32 ppstatus; + u32 cilstatus; + u32 rostatus; + + dev_err(&pcdev->ndev->dev, "Timeout on CSI syncpt\n"); + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", + buf->buffer_addr); + + ppstatus = TC_VI_REG_RD(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); + cilstatus = TC_VI_REG_RD(pcdev, + TEGRA_CSI_CSI_CIL_STATUS); + rostatus = TC_VI_REG_RD(pcdev, + TEGRA_CSI_CSI_READONLY_STATUS); + + dev_err(&pcdev->ndev->dev, + "PPSTATUS = 0x%08x, " + "CILSTATUS = 0x%08x, " + "ROSTATUS = 0x%08x\n", + ppstatus, cilstatus, rostatus); + } else { + u32 vip_input_status; + + dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", + buf->buffer_addr); + + vip_input_status = TC_VI_REG_RD(pcdev, + TEGRA_VI_VIP_INPUT_STATUS); + + dev_err(&pcdev->ndev->dev, + "VIP_INPUT_STATUS = 0x%08x\n", + vip_input_status); + } + + return err; +} + +static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev) +{ + int port = pcdev->pdata->port; + int err; + + BUG_ON(!tegra_camera_port_is_valid(port)); + + if (port == TEGRA_CAMERA_PORT_CSI_A) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, + 0x0000f002); + else if (port == TEGRA_CAMERA_PORT_CSI_B) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, + 0x0000f002); + else + TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, + 0x00000005); + + if (tegra_camera_port_is_csi(port)) + err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_VI, + pcdev->syncpt_vi, + TEGRA_SYNCPT_VI_WAIT_TIMEOUT, + NULL); + else + err = 0; + + if (err) { + u32 buffer_addr; + u32 ppstatus; + u32 cilstatus; + + dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); + buffer_addr = TC_VI_REG_RD(pcdev, + TEGRA_VI_VB0_BASE_ADDRESS_FIRST); + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", + buffer_addr); + + ppstatus = TC_VI_REG_RD(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); + cilstatus = TC_VI_REG_RD(pcdev, + TEGRA_CSI_CSI_CIL_STATUS); + dev_err(&pcdev->ndev->dev, + "PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n", + ppstatus, cilstatus); + } + + return err; +} + +static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) +{ + struct vb2_buffer *vb; + struct tegra_buffer *buf; + int retry = TEGRA_SYNCPT_RETRY_COUNT; + int port = pcdev->pdata->port; + int err; + + if (!pcdev->active) + return 0; + + vb = pcdev->active; + buf = to_tegra_vb(vb); + + while (retry) { + err = tegra_camera_capture_start(pcdev, buf); + if (!err) + err = tegra_camera_capture_stop(pcdev); + + if (err != 0) { + retry--; + + /* Stop streaming. */ + if (port == TEGRA_CAMERA_PORT_CSI_A) { + TC_VI_REG_WT(pcdev, + TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, + 0x0000f002); + /* Clear status registers. */ + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, + 0xffffffff); + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_CIL_STATUS, + 0xffffffff); + } else if (port == TEGRA_CAMERA_PORT_CSI_B) { + TC_VI_REG_WT(pcdev, + TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, + 0x0000f002); + /* Clear status registers. */ + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, + 0xffffffff); + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_CIL_STATUS, + 0xffffffff); + } else { + TC_VI_REG_WT(pcdev, + TEGRA_VI_CAMERA_CONTROL, + 0x00000005); + } + + + tegra_camera_incr_syncpts(pcdev); + tegra_camera_save_syncpts(pcdev); + + continue; + } + + break; + } + + spin_lock_irq(&pcdev->videobuf_queue_lock); + + /* + * If vb->state is VB2_BUF_STATE_ERROR, then the vb has already been + * removed, so we shouldn't remove it again. + */ + if (vb->state != VB2_BUF_STATE_ERROR) + list_del_init(&buf->queue); + + if (!list_empty(&pcdev->capture)) + pcdev->active = &list_entry(pcdev->capture.next, + struct tegra_buffer, queue)->vb; + else + pcdev->active = NULL; + + do_gettimeofday(&vb->v4l2_buf.timestamp); + vb->v4l2_buf.field = pcdev->field; + vb->v4l2_buf.sequence = pcdev->sequence++; + + vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + pcdev->num_frames++; + + spin_unlock_irq(&pcdev->videobuf_queue_lock); + + return err; +} + +static void tegra_camera_work(struct work_struct *work) +{ + struct tegra_camera_dev *pcdev = + container_of(work, struct tegra_camera_dev, work); + + mutex_lock(&pcdev->work_mutex); + + while (pcdev->active) + tegra_camera_capture_frame(pcdev); + + mutex_unlock(&pcdev->work_mutex); +} + +static void tegra_camera_activate(struct tegra_camera_dev *pcdev) +{ + nvhost_module_busy_ext(pcdev->ndev); + + /* Turn on relevant clocks. */ + clk_enable(pcdev->clk_vi); + clk_enable(pcdev->clk_vi_sensor); + clk_enable(pcdev->clk_csi); + clk_enable(pcdev->clk_isp); + clk_enable(pcdev->clk_csus); + + /* Save current syncpt values. */ + tegra_camera_save_syncpts(pcdev); +} + +static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev) +{ + mutex_lock(&pcdev->work_mutex); + + /* Cancel active buffer. */ + if (pcdev->active) { + list_del_init(&to_tegra_vb(pcdev->active)->queue); + vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); + pcdev->active = NULL; + } + + mutex_unlock(&pcdev->work_mutex); + + /* Turn off relevant clocks. */ + clk_disable(pcdev->clk_vi); + clk_disable(pcdev->clk_vi_sensor); + clk_disable(pcdev->clk_csi); + clk_disable(pcdev->clk_isp); + clk_disable(pcdev->clk_csus); + + nvhost_module_idle_ext(pcdev->ndev); +} + +static void tegra_camera_init_buffer(struct tegra_camera_dev *pcdev, + struct tegra_buffer *buf) +{ + struct soc_camera_device *icd = pcdev->icd; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + switch (icd->current_fmt->host_fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); + buf->start_addr = buf->buffer_addr; + + if (pcdev->pdata->flip_v) + buf->start_addr += bytes_per_line * + (icd->user_height-1); + + if (pcdev->pdata->flip_h) + buf->start_addr += bytes_per_line - 1; + + break; + + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); + buf->buffer_addr_u = buf->buffer_addr + + icd->user_width * icd->user_height; + buf->buffer_addr_v = buf->buffer_addr_u + + (icd->user_width * icd->user_height) / 4; + + /* For YVU420, we swap the locations of the U and V planes. */ + if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420) { + dma_addr_t temp = buf->buffer_addr_u; + buf->buffer_addr_u = buf->buffer_addr_v; + buf->buffer_addr_v = temp; + } + + buf->start_addr = buf->buffer_addr; + buf->start_addr_u = buf->buffer_addr_u; + buf->start_addr_v = buf->buffer_addr_v; + + if (pcdev->pdata->flip_v) { + buf->start_addr += icd->user_width * + (icd->user_height - 1); + + buf->start_addr_u += ((icd->user_width/2) * + ((icd->user_height/2) - 1)); + + buf->start_addr_v += ((icd->user_width/2) * + ((icd->user_height/2) - 1)); + } + + if (pcdev->pdata->flip_h) { + buf->start_addr += icd->user_width - 1; + + buf->start_addr_u += (icd->user_width/2) - 1; + + buf->start_addr_v += (icd->user_width/2) - 1; + } + + break; + + default: + BUG_ON(1); + } +} + +/* + * Videobuf operations + */ +static int tegra_camera_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + void *alloc_ctxs[]) +{ + struct soc_camera_device *icd = container_of(vq, + struct soc_camera_device, + vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + dev_dbg(icd->parent, "In tegra_camera_videobuf_setup()\n"); + + if (bytes_per_line < 0) + return bytes_per_line; + + *num_planes = 1; + + pcdev->sequence = 0; + sizes[0] = bytes_per_line * icd->user_height; + alloc_ctxs[0] = pcdev->alloc_ctx; + + if (!*num_buffers) + *num_buffers = 2; + + dev_dbg(icd->parent, "num_buffers=%u, size=%u\n", + *num_buffers, sizes[0]); + + tegra_camera_capture_setup(pcdev); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_setup()\n"); + + return 0; +} + +static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = container_of(vb->vb2_queue, + struct soc_camera_device, + vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + struct tegra_buffer *buf; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + unsigned long size; + + dev_dbg(icd->parent, "In tegra_camera_videobuf_prepare()\n"); + + if (bytes_per_line < 0) + return bytes_per_line; + + buf = to_tegra_vb(vb); + + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_plane_size(vb, 0)); + +#ifdef PREFILL_BUFFER + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ + if (vb2_plane_vaddr(vb, 0)) + memset(vb2_plane_vaddr(vb, 0), 0xbd, vb2_plane_size(vb, 0)); +#endif + + BUG_ON(NULL == icd->current_fmt); + + size = icd->user_height * bytes_per_line; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -ENOBUFS; + } + + vb2_set_plane_payload(vb, 0, size); + + tegra_camera_init_buffer(pcdev, buf); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_prepare()\n"); + + return 0; +} + +static void tegra_camera_videobuf_queue(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = container_of(vb->vb2_queue, + struct soc_camera_device, + vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + struct tegra_buffer *buf = to_tegra_vb(vb); + + dev_dbg(icd->parent, "In tegra_camera_videobuf_queue()\n"); + + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + + spin_lock_irq(&pcdev->videobuf_queue_lock); + list_add_tail(&buf->queue, &pcdev->capture); + + if (!pcdev->active) { + pcdev->active = vb; + schedule_work(&pcdev->work); + } + spin_unlock_irq(&pcdev->videobuf_queue_lock); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_queue()\n"); +} + +static void tegra_camera_videobuf_release(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = container_of(vb->vb2_queue, + struct soc_camera_device, + vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_buffer *buf = to_tegra_vb(vb); + struct tegra_camera_dev *pcdev = ici->priv; + + dev_dbg(icd->parent, "In tegra_camera_videobuf_release()\n"); + + mutex_lock(&pcdev->work_mutex); + + spin_lock_irq(&pcdev->videobuf_queue_lock); + + if (pcdev->active == vb) + pcdev->active = NULL; + + /* + * Doesn't hurt also if the list is empty, but it hurts, if queuing the + * buffer failed, and .buf_init() hasn't been called + */ + if (buf->queue.next) + list_del_init(&buf->queue); + + spin_unlock_irq(&pcdev->videobuf_queue_lock); + + mutex_unlock(&pcdev->work_mutex); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_release()\n"); +} + +static int tegra_camera_videobuf_init(struct vb2_buffer *vb) +{ + /* This is for locking debugging only */ + INIT_LIST_HEAD(&to_tegra_vb(vb)->queue); + + return 0; +} + +static int tegra_camera_stop_streaming(struct vb2_queue *q) +{ + struct soc_camera_device *icd = container_of(q, + struct soc_camera_device, + vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + struct list_head *buf_head, *tmp; + + mutex_lock(&pcdev->work_mutex); + + spin_lock_irq(&pcdev->videobuf_queue_lock); + + pcdev->active = NULL; + + list_for_each_safe(buf_head, tmp, &pcdev->capture) + list_del_init(buf_head); + + spin_unlock_irq(&pcdev->videobuf_queue_lock); + + mutex_unlock(&pcdev->work_mutex); + + return 0; +} + +static struct vb2_ops tegra_camera_videobuf_ops = { + .queue_setup = tegra_camera_videobuf_setup, + .buf_prepare = tegra_camera_videobuf_prepare, + .buf_queue = tegra_camera_videobuf_queue, + .buf_cleanup = tegra_camera_videobuf_release, + .buf_init = tegra_camera_videobuf_init, + .wait_prepare = soc_camera_unlock, + .wait_finish = soc_camera_lock, + .stop_streaming = tegra_camera_stop_streaming, +}; + +/* + * SOC camera host operations + */ +static int tegra_camera_init_videobuf(struct vb2_queue *q, + struct soc_camera_device *icd) +{ + dev_dbg(icd->parent, "In tegra_camera_init_videobuf()\n"); + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = icd; + q->ops = &tegra_camera_videobuf_ops; + q->mem_ops = &vb2_dma_nvmap_memops; + q->buf_struct_size = sizeof(struct tegra_buffer); + + dev_dbg(icd->parent, "Finished tegra_camera_init_videobuf()\n"); + + return vb2_queue_init(q); +} + +/* + * Called with .video_lock held + */ +static int tegra_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + int err; + + if (pcdev->icd) + return -EBUSY; + + pm_runtime_get_sync(ici->v4l2_dev.dev); + + if (pcdev->pdata->enable_camera) { + err = pcdev->pdata->enable_camera(pcdev->ndev); + if (IS_ERR_VALUE(err)) + return err; + } + + tegra_camera_activate(pcdev); + + pcdev->icd = icd; + + pcdev->num_frames = 0; + + dev_dbg(icd->parent, "TEGRA Camera host attached to camera %d\n", + icd->devnum); + + return 0; +} + +/* Called with .video_lock held */ +static void tegra_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + + tegra_camera_deactivate(pcdev); + + pcdev->icd = NULL; + + if (pcdev->pdata->disable_camera) + pcdev->pdata->disable_camera(pcdev->ndev); + + pm_runtime_put_sync(ici->v4l2_dev.dev); + + dev_dbg(icd->parent, "Frames captured: %d\n", pcdev->num_frames); + + dev_dbg(icd->parent, "TEGRA camera host detached from camera %d\n", + icd->devnum); +} + +static int tegra_camera_set_bus_param(struct soc_camera_device *icd) +{ + return 0; +} + +static int tegra_camera_get_formats(struct soc_camera_device *icd, + unsigned int idx, + struct soc_camera_format_xlate *xlate) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct device *dev = icd->parent; + int formats = 0; + int ret; + enum v4l2_mbus_pixelcode code; + const struct soc_mbus_pixelfmt *fmt; + int k; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret != 0) + /* No more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + return 0; + } + + switch (code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + case V4L2_MBUS_FMT_VYUY8_2X8: + case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_YVYU8_2X8: + formats += ARRAY_SIZE(tegra_camera_formats); + for (k = 0; + xlate && (k < ARRAY_SIZE(tegra_camera_formats)); + k++) { + xlate->host_fmt = &tegra_camera_formats[k]; + xlate->code = code; + xlate++; + + dev_info(dev, "Providing format %s using code %d\n", + tegra_camera_formats[k].name, code); + } + break; + default: + dev_info(dev, "Not supporting %s\n", fmt->name); + return 0; + } + + return formats; +} + +static void tegra_camera_put_formats(struct soc_camera_device *icd) +{ + kfree(icd->host_priv); + icd->host_priv = NULL; +} + +static int tegra_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct device *dev = icd->parent; + struct soc_camera_host *ici = to_soc_camera_host(dev); + struct tegra_camera_dev *pcdev = ici->priv; + + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + + dev_dbg(dev, "In tegra_camera_set_fmt()\n"); + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(dev, "Format %x not found\n", pix->pixelformat); + return -EINVAL; + } + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (IS_ERR_VALUE(ret)) { + dev_warn(dev, "Failed to configure for format %x\n", + pix->pixelformat); + return ret; + } + + if (mf.code != xlate->code) { + dev_warn(dev, "mf.code = %d, xlate->code = %d, mismatch\n", + mf.code, xlate->code); + return -EINVAL; + } + + icd->user_width = mf.width; + icd->user_height = mf.height; + icd->current_fmt = xlate; + + pcdev->field = pix->field; + + dev_dbg(dev, "Finished tegra_camera_set_fmt(), returning %d\n", ret); + + return ret; +} + +static int tegra_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + __u32 pixfmt = pix->pixelformat; + int ret; + + dev_dbg(icd->parent, "In tegra_camera_try_fmt()\n"); + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(icd->parent, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + + /* limit to sensor capabilities */ + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (IS_ERR_VALUE(ret)) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->colorspace = mf.colorspace; + /* + * width and height could have been changed, therefore update the + * bytesperline and sizeimage here. + */ + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + pix->sizeimage = pix->height * pix->bytesperline; + + switch (mf.field) { + case V4L2_FIELD_ANY: + case V4L2_FIELD_NONE: + pix->field = V4L2_FIELD_NONE; + break; + default: + /* TODO: support interlaced at least in pass-through mode */ + dev_err(icd->parent, "Field type %d unsupported.\n", + mf.field); + return -EINVAL; + } + + dev_dbg(icd->parent, + "Finished tegra_camera_try_fmt(), returning %d\n", ret); + + return ret; +} + +static int tegra_camera_reqbufs(struct soc_camera_device *icd, + struct v4l2_requestbuffers *p) +{ + return 0; +} + +static unsigned int tegra_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_device *icd = file->private_data; + + return vb2_poll(&icd->vb2_vidq, file, pt); +} + +static int tegra_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + strlcpy(cap->card, TEGRA_CAM_DRV_NAME, sizeof(cap->card)); + cap->version = TEGRA_CAM_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static struct soc_camera_host_ops tegra_soc_camera_host_ops = { + .owner = THIS_MODULE, + .init_videobuf2 = tegra_camera_init_videobuf, + .add = tegra_camera_add_device, + .remove = tegra_camera_remove_device, + .set_bus_param = tegra_camera_set_bus_param, + .get_formats = tegra_camera_get_formats, + .put_formats = tegra_camera_put_formats, + .set_fmt = tegra_camera_set_fmt, + .try_fmt = tegra_camera_try_fmt, + .reqbufs = tegra_camera_reqbufs, + .poll = tegra_camera_poll, + .querycap = tegra_camera_querycap, +}; + +static int __devinit tegra_camera_probe(struct nvhost_device *ndev, + struct nvhost_device_id *id_table) +{ + struct tegra_camera_dev *pcdev; + int err = 0; + + pcdev = kzalloc(sizeof(struct tegra_camera_dev), GFP_KERNEL); + if (!pcdev) { + dev_err(&ndev->dev, "Could not allocate pcdev\n"); + err = -ENOMEM; + goto exit; + } + + pcdev->pdata = ndev->dev.platform_data; + pcdev->ndev = ndev; + + pcdev->ici.priv = pcdev; + pcdev->ici.v4l2_dev.dev = &ndev->dev; + pcdev->ici.nr = ndev->id; + pcdev->ici.drv_name = dev_name(&ndev->dev); + pcdev->ici.ops = &tegra_soc_camera_host_ops; + + INIT_LIST_HEAD(&pcdev->capture); + INIT_WORK(&pcdev->work, tegra_camera_work); + spin_lock_init(&pcdev->videobuf_queue_lock); + mutex_init(&pcdev->work_mutex); + + nvhost_set_drvdata(ndev, pcdev); + + if (!tegra_camera_port_is_valid(pcdev->pdata->port)) { + dev_err(&ndev->dev, "Invalid camera port %d in platform data\n", + pcdev->pdata->port); + goto exit_free_pcdev; + } + + pcdev->clk_vi = clk_get_sys("tegra_camera", "vi"); + if (IS_ERR_OR_NULL(pcdev->clk_vi)) { + dev_err(&ndev->dev, "Failed to get vi clock.\n"); + goto exit_free_pcdev; + } + + pcdev->clk_vi_sensor = clk_get_sys("tegra_camera", "vi_sensor"); + if (IS_ERR_OR_NULL(pcdev->clk_vi_sensor)) { + dev_err(&ndev->dev, "Failed to get vi_sensor clock.\n"); + goto exit_put_clk_vi; + } + + pcdev->clk_csi = clk_get_sys("tegra_camera", "csi"); + if (IS_ERR_OR_NULL(pcdev->clk_csi)) { + dev_err(&ndev->dev, "Failed to get csi clock.\n"); + goto exit_put_clk_vi_sensor; + } + + pcdev->clk_isp = clk_get_sys("tegra_camera", "isp"); + if (IS_ERR_OR_NULL(pcdev->clk_isp)) { + dev_err(&ndev->dev, "Failed to get isp clock.\n"); + goto exit_put_clk_csi; + } + + pcdev->clk_csus = clk_get_sys("tegra_camera", "csus"); + if (IS_ERR_OR_NULL(pcdev->clk_csus)) { + dev_err(&ndev->dev, "Failed to get csus clock.\n"); + goto exit_put_clk_isp; + } + + clk_set_rate(pcdev->clk_vi, 150000000); + clk_set_rate(pcdev->clk_vi_sensor, 24000000); + + err = nvhost_client_device_get_resources(ndev); + if (err) + goto exit_put_clk_csus; + + nvhost_client_device_init(ndev); + + pcdev->vi_base = ndev->aperture; + + pm_suspend_ignore_children(&ndev->dev, true); + pm_runtime_enable(&ndev->dev); + pm_runtime_resume(&ndev->dev); + + pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(NULL); + if (IS_ERR(pcdev->alloc_ctx)) { + err = PTR_ERR(pcdev->alloc_ctx); + goto exit_put_resources; + } + + err = soc_camera_host_register(&pcdev->ici); + if (IS_ERR_VALUE(err)) + goto exit_cleanup_alloc_ctx; + + dev_notice(&ndev->dev, "Tegra camera driver loaded.\n"); + + return err; + +exit_cleanup_alloc_ctx: + vb2_dma_nvmap_cleanup_ctx(&ndev->dev); +exit_put_resources: + pm_runtime_disable(&ndev->dev); + nvhost_client_device_put_resources(ndev); +exit_put_clk_csus: + clk_put(pcdev->clk_csus); +exit_put_clk_isp: + clk_put(pcdev->clk_isp); +exit_put_clk_csi: + clk_put(pcdev->clk_csi); +exit_put_clk_vi_sensor: + clk_put(pcdev->clk_vi_sensor); +exit_put_clk_vi: + clk_put(pcdev->clk_vi); +exit_free_pcdev: + kfree(pcdev); +exit: + return err; +} + +static int __devexit tegra_camera_remove(struct nvhost_device *ndev) +{ + struct soc_camera_host *ici = to_soc_camera_host(&ndev->dev); + struct tegra_camera_dev *pcdev = container_of(ici, + struct tegra_camera_dev, ici); + struct resource *res; + + res = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "regs"); + if (!res) + return -EBUSY; + + soc_camera_host_unregister(ici); + + vb2_dma_nvmap_cleanup_ctx(&ndev->dev); + + pm_runtime_disable(&ndev->dev); + + nvhost_client_device_put_resources(ndev); + + clk_put(pcdev->clk_csus); + clk_put(pcdev->clk_isp); + clk_put(pcdev->clk_csi); + clk_put(pcdev->clk_vi_sensor); + clk_put(pcdev->clk_vi); + + kfree(pcdev); + + dev_notice(&ndev->dev, "Tegra camera host driver unloaded\n"); + + return 0; +} + +#ifdef CONFIG_PM_FISH +static int tegra_camera_suspend(struct nvhost_device *ndev, pm_message_t state) +{ + struct soc_camera_host *ici = to_soc_camera_host(&ndev->dev); + struct tegra_camera_dev *pcdev = container_of(ici, + struct tegra_camera_dev, ici); + + mutex_lock(&pcdev->work_mutex); + + /* We only need to do something if a camera sensor is attached. */ + if (pcdev->icd) { + /* Suspend the camera sensor. */ + WARN_ON(!pcdev->icd->ops->suspend); + pcdev->icd->ops->suspend(pcdev->icd, state); + + /* Power off the camera subsystem. */ + pcdev->pdata->disable_camera(pcdev->ndev); + + nvhost_module_idle_ext(nvhost_get_parent(ndev)); + } + + return 0; +} + +static int tegra_camera_resume(struct nvhost_device *ndev) +{ + struct soc_camera_host *ici = to_soc_camera_host(&ndev->dev); + struct tegra_camera_dev *pcdev = container_of(ici, + struct tegra_camera_dev, ici); + + /* We only need to do something if a camera sensor is attached. */ + if (pcdev->icd) { + nvhost_module_busy_ext(nvhost_get_parent(ndev)); + + /* Power on the camera subsystem. */ + pcdev->pdata->enable_camera(pcdev->ndev); + + /* Resume the camera host. */ + tegra_camera_save_syncpts(pcdev); + tegra_camera_capture_setup(pcdev); + + /* Resume the camera sensor. */ + WARN_ON(!pcdev->icd->ops->resume); + pcdev->icd->ops->resume(pcdev->icd); + } + + mutex_unlock(&pcdev->work_mutex); + + return 0; +} +#endif + +static struct nvhost_driver tegra_camera_driver = { + .driver = { + .name = TEGRA_CAM_DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = tegra_camera_probe, + .remove = __devexit_p(tegra_camera_remove), +#ifdef CONFIG_PM_FISH + .suspend = tegra_camera_suspend, + .resume = tegra_camera_resume, +#endif +}; + + +static int __init tegra_camera_init(void) +{ + return nvhost_driver_register(&tegra_camera_driver); +} + +static void __exit tegra_camera_exit(void) +{ + nvhost_driver_unregister(&tegra_camera_driver); +} + +module_init(tegra_camera_init); +module_exit(tegra_camera_exit); + +MODULE_DESCRIPTION("TEGRA SoC Camera Host driver"); +MODULE_AUTHOR("Andrew Chew "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("nvhost:" TEGRA_CAM_DRV_NAME); diff --git a/include/media/tegra_v4l2_camera.h b/include/media/tegra_v4l2_camera.h new file mode 100644 index 000000000000..f6390b6e5609 --- /dev/null +++ b/include/media/tegra_v4l2_camera.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _TEGRA_CAMERA_H_ +#define _TEGRA_CAMERA_H_ + +#include +#include +#include + +enum tegra_camera_port { + TEGRA_CAMERA_PORT_CSI_A = 1, + TEGRA_CAMERA_PORT_CSI_B, + TEGRA_CAMERA_PORT_VIP, +}; + +struct tegra_camera_platform_data { + int (*enable_camera)(struct nvhost_device *ndev); + void (*disable_camera)(struct nvhost_device *ndev); + bool flip_h; + bool flip_v; + enum tegra_camera_port port; + int lanes; /* For CSI port only */ + bool continuous_clk; /* For CSI port only */ +}; + +#endif /* _TEGRA_CAMERA_H_ */ -- cgit v1.2.3 From 62c2aed60372c97eebda02e8833c15b418a16fb0 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Mon, 20 Aug 2012 13:02:04 -0700 Subject: media: tegra: Tegra videobuf2 This is based off of videobuf2-dma-contig, except we use Tegra's nvmap for the buffer allocations. Signed-off-by: Andrew Chew Change-Id: I15e689c33ee7b4fc0aade794c78701c82483df3f Reviewed-on: http://git-master/r/145345 (cherry picked from commit 70a4f20fbdd6c2c719400d6c59ef58d845657031) Signed-off-by: Bryan Wu Change-Id: Ia0632d7fcb28415e33fbb22c48f29117d7436f1d Reviewed-on: http://git-master/r/170824 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-dma-nvmap.c | 238 ++++++++++++++++++++++++++++++ include/media/videobuf2-dma-nvmap.h | 36 +++++ 4 files changed, 281 insertions(+) create mode 100644 drivers/media/video/videobuf2-dma-nvmap.c create mode 100644 include/media/videobuf2-dma-nvmap.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 18c9805a8140..1d392bf0d521 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -66,6 +66,12 @@ config VIDEOBUF2_DMA_SG select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS tristate + +config VIDEOBUF2_DMA_NVMAP + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 21ec2c37da23..b8663f00366e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -122,6 +122,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o +obj-$(CONFIG_VIDEOBUF2_DMA_NVMAP) += videobuf2-dma-nvmap.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-dma-nvmap.c b/drivers/media/video/videobuf2-dma-nvmap.c new file mode 100644 index 000000000000..27f43e5a3a57 --- /dev/null +++ b/drivers/media/video/videobuf2-dma-nvmap.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include + +struct vb2_dc_conf { + struct device *dev; + struct nvmap_client *nvmap_client; +}; + +struct vb2_dc_buf { + struct vb2_dc_conf *conf; + void *vaddr; + dma_addr_t paddr; + unsigned long size; + struct vm_area_struct *vma; + atomic_t refcount; + struct vb2_vmarea_handler handler; + + struct nvmap_handle_ref *nvmap_ref; +}; + +static void vb2_dma_nvmap_put(void *buf_priv); + +static void *vb2_dma_nvmap_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf *buf; + int ret; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto exit; + } + + buf->nvmap_ref = nvmap_alloc(conf->nvmap_client, size, 32, + NVMAP_HANDLE_CACHEABLE, NVMAP_HEAP_SYSMEM); + if (IS_ERR(buf->nvmap_ref)) { + dev_err(conf->dev, "nvmap_alloc failed\n"); + ret = -ENOMEM; + goto exit_free; + } + + buf->paddr = nvmap_pin(conf->nvmap_client, buf->nvmap_ref); + if (IS_ERR_VALUE(buf->paddr)) { + dev_err(conf->dev, "nvmap_pin failed\n"); + ret = -ENOMEM; + goto exit_dealloc; + } + + buf->vaddr = nvmap_mmap(buf->nvmap_ref); + if (!buf->vaddr) { + dev_err(conf->dev, "nvmap_mmap failed\n"); + ret = -ENOMEM; + goto exit_unpin; + } + + buf->conf = conf; + buf->size = size; + + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_dma_nvmap_put; + buf->handler.arg = buf; + + atomic_inc(&buf->refcount); + + return buf; + +exit_unpin: + nvmap_unpin(conf->nvmap_client, buf->nvmap_ref); +exit_dealloc: + nvmap_free(conf->nvmap_client, buf->nvmap_ref); +exit_free: + kfree(buf); +exit: + return ERR_PTR(ret); +} + +static void vb2_dma_nvmap_put(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (atomic_dec_and_test(&buf->refcount)) { + nvmap_munmap(buf->nvmap_ref, buf->vaddr); + nvmap_unpin(buf->conf->nvmap_client, buf->nvmap_ref); + nvmap_free(buf->conf->nvmap_client, buf->nvmap_ref); + kfree(buf); + } +} + +static void *vb2_dma_nvmap_cookie(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return &buf->paddr; +} + +static void *vb2_dma_nvmap_vaddr(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + if (!buf) + return 0; + + return buf->vaddr; +} + +static unsigned int vb2_dma_nvmap_num_users(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static int vb2_dma_nvmap_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (!buf) { + printk(KERN_ERR "No buffer to map\n"); + return -EINVAL; + } + + return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, + &vb2_common_vm_ops, &buf->handler); +} + +static void *vb2_dma_nvmap_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_dc_buf *buf; + struct vm_area_struct *vma; + dma_addr_t paddr = 0; + int ret; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); + if (ret) { + printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", + vaddr); + kfree(buf); + return ERR_PTR(ret); + } + + buf->size = size; + buf->paddr = paddr; + buf->vma = vma; + + return buf; +} + +static void vb2_dma_nvmap_put_userptr(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + if (!buf) + return; + + vb2_put_vma(buf->vma); + kfree(buf); +} + +const struct vb2_mem_ops vb2_dma_nvmap_memops = { + .alloc = vb2_dma_nvmap_alloc, + .put = vb2_dma_nvmap_put, + .cookie = vb2_dma_nvmap_cookie, + .vaddr = vb2_dma_nvmap_vaddr, + .mmap = vb2_dma_nvmap_mmap, + .get_userptr = vb2_dma_nvmap_get_userptr, + .put_userptr = vb2_dma_nvmap_put_userptr, + .num_users = vb2_dma_nvmap_num_users, +}; +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_memops); + +void *vb2_dma_nvmap_init_ctx(struct device *dev) +{ + struct vb2_dc_conf *conf; + int ret; + + conf = kzalloc(sizeof *conf, GFP_KERNEL); + if (!conf) { + ret = -ENOMEM; + goto exit; + } + + conf->dev = dev; + + conf->nvmap_client = nvmap_create_client(nvmap_dev, + "videobuf2-dma-nvmap"); + if (!conf->nvmap_client) { + ret = -ENOMEM; + goto exit_free; + } + + return conf; + +exit_free: + kfree(conf); +exit: + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_init_ctx); + +void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx) +{ + struct vb2_dc_conf *conf = alloc_ctx; + + nvmap_client_put(conf->nvmap_client); + + kfree(alloc_ctx); +} +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_cleanup_ctx); + +MODULE_DESCRIPTION("DMA-nvmap memory handling routines for videobuf2"); +MODULE_AUTHOR("Andrew Chew "); +MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-nvmap.h b/include/media/videobuf2-dma-nvmap.h new file mode 100644 index 000000000000..39ae3d3a1d5d --- /dev/null +++ b/include/media/videobuf2-dma-nvmap.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MEDIA_VIDEOBUF2_DMA_NVMAP_H +#define _MEDIA_VIDEOBUF2_DMA_NVMAP_H + +#include +#include + +static inline dma_addr_t +vb2_dma_nvmap_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no) +{ + dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no); + + return *paddr; +} + +void *vb2_dma_nvmap_init_ctx(struct device *dev); +void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx); + +extern const struct vb2_mem_ops vb2_dma_nvmap_memops; + +#endif -- cgit v1.2.3 From 681999b928434ecb46d379e2381adb31b83e5437 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Wed, 1 Aug 2012 16:52:42 -0700 Subject: tegra: Add function to release resources Add a companion function to nvhost_client_device_get_resources() called nvhost_client_device_put_resources() that does the opposite thing. This is useful for any nvhost clients that need to be loaded as modules, since the driver removal path will be exercised in that case. Change-Id: Ib5cec6fce7b05c780b135b03fcd88e068f772244 Signed-off-by: Andrew Chew Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/169833 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Winnie Hsu --- drivers/video/tegra/host/bus_client.c | 12 ++++++++++++ drivers/video/tegra/host/bus_client.h | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c index aaa038221971..4614689ec37c 100644 --- a/drivers/video/tegra/host/bus_client.c +++ b/drivers/video/tegra/host/bus_client.c @@ -658,3 +658,15 @@ fail: return -ENXIO; } + +void nvhost_client_device_put_resources(struct nvhost_device *dev) +{ + struct resource *r; + + r = nvhost_get_resource(dev, IORESOURCE_MEM, 0); + BUG_ON(!r); + + iounmap(dev->aperture); + + release_mem_region(r->start, resource_size(r)); +} diff --git a/drivers/video/tegra/host/bus_client.h b/drivers/video/tegra/host/bus_client.h index e95ea0bc3401..8c7bdc9faefe 100644 --- a/drivers/video/tegra/host/bus_client.h +++ b/drivers/video/tegra/host/bus_client.h @@ -37,5 +37,6 @@ int nvhost_client_device_init(struct nvhost_device *dev); int nvhost_client_device_suspend(struct nvhost_device *dev); int nvhost_client_device_get_resources(struct nvhost_device *dev); +void nvhost_client_device_put_resources(struct nvhost_device *dev); #endif -- cgit v1.2.3 From 970c54cc0abc7321d3993caba54d3df3ec0bbdf2 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Fri, 24 Aug 2012 16:25:03 -0700 Subject: tegra: Add nvmap_mark_global() Add this function, to be able to set the global field of an nvmap_handle while preserving the nvmap API's encapsulation mechanisms. Change-Id: I62de773a65119722f059b114e2d0e906c7e04e83 Signed-off-by: Andrew Chew Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/169834 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Winnie Hsu --- drivers/video/tegra/nvmap/nvmap.c | 13 +++++++++++++ include/linux/nvmap.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index a0dcf26337f8..19b821d41284 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -605,3 +605,16 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r) nvmap_free_handle_id(client, nvmap_ref_to_id(r)); } + +int nvmap_mark_global(struct nvmap_client *client, struct nvmap_handle_ref *r) +{ + struct nvmap_handle *h; + + h = nvmap_get_handle_id(client, (unsigned long)r->handle); + if (!h) + return -EINVAL; + r->handle->global = true; + nvmap_handle_put(h); + + return 0; +} diff --git a/include/linux/nvmap.h b/include/linux/nvmap.h index 692956b2fc4f..9cc978ec5a7f 100644 --- a/include/linux/nvmap.h +++ b/include/linux/nvmap.h @@ -124,6 +124,8 @@ void nvmap_unpin_handles(struct nvmap_client *client, struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client, unsigned long id); +int nvmap_mark_global(struct nvmap_client *client, struct nvmap_handle_ref *r); + struct nvmap_platform_carveout { const char *name; unsigned int usage_mask; -- cgit v1.2.3 From 384596a7268916b87d7cea679a6264ff2f65f61b Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 14 Nov 2012 12:07:24 -0800 Subject: media: tegra: enable a clock for VIP in APB MISC register Change-Id: Ic4d91f4ed70fc3daf52768118f6ea537d529a5a8 Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/169835 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Winnie Hsu --- drivers/media/video/tegra_v4l2_camera.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index 22e3f5b73cbb..990f6afe8b10 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -936,6 +938,11 @@ static void tegra_camera_work(struct work_struct *work) static void tegra_camera_activate(struct tegra_camera_dev *pcdev) { +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + u32 val; + void __iomem *apb_misc; +#endif + nvhost_module_busy_ext(pcdev->ndev); /* Turn on relevant clocks. */ @@ -945,6 +952,12 @@ static void tegra_camera_activate(struct tegra_camera_dev *pcdev) clk_enable(pcdev->clk_isp); clk_enable(pcdev->clk_csus); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE); + val = readl(apb_misc + 0x42c); + writel(val | 0x1, apb_misc + 0x42c); +#endif + /* Save current syncpt values. */ tegra_camera_save_syncpts(pcdev); } -- cgit v1.2.3 From 8410f55a21b22ea2dee38bb46e918edd6e99c167 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Wed, 8 Aug 2012 13:35:33 -0700 Subject: media: ov5640: Add Omnivision OV5640 support Based on ov5642 driver. There seem to be some register differences, so forking the driver to make those changes. Change-Id: Idb4a79757cbbcd15d5456ce82a708f433faaff7a Signed-off-by: Andrew Chew Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/169836 Reviewed-by: Winnie Hsu --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/ov5640.c | 1151 +++++++++++++++++++++++++++++++++++++++ include/media/v4l2-chip-ident.h | 1 + 4 files changed, 1159 insertions(+) create mode 100644 drivers/media/video/ov5640.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 1d392bf0d521..7968ea979d1f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -854,6 +854,12 @@ config SOC_CAMERA_OV2640 help This is a ov2640 camera driver +config SOC_CAMERA_OV5640 + tristate "ov5640 camera support" + depends on SOC_CAMERA && I2C + help + This is a V4L2 camera driver for the OmniVision OV5640 sensor + config SOC_CAMERA_OV5642 tristate "ov5642 camera support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b8663f00366e..f63ad7e88fda 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o +obj-$(CONFIG_SOC_CAMERA_OV5640) += ov5640.o obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o diff --git a/drivers/media/video/ov5640.c b/drivers/media/video/ov5640.c new file mode 100644 index 000000000000..8e45fa3de5d2 --- /dev/null +++ b/drivers/media/video/ov5640.c @@ -0,0 +1,1151 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define to_ov5640(sd) container_of(sd, struct ov5640_priv, subdev) + +#define OV5640_SYSTEM_CTRL 0x3008 +#define OV5640_CHIP_ID_HI 0x300a +#define OV5640_CHIP_ID_LO 0x300b +#define OV5640_PAD_OUTPUT_ENABLE00 0x3016 +#define OV5640_PAD_OUTPUT_ENABLE01 0x3017 +#define OV5640_PAD_OUTPUT_ENABLE02 0x3018 +#define OV5640_SC_PLL_CTRL0 0x3034 +#define OV5640_SC_PLL_CTRL1 0x3035 +#define OV5640_SC_PLL_CTRL2 0x3036 +#define OV5640_SC_PLL_CTRL3 0x3037 + +/* SCCB Control */ +#define OV5640_SCCB_SYSTEM_CTRL1 0x3103 +#define OV5640_SYSTEM_ROOT_DIVIDER 0x3108 + +/* Timing Control */ +#define OV5640_TIMING_HS_HI 0x3800 +#define OV5640_TIMING_HS_LO 0x3801 +#define OV5640_TIMING_VS_HI 0x3802 +#define OV5640_TIMING_VS_LO 0x3803 +#define OV5640_TIMING_HW_HI 0x3804 +#define OV5640_TIMING_HW_LO 0x3805 +#define OV5640_TIMING_VH_HI 0x3806 +#define OV5640_TIMING_VH_LO 0x3807 +#define OV5640_TIMING_DVPHO_HI 0x3808 +#define OV5640_TIMING_DVPHO_LO 0x3809 +#define OV5640_TIMING_DVPVO_HI 0x380a +#define OV5640_TIMING_DVPVO_LO 0x380b +#define OV5640_TIMING_HTS_HI 0x380c +#define OV5640_TIMING_HTS_LO 0x380d +#define OV5640_TIMING_VTS_HI 0x380e +#define OV5640_TIMING_VTS_LO 0x380f +#define OV5640_TIMING_HOFFSET_HI 0x3810 +#define OV5640_TIMING_HOFFSET_LO 0x3811 +#define OV5640_TIMING_VOFFSET_HI 0x3812 +#define OV5640_TIMING_VOFFSET_LO 0x3813 +#define OV5640_TIMING_X_INC 0x3814 +#define OV5640_TIMING_Y_INC 0x3815 +#define OV5640_TIMING_TC_REG20 0x3820 +#define OV5640_TIMING_TC_REG21 0x3821 + +/* AEC/AGC Power Down Domain Control */ +#define OV5640_AEC_MAX_EXPO_60HZ_HI 0x3a02 +#define OV5640_AEC_MAX_EXPO_60HZ_LO 0x3a03 +#define OV5640_AEC_B50_STEP_HI 0x3a08 +#define OV5640_AEC_B50_STEP_LO 0x3a09 +#define OV5640_AEC_B60_STEP_HI 0x3a0a +#define OV5640_AEC_B60_STEP_LO 0x3a0b +#define OV5640_AEC_CTRL0C 0x3a0c +#define OV5640_AEC_CTRL0D 0x3a0d +#define OV5640_AEC_CTRL0E 0x3a0e +#define OV5640_AEC_CTRL0F 0x3a0f +#define OV5640_AEC_CTRL10 0x3a10 +#define OV5640_AEC_CTRL11 0x3a11 +#define OV5640_AEC_CTRL12 0x3a12 +#define OV5640_AEC_CTRL13 0x3a13 +#define OV5640_AEC_MAX_EXPO_50HZ_HI 0x3a14 +#define OV5640_AEC_MAX_EXPO_50HZ_LO 0x3a15 +#define OV5640_AEC_GAIN_CEILING_HI 0x3a18 +#define OV5640_AEC_GAIN_CEILING_LO 0x3a19 +#define OV5640_AEC_CTRL1B 0x3a1b +#define OV5640_AEC_CTRL1E 0x3a1e +#define OV5640_AEC_CTRL1F 0x3a1f + +/* 50/60Hz Detector Control */ +#define OV5640_5060HZ_CTRL00 0x3c00 +#define OV5640_5060HZ_CTRL01 0x3c01 +#define OV5640_5060HZ_CTRL02 0x3c02 +#define OV5640_5060HZ_CTRL03 0x3c03 +#define OV5640_5060HZ_CTRL04 0x3c04 +#define OV5640_5060HZ_CTRL05 0x3c05 +#define OV5640_LIGHT_METER1_THRESHOLD_HI 0x3c06 +#define OV5640_LIGHT_METER1_THRESHOLD_LO 0x3c07 +#define OV5640_LIGHT_METER2_THRESHOLD_HI 0x3c08 +#define OV5640_LIGHT_METER2_THRESHOLD_LO 0x3c09 +#define OV5640_SAMPLE_NUMBER_HI 0x3c0a +#define OV5640_SAMPLE_NUMBER_LO 0x3c0b + +/* ISP General Controls */ +#define OV5640_ISP_CTRL00 0x5000 +#define OV5640_ISP_CTRL01 0x5001 +#define OV5640_ISP_CTRL37 0x5025 + +/* AWB Control */ +#define OV5640_AWB_CTRL00 0x5180 +#define OV5640_AWB_CTRL01 0x5181 +#define OV5640_AWB_CTRL02 0x5182 +#define OV5640_AWB_CTRL03 0x5183 +#define OV5640_AWB_CTRL04 0x5184 +#define OV5640_AWB_CTRL05 0x5185 +#define OV5640_AWB_CTRL06 0x5186 +#define OV5640_AWB_CTRL07 0x5187 +#define OV5640_AWB_CTRL08 0x5188 +#define OV5640_AWB_CTRL09 0x5189 +#define OV5640_AWB_CTRL10 0x518a +#define OV5640_AWB_CTRL11 0x518b +#define OV5640_AWB_CTRL12 0x518c +#define OV5640_AWB_CTRL13 0x518d +#define OV5640_AWB_CTRL14 0x518e +#define OV5640_AWB_CTRL15 0x518f +#define OV5640_AWB_CTRL16 0x5190 +#define OV5640_AWB_CTRL17 0x5191 +#define OV5640_AWB_CTRL18 0x5192 +#define OV5640_AWB_CTRL19 0x5193 +#define OV5640_AWB_CTRL20 0x5194 +#define OV5640_AWB_CTRL21 0x5195 +#define OV5640_AWB_CTRL22 0x5196 +#define OV5640_AWB_CTRL23 0x5197 +#define OV5640_AWB_CTRL24 0x5198 +#define OV5640_AWB_CTRL25 0x5199 +#define OV5640_AWB_CTRL26 0x519a +#define OV5640_AWB_CTRL27 0x519b +#define OV5640_AWB_CTRL28 0x519c +#define OV5640_AWB_CTRL29 0x519d +#define OV5640_AWB_CTRL30 0x519e + +/* CIP Control */ +#define OV5640_CIP_SHARPENMT_THRESHOLD_1 0x5300 +#define OV5640_CIP_SHARPENMT_THRESHOLD_2 0x5301 +#define OV5640_CIP_SHARPENMT_OFFSET_1 0x5302 +#define OV5640_CIP_SHARPENMT_OFFSET_2 0x5303 +#define OV5640_CIP_DNS_THRESHOLD_1 0x5304 +#define OV5640_CIP_DNS_THRESHOLD_2 0x5305 +#define OV5640_CIP_DNS_OFFSET_1 0x5306 +#define OV5640_CIP_DNS_OFFSET_2 0x5307 +#define OV5640_CIP_CTRL 0x5308 +#define OV5640_CIP_SHARPENTH_THRESHOLD_1 0x5309 +#define OV5640_CIP_SHARPENTH_THRESHOLD_2 0x530a +#define OV5640_CIP_SHARPENTH_OFFSET_1 0x530b +#define OV5640_CIP_SHARPENTH_OFFSET_2 0x530c +#define OV5640_CIP_EDGE_MT_AUTO 0x530d +#define OV5640_CIP_DNS_THRESHOLD_AUTO 0x530e +#define OF5640_CIP_SHARPEN_THRESHOLD_AUTO 0x530f + +/* CMX Control */ +#define OV5640_CMX_CTRL 0x5380 +#define OV5640_CMX1 0x5381 +#define OV5640_CMX2 0x5382 +#define OV5640_CMX3 0x5383 +#define OV5640_CMX4 0x5384 +#define OV5640_CMX5 0x5385 +#define OV5640_CMX6 0x5386 +#define OV5640_CMX7 0x5387 +#define OV5640_CMX8 0x5388 +#define OV5640_CMX9 0x5389 +#define OV5640_CMXSIGN_HI 0x538a +#define OV5640_CMXSIGN_LO 0x538b + +/* Gamma Control */ +#define OV5640_GAMMA_CTRL00 0x5480 +#define OV5640_YST00 0x5481 +#define OV5640_YST01 0x5482 +#define OV5640_YST02 0x5483 +#define OV5640_YST03 0x5484 +#define OV5640_YST04 0x5485 +#define OV5640_YST05 0x5486 +#define OV5640_YST06 0x5487 +#define OV5640_YST07 0x5488 +#define OV5640_YST08 0x5489 +#define OV5640_YST09 0x548a +#define OV5640_YST0A 0x548b +#define OV5640_YST0B 0x548c +#define OV5640_YST0C 0x548d +#define OV5640_YST0D 0x548e +#define OV5640_YST0E 0x548f +#define OV5640_YST0F 0x5490 + +/* SDE Control */ +#define OV5640_SDE_CTRL_0 0x5580 +#define OV5640_SDE_CTRL_1 0x5581 +#define OV5640_SDE_CTRL_2 0x5582 +#define OV5640_SDE_CTRL_3 0x5583 +#define OV5640_SDE_CTRL_4 0x5584 +#define OV5640_SDE_CTRL_5 0x5585 +#define OV5640_SDE_CTRL_6 0x5586 +#define OV5640_SDE_CTRL_7 0x5587 +#define OV5640_SDE_CTRL_8 0x5588 +#define OV5640_SDE_CTRL_9 0x5589 +#define OV5640_SDE_CTRL_10 0x558a +#define OV5640_SDE_CTRL_11 0x558b +#define OV5640_SDE_CTRL_12 0x558c + +/* LENC Control */ +#define OV5640_GMTRX00 0x5800 +#define OV5640_GMTRX01 0x5801 +#define OV5640_GMTRX02 0x5802 +#define OV5640_GMTRX03 0x5803 +#define OV5640_GMTRX04 0x5804 +#define OV5640_GMTRX05 0x5805 +#define OV5640_GMTRX10 0x5806 +#define OV5640_GMTRX11 0x5807 +#define OV5640_GMTRX12 0x5808 +#define OV5640_GMTRX13 0x5809 +#define OV5640_GMTRX14 0x580a +#define OV5640_GMTRX15 0x580b +#define OV5640_GMTRX20 0x580c +#define OV5640_GMTRX21 0x580d +#define OV5640_GMTRX22 0x580e +#define OV5640_GMTRX23 0x580f +#define OV5640_GMTRX24 0x5810 +#define OV5640_GMTRX25 0x5811 +#define OV5640_GMTRX30 0x5812 +#define OV5640_GMTRX31 0x5813 +#define OV5640_GMTRX32 0x5814 +#define OV5640_GMTRX33 0x5815 +#define OV5640_GMTRX34 0x5816 +#define OV5640_GMTRX35 0x5817 +#define OV5640_GMTRX40 0x5818 +#define OV5640_GMTRX41 0x5819 +#define OV5640_GMTRX42 0x581a +#define OV5640_GMTRX43 0x581b +#define OV5640_GMTRX44 0x581c +#define OV5640_GMTRX45 0x581d +#define OV5640_GMTRX50 0x581e +#define OV5640_GMTRX51 0x581f +#define OV5640_GMTRX52 0x5820 +#define OV5640_GMTRX53 0x5821 +#define OV5640_GMTRX54 0x5822 +#define OV5640_GMTRX55 0x5823 +#define OV5640_BRMATRX00 0x5824 +#define OV5640_BRMATRX01 0x5825 +#define OV5640_BRMATRX02 0x5826 +#define OV5640_BRMATRX03 0x5827 +#define OV5640_BRMATRX04 0x5828 +#define OV5640_BRMATRX05 0x5829 +#define OV5640_BRMATRX06 0x582a +#define OV5640_BRMATRX07 0x582b +#define OV5640_BRMATRX08 0x582c +#define OV5640_BRMATRX09 0x582d +#define OV5640_BRMATRX20 0x582e +#define OV5640_BRMATRX21 0x582f +#define OV5640_BRMATRX22 0x5830 +#define OV5640_BRMATRX23 0x5831 +#define OV5640_BRMATRX24 0x5832 +#define OV5640_BRMATRX30 0x5833 +#define OV5640_BRMATRX31 0x5834 +#define OV5640_BRMATRX32 0x5835 +#define OV5640_BRMATRX33 0x5836 +#define OV5640_BRMATRX34 0x5837 +#define OV5640_BRMATRX40 0x5838 +#define OV5640_BRMATRX41 0x5839 +#define OV5640_BRMATRX42 0x583a +#define OV5640_BRMATRX43 0x583b +#define OV5640_BRMATRX44 0x583c +#define OV5640_LENC_BR_OFFSET 0x583d + +#define OV5640_MAX_WIDTH 640 +#define OV5640_MAX_HEIGHT 480 + +/* Misc. structures */ +struct ov5640_reg { + u16 reg; + u8 val; +}; + +struct ov5640_priv { + struct v4l2_subdev subdev; + + int ident; + u16 chip_id; + u8 revision; + u8 manid; + u8 smiaver; + + bool flag_vflip; + bool flag_hflip; + + /* For suspend/resume. */ + struct v4l2_mbus_framefmt current_mf; + bool current_enable; +}; + +static const struct ov5640_reg ov5640_defaults[] = { + { OV5640_SCCB_SYSTEM_CTRL1, 0x11}, + { OV5640_SYSTEM_CTRL, 0x82}, + { OV5640_SYSTEM_CTRL, 0x42}, + { OV5640_SCCB_SYSTEM_CTRL1, 0x03}, + { OV5640_PAD_OUTPUT_ENABLE01, 0x00}, + { OV5640_PAD_OUTPUT_ENABLE02, 0x00}, + { OV5640_SC_PLL_CTRL0, 0x18}, + { OV5640_SC_PLL_CTRL1, 0x14}, + { OV5640_SC_PLL_CTRL2, 0x38}, + { OV5640_SC_PLL_CTRL3, 0x13}, + { 0x4800, 0x24}, /* noncontinuous clock */ + { OV5640_SYSTEM_ROOT_DIVIDER, 0x01}, + { 0x3630, 0x36}, + { 0x3631, 0x0e}, + { 0x3632, 0xe2}, + { 0x3633, 0x12}, + { 0x3621, 0xe0}, + { 0x3704, 0xa0}, + { 0x3703, 0x5a}, + { 0x3715, 0x78}, + { 0x3717, 0x01}, + { 0x370b, 0x60}, + { 0x3705, 0x1a}, + { 0x3905, 0x02}, + { 0x3906, 0x10}, + { 0x3901, 0x0a}, + { 0x3731, 0x12}, + { 0x3600, 0x08}, + { 0x3601, 0x33}, + { 0x302d, 0x60}, + { 0x3620, 0x52}, + { 0x371b, 0x20}, + { 0x471c, 0x50}, + { 0x3a13, 0x43}, + { 0x3a18, 0x00}, + { 0x3a19, 0xf8}, + { 0x3635, 0x13}, + { 0x3636, 0x03}, + { 0x3634, 0x40}, + { 0x3622, 0x01}, + { 0x3c01, 0x34}, + { 0x3c04, 0x28}, + { 0x3c05, 0x98}, + { 0x3c06, 0x00}, + { 0x3c07, 0x08}, + { 0x3c08, 0x00}, + { 0x3c09, 0x1c}, + { 0x3c0a, 0x9c}, + { 0x3c0b, 0x40}, + { OV5640_TIMING_TC_REG20, 0x41}, + { OV5640_TIMING_TC_REG21, 0x01}, + { 0x3814, 0x31}, + { 0x3815, 0x31}, + { 0x3800, 0x00}, + { 0x3801, 0x00}, + { 0x3802, 0x00}, + { 0x3803, 0x04}, + { 0x3804, 0x0a}, + { 0x3805, 0x3f}, + { 0x3806, 0x07}, + { 0x3807, 0x9b}, + { 0x3808, 0x02}, + { 0x3809, 0x80}, + { 0x380a, 0x01}, + { 0x380b, 0xe0}, + { 0x380c, 0x07}, + { 0x380d, 0x68}, + { 0x380e, 0x03}, + { 0x380f, 0xd8}, + { 0x3810, 0x00}, + { 0x3811, 0x10}, + { 0x3812, 0x00}, + { 0x3813, 0x06}, + { 0x3618, 0x00}, + { 0x3612, 0x29}, + { 0x3708, 0x64}, + { 0x3709, 0x52}, + { 0x370c, 0x03}, + + /* AEC/AGC Power Down Domain Control */ + { OV5640_AEC_MAX_EXPO_60HZ_HI, 0x03}, + { OV5640_AEC_MAX_EXPO_60HZ_LO, 0xd8}, + { OV5640_AEC_B50_STEP_HI, 0x01}, + { OV5640_AEC_B50_STEP_LO, 0x27}, + { OV5640_AEC_B60_STEP_HI, 0x00}, + { OV5640_AEC_B60_STEP_LO, 0xf6}, + { OV5640_AEC_CTRL0E, 0x03}, + { OV5640_AEC_CTRL0D, 0x04}, + { OV5640_AEC_MAX_EXPO_50HZ_HI, 0x03}, + { OV5640_AEC_MAX_EXPO_50HZ_LO, 0xd8}, + + { 0x4001, 0x02}, + { 0x4004, 0x02}, + { 0x3000, 0x00}, + { 0x3002, 0x1c}, + { 0x3004, 0xff}, + { 0x3006, 0xc3}, + { 0x300e, 0x45}, + { 0x302e, 0x08}, + /* org:30 bit[3:0] + 0x0:YUYV 0x1:YVYU 0x2:UYVY + 0x3:VYUY 0xF:UYVY 0x4~0xE:Not-allowed + */ + { 0x4300, 0x32}, + { 0x501f, 0x00}, + { 0x4713, 0x03}, + { 0x4407, 0x04}, + { 0x440e, 0x00}, + { 0x460b, 0x35}, + { 0x460c, 0x22}, + { 0x4837, 0x44}, + { 0x3824, 0x02}, + { 0x5000, 0xa7}, + { 0x5001, 0xa3}, + + /* AWB Control */ + { OV5640_AWB_CTRL00, 0xff}, { OV5640_AWB_CTRL01, 0xf2}, + { OV5640_AWB_CTRL02, 0x00}, { OV5640_AWB_CTRL03, 0x14}, + { OV5640_AWB_CTRL04, 0x25}, { OV5640_AWB_CTRL05, 0x24}, + { OV5640_AWB_CTRL06, 0x09}, { OV5640_AWB_CTRL07, 0x09}, + { OV5640_AWB_CTRL08, 0x09}, { OV5640_AWB_CTRL09, 0x75}, + { OV5640_AWB_CTRL10, 0x54}, { OV5640_AWB_CTRL11, 0xe0}, + { OV5640_AWB_CTRL12, 0xb2}, { OV5640_AWB_CTRL13, 0x42}, + { OV5640_AWB_CTRL14, 0x3d}, { OV5640_AWB_CTRL15, 0x56}, + { OV5640_AWB_CTRL16, 0x46}, { OV5640_AWB_CTRL17, 0xf8}, + { OV5640_AWB_CTRL18, 0x04}, { OV5640_AWB_CTRL19, 0x70}, + { OV5640_AWB_CTRL20, 0xf0}, { OV5640_AWB_CTRL21, 0xf0}, + { OV5640_AWB_CTRL22, 0x03}, { OV5640_AWB_CTRL23, 0x01}, + { OV5640_AWB_CTRL24, 0x04}, { OV5640_AWB_CTRL25, 0x12}, + { OV5640_AWB_CTRL26, 0x04}, { OV5640_AWB_CTRL27, 0x00}, + { OV5640_AWB_CTRL28, 0x06}, { OV5640_AWB_CTRL29, 0x82}, + { OV5640_AWB_CTRL30, 0x38}, + + /* CMX Control */ + { OV5640_CMX1, 0x1e}, + { OV5640_CMX2, 0x5b}, + { OV5640_CMX3, 0x08}, + { OV5640_CMX4, 0x0a}, + { OV5640_CMX5, 0x7e}, + { OV5640_CMX6, 0x88}, + { OV5640_CMX7, 0x7c}, + { OV5640_CMX8, 0x6c}, + { OV5640_CMX9, 0x10}, + { OV5640_CMXSIGN_HI, 0x01}, + { OV5640_CMXSIGN_LO, 0x98}, + + /* CIP Control */ + { OV5640_CIP_SHARPENMT_THRESHOLD_1, 0x08}, + { OV5640_CIP_SHARPENMT_THRESHOLD_2, 0x30}, + { OV5640_CIP_SHARPENMT_OFFSET_1, 0x10}, + { OV5640_CIP_SHARPENMT_OFFSET_2, 0x00}, + { OV5640_CIP_DNS_THRESHOLD_1, 0x08}, + { OV5640_CIP_DNS_THRESHOLD_2, 0x30}, + { OV5640_CIP_DNS_OFFSET_1, 0x08}, + { OV5640_CIP_DNS_OFFSET_2, 0x16}, + { OV5640_CIP_SHARPENTH_THRESHOLD_1, 0x08}, + { OV5640_CIP_SHARPENTH_THRESHOLD_2, 0x30}, + { OV5640_CIP_SHARPENTH_OFFSET_1, 0x04}, + { OV5640_CIP_SHARPENTH_OFFSET_2, 0x06}, + + /* Gamma Control */ + { OV5640_GAMMA_CTRL00, 0x01}, + { OV5640_YST00, 0x08}, { OV5640_YST01, 0x14}, + { OV5640_YST02, 0x28}, { OV5640_YST03, 0x51}, + { OV5640_YST04, 0x65}, { OV5640_YST05, 0x71}, + { OV5640_YST06, 0x7d}, { OV5640_YST07, 0x87}, + { OV5640_YST08, 0x91}, { OV5640_YST09, 0x9a}, + { OV5640_YST0A, 0xaa}, { OV5640_YST0B, 0xb8}, + { OV5640_YST0C, 0xcd}, { OV5640_YST0D, 0xdd}, + { OV5640_YST0E, 0xea}, { OV5640_YST0F, 0x1d}, + + /* SDE Control */ + { OV5640_SDE_CTRL_0, 0x02}, + { OV5640_SDE_CTRL_3, 0x40}, + { OV5640_SDE_CTRL_4, 0x10}, + { OV5640_SDE_CTRL_9, 0x10}, + { OV5640_SDE_CTRL_10, 0x00}, + { OV5640_SDE_CTRL_11, 0xf8}, + + /* LENC Control */ + { OV5640_GMTRX00, 0x23}, { OV5640_GMTRX01, 0x14}, + { OV5640_GMTRX02, 0x0f}, { OV5640_GMTRX03, 0x0f}, + { OV5640_GMTRX04, 0x12}, { OV5640_GMTRX05, 0x26}, + { OV5640_GMTRX10, 0x0c}, { OV5640_GMTRX11, 0x08}, + { OV5640_GMTRX12, 0x05}, { OV5640_GMTRX13, 0x05}, + { OV5640_GMTRX14, 0x08}, { OV5640_GMTRX15, 0x0d}, + { OV5640_GMTRX20, 0x08}, { OV5640_GMTRX21, 0x03}, + { OV5640_GMTRX22, 0x00}, { OV5640_GMTRX23, 0x00}, + { OV5640_GMTRX24, 0x03}, { OV5640_GMTRX25, 0x09}, + { OV5640_GMTRX30, 0x07}, { OV5640_GMTRX31, 0x03}, + { OV5640_GMTRX32, 0x00}, { OV5640_GMTRX33, 0x01}, + { OV5640_GMTRX34, 0x03}, { OV5640_GMTRX35, 0x08}, + { OV5640_GMTRX40, 0x0d}, { OV5640_GMTRX41, 0x08}, + { OV5640_GMTRX42, 0x05}, { OV5640_GMTRX43, 0x06}, + { OV5640_GMTRX44, 0x08}, { OV5640_GMTRX45, 0x0e}, + { OV5640_GMTRX50, 0x29}, { OV5640_GMTRX51, 0x17}, + { OV5640_GMTRX52, 0x11}, { OV5640_GMTRX53, 0x11}, + { OV5640_GMTRX54, 0x15}, { OV5640_GMTRX55, 0x28}, + { OV5640_BRMATRX00, 0x46}, { OV5640_BRMATRX01, 0x26}, + { OV5640_BRMATRX02, 0x08}, { OV5640_BRMATRX03, 0x26}, + { OV5640_BRMATRX04, 0x64}, { OV5640_BRMATRX05, 0x26}, + { OV5640_BRMATRX06, 0x24}, { OV5640_BRMATRX07, 0x22}, + { OV5640_BRMATRX08, 0x24}, { OV5640_BRMATRX09, 0x24}, + { OV5640_BRMATRX20, 0x06}, { OV5640_BRMATRX21, 0x22}, + { OV5640_BRMATRX22, 0x40}, { OV5640_BRMATRX23, 0x42}, + { OV5640_BRMATRX24, 0x24}, { OV5640_BRMATRX30, 0x26}, + { OV5640_BRMATRX31, 0x24}, { OV5640_BRMATRX32, 0x22}, + { OV5640_BRMATRX33, 0x22}, { OV5640_BRMATRX34, 0x26}, + { OV5640_BRMATRX40, 0x44}, { OV5640_BRMATRX41, 0x24}, + { OV5640_BRMATRX42, 0x26}, { OV5640_BRMATRX43, 0x28}, + { OV5640_BRMATRX44, 0x42}, { OV5640_LENC_BR_OFFSET, 0xce}, + + { OV5640_ISP_CTRL37, 0x00}, + { OV5640_AEC_CTRL0F, 0x30}, + { OV5640_AEC_CTRL10, 0x28}, + { OV5640_AEC_CTRL1B, 0x30}, + { OV5640_AEC_CTRL1E, 0x26}, + { OV5640_AEC_CTRL11, 0x60}, + { OV5640_AEC_CTRL1F, 0x14}, + { OV5640_SYSTEM_CTRL, 0x02}, +}; + +static enum v4l2_mbus_pixelcode ov5640_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, +}; + +static const struct v4l2_queryctrl ov5640_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +}; + +/* read a register */ +static int ov5640_reg_read(struct i2c_client *client, u16 reg, u8 *val) +{ + int ret; + unsigned char data[2] = { reg >> 8, reg & 0xff }; + + ret = i2c_master_send(client, data, 2); + if (ret < 2) { + dev_err(&client->dev, "%s: i2c read error, reg: %x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + + ret = i2c_master_recv(client, val, 1); + if (ret < 1) { + dev_err(&client->dev, "%s: i2c read error, reg: %x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +/* write a register */ +static int ov5640_reg_write(struct i2c_client *client, u16 reg, u8 val) +{ + int ret; + unsigned char data[3] = { reg >> 8, reg & 0xff, val }; + + ret = i2c_master_send(client, data, 3); + if (ret < 3) { + dev_err(&client->dev, "%s: i2c write error, reg: %x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + + +/* Read a register, alter its bits, write it back */ +static int ov5640_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset) +{ + u8 val; + int ret; + + ret = ov5640_reg_read(client, reg, &val); + if (ret < 0) { + dev_err(&client->dev, + "[Read]-Modify-Write of register 0x%04x failed!\n", + reg); + return ret; + } + + val |= set; + val &= ~unset; + + ret = ov5640_reg_write(client, reg, val); + if (ret < 0) { + dev_err(&client->dev, + "Read-Modify-[Write] of register 0x%04x failed!\n", + reg); + return ret; + } + + return 0; +} + +static int ov5640_reg_write_array(struct i2c_client *client, + const struct ov5640_reg *regarray, + int regarraylen) +{ + int i; + int ret; + + for (i = 0; i < regarraylen; i++) { + ret = ov5640_reg_write(client, + regarray[i].reg, regarray[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Start/Stop streaming from the device */ +static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640_priv *priv = to_ov5640(sd); + int ret; + + /* Program orientation register. */ + if (priv->flag_vflip) + ret = ov5640_reg_rmw(client, OV5640_TIMING_TC_REG20, 0x2, 0); + else + ret = ov5640_reg_rmw(client, OV5640_TIMING_TC_REG20, 0, 0x2); + if (ret < 0) + return ret; + + if (priv->flag_hflip) + ret = ov5640_reg_rmw(client, OV5640_TIMING_TC_REG21, 0x2, 0); + else + ret = ov5640_reg_rmw(client, OV5640_TIMING_TC_REG21, 0, 0x2); + if (ret < 0) + return ret; + + if (!enable) { + /* Software Reset */ + ret = ov5640_reg_write(client, OV5640_SYSTEM_CTRL, 0x82); + if (!ret) + /* Setting Streaming to Standby */ + ret = ov5640_reg_write(client, OV5640_SYSTEM_CTRL, + 0x42); + } + + priv->current_enable = enable; + + return ret; +} + +/* Alter bus settings on camera side */ +static int ov5640_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +/* Request bus settings on camera side */ +static unsigned long ov5640_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +/* select nearest higher resolution for capture */ +static void ov5640_res_roundup(u32 *width, u32 *height) +{ + /* Width must be a multiple of 4 pixels. */ + *width = ALIGN(*width, 4); + + /* Max resolution is 1280x720 (720p). */ + if (*width > OV5640_MAX_WIDTH) + *width = OV5640_MAX_WIDTH; + + if (*height > OV5640_MAX_HEIGHT) + *height = OV5640_MAX_HEIGHT; +} + +/* Setup registers according to resolution and color encoding */ +static int ov5640_set_res(struct i2c_client *client, u32 width, u32 height) +{ + /* Note, this stuff is bogus. It's just copied from ov9740.c. */ +#if 0 + u32 x_start; + u32 y_start; + u32 x_end; + u32 y_end; + bool scaling = 0; + u32 scale_input_x; + u32 scale_input_y; + int ret; + + if ((width != OV5640_MAX_WIDTH) || (height != OV5640_MAX_HEIGHT)) + scaling = 1; + + /* + * Try to use as much of the sensor area as possible when supporting + * smaller resolutions. Depending on the aspect ratio of the + * chosen resolution, we can either use the full width of the sensor, + * or the full height of the sensor (or both if the aspect ratio is + * the same as 1280x720. + */ + if ((OV5640_MAX_WIDTH * height) > (OV5640_MAX_HEIGHT * width)) { + scale_input_x = (OV5640_MAX_HEIGHT * width) / height; + scale_input_y = OV5640_MAX_HEIGHT; + } else { + scale_input_x = OV5640_MAX_WIDTH; + scale_input_y = (OV5640_MAX_WIDTH * height) / width; + } + + /* These describe the area of the sensor to use. */ + x_start = (OV5640_MAX_WIDTH - scale_input_x) / 2; + y_start = (OV5640_MAX_HEIGHT - scale_input_y) / 2; + x_end = x_start + scale_input_x - 1; + y_end = y_start + scale_input_y - 1; + + ret = ov5640_reg_write(client, OV5640_X_ADDR_START_HI, x_start >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_X_ADDR_START_LO, x_start & 0xff); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_ADDR_START_HI, y_start >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_ADDR_START_LO, y_start & 0xff); + if (ret) + goto done; + + ret = ov5640_reg_write(client, OV5640_X_ADDR_END_HI, x_end >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_X_ADDR_END_LO, x_end & 0xff); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_ADDR_END_HI, y_end >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_ADDR_END_LO, y_end & 0xff); + if (ret) + goto done; + + ret = ov5640_reg_write(client, OV5640_X_OUTPUT_SIZE_HI, width >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_X_OUTPUT_SIZE_LO, width & 0xff); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_OUTPUT_SIZE_HI, height >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_Y_OUTPUT_SIZE_LO, height & 0xff); + if (ret) + goto done; + + ret = ov5640_reg_write(client, OV5640_ISP_CTRL1E, scale_input_x >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_ISP_CTRL1F, scale_input_x & 0xff); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_ISP_CTRL20, scale_input_y >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_ISP_CTRL21, scale_input_y & 0xff); + if (ret) + goto done; + + ret = ov5640_reg_write(client, OV5640_VFIFO_READ_START_HI, + (scale_input_x - width) >> 8); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_VFIFO_READ_START_LO, + (scale_input_x - width) & 0xff); + if (ret) + goto done; + + ret = ov5640_reg_write(client, OV5640_ISP_CTRL00, 0xff); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_ISP_CTRL01, 0xef | + (scaling << 4)); + if (ret) + goto done; + ret = ov5640_reg_write(client, OV5640_ISP_CTRL03, 0xff); + +done: + return ret; +#endif + return 0; +} + +/* set the format we will capture in */ +static int ov5640_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640_priv *priv = to_ov5640(sd); + enum v4l2_colorspace cspace; + enum v4l2_mbus_pixelcode code = mf->code; + int ret; + + ov5640_res_roundup(&mf->width, &mf->height); + + switch (code) { + case V4L2_MBUS_FMT_YUYV8_2X8: + cspace = V4L2_COLORSPACE_SRGB; + break; + default: + return -EINVAL; + } + + ret = ov5640_reg_write_array(client, ov5640_defaults, + ARRAY_SIZE(ov5640_defaults)); + if (ret < 0) + return ret; + + ret = ov5640_set_res(client, mf->width, mf->height); + if (ret < 0) + return ret; + + mf->code = code; + mf->colorspace = cspace; + + memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt)); + + return ret; +} + +static int ov5640_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + ov5640_res_roundup(&mf->width, &mf->height); + + mf->field = V4L2_FIELD_NONE; + mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + mf->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(ov5640_codes)) + return -EINVAL; + + *code = ov5640_codes[index]; + + return 0; +} + +static int ov5640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = OV5640_MAX_WIDTH; + a->bounds.height = OV5640_MAX_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int ov5640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + a->c.left = 0; + a->c.top = 0; + a->c.width = OV5640_MAX_WIDTH; + a->c.height = OV5640_MAX_HEIGHT; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +/* Get status of additional camera capabilities */ +static int ov5640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct ov5640_priv *priv = to_ov5640(sd); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ctrl->value = priv->flag_vflip; + break; + case V4L2_CID_HFLIP: + ctrl->value = priv->flag_hflip; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Set status of additional camera capabilities */ +static int ov5640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct ov5640_priv *priv = to_ov5640(sd); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + priv->flag_vflip = ctrl->value; + break; + case V4L2_CID_HFLIP: + priv->flag_hflip = ctrl->value; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Get chip identification */ +static int ov5640_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct ov5640_priv *priv = to_ov5640(sd); + + id->ident = priv->ident; + id->revision = priv->revision; + + return 0; +} + +static int ov5640_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov5640_priv *priv = to_ov5640(sd); + + if (!priv->current_enable) + return 0; + + if (on) { + ov5640_s_fmt(sd, &priv->current_mf); + ov5640_s_stream(sd, priv->current_enable); + } else { + ov5640_s_stream(sd, 0); + priv->current_enable = true; + } + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov5640_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 val; + + if (reg->reg & ~0xffff) + return -EINVAL; + + reg->size = 2; + + ret = ov5640_reg_read(client, reg->reg, &val); + if (ret) + return ret; + + reg->val = (__u64)val; + + return ret; +} + +static int ov5640_set_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg & ~0xffff || reg->val & ~0xff) + return -EINVAL; + + return ov5640_reg_write(client, reg->reg, reg->val); +} +#endif + +static int ov5640_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5640_priv *priv = to_ov5640(sd); + u8 chip_id_hi, chip_id_lo; + int ret; + + /* We must have a parent by now. And it cannot be a wrong one. */ + BUG_ON(!icd->parent || + to_soc_camera_host(icd->parent)->nr != icd->iface); + + /* + * check and show product ID and manufacturer ID + */ + ret = ov5640_reg_read(client, OV5640_CHIP_ID_HI, &chip_id_hi); + if (ret < 0) + goto err; + + ret = ov5640_reg_read(client, OV5640_CHIP_ID_LO, &chip_id_lo); + if (ret < 0) + goto err; + + priv->chip_id = (chip_id_hi << 8) | chip_id_lo; + + if (priv->chip_id != 0x5640) { + ret = -ENODEV; + goto err; + } + + priv->ident = V4L2_IDENT_OV5640; + + dev_info(&client->dev, "Chip ID 0x%04x\n", priv->chip_id); + +err: + return ret; +} + +static struct soc_camera_ops ov5640_ops = { + .set_bus_param = ov5640_set_bus_param, + .query_bus_param = ov5640_query_bus_param, + .controls = ov5640_controls, + .num_controls = ARRAY_SIZE(ov5640_controls), +}; + +static struct v4l2_subdev_video_ops ov5640_video_ops = { + .s_stream = ov5640_s_stream, + .s_mbus_fmt = ov5640_s_fmt, + .try_mbus_fmt = ov5640_try_fmt, + .enum_mbus_fmt = ov5640_enum_fmt, + .cropcap = ov5640_cropcap, + .g_crop = ov5640_g_crop, +}; + +static struct v4l2_subdev_core_ops ov5640_core_ops = { + .g_ctrl = ov5640_g_ctrl, + .s_ctrl = ov5640_s_ctrl, + .g_chip_ident = ov5640_g_chip_ident, + .s_power = ov5640_s_power, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov5640_get_register, + .s_register = ov5640_set_register, +#endif +}; + +static struct v4l2_subdev_ops ov5640_subdev_ops = { + .core = &ov5640_core_ops, + .video = &ov5640_video_ops, +}; + +/* + * i2c_driver function + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov5640_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "Missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "Missing platform_data for driver\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(struct ov5640_priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, "Failed to allocate private data!\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov5640_subdev_ops); + + icd->ops = &ov5640_ops; + + ret = ov5640_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + kfree(priv); + } + + return ret; +} + +static int ov5640_remove(struct i2c_client *client) +{ + struct ov5640_priv *priv = i2c_get_clientdata(client); + + kfree(priv); + + return 0; +} + +static const struct i2c_device_id ov5640_id[] = { + { "ov5640", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .name = "ov5640", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static int __init ov5640_module_init(void) +{ + return i2c_add_driver(&ov5640_i2c_driver); +} + +static void __exit ov5640_module_exit(void) +{ + i2c_del_driver(&ov5640_i2c_driver); +} + +module_init(ov5640_module_init); +module_exit(ov5640_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV5640"); +MODULE_AUTHOR("Andrew Chew "); +MODULE_LICENSE("GPL v2"); diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 63fd9d3db296..fb929eacd2e6 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -77,6 +77,7 @@ enum { V4L2_IDENT_OV2640 = 259, V4L2_IDENT_OV9740 = 260, V4L2_IDENT_OV5642 = 261, + V4L2_IDENT_OV5640 = 262, /* module saa7146: reserved range 300-309 */ V4L2_IDENT_SAA7146 = 300, -- cgit v1.2.3 From af944493416445c329f8d496b31c4d98937d4735 Mon Sep 17 00:00:00 2001 From: Jong Kim Date: Wed, 12 Dec 2012 16:01:39 -0800 Subject: arm: tegra: display: provide framebuffer clear function Add tegra_clear_framebuffer function. bug 1175957 Change-Id: I12c249e011ecd839bbe9c5371b8be6e8a4b27bba Signed-off-by: Jong Kim Reviewed-on: http://git-master/r/170661 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- arch/arm/mach-tegra/board.h | 1 + arch/arm/mach-tegra/common.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 85d02d501b63..b02adb2cfc20 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -102,6 +102,7 @@ void __init tegra_protected_aperture_init(unsigned long aperture); int __init tegra_init_board_info(void); void tegra_move_framebuffer(unsigned long to, unsigned long from, unsigned long size); +void tegra_clear_framebuffer(unsigned long to, unsigned long size); bool is_tegra_debug_uartport_hs(void); int get_tegra_uart_debug_port_id(void); int arb_lost_recovery(int scl_gpio, int sda_gpio); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 8364589e1ff6..4c5838b355f0 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -838,6 +838,30 @@ out: iounmap(to_io); } +void tegra_clear_framebuffer(unsigned long to, unsigned long size) +{ + void __iomem *to_io; + unsigned long i; + + BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to); + BUG_ON(PAGE_ALIGN(size) != size); + + to_io = ioremap(to, size); + if (!to_io) { + pr_err("%s: Failed to map target framebuffer\n", __func__); + return; + } + + if (pfn_valid(page_to_pfn(phys_to_page(to)))) { + for (i = 0 ; i < size; i += PAGE_SIZE) + memset(to_io + i, 0, PAGE_SIZE); + } else { + for (i = 0; i < size; i += 4) + writel(0, to_io + i); + } + iounmap(to_io); +} + void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, unsigned long fb2_size) { -- cgit v1.2.3 From bf5e8d0816d9b92219813f303f882f2c07e7230a Mon Sep 17 00:00:00 2001 From: Jong Kim Date: Wed, 12 Dec 2012 16:07:54 -0800 Subject: arm: tegra: display: handle fbmem2 cmdline parameter Parse and handle fbmem2 cmdline parameter. bug 1175957 Change-Id: I0933825371bf13782e9f4364a4dba078929ae836 Signed-off-by: Jong Kim Reviewed-on: http://git-master/r/170662 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- arch/arm/mach-tegra/board.h | 2 ++ arch/arm/mach-tegra/common.c | 52 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index b02adb2cfc20..6aaba219c916 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -109,6 +109,8 @@ int arb_lost_recovery(int scl_gpio, int sda_gpio); extern unsigned long tegra_bootloader_fb_start; extern unsigned long tegra_bootloader_fb_size; +extern unsigned long tegra_bootloader_fb2_start; +extern unsigned long tegra_bootloader_fb2_size; extern unsigned long tegra_fb_start; extern unsigned long tegra_fb_size; extern unsigned long tegra_fb2_start; diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 4c5838b355f0..0d1407b6b668 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -85,6 +85,8 @@ unsigned long tegra_bootloader_fb_start; unsigned long tegra_bootloader_fb_size; +unsigned long tegra_bootloader_fb2_start; +unsigned long tegra_bootloader_fb2_size; unsigned long tegra_fb_start; unsigned long tegra_fb_size; unsigned long tegra_fb2_start; @@ -479,6 +481,21 @@ static int __init tegra_bootloader_fb_arg(char *options) } early_param("tegra_fbmem", tegra_bootloader_fb_arg); +static int __init tegra_bootloader_fb2_arg(char *options) +{ + char *p = options; + + tegra_bootloader_fb2_size = memparse(p, &p); + if (*p == '@') + tegra_bootloader_fb2_start = memparse(p+1, &p); + + pr_info("Found tegra_fbmem2: %08lx@%08lx\n", + tegra_bootloader_fb2_size, tegra_bootloader_fb2_start); + + return 0; +} +early_param("tegra_fbmem2", tegra_bootloader_fb2_arg); + static int __init tegra_sku_override(char *id) { char *p = id; @@ -938,19 +955,36 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, } } + if (tegra_bootloader_fb2_size) { + tegra_bootloader_fb2_size = + PAGE_ALIGN(tegra_bootloader_fb2_size); + if (memblock_reserve(tegra_bootloader_fb2_start, + tegra_bootloader_fb2_size)) { + pr_err("Failed to reserve bootloader frame buffer2 " + "%08lx@%08lx\n", tegra_bootloader_fb2_size, + tegra_bootloader_fb2_start); + tegra_bootloader_fb2_start = 0; + tegra_bootloader_fb2_size = 0; + } + } + pr_info("Tegra reserved memory:\n" - "LP0: %08lx - %08lx\n" - "Bootloader framebuffer: %08lx - %08lx\n" - "Framebuffer: %08lx - %08lx\n" - "2nd Framebuffer: %08lx - %08lx\n" - "Carveout: %08lx - %08lx\n" - "Vpr: %08lx - %08lx\n", + "LP0: %08lx - %08lx\n" + "Bootloader framebuffer: %08lx - %08lx\n" + "Bootloader framebuffer2: %08lx - %08lx\n" + "Framebuffer: %08lx - %08lx\n" + "2nd Framebuffer: %08lx - %08lx\n" + "Carveout: %08lx - %08lx\n" + "Vpr: %08lx - %08lx\n", tegra_lp0_vec_start, tegra_lp0_vec_size ? tegra_lp0_vec_start + tegra_lp0_vec_size - 1 : 0, tegra_bootloader_fb_start, tegra_bootloader_fb_size ? - tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1 : 0, + tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1 : 0, + tegra_bootloader_fb2_start, + tegra_bootloader_fb2_size ? + tegra_bootloader_fb2_start + tegra_bootloader_fb2_size - 1 : 0, tegra_fb_start, tegra_fb_size ? tegra_fb_start + tegra_fb_size - 1 : 0, @@ -1017,6 +1051,10 @@ void __init tegra_release_bootloader_fb(void) if (memblock_free(tegra_bootloader_fb_start, tegra_bootloader_fb_size)) pr_err("Failed to free bootloader fb.\n"); + if (tegra_bootloader_fb2_size) + if (memblock_free(tegra_bootloader_fb2_start, + tegra_bootloader_fb2_size)) + pr_err("Failed to free bootloader fb2.\n"); } #ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND -- cgit v1.2.3 From c1e028a7d3f2c2a5cda48a038053898458e7198c Mon Sep 17 00:00:00 2001 From: Jong Kim Date: Wed, 12 Dec 2012 16:20:22 -0800 Subject: video: tegra: clear fb2 unspecified by bootloader Clear framebuffer2 if and only if framebuffer2 is not specified by the bootloader. If the bootloader framebuffer2 is specified, then copy the contents to kernel framebuffer2. bug 1175957 Change-Id: I4ac4432c1dac6a6c634ab3e6ae31628f9c64ddb4 Signed-off-by: Jong Kim Reviewed-on: http://git-master/r/170663 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- arch/arm/mach-tegra/board-cardhu-panel.c | 13 ++++++++++--- arch/arm/mach-tegra/board-ventana-panel.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-tegra/board-cardhu-panel.c b/arch/arm/mach-tegra/board-cardhu-panel.c index d7101af55712..bbd6d4aaac37 100644 --- a/arch/arm/mach-tegra/board-cardhu-panel.c +++ b/arch/arm/mach-tegra/board-cardhu-panel.c @@ -1444,9 +1444,16 @@ skip_lvds: res->start = tegra_fb2_start; res->end = tegra_fb2_start + tegra_fb2_size - 1; - /* Copy the bootloader fb to the fb2. */ - tegra_move_framebuffer(tegra_fb2_start, tegra_bootloader_fb_start, - min(tegra_fb2_size, tegra_bootloader_fb_size)); + /* + * If the bootloader fb2 is valid, copy it to the fb2, or else + * clear fb2 to avoid garbage on dispaly2. + */ + if (tegra_bootloader_fb2_size) + tegra_move_framebuffer(tegra_fb2_start, + tegra_bootloader_fb2_start, + min(tegra_fb2_size, tegra_bootloader_fb2_size)); + else + tegra_clear_framebuffer(tegra_fb2_start, tegra_fb2_size); if (!err) err = nvhost_device_register(&cardhu_disp2_device); diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c index 56a222432fe0..d2d89392e1c5 100644 --- a/arch/arm/mach-tegra/board-ventana-panel.c +++ b/arch/arm/mach-tegra/board-ventana-panel.c @@ -433,9 +433,16 @@ int __init ventana_panel_init(void) tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start, min(tegra_fb_size, tegra_bootloader_fb_size)); - /* Copy the bootloader fb to the fb2. */ - tegra_move_framebuffer(tegra_fb2_start, tegra_bootloader_fb_start, - min(tegra_fb2_size, tegra_bootloader_fb_size)); + /* + * If the bootloader fb2 is valid, copy it to the fb2, or else + * clear fb2 to avoid garbage on dispaly2. + */ + if (tegra_bootloader_fb2_size) + tegra_move_framebuffer(tegra_fb2_start, + tegra_bootloader_fb2_start, + min(tegra_fb2_size, tegra_bootloader_fb2_size)); + else + tegra_clear_framebuffer(tegra_fb2_start, tegra_fb2_size); #if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) -- cgit v1.2.3 From be0b31a190aba37065f77fe81ee0a3fadcf33489 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 5 Dec 2012 16:43:55 -0800 Subject: ARM: tegra3: pm315/beaver: enable Realtek ALC5640 audio codec support - select RT5640 ASoC support in Cardhu machine Kconfig - enable RT5640 ASoC driver in tegra3_defconfig - select RT5639 ASoC codec when selecting RT5640, othwise kernel linking will fail Bug 1190823 Change-Id: I1046c30667d4ca8276080f1b3174eccd0b25328c Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/168884 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Winnie Hsu --- arch/arm/configs/tegra3_defconfig | 1 + arch/arm/mach-tegra/Kconfig | 1 + sound/soc/tegra/Kconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index 26889bd74d5f..cda1ff1c9c98 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -356,6 +356,7 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_TEGRA=y CONFIG_SND_SOC_TEGRA_WM8903=y CONFIG_SND_SOC_TEGRA_MAX98088=y +CONFIG_SND_SOC_TEGRA_RT5640=y CONFIG_HID_A4TECH=m CONFIG_HID_APPLE=m CONFIG_HID_BELKIN=m diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 617f08bd54bd..8db76065ea6d 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -179,6 +179,7 @@ config MACH_CARDHU select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC select MACH_HAS_SND_SOC_TEGRA_TLV320AIC326X if SND_SOC select MACH_HAS_SND_SOC_TEGRA_MAX98095 if SND_SOC + select MACH_HAS_SND_SOC_TEGRA_RT5640 if SND_SOC help Support for NVIDIA Cardhu development platform diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 2a8b4f1cef64..de8309be3816 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -200,6 +200,7 @@ config SND_SOC_TEGRA_RT5640 select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC select SND_SOC_RT5640 + select SND_SOC_RT5639 select SND_SOC_SPDIF select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC help -- cgit v1.2.3 From 59afb2be3f9ba5b4fc2d603365f5fe353b257dbc Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Fri, 14 Dec 2012 15:03:10 -0800 Subject: net: wireless: bcmdhd: Do not use P2P Do not use P2P, as it does not fit well with network manager. Bug 1199933 Change-Id: I355515574baabeace7c48932c52007c1fe0c3d5f Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/171551 Reviewed-by: Matthew Pedro Tested-by: Matthew Pedro --- arch/arm/configs/tegra3_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index cda1ff1c9c98..55326f14c2f1 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -234,7 +234,6 @@ CONFIG_BCM4329_WIFI_CONTROL_FUNC=y CONFIG_BCMDHD=m CONFIG_BCMDHD_FW_DIR="/lib/firmware" CONFIG_BCMDHD_NVRAM_DIR="/lib/firmware" -CONFIG_DHD_ENABLE_P2P=y CONFIG_BCMDHD_CFG80211=y CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y CONFIG_BCMDHD_HW_OOB=y -- cgit v1.2.3 From 83009bd159cfc34e30fdf0add82722d09ad92556 Mon Sep 17 00:00:00 2001 From: Jong Kim Date: Wed, 12 Dec 2012 16:26:53 -0800 Subject: arm: tegra: fb: Update line_length using display width Unconditionally update line_length using disply width to avoid discrepancy between line_length and actual display width. bug 1186388 Change-Id: I8ef2f9cf76a61764c2121f3c2c013b72b830ce2e Signed-off-by: Jong Kim Reviewed-on: http://git-master/r/170664 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- drivers/video/tegra/fb.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 59c162bb3b4c..46cbabfe73f0 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -126,12 +126,9 @@ static int tegra_fb_set_par(struct fb_info *info) return -EINVAL; } /* if line_length unset, then pad the stride */ - if (!info->fix.line_length) { - info->fix.line_length = var->xres * var->bits_per_pixel - / 8; - info->fix.line_length = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); - } + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.line_length = round_up(info->fix.line_length, + TEGRA_LINEAR_PITCH_ALIGNMENT); tegra_fb->win->stride = info->fix.line_length; tegra_fb->win->stride_uv = 0; tegra_fb->win->phys_addr_u = 0; @@ -649,12 +646,8 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_fb->valid = true; } - info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8; - - stride = tegra_dc_get_stride(dc, 0); - if (!stride) /* default to pad the stride */ - stride = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); + stride = fb_data->xres * fb_data->bits_per_pixel / 8; + stride = round_up(stride, TEGRA_LINEAR_PITCH_ALIGNMENT); info->fbops = &tegra_fb_ops; info->pseudo_palette = pseudo_palette; -- cgit v1.2.3 From a7d49070ee698d42f0fffee54d184c6ebb6ce487 Mon Sep 17 00:00:00 2001 From: Jong Kim Date: Thu, 20 Dec 2012 17:16:57 -0800 Subject: arm: tegra: dc: corrct order to enable/disable dc irq When porting change from mainline to balance dc irq, the change of enable/disable order was not ported, thus dc irq is disabled if dc is enabled during probe. This is part of http://git-master/r/146107. Original change is big for many bugs, only port one here. bug 1173177 bug 1173038 bug 1008313 Change-Id: Idd703daca9f980e905b185eeeae19dc6309d76e5 Signed-off-by: Dongfang Shi Reviewed-on: http://git-master/r/162868 (cherry picked from commit 6ddd8b02f7a17d2269290d06159c20860ffb92e9) Signed-off-by: Jong Kim Reviewed-on: http://git-master/r/173249 Reviewed-by: Winnie Hsu Reviewed-by: Jon Mayo --- drivers/video/tegra/dc/dc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index d01df2f520b8..ed54e9e495c2 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1875,13 +1875,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev, dc->ext = NULL; } - mutex_lock(&dc->lock); - if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) { - _tegra_dc_set_default_videomode(dc); - dc->enabled = _tegra_dc_enable(dc); - } - mutex_unlock(&dc->lock); - /* interrupt handler must be registered before tegra_fb_register() */ if (request_irq(irq, tegra_dc_irq, 0, dev_name(&ndev->dev), dc)) { @@ -1889,6 +1882,14 @@ static int tegra_dc_probe(struct nvhost_device *ndev, ret = -EBUSY; goto err_put_emc_clk; } + disable_dc_irq(irq); + + mutex_lock(&dc->lock); + if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) { + _tegra_dc_set_default_videomode(dc); + dc->enabled = _tegra_dc_enable(dc); + } + mutex_unlock(&dc->lock); tegra_dc_create_debugfs(dc); -- cgit v1.2.3 From 4f8461ffb6746c7f4a2258834afead13bcb29d72 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Wed, 5 Dec 2012 14:11:25 +0530 Subject: arm: tegra: fb: Set new mode to all vc's Send change all vc's notification from HDMI hot-plug reader to fbcon, so that the new selected mode can be applied on all the vc's from vc1 to vc6. This sometimes causes corruption on HDMI hot plugin, when fbcon is mapped to HDMI Bug 1166008 Signed-off-by: Shashank Sharma Change-Id: Id173de3014597f79c8c8b31bbbee7c9c560547b6 Reviewed-on: http://git-master/r/168683 Reviewed-by: Matthew Pedro Tested-by: Matthew Pedro --- drivers/video/tegra/dc/dc.c | 48 ++------------------------------ drivers/video/tegra/fb.c | 68 +++++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 88 deletions(-) diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index ed54e9e495c2..13e094a7003b 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -58,21 +58,6 @@ #define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000 #define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0 -static struct fb_videomode tegra_dc_hdmi_fallback_mode = { - .refresh = 60, - .xres = 640, - .yres = 480, - .pixclock = KHZ2PICOS(25200), - .hsync_len = 96, /* h_sync_width */ - .vsync_len = 2, /* v_sync_width */ - .left_margin = 48, /* h_back_porch */ - .upper_margin = 33, /* v_back_porch */ - .right_margin = 16, /* h_front_porch */ - .lower_margin = 10, /* v_front_porch */ - .vmode = 0, - .sync = 0, -}; - static struct tegra_dc_mode override_disp_mode[3]; static void _tegra_dc_controller_disable(struct tegra_dc *dc); @@ -1458,34 +1443,6 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc) } #endif -static int _tegra_dc_set_default_videomode(struct tegra_dc *dc) -{ - if (dc->mode.pclk == 0) { - switch (dc->out->type) { - case TEGRA_DC_OUT_HDMI: - /* DC enable called but no videomode is loaded. - Check if HDMI is connected, then set fallback mdoe */ - if (tegra_dc_hpd(dc)) { - return tegra_dc_set_fb_mode(dc, - &tegra_dc_hdmi_fallback_mode, 0); - } else - return false; - - break; - - /* Do nothing for other outputs for now */ - case TEGRA_DC_OUT_RGB: - - case TEGRA_DC_OUT_DSI: - - default: - return false; - } - } - - return false; -} - static bool _tegra_dc_enable(struct tegra_dc *dc) { if (dc->mode.pclk == 0) @@ -1914,6 +1871,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev, } dc->fb = tegra_fb_register(ndev, dc, dc->pdata->fb, fb_mem); + if (IS_ERR_OR_NULL(dc->fb)) dc->fb = NULL; } @@ -2028,10 +1986,8 @@ static int tegra_dc_resume(struct nvhost_device *ndev) mutex_lock(&dc->lock); dc->suspended = false; - if (dc->enabled) { - _tegra_dc_set_default_videomode(dc); + if (dc->enabled) _tegra_dc_enable(dc); - } if (dc->out && dc->out->hotplug_init) dc->out->hotplug_init(); diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 46cbabfe73f0..f69048f62cc2 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -493,33 +493,15 @@ const struct fb_videomode *tegra_fb_find_best_mode( return best; } -static int tegra_fb_activate_mode(struct tegra_fb_info *fb_info, - struct fb_var_screeninfo *var) -{ - int err; - struct fb_info *info = fb_info->info; - - var->activate |= FB_ACTIVATE_FORCE; - console_lock(); - info->flags |= FBINFO_MISC_USEREVENT; - err = fb_set_var(info, var); - info->flags &= ~FBINFO_MISC_USEREVENT; - console_unlock(); - if (err) - return err; - return 0; -} - void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, struct fb_monspecs *specs, bool (*mode_filter)(const struct tegra_dc *dc, struct fb_videomode *mode)) { int i; - int ret = 0; + bool first = false; struct fb_event event; struct fb_info *info = fb_info->info; - const struct fb_videomode *best_mode = NULL; struct fb_var_screeninfo var = {0,}; mutex_lock(&fb_info->info->lock); @@ -558,6 +540,13 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, fb_var_to_videomode(&m, &var); fb_add_videomode(&m, &fb_info->info->modelist); + /* EDID stds recommend first detailed mode + to be applied as default,but if first mode + doesn't pass mode filter, we have to select + and apply other mode. So flag on if first + mode passes mode filter */ + if (!i) + first = true; } } else { fb_add_videomode(&specs->modedb[i], @@ -565,36 +554,31 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, } } - /* Get the best mode from modedb and apply on fb */ - var.xres = 0; - var.yres = 0; - best_mode = tegra_fb_find_best_mode(&var, &info->modelist); - - /* Update framebuffer with best mode */ - fb_videomode_to_var(&var, best_mode); - - /* TODO: Get proper way of getting rid of a 0 bpp */ - if (!var.bits_per_pixel) - var.bits_per_pixel = 32; - - memcpy(&info->var, &var, sizeof(struct fb_var_screeninfo)); - - ret = tegra_fb_activate_mode(fb_info, &var); - if (ret) - return; + /* We can't apply first detailed mode, so get the best mode + based on resolution and apply on fb */ + if (!first) { + var.xres = 0; + var.yres = 0; + info->mode = (struct fb_videomode *) + tegra_fb_find_best_mode(&var, &info->modelist); + } + /* Prepare fb info with new mode details */ + fb_videomode_to_var(&info->var, info->mode); event.info = fb_info->info; #ifdef CONFIG_FRAMEBUFFER_CONSOLE -/* Lock the console before sending the noti. Fbconsole - * on HDMI might be using console - */ + /* Send a noti to change fb_display[].mode for all vc's */ + console_lock(); + fb_notifier_call_chain(FB_EVENT_MODE_CHANGE_ALL, &event); + console_unlock(); + + /* Notify framebuffer console about mode change */ console_lock(); -#endif fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); -#ifdef CONFIG_FRAMEBUFFER_CONSOLE -/* Unlock the console */ console_unlock(); +#else + fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); #endif mutex_unlock(&fb_info->info->lock); -- cgit v1.2.3 From 8bd060e546c9c7f4296caca52ea35a3ccd2c953a Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Fri, 21 Dec 2012 12:50:35 +0530 Subject: arm: tegra: fb: Fix merge error Fix manual rebase error Change-Id: I3b2165488b11bddda271cecdc979341c130def9b Signed-off-by: Shashank Sharma Reviewed-on: http://git-master/r/173554 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Winnie Hsu --- drivers/video/tegra/dc/dc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 13e094a7003b..bfd916e0e16e 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1842,10 +1842,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev, disable_dc_irq(irq); mutex_lock(&dc->lock); - if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) { - _tegra_dc_set_default_videomode(dc); + if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) dc->enabled = _tegra_dc_enable(dc); - } mutex_unlock(&dc->lock); tegra_dc_create_debugfs(dc); -- cgit v1.2.3 From c319d0e904e6bff6e6c89d3c8cf651949c379925 Mon Sep 17 00:00:00 2001 From: Yen Lin Date: Thu, 3 Jan 2013 15:01:56 -0800 Subject: arm: tegra: sata: Fix LP0 resume problem - Fix a bug in ahci-tegra.c when checking if SATA is on when resuming - Add codes to support PM315 which uses LDO1 regulator for SATA rails bug 1206518 Change-Id: Iaa910b1948fbcf5e45491977fd8ed0b313d2e0ae Signed-off-by: Yen Lin Reviewed-on: http://git-master/r/188441 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bibek Basu GVS: Gerrit_Virtual_Submit Reviewed-by: Allen Martin Reviewed-by: Peng Wu Tested-by: Peng Wu Reviewed-by: Eric Brower --- arch/arm/mach-tegra/board-cardhu-power.c | 20 ++++++++++++++++++++ drivers/ata/ahci-tegra.c | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c index db86a07778b4..d69426a30c67 100644 --- a/arch/arm/mach-tegra/board-cardhu-power.c +++ b/arch/arm/mach-tegra/board-cardhu-power.c @@ -115,6 +115,18 @@ static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = { REGULATOR_SUPPLY("vdd_pexa", NULL), }; +static struct regulator_consumer_supply tps6591x_ldo1_supply_pm315[] = { + REGULATOR_SUPPLY("avdd_pexb", NULL), + REGULATOR_SUPPLY("vdd_pexb", NULL), + REGULATOR_SUPPLY("avdd_pex_pll", NULL), + REGULATOR_SUPPLY("avdd_pexa", NULL), + REGULATOR_SUPPLY("vdd_pexa", NULL), + REGULATOR_SUPPLY("avdd_sata", NULL), + REGULATOR_SUPPLY("vdd_sata", NULL), + REGULATOR_SUPPLY("avdd_sata_pll", NULL), + REGULATOR_SUPPLY("avdd_plle", NULL), +}; + static struct regulator_consumer_supply tps6591x_ldo2_supply_0[] = { REGULATOR_SUPPLY("avdd_sata", NULL), REGULATOR_SUPPLY("vdd_sata", NULL), @@ -453,6 +465,14 @@ int __init cardhu_regulator_init(void) pr_info("VSEL 1:0 %d%d\n", tps62361_pdata.vsel1_def_state, tps62361_pdata.vsel0_def_state); + } else if (board_info.board_id == BOARD_PM315) { + /* On PM315, SATA rails are on LDO1 */ + pdata_ldo1_0.regulator.num_consumer_supplies = + ARRAY_SIZE(tps6591x_ldo1_supply_pm315); + pdata_ldo1_0.regulator.consumer_supplies = + tps6591x_ldo1_supply_pm315; + pdata_ldo2_0.regulator.num_consumer_supplies = 0; + pdata_ldo2_0.regulator.consumer_supplies = NULL; } if (((board_info.board_id == BOARD_E1291) || diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c index 39cf4acf0ae6..c90472827b9b 100644 --- a/drivers/ata/ahci-tegra.c +++ b/drivers/ata/ahci-tegra.c @@ -926,7 +926,7 @@ static int tegra_ahci_controller_resume(struct platform_device *pdev) } spin_lock_irqsave(&host->lock, flags); - if (!tegra_hpriv->pg_state == SATA_ON) { + if (tegra_hpriv->pg_state == SATA_ON) { dev_dbg(host->dev, "resume: SATA already powered on\n"); } else { dev_dbg(host->dev, "resume: powering on SATA...\n"); -- cgit v1.2.3 From 8acf989d5896b152cc88f8b29afd11d522f903e3 Mon Sep 17 00:00:00 2001 From: Preetham Chandru R Date: Mon, 31 Dec 2012 19:47:13 +0530 Subject: usb: otg: tegra: Do not free platform data twice when platform device is unregistered, the call to platform_device_release() will kfree the platform data. Hence do not free the platform data again. Bug 1209618 Change-Id: Ied67f550223ec199da4bc8e38a12e7ee94c2d98a Signed-off-by: Preetham Chandru R Reviewed-on: http://git-master/r/187806 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Kiran Adduri Reviewed-by: Rakesh Bodla Reviewed-by: Venkat Moganty Reviewed-by: Matthew Pedro --- drivers/usb/otg/tegra-otg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index ce19f77433fc..12c359bcbe46 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -173,8 +173,6 @@ static void tegra_stop_host(struct tegra_otg_data *tegra) if (pdev) { /* unregister host from otg */ - kfree(pdev->dev.platform_data); - pdev->dev.platform_data = NULL; platform_device_unregister(pdev); tegra->pdev = NULL; } -- cgit v1.2.3 From e4e11f3c524c2679ee007588e2199a5c22a6a104 Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Tue, 8 Jan 2013 16:32:05 -0800 Subject: driver: bcmdhd: do not allow hang thread after cleanup do not allow scheduling hang thread after cleanup is done. Bug 1210849 Bug 1205910 Bug 1163014 Change-Id: Idc5f9fd6a3d210843f1168e57ceef107599d5789 Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/189721 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro Reviewed-by: Allen Martin --- drivers/net/wireless/bcmdhd/dhd_linux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 44879e4a1170..a6b6dc8be91f 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -3676,6 +3676,7 @@ void dhd_detach(dhd_pub_t *dhdp) #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + dhd->pub.hang_was_sent = 1; cancel_work_sync(&dhd->work_hang); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -- cgit v1.2.3 From a723afef635b98add42cbf28614740df38d90a98 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 9 Jan 2013 11:18:43 -0800 Subject: media: videobuf2-dma-nvmap: fixing nvmap_alloc failure Videobuf2-dma-nvmap driver using by Tegra v4l2 camera driver needs to allocation memory from system memory with nvmap_alloc(). If we don't enable config option CONFIG_NVMAP_ALLOW_SYSMEM, nvmap_alloc() will fail and application stops working. Bug 1215629 Change-Id: I40af697d8aee1a4981a9684953107dd070cc9bea Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/190037 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew Reviewed-by: Winnie Hsu --- drivers/media/video/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7968ea979d1f..651a17e04fd0 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -70,6 +70,7 @@ config VIDEOBUF2_DMA_SG config VIDEOBUF2_DMA_NVMAP select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + select NVMAP_ALLOW_SYSMEM tristate # -- cgit v1.2.3 From 8656b6e45005302d21a89a497ed53b6579336140 Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Fri, 11 Jan 2013 09:41:14 -0800 Subject: driver: bcm4329: initialize SSID variable properly initialize SSID variable properly to ensure no memory overrun. Bug 1204024 Change-Id: I2485c13edcf6a0feeae3cd4b2e9e98910a771dd2 Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/190684 Reviewed-by: Matthew Pedro Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/net/wireless/bcm4329/wl_iw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c index e71ab64c2caa..8cb0f3af84ee 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.c +++ b/drivers/net/wireless/bcm4329/wl_iw.c @@ -4339,6 +4339,7 @@ wl_iw_get_essid( if (!extra) return -EINVAL; + memset(&ssid, 0, sizeof(ssid)); if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { WL_ERROR(("Error getting the SSID\n")); return error; -- cgit v1.2.3 From 511d59ce01b5dfab121f0d3c9badd00283b4f83e Mon Sep 17 00:00:00 2001 From: Jon Mayo Date: Thu, 20 Dec 2012 17:32:05 -0800 Subject: video: tegra: dc: minimum window size is 1x1 Use 1x1 as the minimum window size. Bug 1193195 Change-Id: I42e13fec82bbc2dc37bde6416088f3ae49b304b7 Signed-off-by: Jon Mayo Reviewed-on: http://git-master/r/173302 (cherry picked from commit 3f160560b48fdf501547b9fc1f7c5bf8bd5e32af) Reviewed-on: http://git-master/r/190810 Reviewed-by: Eric Brower Tested-by: Eric Brower Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Matthew Pedro --- drivers/video/tegra/dc/dc_config.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/video/tegra/dc/dc_config.c b/drivers/video/tegra/dc/dc_config.c index f238faddab12..90f505bba28a 100644 --- a/drivers/video/tegra/dc/dc_config.c +++ b/drivers/video/tegra/dc/dc_config.c @@ -23,7 +23,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_a[] = { { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} }, { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} }, { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -32,7 +32,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_a[] = { { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} }, { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -40,7 +40,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_a[] = { { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} }, { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} }, { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -50,7 +50,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_a[] = { static struct tegra_dc_feature_entry t20_feature_entries_b[] = { { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} }, { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} }, { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -59,7 +59,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_b[] = { { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} }, { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -67,7 +67,7 @@ static struct tegra_dc_feature_entry t20_feature_entries_b[] = { { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} }, { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} }, { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -85,7 +85,7 @@ struct tegra_dc_feature t20_feature_table_b = { static struct tegra_dc_feature_entry t30_feature_entries_a[] = { { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} }, { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} }, { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} }, @@ -94,7 +94,7 @@ static struct tegra_dc_feature_entry t30_feature_entries_a[] = { { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} }, { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} }, @@ -102,7 +102,7 @@ static struct tegra_dc_feature_entry t30_feature_entries_a[] = { { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} }, { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} }, { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} }, @@ -112,7 +112,7 @@ static struct tegra_dc_feature_entry t30_feature_entries_a[] = { static struct tegra_dc_feature_entry t30_feature_entries_b[] = { { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} }, { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} }, { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -121,7 +121,7 @@ static struct tegra_dc_feature_entry t30_feature_entries_b[] = { { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} }, { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} }, { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, @@ -129,7 +129,7 @@ static struct tegra_dc_feature_entry t30_feature_entries_b[] = { { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} }, { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} }, - { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} }, + { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 1, 4095, 1,} }, { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} }, { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} }, { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} }, -- cgit v1.2.3 From 185f345ed930377d945397b2b710bf62d91f5fa4 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 9 Jan 2013 10:29:55 -0800 Subject: media: v4l2: tegra: fixing memory access oops in tegra camera driver Function pointer int (*queue_setup)() of struct vb2_ops in include/media/videobuf2-core.h is not compatible with our function call tegra_camera_videobuf_setup(). So building will generate warning and it will cause alloc_ctxs[] with wrong value, then introduce memory access oops later. Bug 1215617 Change-Id: I5d49ccd611a9435a5ee3b21e344bc0b5464ba747 Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/190036 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew Reviewed-by: Winnie Hsu --- drivers/media/video/tegra_v4l2_camera.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index 990f6afe8b10..644d0be53803 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -1058,10 +1058,9 @@ static void tegra_camera_init_buffer(struct tegra_camera_dev *pcdev, * Videobuf operations */ static int tegra_camera_videobuf_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], + unsigned long sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = container_of(vq, @@ -1321,7 +1320,8 @@ static void tegra_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -static int tegra_camera_set_bus_param(struct soc_camera_device *icd) +static int tegra_camera_set_bus_param(struct soc_camera_device *icd, + __u32 pixfmt) { return 0; } -- cgit v1.2.3 From 364f8d1cf478a94acdb1bec96614372da0ec883b Mon Sep 17 00:00:00 2001 From: Rakesh Bodla Date: Wed, 17 Oct 2012 11:36:21 +0530 Subject: usb: gadget: tegra:change condition for vbus check Changing the condition for vbus check. VBUS will be present when OTG cable is connected, hence vbus status will be reflected wrong. Correct status is tracked through vbus_active variable. Bug 1158853 Bug 1214802 Change-Id: Ic904beb5919ddafef5becf39ddac1767cdda79cd Signed-off-by: Rakesh Bodla Reviewed-on: http://git-master/r/145148 (cherry picked from commit 00777683b05af76f15daa0152fb014183a32fa28) Reviewed-on: http://git-master/r/190673 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Preetham Chandru GVS: Gerrit_Virtual_Submit Reviewed-by: Matthew Pedro Reviewed-by: Winnie Hsu --- drivers/usb/gadget/tegra_udc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index 9af22ebe8b58..c130dae3a8e9 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -635,7 +635,7 @@ static int tegra_ep_disable(struct usb_ep *_ep) ep_num = ep_index(ep); /* Touch the registers if cable is connected and phy is on */ - if (vbus_enabled(udc)) { + if (udc->vbus_active) { epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4)); if (ep_is_in(ep)) epctrl &= ~EPCTRL_TX_ENABLE; @@ -995,7 +995,7 @@ static int tegra_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ep_num = ep_index(ep); /* Touch the registers if cable is connected and phy is on */ - if (vbus_enabled(udc)) { + if (udc->vbus_active) { epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4)); if (ep_is_in(ep)) epctrl &= ~EPCTRL_TX_ENABLE; @@ -1046,7 +1046,7 @@ static int tegra_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* Enable EP */ out: /* Touch the registers if cable is connected and phy is on */ - if (vbus_enabled(udc)) { + if (udc->vbus_active) { epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4)); if (ep_is_in(ep)) epctrl |= EPCTRL_TX_ENABLE; @@ -1168,7 +1168,7 @@ static void tegra_ep_fifo_flush(struct usb_ep *_ep) bits = 1 << ep_num; /* Touch the registers if cable is connected and phy is on */ - if (!vbus_enabled(udc)) + if (!udc->vbus_active) return; timeout = jiffies + UDC_FLUSH_TIMEOUT_MS; @@ -2363,14 +2363,13 @@ static int tegra_udc_start(struct usb_gadget_driver *driver, goto out; } - /* Enable DR IRQ reg and Set usbcmd reg Run bit */ if (vbus_enabled(udc)) { dr_controller_run(udc); udc->usb_state = USB_STATE_ATTACHED; udc->ep0_state = WAIT_FOR_SETUP; udc->ep0_dir = 0; - udc->vbus_active = vbus_enabled(udc); + udc->vbus_active = 1; } printk(KERN_INFO "%s: bind to driver %s\n", -- cgit v1.2.3 From 8c886374c74324c5bd627815126d7df052a8c885 Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Wed, 16 Jan 2013 12:02:31 +0530 Subject: arm: Tegra: Beaver: PWRON key registration Registration of PWRON key through PMU interrupt Bug 1218247 Change-Id: I4d5d4a404fff28f2e34b1fd4af5712796eb8806c Signed-off-by: Ramalingam C Reviewed-on: http://git-master/r/191574 Reviewed-by: Preetham Chandru Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Peer Chen GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/board-cardhu-kbc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c index 5bbb27176159..6239b1d2d77d 100644 --- a/arch/arm/mach-tegra/board-cardhu-kbc.c +++ b/arch/arm/mach-tegra/board-cardhu-kbc.c @@ -2,7 +2,7 @@ * arch/arm/mach-tegra/board-cardhu-kbc.c * Keys configuration for Nvidia tegra3 cardhu platform. * - * Copyright (C) 2011 NVIDIA, Inc. + * Copyright (C) 2011-2013 NVIDIA, Inc. * * 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 @@ -241,6 +241,7 @@ int __init cardhu_keys_init(void) tegra_get_board_info(&board_info); if (!((board_info.board_id == BOARD_E1198) || (board_info.board_id == BOARD_E1291) || + (board_info.board_id == BOARD_PM315) || (board_info.board_id == BOARD_E1186) || (board_info.board_id == BOARD_E1257) || (board_info.board_id == BOARD_PM305) || @@ -301,6 +302,7 @@ int __init cardhu_keys_init(void) if ((board_info.board_id == BOARD_E1257) || (board_info.board_id == BOARD_E1186) || (board_info.board_id == BOARD_PM305) || + (board_info.board_id == BOARD_PM315) || (board_info.board_id == BOARD_PM311) || (board_info.board_id == BOARD_PM267) || (board_info.board_id == BOARD_PM269)) { -- cgit v1.2.3 From e722b2e725a3fd413fc4da578f2b45300d0bfd7e Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Wed, 16 Jan 2013 10:29:56 +0530 Subject: arm: tegra: cardhu: no gyro in beaver Add support for PM315 Bug 1217569 Change-Id: I230fcec04eb5a96441e2c19b304d608d86eaf996 Signed-off-by: Bibek Basu Reviewed-on: http://git-master/r/191555 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- arch/arm/mach-tegra/board-cardhu-sensors.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c index 365da60fa9ec..08ad0d5fb0fc 100644 --- a/arch/arm/mach-tegra/board-cardhu-sensors.c +++ b/arch/arm/mach-tegra/board-cardhu-sensors.c @@ -1131,7 +1131,8 @@ int __init cardhu_sensors_init(void) i2c_register_board_info(4, cardhu_i2c4_nct1008_board_info, ARRAY_SIZE(cardhu_i2c4_nct1008_board_info)); - mpuirq_init(); + if (board_info.board_id != BOARD_PM315) + mpuirq_init(); return 0; } -- cgit v1.2.3 From 9f91433d1807ec7daa4a5672b3c2669d27ee28b2 Mon Sep 17 00:00:00 2001 From: Preetham Chandru R Date: Thu, 31 Jan 2013 11:06:58 +0530 Subject: staging: iio: light: isl29028: appropriately set interrupt flag set is_int_enable to true only if we register for a irq. Bug 1211260 Change-Id: I603efe721796db70d504da7999e5d7939d45d13a Signed-off-by: Preetham Chandru R Reviewed-on: http://git-master/r/193047 (cherry picked from commit 8b89b2b64c67d80fcfc29cd4f6a92d4527e70df9) Reviewed-on: http://git-master/r/195844 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu Reviewed-by: Matthew Pedro --- drivers/staging/iio/light/isl29028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index 0b1d2f2f73aa..5874c32958d9 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -1193,9 +1193,9 @@ static int __devinit isl29028_probe(struct i2c_client *client, "error %d\n", chip->irq, err); goto exit_free; } + chip->is_int_enable = true; } - chip->is_int_enable = true; chip->indio_dev = iio_allocate_device(0); if (!chip->indio_dev) { dev_err(&client->dev, "iio allocation fails\n"); -- cgit v1.2.3 From d99083e607e17d47ff686146a470044e00c320f0 Mon Sep 17 00:00:00 2001 From: Mursalin Akon Date: Thu, 31 Jan 2013 16:33:41 -0800 Subject: config: tegra3: enable /dev mount with ACL enable /dev mount with ACL Bug 1225372 Bug 1219372 Change-Id: I3b80012e97c3a5ec8358285f81c5111a30ed19f8 Signed-off-by: Mursalin Akon Reviewed-on: http://git-master/r/196206 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Matthew Pedro --- arch/arm/configs/tegra3_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig index 55326f14c2f1..d8ba44fc373e 100644 --- a/arch/arm/configs/tegra3_defconfig +++ b/arch/arm/configs/tegra3_defconfig @@ -192,6 +192,7 @@ CONFIG_CAIF=y CONFIG_NFC=y CONFIG_PN544_NFC=y CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_BLK_DEV_LOOP=y CONFIG_MISC_DEVICES=y @@ -435,6 +436,7 @@ CONFIG_VFAT_FS=y CONFIG_NTFS_FS=m CONFIG_NTFS_RW=y CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y -- cgit v1.2.3 From 1ff6b9489fbc737e3e2bc7660b92cebbfaea5247 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 22 Jan 2013 19:15:35 +0530 Subject: ARM: tegra: cardhu: Add battery regulator Add battery regulator which is always-on. The rail which is powered from battery can be added on this rail as consumer. bug 1218527 Change-Id: I2394e1894649cd4fa736646981374681f603c832 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/#change,193052 (cherry picked from commit 4b9cabe87060bf5f252206aba5b62ea1ccb2ff83) Reviewed-on: http://git-master/r/193777 Tested-by: Preetham Chandru Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/board-cardhu-power.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c index d69426a30c67..2ca143010165 100644 --- a/arch/arm/mach-tegra/board-cardhu-power.c +++ b/arch/arm/mach-tegra/board-cardhu-power.c @@ -709,6 +709,11 @@ static struct regulator_consumer_supply fixed_reg_en_vddio_vid_oc_supply[] = { REGULATOR_SUPPLY("vdd_hdmi_con", NULL), }; +/* Battery powered rail*/ +static struct regulator_consumer_supply fixed_reg_en_battery_supply[] = { + REGULATOR_SUPPLY("usb_vbus", "tegra-ehci.1"), +}; + /* Macro for defining fixed regulator sub device data */ #define FIXED_SUPPLY(_name) "fixed_reg_"#_name #define FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, \ @@ -828,6 +833,8 @@ FIXED_REG_OD(16, en_usb3_vbus_oc_a03, en_usb3_vbus_oc, FIXED_SUPPLY(en_5v0), 0 /* E1198/E1291 specific */ FIXED_REG_OD(17, en_vddio_vid_oc, en_vddio_vid_oc, FIXED_SUPPLY(en_5v0), 0, 0, TEGRA_GPIO_PT0, true, 0, 5000, true); +/* Always ON */ +FIXED_REG(22, en_battery, en_battery, NULL, 1, 1, -1, true, 1, 5000); /* * Creating the fixed/gpio-switch regulator device tables for different boards */ @@ -846,7 +853,8 @@ FIXED_REG_OD(17, en_vddio_vid_oc, en_vddio_vid_oc, FIXED_SUPPLY(en_5v0), 0, ADD_FIXED_REG(en_3v3_emmc), \ ADD_FIXED_REG(en_vdd_sdmmc1), \ ADD_FIXED_REG(en_3v3_pex_hvdd), \ - ADD_FIXED_REG(en_1v8_cam), + ADD_FIXED_REG(en_1v8_cam), \ + ADD_FIXED_REG(en_battery), #define COMMON_FIXED_REG_E1291_A04 \ ADD_FIXED_REG(en_5v_cp), \ @@ -861,7 +869,8 @@ FIXED_REG_OD(17, en_vddio_vid_oc, en_vddio_vid_oc, FIXED_SUPPLY(en_5v0), 0, ADD_FIXED_REG(en_3v3_emmc), \ ADD_FIXED_REG(en_vdd_sdmmc1), \ ADD_FIXED_REG(en_3v3_pex_hvdd), \ - ADD_FIXED_REG(en_1v8_cam), + ADD_FIXED_REG(en_1v8_cam), \ + ADD_FIXED_REG(en_battery), #define PM269_FIXED_REG \ ADD_FIXED_REG(en_5v_cp), \ -- cgit v1.2.3