summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Andreyanau <a.andreyanau@sam-solutions.net>2013-05-07 13:26:43 +0300
committerJustin Waters <justin.waters@timesys.com>2013-11-07 12:19:31 -0500
commitd27f81d4395980edc5c45ad2f146a57bd8f9ebf6 (patch)
tree23bd32142ce0f577f5115f89e9ddf020c66be612
parent546d12ff33b4ab944c37903dbf7764fc1afd4b09 (diff)
Added support for specific setting for different resolutions for MT9P031 camera. Fixed support for switching on/off internal pll of MT9P031 camera and selecion of various target clocks (through the params got from the board specific code).
modified: drivers/media/video/mt9p031.c Signed-off-by: Uladzimir Bely <u.bely@sam-solutions.net> Signed-off-by: Christian Hemp <c.hemp@phytec.de>
-rw-r--r--drivers/media/video/mt9p031.c108
1 files changed, 77 insertions, 31 deletions
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index e9f9b97727dc..ea5eec125b23 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -83,8 +83,6 @@
#define MT9P031_TEST_PATTERN_RED 0xa2
#define MT9P031_TEST_PATTERN_BLUE 0xa3
-#define MT9P031_TARGET_FREQ_DEF 96000000
-
static bool g_is_mono;
module_param_named(mono, g_is_mono, bool, 0444);
@@ -211,8 +209,8 @@ static void mt9p031_video_remove(struct soc_camera_device *icd)
/*TODO: add new dividers */
static const struct mt9p031_pll_divs mt9p031_divs[] = {
/* ext_freq target_freq m n p1 */
-// {26400000, MT9P031_TARGET_FREQ_DEF, 29, 2, 8} //This is for 48MHz PCLK
- {26400000, MT9P031_TARGET_FREQ_DEF, 58, 2, 8}
+ {26400000, 48000000, 29, 2, 8},
+ {26400000, 96000000, 58, 2, 8}
};
static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
@@ -223,19 +221,24 @@ static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
struct mxc_camera_dev *mxc_cam = ici->priv;
int i;
+ if ((mxc_cam->pdata->mclk_default_rate ==
+ mxc_cam->pdata->mclk_target_rate) ||
+ (!mxc_cam->pdata->use_pll)) {
+ mt9p031->use_pll = false;
+ return 0;
+ }
+
for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) {
- if (mt9p031_divs[i].ext_freq == mxc_cam->pdata->mclk_default_rate) {
+ if (mt9p031_divs[i].ext_freq ==
+ mxc_cam->pdata->mclk_default_rate &&
+ mt9p031_divs[i].target_freq ==
+ mxc_cam->pdata->mclk_target_rate) {
mt9p031->pll = &mt9p031_divs[i];
mt9p031->use_pll = true;
return 0;
}
}
- if (mxc_cam->pdata->mclk_default_rate == MT9P031_TARGET_FREQ_DEF) {
- mt9p031->use_pll = false;
- return 0;
- }
-
dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %ld\n", mxc_cam->pdata->mclk_default_rate);
return -EINVAL;
}
@@ -347,29 +350,14 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031)
unsigned int ybin;
unsigned int width;
unsigned int height;
+ unsigned int crop_top = crop->top;
+ unsigned int crop_left = crop->left;
+ unsigned int crop_width = crop->width;
+ unsigned int crop_height = crop->height;
int shutter_width_upper;
int shutter_width_lower;
int ret;
- /* Windows position and size.
- *
- * TODO: Make sure the start coordinates and window size match the
- * skipping, binning and mirroring (see description of registers 2 and 4
- * in table 13, and Binning section on page 41).
- */
- ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left);
- if (ret < 0)
- return ret;
- ret = mt9p031_write(client, MT9P031_ROW_START, crop->top);
- if (ret < 0)
- return ret;
- ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1);
- if (ret < 0)
- return ret;
- ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1);
- if (ret < 0)
- return ret;
-
/* Row and column binning and skipping. Use the maximum binning value
* compatible with the skipping settings.
*/
@@ -382,9 +370,67 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031)
mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER, height - 1);
- xskip = DIV_ROUND_CLOSEST(crop->width, width);
- yskip = DIV_ROUND_CLOSEST(crop->height, height);
+ switch (width) {
+ case (2048):
+ crop_top = crop->top + ((2592 - 2048) / 2);
+ crop_left = crop->left + ((1944 - 1536) / 2);
+ break;
+ case (1920):
+ crop_top = crop->top + ((2592 - 1920) / 2);
+ crop_left = crop->left + ((1944 - 1080) / 2);
+ break;
+ case (1600):
+ crop_top = crop->top + ((2592 - 1600) / 2);
+ crop_left = crop->left + ((1944 - 1200) / 2);
+ break;
+ case (1280):
+ if (height == 1024) {
+ crop_top = crop->top + ((2592 - width) / 2);
+ crop_left = crop->left + ((1944 - height) / 2);
+ } else if (height == 720) {
+ crop_width = 2560;
+ crop_top = crop->top + ((2592 - crop_width) / 2);
+ crop_height = 1440;
+ crop_left = crop->left + ((1944 - crop_height) / 2);
+ }
+ break;
+ case (1024):
+ crop_width = 2048;
+ crop_top = crop->top + ((2592 - crop_width) / 2);
+ crop_height = 1536;
+ crop_left = crop->left + ((1944 - crop_height) / 2);
+ break;
+ case (800):
+ crop_width = 1600;
+ crop_top = crop->top + ((2592 - crop_width) / 2);
+ crop_height = 1200;
+ crop_left = crop->left + ((1944 - crop_height) / 2);
+ break;
+ case (640):
+ crop_width = 2560;
+ crop_top = crop->top + ((2592 - crop_width) / 2);
+ crop_height = 1920;
+ crop_left = crop->left + ((1944 - crop_height) / 2);
+ break;
+ default:
+ break;
+ }
+
+ ret = mt9p031_write(client, MT9P031_COLUMN_START, crop_left);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_write(client, MT9P031_ROW_START, crop_top);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop_width - 1);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop_height - 1);
+ if (ret < 0)
+ return ret;
+ xskip = DIV_ROUND_CLOSEST(crop_width, width);
+ yskip = DIV_ROUND_CLOSEST(crop_height, height);
xbin = 1 << (ffs(xskip) - 1);
ybin = 1 << (ffs(yskip) - 1);