From eb3f1b7f2d09ffcc9638b03c4e7e69354e2d3cbb Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Fri, 2 Dec 2016 02:48:01 -0200 Subject: [media] bdisp: Clean up file handle in open() error path The File handle is not yet added in the vdev list.So no need to call v4l2_fh_del(&ctx->fh)if it fails to create control. Signed-off-by: Shailendra Verma Reviewed-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 823608112d89..7918b928f058 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -632,8 +632,8 @@ static int bdisp_open(struct file *file) error_ctrls: bdisp_ctrls_delete(ctx); -error_fh: v4l2_fh_del(&ctx->fh); +error_fh: v4l2_fh_exit(&ctx->fh); bdisp_hw_free_nodes(ctx); mem_ctx: -- cgit v1.2.3 From 50ad58f9dc11ebdf7d66253dd1f4cd3f6642749d Mon Sep 17 00:00:00 2001 From: Shilpa P Date: Sat, 3 Dec 2016 05:02:01 -0200 Subject: [media] staging: Replaced BUG_ON with warnings Don't crash the Kernel for driver errors Signed-off-by: Shilpa P Acked-by: Allen Pais Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 37bd439ee08b..5696982d6955 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -1534,7 +1534,11 @@ static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i, if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) return 0; - BUG_ON((index+2) >= BCM2048_MAX_RDS_RT); + if ((index + 2) >= BCM2048_MAX_RDS_RT) { + dev_err(&bdev->client->dev, + "Incorrect index = %d\n", index); + return 0; + } if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == BCM2048_RDS_BLOCK_C) { @@ -1557,7 +1561,11 @@ static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i, if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) return; - BUG_ON((index+4) >= BCM2048_MAX_RDS_RT); + if ((index + 4) >= BCM2048_MAX_RDS_RT) { + dev_err(&bdev->client->dev, + "Incorrect index = %d\n", index); + return; + } if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == BCM2048_RDS_BLOCK_D) -- cgit v1.2.3 From 93d4a26c3dabcee4d8bd6c9a1aba779484dc3cc3 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 24 Jan 2017 06:05:57 -0200 Subject: [media] atmel-isc: add the isc pipeline function Image Sensor Controller has an internal image processor. It can convert raw format to the other formats, like RGB565, YUV420P. A module parameter 'sensor_preferred' is used to enable or disable the pipeline function. Some v4l2 controls are added to tuning the image when the pipeline function is enabled. Signed-off-by: Songjun Wu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-regs.h | 102 ++++- drivers/media/platform/atmel/atmel-isc.c | 627 +++++++++++++++++++++----- 2 files changed, 620 insertions(+), 109 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 00c449717cde..6936ac467609 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -65,6 +65,7 @@ #define ISC_INTSR 0x00000034 #define ISC_INT_DDONE BIT(8) +#define ISC_INT_HISDONE BIT(12) /* ISC White Balance Control Register */ #define ISC_WB_CTRL 0x00000058 @@ -72,30 +73,98 @@ /* ISC White Balance Configuration Register */ #define ISC_WB_CFG 0x0000005c +/* ISC White Balance Offset for R, GR Register */ +#define ISC_WB_O_RGR 0x00000060 + +/* ISC White Balance Offset for B, GB Register */ +#define ISC_WB_O_BGR 0x00000064 + +/* ISC White Balance Gain for R, GR Register */ +#define ISC_WB_G_RGR 0x00000068 + +/* ISC White Balance Gain for B, GB Register */ +#define ISC_WB_G_BGR 0x0000006c + /* ISC Color Filter Array Control Register */ #define ISC_CFA_CTRL 0x00000070 /* ISC Color Filter Array Configuration Register */ #define ISC_CFA_CFG 0x00000074 +#define ISC_CFA_CFG_EITPOL BIT(4) #define ISC_BAY_CFG_GRGR 0x0 #define ISC_BAY_CFG_RGRG 0x1 #define ISC_BAY_CFG_GBGB 0x2 #define ISC_BAY_CFG_BGBG 0x3 -#define ISC_BAY_CFG_MASK GENMASK(1, 0) /* ISC Color Correction Control Register */ #define ISC_CC_CTRL 0x00000078 +/* ISC Color Correction RR RG Register */ +#define ISC_CC_RR_RG 0x0000007c + +/* ISC Color Correction RB OR Register */ +#define ISC_CC_RB_OR 0x00000080 + +/* ISC Color Correction GR GG Register */ +#define ISC_CC_GR_GG 0x00000084 + +/* ISC Color Correction GB OG Register */ +#define ISC_CC_GB_OG 0x00000088 + +/* ISC Color Correction BR BG Register */ +#define ISC_CC_BR_BG 0x0000008c + +/* ISC Color Correction BB OB Register */ +#define ISC_CC_BB_OB 0x00000090 + /* ISC Gamma Correction Control Register */ #define ISC_GAM_CTRL 0x00000094 +/* ISC_Gamma Correction Blue Entry Register */ +#define ISC_GAM_BENTRY 0x00000098 + +/* ISC_Gamma Correction Green Entry Register */ +#define ISC_GAM_GENTRY 0x00000198 + +/* ISC_Gamma Correction Green Entry Register */ +#define ISC_GAM_RENTRY 0x00000298 + /* Color Space Conversion Control Register */ #define ISC_CSC_CTRL 0x00000398 +/* Color Space Conversion YR YG Register */ +#define ISC_CSC_YR_YG 0x0000039c + +/* Color Space Conversion YB OY Register */ +#define ISC_CSC_YB_OY 0x000003a0 + +/* Color Space Conversion CBR CBG Register */ +#define ISC_CSC_CBR_CBG 0x000003a4 + +/* Color Space Conversion CBB OCB Register */ +#define ISC_CSC_CBB_OCB 0x000003a8 + +/* Color Space Conversion CRR CRG Register */ +#define ISC_CSC_CRR_CRG 0x000003ac + +/* Color Space Conversion CRB OCR Register */ +#define ISC_CSC_CRB_OCR 0x000003b0 + /* Contrast And Brightness Control Register */ #define ISC_CBC_CTRL 0x000003b4 +/* Contrast And Brightness Configuration Register */ +#define ISC_CBC_CFG 0x000003b8 + +/* Brightness Register */ +#define ISC_CBC_BRIGHT 0x000003bc +#define ISC_CBC_BRIGHT_MASK GENMASK(10, 0) + +/* Contrast Register */ +#define ISC_CBC_CONTRAST 0x000003c0 +#define ISC_CBC_CONTRAST_MASK GENMASK(11, 0) + /* Subsampling 4:4:4 to 4:2:2 Control Register */ #define ISC_SUB422_CTRL 0x000003c4 @@ -120,6 +189,27 @@ #define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc #define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0) +/* Histogram Control Register */ +#define ISC_HIS_CTRL 0x000003d4 + +#define ISC_HIS_CTRL_EN BIT(0) +#define ISC_HIS_CTRL_DIS 0x0 + +/* Histogram Configuration Register */ +#define ISC_HIS_CFG 0x000003d8 + +#define ISC_HIS_CFG_MODE_GR 0x0 +#define ISC_HIS_CFG_MODE_R 0x1 +#define ISC_HIS_CFG_MODE_GB 0x2 +#define ISC_HIS_CFG_MODE_B 0x3 +#define ISC_HIS_CFG_MODE_Y 0x4 +#define ISC_HIS_CFG_MODE_RAW 0x5 +#define ISC_HIS_CFG_MODE_YCCIR656 0x6 + +#define ISC_HIS_CFG_BAYSEL_SHIFT 4 + +#define ISC_HIS_CFG_RAR BIT(8) + /* DMA Configuration Register */ #define ISC_DCFG 0x000003e0 #define ISC_DCFG_IMODE_PACKED8 0x0 @@ -159,7 +249,13 @@ /* DMA Address 0 Register */ #define ISC_DAD0 0x000003ec -/* DMA Stride 0 Register */ -#define ISC_DST0 0x000003f0 +/* DMA Address 1 Register */ +#define ISC_DAD1 0x000003f4 + +/* DMA Address 2 Register */ +#define ISC_DAD2 0x000003fc + +/* Histogram Entry */ +#define ISC_HIS_ENTRY 0x00000410 #endif diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index fa68fe912c95..b380a7d40d85 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,9 @@ #include #include +#include #include +#include #include #include #include @@ -89,10 +92,12 @@ struct isc_subdev_entity { * struct isc_format - ISC media bus format information * @fourcc: Fourcc code for this format * @mbus_code: V4L2 media bus format code. - * @bpp: Bytes per pixel (when stored in memory) + * @bpp: Bits per pixel (when stored in memory) * @reg_bps: reg value for bits per sample * (when transferred over a bus) - * @support: Indicates format supported by subdev + * @pipeline: pipeline switch + * @sd_support: Subdev supports this format + * @isc_support: ISC can convert raw format to this format */ struct isc_format { u32 fourcc; @@ -100,11 +105,42 @@ struct isc_format { u8 bpp; u32 reg_bps; + u32 reg_bay_cfg; u32 reg_rlp_mode; u32 reg_dcfg_imode; u32 reg_dctrl_dview; - bool support; + u32 pipeline; + + bool sd_support; + bool isc_support; +}; + + +#define HIST_ENTRIES 512 +#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) + +enum{ + HIST_INIT = 0, + HIST_ENABLED, + HIST_DISABLED, +}; + +struct isc_ctrls { + struct v4l2_ctrl_handler handler; + + u32 brightness; + u32 contrast; + u8 gamma_index; + u8 awb; + + u32 r_gain; + u32 b_gain; + + u32 hist_entry[HIST_ENTRIES]; + u32 hist_count[HIST_BAYER]; + u8 hist_id; + u8 hist_stat; }; #define ISC_PIPE_LINE_NODE_NUM 11 @@ -131,6 +167,10 @@ struct isc_device { struct isc_format **user_formats; unsigned int num_user_formats; const struct isc_format *current_fmt; + const struct isc_format *raw_fmt; + + struct isc_ctrls ctrls; + struct work_struct awb_work; struct mutex lock; @@ -140,51 +180,134 @@ struct isc_device { struct list_head subdev_entities; }; +#define RAW_FMT_IND_START 0 +#define RAW_FMT_IND_END 11 +#define ISC_FMT_IND_START 12 +#define ISC_FMT_IND_END 14 + static struct isc_format isc_formats[] = { - { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, - 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, - 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, - 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, - 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, - - { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, - 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, - 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, - 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, - 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - - { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, - 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, - 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, - 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, - 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, - - { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, - 2, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, + { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, + ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8, + ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8, + ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8, + ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + + { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16, + ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16, + ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16, + ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16, + ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + + { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16, + ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16, + ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16, + ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16, + ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, + + { V4L2_PIX_FMT_YUV420, 0x0, 12, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, + ISC_DCFG_IMODE_YC420P | ISC_DCFG_YMBSIZE_BEATS8 | + ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x7fb, + false, false }, + { V4L2_PIX_FMT_YUV422P, 0x0, 16, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, + ISC_DCFG_IMODE_YC422P | ISC_DCFG_YMBSIZE_BEATS8 | + ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x3fb, + false, false }, + { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565, + ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b, + false, false }, + + { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16, + ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, + ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, + false, false }, +}; + +#define GAMMA_MAX 2 +#define GAMMA_ENTRIES 64 + +/* Gamma table with gamma 1/2.2 */ +static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { + /* 0 --> gamma 1/1.8 */ + { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, + 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, + 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, + 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, + 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, + 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, + 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, + 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, + 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, + 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, + 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, + + /* 1 --> gamma 1/2 */ + { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, + 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, + 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, + 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, + 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, + 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, + 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, + 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, + 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, + 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, + 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, + + /* 2 --> gamma 1/2.2 */ + { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, + 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, + 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, + 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, + 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, + 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, + 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, + 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, + 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, + 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, + 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, }; +static unsigned int sensor_preferred = 1; +module_param(sensor_preferred, uint, 0644); +MODULE_PARM_DESC(sensor_preferred, + "Sensor is preferred to output the specified format (1-on 0-off), default 1"); + static int isc_clk_enable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); @@ -447,27 +570,155 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) return 0; } -static inline void isc_start_dma(struct regmap *regmap, - struct isc_buffer *frm, u32 dview) +static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) { - dma_addr_t addr; + return (sensor_preferred && isc_fmt->sd_support) || + !isc_fmt->isc_support; +} - addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0); +static void isc_start_dma(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; + u32 sizeimage = pixfmt->sizeimage; + u32 dctrl_dview; + dma_addr_t addr0; + + addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); + regmap_write(regmap, ISC_DAD0, addr0); + + switch (pixfmt->pixelformat) { + case V4L2_PIX_FMT_YUV420: + regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); + break; + case V4L2_PIX_FMT_YUV422P: + regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); + break; + default: + break; + } + + if (sensor_is_preferred(isc->current_fmt)) + dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + else + dctrl_dview = isc->current_fmt->reg_dctrl_dview; - regmap_write(regmap, ISC_DCTRL, dview | ISC_DCTRL_IE_IS); - regmap_write(regmap, ISC_DAD0, addr); + regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); } static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) { - u32 val; + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 val, bay_cfg; + const u32 *gamma; unsigned int i; + /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { val = pipeline & BIT(i) ? 1 : 0; regmap_field_write(isc->pipeline[i], val); } + + if (!pipeline) + return; + + bay_cfg = isc->raw_fmt->reg_bay_cfg; + + regmap_write(regmap, ISC_WB_CFG, bay_cfg); + regmap_write(regmap, ISC_WB_O_RGR, 0x0); + regmap_write(regmap, ISC_WB_O_BGR, 0x0); + regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25)); + regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25)); + + regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); + + gamma = &isc_gamma_table[ctrls->gamma_index][0]; + regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); + + /* Convert RGB to YUV */ + regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); + regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); + regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); + regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); + regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); + regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); + + regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); + regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); +} + +static int isc_update_profile(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sr; + int counter = 100; + + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); + + regmap_read(regmap, ISC_CTRLSR, &sr); + while ((sr & ISC_CTRL_UPPRO) && counter--) { + usleep_range(1000, 2000); + regmap_read(regmap, ISC_CTRLSR, &sr); + } + + if (counter < 0) { + v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void isc_set_histogram(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + + if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { + regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | + (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); + regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); + ctrls->hist_id = ISC_HIS_CFG_MODE_R; + isc_update_profile(isc); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + ctrls->hist_stat = HIST_ENABLED; + } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) { + regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); + + ctrls->hist_stat = HIST_DISABLED; + } +} + +static inline void isc_get_param(const struct isc_format *fmt, + u32 *rlp_mode, u32 *dcfg_imode) +{ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + *rlp_mode = fmt->reg_rlp_mode; + *dcfg_imode = fmt->reg_dcfg_imode; + break; + default: + *rlp_mode = ISC_RLP_CFG_MODE_DAT8; + *dcfg_imode = ISC_DCFG_IMODE_PACKED8; + break; + } } static int isc_configure(struct isc_device *isc) @@ -475,39 +726,40 @@ static int isc_configure(struct isc_device *isc) struct regmap *regmap = isc->regmap; const struct isc_format *current_fmt = isc->current_fmt; struct isc_subdev_entity *subdev = isc->current_subdev; - u32 val, mask; - int counter = 10; + u32 pfe_cfg0, rlp_mode, dcfg_imode, mask, pipeline; + + if (sensor_is_preferred(current_fmt)) { + pfe_cfg0 = current_fmt->reg_bps; + pipeline = 0x0; + isc_get_param(current_fmt, &rlp_mode, &dcfg_imode); + isc->ctrls.hist_stat = HIST_INIT; + } else { + pfe_cfg0 = isc->raw_fmt->reg_bps; + pipeline = current_fmt->pipeline; + rlp_mode = current_fmt->reg_rlp_mode; + dcfg_imode = current_fmt->reg_dcfg_imode; + } - val = current_fmt->reg_bps | subdev->pfe_cfg0 | - ISC_PFE_CFG0_MODE_PROGRESSIVE; + pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | ISC_PFE_CFG0_MODE_MASK; - regmap_update_bits(regmap, ISC_PFE_CFG0, mask, val); + regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, - current_fmt->reg_rlp_mode); + rlp_mode); - regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, - current_fmt->reg_dcfg_imode); + regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, dcfg_imode); - /* Disable the pipeline */ - isc_set_pipeline(isc, 0x0); + /* Set the pipeline */ + isc_set_pipeline(isc, pipeline); - /* Update profile */ - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); + if (pipeline) + isc_set_histogram(isc); - regmap_read(regmap, ISC_CTRLSR, &val); - while ((val & ISC_CTRL_UPPRO) && counter--) { - usleep_range(1000, 2000); - regmap_read(regmap, ISC_CTRLSR, &val); - } - - if (counter < 0) - return -ETIMEDOUT; - - return 0; + /* Update profile */ + return isc_update_profile(isc); } static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) @@ -517,7 +769,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) struct isc_buffer *buf; unsigned long flags; int ret; - u32 val; /* Enable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); @@ -528,12 +779,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) pm_runtime_get_sync(isc->dev); - /* Disable all the interrupts */ - regmap_write(isc->regmap, ISC_INTDIS, (u32)~0UL); - - /* Clean the interrupt status register */ - regmap_read(regmap, ISC_INTSR, &val); - ret = isc_configure(isc); if (unlikely(ret)) goto err_configure; @@ -551,7 +796,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) struct isc_buffer, list); list_del(&isc->cur_frm->list); - isc_start_dma(regmap, isc->cur_frm, isc->current_fmt->reg_dctrl_dview); + isc_start_dma(isc); spin_unlock_irqrestore(&isc->dma_queue_lock, flags); @@ -620,8 +865,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb) if (!isc->cur_frm && list_empty(&isc->dma_queue) && vb2_is_streaming(vb->vb2_queue)) { isc->cur_frm = buf; - isc_start_dma(isc->regmap, isc->cur_frm, - isc->current_fmt->reg_dctrl_dview); + isc_start_dma(isc); } else list_add_tail(&buf->list, &isc->dma_queue); spin_unlock_irqrestore(&isc->dma_queue_lock, flags); @@ -691,13 +935,14 @@ static struct isc_format *find_format_by_fourcc(struct isc_device *isc, } static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, - struct isc_format **current_fmt) + struct isc_format **current_fmt, u32 *code) { struct isc_format *isc_fmt; struct v4l2_pix_format *pixfmt = &f->fmt.pix; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; + u32 mbus_code; int ret; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -717,7 +962,12 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; - v4l2_fill_mbus_format(&format.format, pixfmt, isc_fmt->mbus_code); + if (sensor_is_preferred(isc_fmt)) + mbus_code = isc_fmt->mbus_code; + else + mbus_code = isc->raw_fmt->mbus_code; + + v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, isc->current_subdev->config, &format); if (ret < 0) @@ -726,12 +976,15 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, v4l2_fill_pix_format(pixfmt, &format.format); pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = pixfmt->width * isc_fmt->bpp; + pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; if (current_fmt) *current_fmt = isc_fmt; + if (code) + *code = mbus_code; + return 0; } @@ -741,14 +994,14 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; struct isc_format *current_fmt; + u32 mbus_code; int ret; - ret = isc_try_fmt(isc, f, ¤t_fmt); + ret = isc_try_fmt(isc, f, ¤t_fmt, &mbus_code); if (ret) return ret; - v4l2_fill_mbus_format(&format.format, &f->fmt.pix, - current_fmt->mbus_code); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, NULL, &format); if (ret < 0) @@ -776,7 +1029,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv, { struct isc_device *isc = video_drvdata(file); - return isc_try_fmt(isc, f, NULL); + return isc_try_fmt(isc, f, NULL, NULL); } static int isc_enum_input(struct file *file, void *priv, @@ -842,7 +1095,10 @@ static int isc_enum_framesizes(struct file *file, void *fh, if (!isc_fmt) return -EINVAL; - fse.code = isc_fmt->mbus_code; + if (sensor_is_preferred(isc_fmt)) + fse.code = isc_fmt->mbus_code; + else + fse.code = isc->raw_fmt->mbus_code; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, NULL, &fse); @@ -873,7 +1129,10 @@ static int isc_enum_frameintervals(struct file *file, void *fh, if (!isc_fmt) return -EINVAL; - fie.code = isc_fmt->mbus_code; + if (sensor_is_preferred(isc_fmt)) + fie.code = isc_fmt->mbus_code; + else + fie.code = isc->raw_fmt->mbus_code; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_interval, NULL, &fie); @@ -911,6 +1170,10 @@ static const struct v4l2_ioctl_ops isc_ioctl_ops = { .vidioc_s_parm = isc_s_parm, .vidioc_enum_framesizes = isc_enum_framesizes, .vidioc_enum_frameintervals = isc_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static int isc_open(struct file *file) @@ -984,14 +1247,13 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) u32 isc_intsr, isc_intmask, pending; irqreturn_t ret = IRQ_NONE; - spin_lock(&isc->dma_queue_lock); - regmap_read(regmap, ISC_INTSR, &isc_intsr); regmap_read(regmap, ISC_INTMASK, &isc_intmask); pending = isc_intsr & isc_intmask; if (likely(pending & ISC_INT_DDONE)) { + spin_lock(&isc->dma_queue_lock); if (isc->cur_frm) { struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; struct vb2_buffer *vb = &vbuf->vb2_buf; @@ -1007,21 +1269,144 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) struct isc_buffer, list); list_del(&isc->cur_frm->list); - isc_start_dma(regmap, isc->cur_frm, - isc->current_fmt->reg_dctrl_dview); + isc_start_dma(isc); } if (isc->stop) complete(&isc->comp); ret = IRQ_HANDLED; + spin_unlock(&isc->dma_queue_lock); } - spin_unlock(&isc->dma_queue_lock); + if (pending & ISC_INT_HISDONE) { + schedule_work(&isc->awb_work); + ret = IRQ_HANDLED; + } return ret; } +static void isc_hist_count(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; + u32 *hist_entry = &ctrls->hist_entry[0]; + u32 i; + + regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); + + *hist_count = 0; + for (i = 0; i <= HIST_ENTRIES; i++) + *hist_count += i * (*hist_entry++); +} + +static void isc_wb_update(struct isc_ctrls *ctrls) +{ + u32 *hist_count = &ctrls->hist_count[0]; + u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9; + u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R]; + u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B]; + + if (hist_r) + ctrls->r_gain = div_u64(g_count, hist_r); + + if (hist_b) + ctrls->b_gain = div_u64(g_count, hist_b); +} + +static void isc_awb_work(struct work_struct *w) +{ + struct isc_device *isc = + container_of(w, struct isc_device, awb_work); + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 hist_id = ctrls->hist_id; + u32 baysel; + + if (ctrls->hist_stat != HIST_ENABLED) + return; + + isc_hist_count(isc); + + if (hist_id != ISC_HIS_CFG_MODE_B) { + hist_id++; + } else { + isc_wb_update(ctrls); + hist_id = ISC_HIS_CFG_MODE_R; + } + + ctrls->hist_id = hist_id; + baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT; + + pm_runtime_get_sync(isc->dev); + + regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); + isc_update_profile(isc); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + pm_runtime_put_sync(isc->dev); +} + +static int isc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct isc_device *isc = container_of(ctrl->handler, + struct isc_device, ctrls.handler); + struct isc_ctrls *ctrls = &isc->ctrls; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; + break; + case V4L2_CID_CONTRAST: + ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; + break; + case V4L2_CID_GAMMA: + ctrls->gamma_index = ctrl->val; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + ctrls->awb = ctrl->val; + if (ctrls->hist_stat != HIST_ENABLED) { + ctrls->r_gain = 0x1 << 9; + ctrls->b_gain = 0x1 << 9; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops isc_ctrl_ops = { + .s_ctrl = isc_s_ctrl, +}; + +static int isc_ctrl_init(struct isc_device *isc) +{ + const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; + struct isc_ctrls *ctrls = &isc->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int ret; + + ctrls->hist_stat = HIST_INIT; + + ret = v4l2_ctrl_handler_init(hdl, 4); + if (ret < 0) + return ret; + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + + v4l2_ctrl_handler_setup(hdl); + + return 0; +} + + static int isc_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1047,10 +1432,11 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); - + cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); if (isc->current_subdev->config) v4l2_subdev_free_pad_config(isc->current_subdev->config); + v4l2_ctrl_handler_free(&isc->ctrls.handler); } static struct isc_format *find_format_by_code(unsigned int code, int *index) @@ -1074,14 +1460,16 @@ static int isc_formats_init(struct isc_device *isc) { struct isc_format *fmt; struct v4l2_subdev *subdev = isc->current_subdev->sd; - int num_fmts = 0, i, j; + unsigned int num_fmts, i, j; struct v4l2_subdev_mbus_code_enum mbus_code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; fmt = &isc_formats[0]; for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { - fmt->support = false; + fmt->isc_support = false; + fmt->sd_support = false; + fmt++; } @@ -1092,8 +1480,21 @@ static int isc_formats_init(struct isc_device *isc) if (!fmt) continue; - fmt->support = true; - num_fmts++; + fmt->sd_support = true; + + if (i <= RAW_FMT_IND_END) { + for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++) + isc_formats[j].isc_support = true; + + isc->raw_fmt = fmt; + } + } + + for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) { + if (fmt->isc_support || fmt->sd_support) + num_fmts++; + + fmt++; } if (!num_fmts) @@ -1110,7 +1511,7 @@ static int isc_formats_init(struct isc_device *isc) fmt = &isc_formats[0]; for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { - if (fmt->support) + if (fmt->isc_support || fmt->sd_support) isc->user_formats[j++] = fmt; fmt++; @@ -1132,7 +1533,7 @@ static int isc_set_default_fmt(struct isc_device *isc) }; int ret; - ret = isc_try_fmt(isc, &f, NULL); + ret = isc_try_fmt(isc, &f, NULL, NULL); if (ret) return ret; @@ -1151,6 +1552,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) struct vb2_queue *q = &isc->vb2_vidq; int ret; + ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); + return ret; + } + isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); sd_entity = isc->current_subdev; @@ -1198,6 +1605,14 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) return ret; } + ret = isc_ctrl_init(isc); + if (ret) { + v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); + return ret; + } + + INIT_WORK(&isc->awb_work, isc_awb_work); + /* Register video device */ strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); vdev->release = video_device_release_empty; @@ -1207,7 +1622,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &isc->lock; - vdev->ctrl_handler = isc->current_subdev->sd->ctrl_handler; + vdev->ctrl_handler = &isc->ctrls.handler; vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; video_set_drvdata(vdev, isc); -- cgit v1.2.3 From 8ecc54138aa1fc1be10bac7890248a0c00065427 Mon Sep 17 00:00:00 2001 From: Vincent ABRIOU Date: Mon, 12 Sep 2016 05:47:27 -0300 Subject: [media] vivid: support for contiguous DMA buffers It allows to simulate the behavior of hardware with such limitations or to connect vivid to real hardware with such limitations. Add the "allocators" module parameter option to let vivid use the dma-contig instead of vmalloc. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Vincent Abriou Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/v4l-drivers/vivid.rst | 8 ++++++++ drivers/media/platform/vivid/Kconfig | 2 ++ drivers/media/platform/vivid/vivid-core.c | 32 ++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Documentation/media/v4l-drivers/vivid.rst b/Documentation/media/v4l-drivers/vivid.rst index c8cf371e8bb9..3e44b2217f2d 100644 --- a/Documentation/media/v4l-drivers/vivid.rst +++ b/Documentation/media/v4l-drivers/vivid.rst @@ -263,6 +263,14 @@ all configurable using the following module options: removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the will default to enabling crop, compose and scaling. +- allocators: + + memory allocator selection, default is 0. It specifies the way buffers + will be allocated. + + - 0: vmalloc + - 1: dma-contig + Taken together, all these module options allow you to precisely customize the driver behavior and test your application with all sorts of permutations. It is also very suitable to emulate hardware that is not yet available, e.g. diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index db0dd19d227a..94ab1364a792 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -1,6 +1,7 @@ config VIDEO_VIVID tristate "Virtual Video Test Driver" depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB + depends on HAS_DMA select FONT_SUPPORT select FONT_8x16 select FB_CFB_FILLRECT @@ -8,6 +9,7 @@ config VIDEO_VIVID select FB_CFB_IMAGEBLIT select MEDIA_CEC_EDID select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG default n ---help--- diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 51e37812ec98..ef344b9a48af 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,12 @@ static bool no_error_inj; module_param(no_error_inj, bool, 0444); MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); +static unsigned int allocators[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0 }; +module_param_array(allocators, uint, NULL, 0444); +MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n" + "\t\t 0 == vmalloc\n" + "\t\t 1 == dma-contig"); + static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; const struct v4l2_rect vivid_min_rect = { @@ -636,6 +643,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = V4L2_DV_BT_CEA_1280X720P60; + static const struct vb2_mem_ops * const vivid_mem_ops[2] = { + &vb2_vmalloc_memops, + &vb2_dma_contig_memops, + }; unsigned in_type_counter[4] = { 0, 0, 0, 0 }; unsigned out_type_counter[4] = { 0, 0, 0, 0 }; int ccs_cap = ccs_cap_mode[inst]; @@ -646,6 +657,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) struct video_device *vfd; struct vb2_queue *q; unsigned node_type = node_types[inst]; + unsigned int allocator = allocators[inst]; v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; int ret; int i; @@ -1039,6 +1051,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) goto unreg_dev; } + if (allocator == 1) + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + else if (allocator >= ARRAY_SIZE(vivid_mem_ops)) + allocator = 0; + /* start creating the vb2 queues */ if (dev->has_vid_cap) { /* initialize vid_cap queue */ @@ -1049,10 +1066,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_cap_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = vivid_mem_ops[allocator]; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; ret = vb2_queue_init(q); if (ret) @@ -1068,10 +1086,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_out_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = vivid_mem_ops[allocator]; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; ret = vb2_queue_init(q); if (ret) @@ -1087,10 +1106,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_cap_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = vivid_mem_ops[allocator]; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; ret = vb2_queue_init(q); if (ret) @@ -1106,10 +1126,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_out_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = vivid_mem_ops[allocator]; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; ret = vb2_queue_init(q); if (ret) @@ -1124,10 +1145,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_sdr_cap_qops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = vivid_mem_ops[allocator]; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 8; q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; ret = vb2_queue_init(q); if (ret) -- cgit v1.2.3 From 6830733d53a4517588e56227b9c8538633f0c496 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 2 Feb 2017 12:53:04 -0200 Subject: [media] pvrusb2: reduce stack usage pvr2_eeprom_analyze() The driver uses a relatively large data structure on the stack, which showed up on my radar as we get a warning with the "latent entropy" GCC plugin: drivers/media/usb/pvrusb2/pvrusb2-eeprom.c:153:1: error: the frame size of 1376 bytes is larger than 1152 bytes [-Werror=frame-larger-than=] The warning is usually hidden as we raise the warning limit to 2048 when the plugin is enabled, but I'd like to lower that again in the future, and making this function smaller helps to do that without build regressions. Further analysis shows that putting an 'i2c_client' structure on the stack is not really supported, as the embedded 'struct device' is not initialized here, and we are only saved by the fact that the function that is called here does not use the pointer at all. Fixes: d855497edbfb ("V4L/DVB (4228a): pvrusb2 to kernel 2.6.18") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-eeprom.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 4af2fb5c85d5..7252f113df2f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -118,15 +118,10 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) memset(&tvdata,0,sizeof(tvdata)); eeprom = pvr2_eeprom_fetch(hdw); - if (!eeprom) return -EINVAL; - - { - struct i2c_client fake_client; - /* Newer version expects a useless client interface */ - fake_client.addr = hdw->eeprom_addr; - fake_client.adapter = &hdw->i2c_adap; - tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom); - } + if (!eeprom) + return -EINVAL; + + tveeprom_hauppauge_analog(NULL, &tvdata, eeprom); trace_eeprom("eeprom assumed v4l tveeprom module"); trace_eeprom("eeprom direct call results:"); -- cgit v1.2.3 From 4063987c9bb419bb14d83b9ad812ad3d6a3c65e4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 2 Feb 2017 12:53:06 -0200 Subject: [media] cx231xx-i2c: reduce stack size in bus scan The cx231xx_do_i2c_scan function needs a lot of stack because it puts an i2c_client structure on it: drivers/media/usb/cx231xx/cx231xx-i2c.c: In function 'cx231xx_do_i2c_scan': drivers/media/usb/cx231xx/cx231xx-i2c.c:518:1: error: the frame size of 1248 bytes is larger than 1152 bytes [-Werror=frame-larger-than=] This changes it to call i2c_transfer() directly instead, avoiding the need for the structure. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-i2c.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 35e9acfe63d3..24e23a06d8c6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -491,20 +491,24 @@ void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port) { unsigned char buf; int i, rc; - struct i2c_client client; + struct i2c_adapter *adap; + struct i2c_msg msg = { + .flags = I2C_M_RD, + .len = 1, + .buf = &buf, + }; if (!i2c_scan) return; /* Don't generate I2C errors during scan */ dev->i2c_scan_running = true; - - memset(&client, 0, sizeof(client)); - client.adapter = cx231xx_get_i2c_adap(dev, i2c_port); + adap = cx231xx_get_i2c_adap(dev, i2c_port); for (i = 0; i < 128; i++) { - client.addr = i; - rc = i2c_master_recv(&client, &buf, 0); + msg.addr = i; + rc = i2c_transfer(adap, &msg, 1); + if (rc < 0) continue; dev_info(dev->dev, -- cgit v1.2.3 From 371d1143a5581718f7c687e4da259f80ab0c4634 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 2 Feb 2017 12:53:07 -0200 Subject: [media] mxl111sf: reduce stack usage in init function mxl111sf uses a lot of kernel stack memory as it puts an i2c_client structure on the stack: drivers/media/usb/dvb-usb-v2/mxl111sf.c: In function 'mxl111sf_init': drivers/media/usb/dvb-usb-v2/mxl111sf.c:953:1: error: the frame size of 1248 bytes is larger than 1152 bytes [-Werror=frame-larger-than=] We can avoid doing this by open-coding the call to i2c_transfer() instead of calling tveeprom_read(), and not passing an i2c_client pointer to tveeprom_hauppauge_analog(), which would ignore that anyway. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 80c635980526..60bc5cc9a483 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -919,7 +919,12 @@ static int mxl111sf_init(struct dvb_usb_device *d) struct mxl111sf_state *state = d_to_priv(d); int ret; static u8 eeprom[256]; - struct i2c_client c; + u8 reg = 0; + struct i2c_msg msg[2] = { + { .addr = 0xa0 >> 1, .len = 1, .buf = ® }, + { .addr = 0xa0 >> 1, .flags = I2C_M_RD, + .len = sizeof(eeprom), .buf = eeprom }, + }; ret = get_chip_info(state); if (mxl_fail(ret)) @@ -930,13 +935,10 @@ static int mxl111sf_init(struct dvb_usb_device *d) if (state->chip_rev > MXL111SF_V6) mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); - c.adapter = &d->i2c_adap; - c.addr = 0xa0 >> 1; - - ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); + ret = i2c_transfer(&d->i2c_adap, msg, 2); if (mxl_fail(ret)) return 0; - tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? + tveeprom_hauppauge_analog(NULL, &state->tv, (0x84 == eeprom[0xa0]) ? eeprom + 0xa0 : eeprom + 0x80); #if 0 switch (state->tv.model) { -- cgit v1.2.3 From 3538aa6ecfb2dd727a40f9ebbbf25a0c2afe6226 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Feb 2017 19:14:13 -0200 Subject: [media] tc358743: fix register i2c_rd/wr functions While testing with CONFIG_UBSAN, I got this warning: drivers/media/i2c/tc358743.c: In function 'tc358743_probe': drivers/media/i2c/tc358743.c:1930:1: error: the frame size of 2480 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] The problem is that the i2c_rd8/wr8/rd16/... functions in this driver pass a pointer to a local variable into a common function, and each call to one of them adds another variable plus redzone to the stack. I also noticed that the way this is done is broken on big-endian machines, as we copy the registers in CPU byte order. To address both those problems, I'm adding two helper functions for reading a register of up to 32 bits with correct endianess and change all other functions to use that instead. Just to be sure we don't get the problem back with changed optimizations in gcc, I'm also marking the new functions as 'noinline', although my tests with gcc-7 don't require that. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 46 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index f569a05fe105..140c804a6dc3 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -194,57 +194,61 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) } } -static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) +static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) { - u8 val; + __le32 val = 0; - i2c_rd(sd, reg, &val, 1); + i2c_rd(sd, reg, (u8 __force *)&val, n); - return val; + return le32_to_cpu(val); +} + +static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) +{ + __le32 raw = cpu_to_le32(val); + + i2c_wr(sd, reg, (u8 __force *)&raw, n); +} + +static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) +{ + return i2c_rdreg(sd, reg, 1); } static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) { - i2c_wr(sd, reg, &val, 1); + i2c_wrreg(sd, reg, val, 1); } static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, u8 mask, u8 val) { - i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); + i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); } static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) { - u16 val; - - i2c_rd(sd, reg, (u8 *)&val, 2); - - return val; + return i2c_rdreg(sd, reg, 2); } static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) { - i2c_wr(sd, reg, (u8 *)&val, 2); + i2c_wrreg(sd, reg, val, 2); } static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) { - i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); + i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); } static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) { - u32 val; - - i2c_rd(sd, reg, (u8 *)&val, 4); - - return val; + return i2c_rdreg(sd, reg, 4); } static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) { - i2c_wr(sd, reg, (u8 *)&val, 4); + i2c_wrreg(sd, reg, val, 4); } /* --------------- STATUS --------------- */ @@ -1227,7 +1231,7 @@ static int tc358743_g_register(struct v4l2_subdev *sd, reg->size = tc358743_get_reg_size(reg->reg); - i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); + reg->val = i2c_rdreg(sd, reg->reg, reg->size); return 0; } @@ -1253,7 +1257,7 @@ static int tc358743_s_register(struct v4l2_subdev *sd, reg->reg == BCAPS) return 0; - i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, + i2c_wrreg(sd, (u16)reg->reg, reg->val, tc358743_get_reg_size(reg->reg)); return 0; -- cgit v1.2.3 From 227dc9b6bfdfe994ea67b26e6c8d72e4c21bd743 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 9 Feb 2017 13:09:08 -0200 Subject: [media] coda/imx-vdoa: platform_driver should not be const The device driver platform is actually written to during registration, for setting the owner field, so platform_driver_register() does not take a const pointer: drivers/media/platform/coda/imx-vdoa.c: In function 'vdoa_driver_init': drivers/media/platform/coda/imx-vdoa.c:333:213: error: passing argument 1 of '__platform_driver_register' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] module_platform_driver(vdoa_driver); In file included from drivers/media/platform/coda/imx-vdoa.c:22:0: include/linux/platform_device.h:199:12: note: expected 'struct platform_driver *' but argument is of type 'const struct platform_driver *' extern int __platform_driver_register(struct platform_driver *, ^~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/media/platform/coda/imx-vdoa.c: In function 'vdoa_driver_exit': drivers/media/platform/coda/imx-vdoa.c:333:626: error: passing argument 1 of 'platform_driver_unregister' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] Remove the modifier again. Fixes: d2fe28feaebb ("[media] coda/imx-vdoa: constify structs") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/imx-vdoa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c index 67fd8ffa60a4..669a4c82f1ff 100644 --- a/drivers/media/platform/coda/imx-vdoa.c +++ b/drivers/media/platform/coda/imx-vdoa.c @@ -321,7 +321,7 @@ static const struct of_device_id vdoa_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, vdoa_dt_ids); -static const struct platform_driver vdoa_driver = { +static struct platform_driver vdoa_driver = { .probe = vdoa_probe, .remove = vdoa_remove, .driver = { -- cgit v1.2.3 From 6e9b73c695022b2c083517aaed455671ed0cdb2b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Feb 2017 13:14:13 -0200 Subject: [media] cec.h: small typo fix ad -> as It won't bring about world peace, but every little bit helps :-) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/cec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 14b6f24b189e..a0dfe27bc6c7 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -223,7 +223,7 @@ static inline int cec_msg_status_is_ok(const struct cec_msg *msg) #define CEC_LOG_ADDR_BACKUP_2 13 #define CEC_LOG_ADDR_SPECIFIC 14 #define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */ -#define CEC_LOG_ADDR_BROADCAST 15 /* ad destination address */ +#define CEC_LOG_ADDR_BROADCAST 15 /* as destination address */ /* The logical address types that the CEC device wants to claim */ #define CEC_LOG_ADDR_TYPE_TV 0 -- cgit v1.2.3 From 3406e89ae11407187596f5a2c2c156bc0fa87713 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 10 Feb 2017 06:19:14 -0200 Subject: [media] vidioc-g-dv-timings.rst: update v4l2_bt_timings struct The new picture_aspect, cea861_vic and hdmi_vic fields were not documented, even though the corresponding flags were. Add documentation for these new fields. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst index aea276502f5e..e573c74138de 100644 --- a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst +++ b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst @@ -146,8 +146,20 @@ EBUSY - ``flags`` - Several flags giving more information about the format. See :ref:`dv-bt-flags` for a description of the flags. - * - __u32 - - ``reserved[14]`` + * - struct :c:type:`v4l2_fract` + - ``picture_aspect`` + - The picture aspect if the pixels are not square. Only valid if the + ``V4L2_DV_FL_HAS_PICTURE_ASPECT`` flag is set. + * - __u8 + - ``cea861_vic`` + - The Video Identification Code according to the CEA-861 standard. + Only valid if the ``V4L2_DV_FL_HAS_CEA861_VIC`` flag is set. + * - __u8 + - ``hdmi_vic`` + - The Video Identification Code according to the HDMI standard. + Only valid if the ``V4L2_DV_FL_HAS_HDMI_VIC`` flag is set. + * - __u8 + - ``reserved[46]`` - Reserved for future extensions. Drivers and applications must set the array to zero. -- cgit v1.2.3 From 446aba663b8240b24202cb8902b0d5c8f91aa3da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 3 Mar 2017 07:28:29 -0300 Subject: [media] tveeprom: get rid of unused arg on tveeprom_hauppauge_analog() tveeprom_hauppauge_analog() used to need the I2C adapter in order to print debug messages. As it now uses pr_foo() facilities since commit 6037b3ca28f4 ("[media] tveeprom: print log messages using pr_foo()"), the first argument of the function is not needed anymore. So, get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tveeprom.c | 4 ++-- drivers/media/pci/bt8xx/bttv-cards.c | 2 +- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/cx23885/cx23885-cards.c | 3 +-- drivers/media/pci/cx88/cx88-cards.c | 2 +- drivers/media/pci/ivtv/ivtv-driver.c | 2 +- drivers/media/pci/saa7134/saa7134-cards.c | 2 +- drivers/media/pci/saa7164/saa7164-cards.c | 4 +--- drivers/media/usb/au0828/au0828-cards.c | 2 +- drivers/media/usb/cx231xx/cx231xx-cards.c | 3 +-- drivers/media/usb/dvb-usb-v2/mxl111sf.c | 4 ++-- drivers/media/usb/em28xx/em28xx-cards.c | 3 +-- drivers/media/usb/pvrusb2/pvrusb2-eeprom.c | 2 +- include/media/tveeprom.h | 2 +- 14 files changed, 16 insertions(+), 21 deletions(-) diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c index 6e1020227f9f..ccf2d3b12aec 100644 --- a/drivers/media/common/tveeprom.c +++ b/drivers/media/common/tveeprom.c @@ -420,8 +420,8 @@ static int hasRadioTuner(int tunerType) return 0; } -void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, - unsigned char *eeprom_data) +void tveeprom_hauppauge_analog(struct tveeprom *tvee, + unsigned char *eeprom_data) { /* ---------------------------------------------- ** The hauppauge eeprom format is tagged diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index a1b0f3193bc0..5cc42b426715 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3717,7 +3717,7 @@ static void hauppauge_eeprom(struct bttv *btv) { struct tveeprom tv; - tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); + tveeprom_hauppauge_analog(&tv, eeprom_data); btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 206db81ef78e..8bce49cdad46 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -339,7 +339,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: case CX18_CARD_HVR_1600_S5H1411: - tveeprom_hauppauge_analog(c, tv, eedata); + tveeprom_hauppauge_analog(tv, eedata); break; case CX18_CARD_YUAN_MPC718: case CX18_CARD_GOTVIEW_PCI_DVD3: diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 0350f13c5a9f..9e39aea85df6 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1143,8 +1143,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) { struct tveeprom tv; - tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, - eeprom_data); + tveeprom_hauppauge_analog(&tv, eeprom_data); /* Make sure we support the board model */ switch (tv.model) { diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index cdfbde277b8b..61e1803882d9 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -2854,7 +2854,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { struct tveeprom tv; - tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); + tveeprom_hauppauge_analog(&tv, eeprom_data); core->board.tuner_type = tv.tuner_type; core->tuner_formats = tv.tuner_formats; core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index ab2ae53618e8..aaccc1187791 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -408,7 +408,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) itv->i2c_client.addr = 0xA0 >> 1; tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); - tveeprom_hauppauge_a