aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-12-11 09:53:45 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-16 06:27:30 -0500
commita6b5f2008a3d54b5f5350a01121b718dd6bfead7 (patch)
tree55d3f6551a548f01a031f26ff845163985b59e14
parent760697beca338599a65484389c7abbe54aedb664 (diff)
V4L/DVB (13661): rj54n1cb0c: Add cropping, auto white balance, restrict sizes, add platform data
It has been experimentally found out, that the sensor only supports up to 512x384 video output and also has some restrictions on minimum scale. We disable non-working size ranges until, maybe, someone finds out how to properly set them up. Also add cropping support, an auto white balance control, platform data to specify master clock frequency and polarity of the IOCTL pin. create mode 100644 include/media/rj54n1cb0c.h Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c13
-rw-r--r--drivers/media/video/rj54n1cb0c.c277
-rw-r--r--include/media/rj54n1cb0c.h19
3 files changed, 261 insertions, 48 deletions
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 87438d6603d6..9038d768a525 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -19,6 +19,7 @@
19#include <linux/input/sh_keysc.h> 19#include <linux/input/sh_keysc.h>
20#include <linux/i2c.h> 20#include <linux/i2c.h>
21#include <linux/usb/r8a66597.h> 21#include <linux/usb/r8a66597.h>
22#include <media/rj54n1cb0c.h>
22#include <media/soc_camera.h> 23#include <media/soc_camera.h>
23#include <media/sh_mobile_ceu.h> 24#include <media/sh_mobile_ceu.h>
24#include <video/sh_mobile_lcdc.h> 25#include <video/sh_mobile_lcdc.h>
@@ -255,6 +256,9 @@ static struct i2c_board_info kfr2r09_i2c_camera = {
255 256
256static struct clk *camera_clk; 257static struct clk *camera_clk;
257 258
259/* set VIO_CKO clock to 25MHz */
260#define CEU_MCLK_FREQ 25000000
261
258#define DRVCRB 0xA405018C 262#define DRVCRB 0xA405018C
259static int camera_power(struct device *dev, int mode) 263static int camera_power(struct device *dev, int mode)
260{ 264{
@@ -267,8 +271,7 @@ static int camera_power(struct device *dev, int mode)
267 if (IS_ERR(camera_clk)) 271 if (IS_ERR(camera_clk))
268 return PTR_ERR(camera_clk); 272 return PTR_ERR(camera_clk);
269 273
270 /* set VIO_CKO clock to 25MHz */ 274 rate = clk_round_rate(camera_clk, CEU_MCLK_FREQ);
271 rate = clk_round_rate(camera_clk, 25000000);
272 ret = clk_set_rate(camera_clk, rate); 275 ret = clk_set_rate(camera_clk, rate);
273 if (ret < 0) 276 if (ret < 0)
274 goto eclkrate; 277 goto eclkrate;
@@ -318,11 +321,17 @@ eclkrate:
318 return ret; 321 return ret;
319} 322}
320 323
324static struct rj54n1_pdata rj54n1_priv = {
325 .mclk_freq = CEU_MCLK_FREQ,
326 .ioctl_high = false,
327};
328
321static struct soc_camera_link rj54n1_link = { 329static struct soc_camera_link rj54n1_link = {
322 .power = camera_power, 330 .power = camera_power,
323 .board_info = &kfr2r09_i2c_camera, 331 .board_info = &kfr2r09_i2c_camera,
324 .i2c_adapter_id = 1, 332 .i2c_adapter_id = 1,
325 .module_name = "rj54n1cb0c", 333 .module_name = "rj54n1cb0c",
334 .priv = &rj54n1_priv,
326}; 335};
327 336
328static struct platform_device kfr2r09_camera = { 337static struct platform_device kfr2r09_camera = {
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 7b08bff443f5..7e42989ce0e4 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -13,10 +13,11 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/videodev2.h> 14#include <linux/videodev2.h>
15 15
16#include <media/v4l2-subdev.h> 16#include <media/rj54n1cb0c.h>
17#include <media/v4l2-chip-ident.h>
18#include <media/soc_camera.h> 17#include <media/soc_camera.h>
19#include <media/soc_mediabus.h> 18#include <media/soc_mediabus.h>
19#include <media/v4l2-subdev.h>
20#include <media/v4l2-chip-ident.h>
20 21
21#define RJ54N1_DEV_CODE 0x0400 22#define RJ54N1_DEV_CODE 0x0400
22#define RJ54N1_DEV_CODE2 0x0401 23#define RJ54N1_DEV_CODE2 0x0401
@@ -39,6 +40,7 @@
39#define RJ54N1_H_OBEN_OFS 0x0413 40#define RJ54N1_H_OBEN_OFS 0x0413
40#define RJ54N1_V_OBEN_OFS 0x0414 41#define RJ54N1_V_OBEN_OFS 0x0414
41#define RJ54N1_RESIZE_CONTROL 0x0415 42#define RJ54N1_RESIZE_CONTROL 0x0415
43#define RJ54N1_STILL_CONTROL 0x0417
42#define RJ54N1_INC_USE_SEL_H 0x0425 44#define RJ54N1_INC_USE_SEL_H 0x0425
43#define RJ54N1_INC_USE_SEL_L 0x0426 45#define RJ54N1_INC_USE_SEL_L 0x0426
44#define RJ54N1_MIRROR_STILL_MODE 0x0427 46#define RJ54N1_MIRROR_STILL_MODE 0x0427
@@ -50,10 +52,21 @@
50#define RJ54N1_RA_SEL_UL 0x0530 52#define RJ54N1_RA_SEL_UL 0x0530
51#define RJ54N1_BYTE_SWAP 0x0531 53#define RJ54N1_BYTE_SWAP 0x0531
52#define RJ54N1_OUT_SIGPO 0x053b 54#define RJ54N1_OUT_SIGPO 0x053b
55#define RJ54N1_WB_SEL_WEIGHT_I 0x054e
56#define RJ54N1_BIT8_WB 0x0569
57#define RJ54N1_HCAPS_WB 0x056a
58#define RJ54N1_VCAPS_WB 0x056b
59#define RJ54N1_HCAPE_WB 0x056c
60#define RJ54N1_VCAPE_WB 0x056d
61#define RJ54N1_EXPOSURE_CONTROL 0x058c
53#define RJ54N1_FRAME_LENGTH_S_H 0x0595 62#define RJ54N1_FRAME_LENGTH_S_H 0x0595
54#define RJ54N1_FRAME_LENGTH_S_L 0x0596 63#define RJ54N1_FRAME_LENGTH_S_L 0x0596
55#define RJ54N1_FRAME_LENGTH_P_H 0x0597 64#define RJ54N1_FRAME_LENGTH_P_H 0x0597
56#define RJ54N1_FRAME_LENGTH_P_L 0x0598 65#define RJ54N1_FRAME_LENGTH_P_L 0x0598
66#define RJ54N1_PEAK_H 0x05b7
67#define RJ54N1_PEAK_50 0x05b8
68#define RJ54N1_PEAK_60 0x05b9
69#define RJ54N1_PEAK_DIFF 0x05ba
57#define RJ54N1_IOC 0x05ef 70#define RJ54N1_IOC 0x05ef
58#define RJ54N1_TG_BYPASS 0x0700 71#define RJ54N1_TG_BYPASS 0x0700
59#define RJ54N1_PLL_L 0x0701 72#define RJ54N1_PLL_L 0x0701
@@ -69,6 +82,7 @@
69#define RJ54N1_OCLK_SEL_EN 0x0713 82#define RJ54N1_OCLK_SEL_EN 0x0713
70#define RJ54N1_CLK_RST 0x0717 83#define RJ54N1_CLK_RST 0x0717
71#define RJ54N1_RESET_STANDBY 0x0718 84#define RJ54N1_RESET_STANDBY 0x0718
85#define RJ54N1_FWFLG 0x07fe
72 86
73#define E_EXCLK (1 << 7) 87#define E_EXCLK (1 << 7)
74#define SOFT_STDBY (1 << 4) 88#define SOFT_STDBY (1 << 4)
@@ -79,11 +93,18 @@
79#define RESIZE_HOLD_SEL (1 << 2) 93#define RESIZE_HOLD_SEL (1 << 2)
80#define RESIZE_GO (1 << 1) 94#define RESIZE_GO (1 << 1)
81 95
96/*
97 * When cropping, the camera automatically centers the cropped region, there
98 * doesn't seem to be a way to specify an explicit location of the rectangle.
99 */
82#define RJ54N1_COLUMN_SKIP 0 100#define RJ54N1_COLUMN_SKIP 0
83#define RJ54N1_ROW_SKIP 0 101#define RJ54N1_ROW_SKIP 0
84#define RJ54N1_MAX_WIDTH 1600 102#define RJ54N1_MAX_WIDTH 1600
85#define RJ54N1_MAX_HEIGHT 1200 103#define RJ54N1_MAX_HEIGHT 1200
86 104
105#define PLL_L 2
106#define PLL_N 0x31
107
87/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ 108/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
88 109
89/* RJ54N1CB0C has only one fixed colorspace per pixelcode */ 110/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
@@ -118,7 +139,7 @@ static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
118}; 139};
119 140
120struct rj54n1_clock_div { 141struct rj54n1_clock_div {
121 u8 ratio_tg; 142 u8 ratio_tg; /* can be 0 or an odd number */
122 u8 ratio_t; 143 u8 ratio_t;
123 u8 ratio_r; 144 u8 ratio_r;
124 u8 ratio_op; 145 u8 ratio_op;
@@ -127,12 +148,14 @@ struct rj54n1_clock_div {
127 148
128struct rj54n1 { 149struct rj54n1 {
129 struct v4l2_subdev subdev; 150 struct v4l2_subdev subdev;
151 struct rj54n1_clock_div clk_div;
130 const struct rj54n1_datafmt *fmt; 152 const struct rj54n1_datafmt *fmt;
131 struct v4l2_rect rect; /* Sensor window */ 153 struct v4l2_rect rect; /* Sensor window */
154 unsigned int tgclk_mhz;
155 bool auto_wb;
132 unsigned short width; /* Output window */ 156 unsigned short width; /* Output window */
133 unsigned short height; 157 unsigned short height;
134 unsigned short resize; /* Sensor * 1024 / resize = Output */ 158 unsigned short resize; /* Sensor * 1024 / resize = Output */
135 struct rj54n1_clock_div clk_div;
136 unsigned short scale; 159 unsigned short scale;
137 u8 bank; 160 u8 bank;
138}; 161};
@@ -189,7 +212,7 @@ const static struct rj54n1_reg_val bank_7[] = {
189 {0x714, 0xff}, 212 {0x714, 0xff},
190 {0x715, 0xff}, 213 {0x715, 0xff},
191 {0x716, 0x1f}, 214 {0x716, 0x1f},
192 {0x7FE, 0x02}, 215 {0x7FE, 2},
193}; 216};
194 217
195const static struct rj54n1_reg_val bank_8[] = { 218const static struct rj54n1_reg_val bank_8[] = {
@@ -377,7 +400,7 @@ const static struct rj54n1_reg_val bank_8[] = {
377 {0x8BB, 0x00}, 400 {0x8BB, 0x00},
378 {0x8BC, 0xFF}, 401 {0x8BC, 0xFF},
379 {0x8BD, 0x00}, 402 {0x8BD, 0x00},
380 {0x8FE, 0x02}, 403 {0x8FE, 2},
381}; 404};
382 405
383const static struct rj54n1_reg_val bank_10[] = { 406const static struct rj54n1_reg_val bank_10[] = {
@@ -470,8 +493,10 @@ static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index,
470 493
471static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) 494static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
472{ 495{
473 /* TODO: start / stop streaming */ 496 struct i2c_client *client = sd->priv;
474 return 0; 497
498 /* Switch between preview and still shot modes */
499 return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
475} 500}
476 501
477static int rj54n1_set_bus_param(struct soc_camera_device *icd, 502static int rj54n1_set_bus_param(struct soc_camera_device *icd,
@@ -530,6 +555,44 @@ static int rj54n1_commit(struct i2c_client *client)
530 return ret; 555 return ret;
531} 556}
532 557
558static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
559 u32 *out_w, u32 *out_h);
560
561static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
562{
563 struct i2c_client *client = sd->priv;
564 struct rj54n1 *rj54n1 = to_rj54n1(client);
565 struct v4l2_rect *rect = &a->c;
566 unsigned int dummy, output_w, output_h,
567 input_w = rect->width, input_h = rect->height;
568 int ret;
569
570 /* arbitrary minimum width and height, edges unimportant */
571 soc_camera_limit_side(&dummy, &input_w,
572 RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
573
574 soc_camera_limit_side(&dummy, &input_h,
575 RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
576
577 output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
578 output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
579
580 dev_dbg(&client->dev, "Scaling for %ux%u : %u = %ux%u\n",
581 input_w, input_h, rj54n1->resize, output_w, output_h);
582
583 ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
584 if (ret < 0)
585 return ret;
586
587 rj54n1->width = output_w;
588 rj54n1->height = output_h;
589 rj54n1->resize = ret;
590 rj54n1->rect.width = input_w;
591 rj54n1->rect.height = input_h;
592
593 return 0;
594}
595
533static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 596static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
534{ 597{
535 struct i2c_client *client = sd->priv; 598 struct i2c_client *client = sd->priv;
@@ -579,11 +642,44 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
579 u32 *out_w, u32 *out_h) 642 u32 *out_w, u32 *out_h)
580{ 643{
581 struct i2c_client *client = sd->priv; 644 struct i2c_client *client = sd->priv;
645 struct rj54n1 *rj54n1 = to_rj54n1(client);
582 unsigned int skip, resize, input_w = *in_w, input_h = *in_h, 646 unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
583 output_w = *out_w, output_h = *out_h; 647 output_w = *out_w, output_h = *out_h;
584 u16 inc_sel; 648 u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
649 unsigned int peak, peak_50, peak_60;
585 int ret; 650 int ret;
586 651
652 /*
653 * We have a problem with crops, where the window is larger than 512x384
654 * and output window is larger than a half of the input one. In this
655 * case we have to either reduce the input window to equal or below
656 * 512x384 or the output window to equal or below 1/2 of the input.
657 */
658 if (output_w > max(512U, input_w / 2)) {
659 if (2 * output_w > RJ54N1_MAX_WIDTH) {
660 input_w = RJ54N1_MAX_WIDTH;
661 output_w = RJ54N1_MAX_WIDTH / 2;
662 } else {
663 input_w = output_w * 2;
664 }
665
666 dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
667 input_w, output_w);
668 }
669
670 if (output_h > max(384U, input_h / 2)) {
671 if (2 * output_h > RJ54N1_MAX_HEIGHT) {
672 input_h = RJ54N1_MAX_HEIGHT;
673 output_h = RJ54N1_MAX_HEIGHT / 2;
674 } else {
675 input_h = output_h * 2;
676 }
677
678 dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
679 input_h, output_h);
680 }
681
682 /* Idea: use the read mode for snapshots, handle separate geometries */
587 ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, 683 ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
588 RJ54N1_Y_OUTPUT_SIZE_S_L, 684 RJ54N1_Y_OUTPUT_SIZE_S_L,
589 RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); 685 RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
@@ -595,17 +691,27 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
595 if (ret < 0) 691 if (ret < 0)
596 return ret; 692 return ret;
597 693
598 if (output_w > input_w || output_h > input_h) { 694 if (output_w > input_w && output_h > input_h) {
599 input_w = output_w; 695 input_w = output_w;
600 input_h = output_h; 696 input_h = output_h;
601 697
602 resize = 1024; 698 resize = 1024;
603 } else { 699 } else {
604 unsigned int resize_x, resize_y; 700 unsigned int resize_x, resize_y;
605 resize_x = input_w * 1024 / output_w; 701 resize_x = (input_w * 1024 + output_w / 2) / output_w;
606 resize_y = input_h * 1024 / output_h; 702 resize_y = (input_h * 1024 + output_h / 2) / output_h;
607 703
608 resize = min(resize_x, resize_y); 704 /* We want max(resize_x, resize_y), check if it still fits */
705 if (resize_x > resize_y &&
706 (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
707 resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
708 output_h;
709 else if (resize_y > resize_x &&
710 (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
711 resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
712 output_w;
713 else
714 resize = max(resize_x, resize_y);
609 715
610 /* Prohibited value ranges */ 716 /* Prohibited value ranges */
611 switch (resize) { 717 switch (resize) {
@@ -618,12 +724,9 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
618 case 8160 ... 8191: 724 case 8160 ... 8191:
619 resize = 8159; 725 resize = 8159;
620 break; 726 break;
621 case 16320 ... 16383: 727 case 16320 ... 16384:
622 resize = 16319; 728 resize = 16319;
623 } 729 }
624
625 input_w = output_w * resize / 1024;
626 input_h = output_h * resize / 1024;
627 } 730 }
628 731
629 /* Set scaling */ 732 /* Set scaling */
@@ -636,9 +739,18 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
636 739
637 /* 740 /*
638 * Configure a skipping bitmask. The sensor will select a skipping value 741 * Configure a skipping bitmask. The sensor will select a skipping value
639 * among set bits automatically. 742 * among set bits automatically. This is very unclear in the datasheet
743 * too. I was told, in this register one enables all skipping values,
744 * that are required for a specific resize, and the camera selects
745 * automatically, which ones to use. But it is unclear how to identify,
746 * which cropping values are needed. Secondly, why don't we just set all
747 * bits and let the camera choose? Would it increase processing time and
748 * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
749 * improve the image quality or stability for larger frames (see comment
750 * above), but I didn't check the framerate.
640 */ 751 */
641 skip = min(resize / 1024, (unsigned)15); 752 skip = min(resize / 1024, (unsigned)15);
753
642 inc_sel = 1 << skip; 754 inc_sel = 1 << skip;
643 755
644 if (inc_sel <= 2) 756 if (inc_sel <= 2)
@@ -650,6 +762,43 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
650 if (!ret) 762 if (!ret)
651 ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); 763 ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
652 764
765 if (!rj54n1->auto_wb) {
766 /* Auto white balance window */
767 wb_left = output_w / 16;
768 wb_right = (3 * output_w / 4 - 3) / 4;
769 wb_top = output_h / 16;
770 wb_bottom = (3 * output_h / 4 - 3) / 4;
771 wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
772 ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
773
774 if (!ret)
775 ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
776 if (!ret)
777 ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
778 if (!ret)
779 ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
780 if (!ret)
781 ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
782 if (!ret)
783 ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
784 }
785
786 /* Antiflicker */
787 peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
788 10000;
789 peak_50 = peak / 6;
790 peak_60 = peak / 5;
791
792 if (!ret)
793 ret = reg_write(client, RJ54N1_PEAK_H,
794 ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
795 if (!ret)
796 ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
797 if (!ret)
798 ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
799 if (!ret)
800 ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
801
653 /* Start resizing */ 802 /* Start resizing */
654 if (!ret) 803 if (!ret)
655 ret = reg_write(client, RJ54N1_RESIZE_CONTROL, 804 ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
@@ -658,8 +807,6 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
658 if (ret < 0) 807 if (ret < 0)
659 return ret; 808 return ret;
660 809
661 dev_dbg(&client->dev, "resize %u, skip %u\n", resize, skip);
662
663 /* Constant taken from manufacturer's example */ 810 /* Constant taken from manufacturer's example */
664 msleep(230); 811 msleep(230);
665 812
@@ -667,11 +814,14 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
667 if (ret < 0) 814 if (ret < 0)
668 return ret; 815 return ret;
669 816
670 *in_w = input_w; 817 *in_w = (output_w * resize + 512) / 1024;
671 *in_h = input_h; 818 *in_h = (output_h * resize + 512) / 1024;
672 *out_w = output_w; 819 *out_w = output_w;
673 *out_h = output_h; 820 *out_h = output_h;
674 821
822 dev_dbg(&client->dev, "Scaled for %ux%u : %u = %ux%u, skip %u\n",
823 *in_w, *in_h, resize, output_w, output_h, skip);
824
675 return resize; 825 return resize;
676} 826}
677 827
@@ -682,14 +832,14 @@ static int rj54n1_set_clock(struct i2c_client *client)
682 832
683 /* Enable external clock */ 833 /* Enable external clock */
684 ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); 834 ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
685 /* Leave stand-by */ 835 /* Leave stand-by. Note: use this when implementing suspend / resume */
686 if (!ret) 836 if (!ret)
687 ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); 837 ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
688 838
689 if (!ret) 839 if (!ret)
690 ret = reg_write(client, RJ54N1_PLL_L, 2); 840 ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
691 if (!ret) 841 if (!ret)
692 ret = reg_write(client, RJ54N1_PLL_N, 0x31); 842 ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
693 843
694 /* TGCLK dividers */ 844 /* TGCLK dividers */
695 if (!ret) 845 if (!ret)
@@ -748,6 +898,7 @@ static int rj54n1_set_clock(struct i2c_client *client)
748 "Resetting RJ54N1CB0C clock failed: %d!\n", ret); 898 "Resetting RJ54N1CB0C clock failed: %d!\n", ret);
749 return -EIO; 899 return -EIO;
750 } 900 }
901
751 /* Start the PLL */ 902 /* Start the PLL */
752 ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); 903 ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
753 904
@@ -760,6 +911,7 @@ static int rj54n1_set_clock(struct i2c_client *client)
760 911
761static int rj54n1_reg_init(struct i2c_client *client) 912static int rj54n1_reg_init(struct i2c_client *client)
762{ 913{
914 struct rj54n1 *rj54n1 = to_rj54n1(client);
763 int ret = rj54n1_set_clock(client); 915 int ret = rj54n1_set_clock(client);
764 916
765 if (!ret) 917 if (!ret)
@@ -782,14 +934,26 @@ static int rj54n1_reg_init(struct i2c_client *client)
782 if (!ret) 934 if (!ret)
783 ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); 935 ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
784 936
785 /* Mirror the image back: default is upside down and left-to-right... */ 937 /*
938 * Mirror the image back: default is upside down and left-to-right...
939 * Set manual preview / still shot switching
940 */
786 if (!ret) 941 if (!ret)
787 ret = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 3, 3); 942 ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
788 943
789 if (!ret) 944 if (!ret)
790 ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); 945 ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
946
947 /* Auto exposure area */
948 if (!ret)
949 ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
950 /* Check current auto WB config */
791 if (!ret) 951 if (!ret)
952 ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
953 if (ret >= 0) {
954 rj54n1->auto_wb = ret & 0x80;
792 ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); 955 ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
956 }
793 if (!ret) 957 if (!ret)
794 ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); 958 ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
795 959
@@ -806,8 +970,9 @@ static int rj54n1_reg_init(struct i2c_client *client)
806 ret = reg_write(client, RJ54N1_RESET_STANDBY, 970 ret = reg_write(client, RJ54N1_RESET_STANDBY,
807 E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); 971 E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
808 972
973 /* Start register update? Same register as 0x?FE in many bank_* sets */
809 if (!ret) 974 if (!ret)
810 ret = reg_write(client, 0x7fe, 2); 975 ret = reg_write(client, RJ54N1_FWFLG, 2);
811 976
812 /* Constant taken from manufacturer's example */ 977 /* Constant taken from manufacturer's example */
813 msleep(700); 978 msleep(700);
@@ -815,7 +980,6 @@ static int rj54n1_reg_init(struct i2c_client *client)
815 return ret; 980 return ret;
816} 981}
817 982
818/* FIXME: streaming output only up to 800x600 is functional */
819static int rj54n1_try_fmt(struct v4l2_subdev *sd, 983static int rj54n1_try_fmt(struct v4l2_subdev *sd,
820 struct v4l2_mbus_framefmt *mf) 984 struct v4l2_mbus_framefmt *mf)
821{ 985{
@@ -861,14 +1025,13 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
861 * The host driver can call us without .try_fmt(), so, we have to take 1025 * The host driver can call us without .try_fmt(), so, we have to take
862 * care ourseleves 1026 * care ourseleves
863 */ 1027 */
864 ret = rj54n1_try_fmt(sd, mf); 1028 rj54n1_try_fmt(sd, mf);
865 1029
866 /* 1030 /*
867 * Verify if the sensor has just been powered on. TODO: replace this 1031 * Verify if the sensor has just been powered on. TODO: replace this
868 * with proper PM, when a suitable API is available. 1032 * with proper PM, when a suitable API is available.
869 */ 1033 */
870 if (!ret) 1034 ret = reg_read(client, RJ54N1_RESET_STANDBY);
871 ret = reg_read(client, RJ54N1_RESET_STANDBY);
872 if (ret < 0) 1035 if (ret < 0)
873 return ret; 1036 return ret;
874 1037
@@ -878,6 +1041,9 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
878 return ret; 1041 return ret;
879 } 1042 }
880 1043
1044 dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
1045 __func__, mf->code, mf->width, mf->height);
1046
881 /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ 1047 /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
882 switch (mf->code) { 1048 switch (mf->code) {
883 case V4L2_MBUS_FMT_YUYV8_2X8_LE: 1049 case V4L2_MBUS_FMT_YUYV8_2X8_LE:
@@ -1062,6 +1228,14 @@ static const struct v4l2_queryctrl rj54n1_controls[] = {
1062 .step = 1, 1228 .step = 1,
1063 .default_value = 66, 1229 .default_value = 66,
1064 .flags = V4L2_CTRL_FLAG_SLIDER, 1230 .flags = V4L2_CTRL_FLAG_SLIDER,
1231 }, {
1232 .id = V4L2_CID_AUTO_WHITE_BALANCE,
1233 .type = V4L2_CTRL_TYPE_BOOLEAN,
1234 .name = "Auto white balance",
1235 .minimum = 0,
1236 .maximum = 1,
1237 .step = 1,
1238 .default_value = 1,
1065 }, 1239 },
1066}; 1240};
1067 1241
@@ -1075,6 +1249,7 @@ static struct soc_camera_ops rj54n1_ops = {
1075static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 1249static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
1076{ 1250{
1077 struct i2c_client *client = sd->priv; 1251 struct i2c_client *client = sd->priv;
1252 struct rj54n1 *rj54n1 = to_rj54n1(client);
1078 int data; 1253 int data;
1079 1254
1080 switch (ctrl->id) { 1255 switch (ctrl->id) {
@@ -1097,6 +1272,9 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
1097 1272
1098 ctrl->value = data / 2; 1273 ctrl->value = data / 2;
1099 break; 1274 break;
1275 case V4L2_CID_AUTO_WHITE_BALANCE:
1276 ctrl->value = rj54n1->auto_wb;
1277 break;
1100 } 1278 }
1101 1279
1102 return 0; 1280 return 0;
@@ -1106,6 +1284,7 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
1106{ 1284{
1107 int data; 1285 int data;
1108 struct i2c_client *client = sd->priv; 1286 struct i2c_client *client = sd->priv;
1287 struct rj54n1 *rj54n1 = to_rj54n1(client);
1109 const struct v4l2_queryctrl *qctrl; 1288 const struct v4l2_queryctrl *qctrl;
1110 1289
1111 qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); 1290 qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id);
@@ -1136,6 +1315,13 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
1136 else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) 1315 else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0)
1137 return -EIO; 1316 return -EIO;
1138 break; 1317 break;
1318 case V4L2_CID_AUTO_WHITE_BALANCE:
1319 /* Auto WB area - whole image */
1320 if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7,
1321 0x80) < 0)
1322 return -EIO;
1323 rj54n1->auto_wb = ctrl->value;
1324 break;
1139 } 1325 }
1140 1326
1141 return 0; 1327 return 0;
@@ -1158,6 +1344,7 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
1158 .try_mbus_fmt = rj54n1_try_fmt, 1344 .try_mbus_fmt = rj54n1_try_fmt,
1159 .enum_mbus_fmt = rj54n1_enum_fmt, 1345 .enum_mbus_fmt = rj54n1_enum_fmt,
1160 .g_crop = rj54n1_g_crop, 1346 .g_crop = rj54n1_g_crop,
1347 .s_crop = rj54n1_s_crop,
1161 .cropcap = rj54n1_cropcap, 1348 .cropcap = rj54n1_cropcap,
1162}; 1349};
1163 1350
@@ -1166,21 +1353,13 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = {
1166 .video = &rj54n1_subdev_video_ops, 1353 .video = &rj54n1_subdev_video_ops,
1167}; 1354};
1168 1355
1169static int rj54n1_pin_config(struct i2c_client *client)
1170{
1171 /*
1172 * Experimentally found out IOCTRL wired to 0. TODO: add to platform
1173 * data: 0 or 1 << 7.
1174 */
1175 return reg_write(client, RJ54N1_IOC, 0);
1176}
1177
1178/* 1356/*
1179 * Interface active, can use i2c. If it fails, it can indeed mean, that 1357 * Interface active, can use i2c. If it fails, it can indeed mean, that
1180 * this wasn't our capture interface, so, we wait for the right one 1358 * this wasn't our capture interface, so, we wait for the right one
1181 */ 1359 */
1182static int rj54n1_video_probe(struct soc_camera_device *icd, 1360static int rj54n1_video_probe(struct soc_camera_device *icd,
1183 struct i2c_client *client) 1361 struct i2c_client *client,
1362 struct rj54n1_pdata *priv)
1184{ 1363{
1185 int data1, data2; 1364 int data1, data2;
1186 int ret; 1365 int ret;
@@ -1201,7 +1380,8 @@ static int rj54n1_video_probe(struct soc_camera_device *icd,
1201 goto ei2c; 1380 goto ei2c;
1202 } 1381 }
1203 1382
1204 ret = rj54n1_pin_config(client); 1383 /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
1384 ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
1205 if (ret < 0) 1385 if (ret < 0)
1206 goto ei2c; 1386 goto ei2c;
1207 1387
@@ -1219,6 +1399,7 @@ static int rj54n1_probe(struct i2c_client *client,
1219 struct soc_camera_device *icd = client->dev.platform_data; 1399 struct soc_camera_device *icd = client->dev.platform_data;
1220 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 1400 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1221 struct soc_camera_link *icl; 1401 struct soc_camera_link *icl;
1402 struct rj54n1_pdata *rj54n1_priv;
1222 int ret; 1403 int ret;
1223 1404
1224 if (!icd) { 1405 if (!icd) {
@@ -1227,11 +1408,13 @@ static int rj54n1_probe(struct i2c_client *client,
1227 } 1408 }
1228 1409
1229 icl = to_soc_camera_link(icd); 1410 icl = to_soc_camera_link(icd);
1230 if (!icl) { 1411 if (!icl || !icl->priv) {
1231 dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); 1412 dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
1232 return -EINVAL; 1413 return -EINVAL;
1233 } 1414 }
1234 1415
1416 rj54n1_priv = icl->priv;
1417
1235 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 1418 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1236 dev_warn(&adapter->dev, 1419 dev_warn(&adapter->dev,
1237 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); 1420 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
@@ -1255,8 +1438,10 @@ static int rj54n1_probe(struct i2c_client *client,
1255 rj54n1->height = RJ54N1_MAX_HEIGHT; 1438 rj54n1->height = RJ54N1_MAX_HEIGHT;
1256 rj54n1->fmt = &rj54n1_colour_fmts[0]; 1439 rj54n1->fmt = &rj54n1_colour_fmts[0];
1257 rj54n1->resize = 1024; 1440 rj54n1->resize = 1024;
1441 rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
1442 (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
1258 1443
1259 ret = rj54n1_video_probe(icd, client); 1444 ret = rj54n1_video_probe(icd, client, rj54n1_priv);
1260 if (ret < 0) { 1445 if (ret < 0) {
1261 icd->ops = NULL; 1446 icd->ops = NULL;
1262 i2c_set_clientdata(client, NULL); 1447 i2c_set_clientdata(client, NULL);
diff --git a/include/media/rj54n1cb0c.h b/include/media/rj54n1cb0c.h
new file mode 100644
index 000000000000..8ae3288ae925
--- /dev/null
+++ b/include/media/rj54n1cb0c.h
@@ -0,0 +1,19 @@
1/*
2 * RJ54N1CB0C Private data
3 *
4 * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef __RJ54N1CB0C_H__
12#define __RJ54N1CB0C_H__
13
14struct rj54n1_pdata {
15 unsigned int mclk_freq;
16 bool ioctl_high;
17};
18
19#endif