1babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/* 2babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver 3babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * 4babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> 5babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> 6babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * 7babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * This program is free software; you can redistribute it and/or modify 8babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * it under the terms of the GNU General Public License as published 9babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * by the Free Software Foundation, either version 2 of the License, 10babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * or (at your option) any later version. 11babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */ 12babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ 13babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 14babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/bug.h> 15babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/clk.h> 16babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/delay.h> 17babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/device.h> 18babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/errno.h> 19babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/gpio.h> 20babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/i2c.h> 21babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/interrupt.h> 22babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/io.h> 23babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/kernel.h> 24babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/list.h> 25babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/module.h> 26babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/platform_device.h> 27babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/pm_runtime.h> 28babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/slab.h> 29babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/types.h> 30250539a36f69aa51e4c68a1f92c4ed2bcc042a1aSachin Kamat#include <linux/version.h> 31babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 32babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/media-device.h> 33babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/v4l2-ctrls.h> 34babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/v4l2-ioctl.h> 35babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/videobuf2-core.h> 36babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/videobuf2-dma-contig.h> 37babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 38babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include "camif-core.h" 39babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 40babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic char *camif_clocks[CLK_MAX_NUM] = { 41babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* HCLK CAMIF clock */ 42babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [CLK_GATE] = "camif", 43babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* CAMIF / external camera sensor master clock */ 44babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [CLK_CAM] = "camera", 45babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 46babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 47babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct camif_fmt camif_formats[] = { 48babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki { 49babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "YUV 4:2:2 planar, Y/Cb/Cr", 50babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_YUV422P, 51babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 16, 52babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 1, 53babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_YCBCR422P, 54babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 3, 55babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C24XX_CODEC | 56babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki FMT_FL_S3C64XX, 57babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 58babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "YUV 4:2:0 planar, Y/Cb/Cr", 59babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_YUV420, 60babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 12, 61babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 1, 62babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_YCBCR420, 63babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 3, 64babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C24XX_CODEC | 65babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki FMT_FL_S3C64XX, 66babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 67babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "YVU 4:2:0 planar, Y/Cr/Cb", 68babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_YVU420, 69babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 12, 70babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 1, 71babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_YCRCB420, 72babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 3, 73babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C24XX_CODEC | 74babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki FMT_FL_S3C64XX, 75babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 76babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "RGB565, 16 bpp", 77babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_RGB565X, 78babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 16, 79babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 2, 80babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_RGB565, 81babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 1, 82babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C24XX_PREVIEW | 83babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki FMT_FL_S3C64XX, 84babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 85babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "XRGB8888, 32 bpp", 86babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_RGB32, 87babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 32, 88babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 4, 89babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_XRGB8888, 90babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 1, 91babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C24XX_PREVIEW | 92babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki FMT_FL_S3C64XX, 93babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 94babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "BGR666", 95babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .fourcc = V4L2_PIX_FMT_BGR666, 96babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .depth = 32, 97babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ybpp = 4, 98babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .color = IMG_FMT_RGB666, 99babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .colplanes = 1, 100babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .flags = FMT_FL_S3C64XX, 101babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 102babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 103babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 104babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/** 105babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * s3c_camif_find_format() - lookup camif color format by fourcc or an index 106babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * @pixelformat: fourcc to match, ignored if null 107babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * @index: index to the camif_formats array, ignored if negative 108babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */ 109babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockiconst struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp, 110babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki const u32 *pixelformat, 111babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int index) 112babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 113babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki const struct camif_fmt *fmt, *def_fmt = NULL; 114babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki unsigned int i; 115babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int id = 0; 116babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 117babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (index >= (int)ARRAY_SIZE(camif_formats)) 118babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return NULL; 119babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 120babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki for (i = 0; i < ARRAY_SIZE(camif_formats); ++i) { 121babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki fmt = &camif_formats[i]; 122babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (vp && !(vp->fmt_flags & fmt->flags)) 123babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki continue; 124babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (pixelformat && fmt->fourcc == *pixelformat) 125babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return fmt; 126babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (index == id) 127babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki def_fmt = fmt; 128babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki id++; 129babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 130babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return def_fmt; 131babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 132babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 133babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) 134babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 135babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki unsigned int sh = 6; 136babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 137babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (src >= 64 * tar) 138babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -EINVAL; 139babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 140babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki while (sh--) { 141babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki unsigned int tmp = 1 << sh; 142babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (src >= tar * tmp) { 143babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki *shift = sh, *ratio = tmp; 144babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 145babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 146babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 147babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki *shift = 0, *ratio = 1; 148babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 149babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 150babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 151babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockiint s3c_camif_get_scaler_config(struct camif_vp *vp, 152babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_scaler *scaler) 153babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 154babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_rect *camif_crop = &vp->camif->camif_crop; 155babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int source_x = camif_crop->width; 156babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int source_y = camif_crop->height; 157babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int target_x = vp->out_frame.rect.width; 158babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int target_y = vp->out_frame.rect.height; 159babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret; 160babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 161babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (vp->rotation == 90 || vp->rotation == 270) 162babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki swap(target_x, target_y); 163babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 164babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_get_scaler_factor(source_x, target_x, &scaler->pre_h_ratio, 165babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki &scaler->h_shift); 166babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 167babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 168babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 169babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_get_scaler_factor(source_y, target_y, &scaler->pre_v_ratio, 170babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki &scaler->v_shift); 171babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 172babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 173babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 174babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->pre_dst_width = source_x / scaler->pre_h_ratio; 175babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->pre_dst_height = source_y / scaler->pre_v_ratio; 176babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 177babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->main_h_ratio = (source_x << 8) / (target_x << scaler->h_shift); 178babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->main_v_ratio = (source_y << 8) / (target_y << scaler->v_shift); 179babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 180babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->scaleup_h = (target_x >= source_x); 181babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->scaleup_v = (target_y >= source_y); 182babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 183babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->copy = 0; 184babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 185babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pr_debug("H: ratio: %u, shift: %u. V: ratio: %u, shift: %u.\n", 186babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->pre_h_ratio, scaler->h_shift, 187babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->pre_v_ratio, scaler->v_shift); 188babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 189babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pr_debug("Source: %dx%d, Target: %dx%d, scaleup_h/v: %d/%d\n", 190babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki source_x, source_y, target_x, target_y, 191babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki scaler->scaleup_h, scaler->scaleup_v); 192babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 193babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 194babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 195babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 196babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_register_sensor(struct camif_dev *camif) 197babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 198babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct s3c_camif_sensor_info *sensor = &camif->pdata.sensor; 199babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_device *v4l2_dev = &camif->v4l2_dev; 200babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct i2c_adapter *adapter; 201babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_subdev_format format; 202babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_subdev *sd; 203babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret; 204babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 205babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->sensor.sd = NULL; 206babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 207babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (sensor->i2c_board_info.addr == 0) 208babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -EINVAL; 209babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 210babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki adapter = i2c_get_adapter(sensor->i2c_bus_num); 211babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (adapter == NULL) { 212babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_warn(v4l2_dev, "failed to get I2C adapter %d\n", 213babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki sensor->i2c_bus_num); 214babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -EPROBE_DEFER; 215babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 216babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 217babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter, 218babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki &sensor->i2c_board_info, NULL); 219babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (sd == NULL) { 220babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki i2c_put_adapter(adapter); 221babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_warn(v4l2_dev, "failed to acquire subdev %s\n", 222babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki sensor->i2c_board_info.type); 223babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -EPROBE_DEFER; 224babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 225babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->sensor.sd = sd; 226babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 227babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_info(v4l2_dev, "registered sensor subdevice %s\n", sd->name); 228babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 229babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* Get initial pixel format and set it at the camif sink pad */ 230babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki format.pad = 0; 231babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki format.which = V4L2_SUBDEV_FORMAT_ACTIVE; 232babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); 233babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 234babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 235babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 236babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 237babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki format.pad = CAMIF_SD_PAD_SINK; 238babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_subdev_call(&camif->subdev, pad, set_fmt, NULL, &format); 239babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 240babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_info(sd, "Initial format from sensor: %dx%d, %#x\n", 241babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki format.format.width, format.format.height, 242babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki format.format.code); 243babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 244babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 245babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 246babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_sensor(struct camif_dev *camif) 247babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 248babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_subdev *sd = camif->sensor.sd; 249babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct i2c_client *client = sd ? v4l2_get_subdevdata(sd) : NULL; 250babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct i2c_adapter *adapter; 251babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 252babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (client == NULL) 253babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return; 254babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 255babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki adapter = client->adapter; 256babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_device_unregister_subdev(sd); 257babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->sensor.sd = NULL; 258babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki i2c_unregister_device(client); 259babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (adapter) 260babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki i2c_put_adapter(adapter); 261babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 262babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 263babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_create_media_links(struct camif_dev *camif) 264babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 265babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int i, ret; 266babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 267babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = media_entity_create_link(&camif->sensor.sd->entity, 0, 268babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki &camif->subdev.entity, CAMIF_SD_PAD_SINK, 269babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki MEDIA_LNK_FL_IMMUTABLE | 270babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki MEDIA_LNK_FL_ENABLED); 271babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret) 272babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 273babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 274babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) { 275babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = media_entity_create_link(&camif->subdev.entity, i, 276babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki &camif->vp[i - 1].vdev.entity, 0, 277babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki MEDIA_LNK_FL_IMMUTABLE | 278babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki MEDIA_LNK_FL_ENABLED); 279babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 280babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 281babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 282babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 283babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 284babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_register_video_nodes(struct camif_dev *camif) 285babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 286babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret = s3c_camif_register_video_node(camif, VP_CODEC); 287babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 288babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 289babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 290babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return s3c_camif_register_video_node(camif, VP_PREVIEW); 291babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 292babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 293babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_video_nodes(struct camif_dev *camif) 294babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 295babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki s3c_camif_unregister_video_node(camif, VP_CODEC); 296babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki s3c_camif_unregister_video_node(camif, VP_PREVIEW); 297babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 298babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 299babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_media_entities(struct camif_dev *camif) 300babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 301babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_unregister_video_nodes(camif); 302babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_unregister_sensor(camif); 303babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki s3c_camif_unregister_subdev(camif); 304babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 305babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 306babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/* 307babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Media device 308babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */ 309babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_media_dev_register(struct camif_dev *camif) 310babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 311babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct media_device *md = &camif->media_dev; 312babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct v4l2_device *v4l2_dev = &camif->v4l2_dev; 313babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki unsigned int ip_rev = camif->variant->ip_revision; 314babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret; 315babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 316babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki memset(md, 0, sizeof(*md)); 317babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF", 318babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X"); 319babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki strlcpy(md->bus_info, "platform", sizeof(md->bus_info)); 320babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki md->hw_revision = ip_rev; 321babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki md->driver_version = KERNEL_VERSION(1, 0, 0); 322babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 323babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki md->dev = camif->dev; 324babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 325babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name)); 326babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_dev->mdev = md; 327babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 328babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = v4l2_device_register(camif->dev, v4l2_dev); 329babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 330babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 331babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 332babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = media_device_register(md); 333babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 334babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_device_unregister(v4l2_dev); 335babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 336babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 337babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 338babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 339babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_clk_put(struct camif_dev *camif) 340babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 341babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int i; 342babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 343babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki for (i = 0; i < CLK_MAX_NUM; i++) { 344d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat if (IS_ERR(camif->clock[i])) 345babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki continue; 346babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_unprepare(camif->clock[i]); 347babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_put(camif->clock[i]); 348d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat camif->clock[i] = ERR_PTR(-EINVAL); 349babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 350babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 351babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 352babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_clk_get(struct camif_dev *camif) 353babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 354babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret, i; 355babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 356d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat for (i = 1; i < CLK_MAX_NUM; i++) 357d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat camif->clock[i] = ERR_PTR(-EINVAL); 358d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat 359babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki for (i = 0; i < CLK_MAX_NUM; i++) { 360babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->clock[i] = clk_get(camif->dev, camif_clocks[i]); 361babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (IS_ERR(camif->clock[i])) { 362babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = PTR_ERR(camif->clock[i]); 363babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err; 364babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 365babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = clk_prepare(camif->clock[i]); 366babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) { 367babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_put(camif->clock[i]); 368babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->clock[i] = NULL; 369babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err; 370babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 371babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 372babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 373babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr: 374babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_clk_put(camif); 375babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki dev_err(camif->dev, "failed to get clock: %s\n", 376babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_clocks[i]); 377babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 378babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 379babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 380babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/* 381babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * The CAMIF device has two relatively independent data processing paths 382babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * that can source data from memory or the common camera input frontend. 383babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Register interrupts for each data processing path (camif_vp). 384babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */ 385babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_request_irqs(struct platform_device *pdev, 386babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_dev *camif) 387babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 388babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int irq, ret, i; 389babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 390babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki for (i = 0; i < CAMIF_VP_NUM; i++) { 391babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_vp *vp = &camif->vp[i]; 392babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 393babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki init_waitqueue_head(&vp->irq_queue); 394babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 395babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki irq = platform_get_irq(pdev, i); 396babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (irq <= 0) { 397babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki dev_err(&pdev->dev, "failed to get IRQ %d\n", i); 398babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -ENXIO; 399babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 400babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 401babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler, 402babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 0, dev_name(&pdev->dev), vp); 403babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) { 404babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki dev_err(&pdev->dev, "failed to install IRQ: %d\n", ret); 405babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki break; 406babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 407babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 408babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 409babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 410babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 411babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 412babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_probe(struct platform_device *pdev) 413babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 414babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct device *dev = &pdev->dev; 415babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct s3c_camif_plat_data *pdata = dev->platform_data; 416babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct s3c_camif_drvdata *drvdata; 417babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_dev *camif; 418babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct resource *mres; 419babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki int ret = 0; 420babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 421babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif = devm_kzalloc(dev, sizeof(*camif), GFP_KERNEL); 422babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (!camif) 423babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -ENOMEM; 424babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 425babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki spin_lock_init(&camif->slock); 426babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki mutex_init(&camif->lock); 427babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 428babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->dev = dev; 429babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 430babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (!pdata || !pdata->gpio_get || !pdata->gpio_put) { 431babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki dev_err(dev, "wrong platform data\n"); 432babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return -EINVAL; 433babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 434babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 435babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->pdata = *pdata; 436babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki drvdata = (void *)platform_get_device_id(pdev)->driver_data; 437babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->variant = drvdata->variant; 438babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 439babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 440babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 441f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding camif->io_base = devm_ioremap_resource(dev, mres); 442f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding if (IS_ERR(camif->io_base)) 443f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding return PTR_ERR(camif->io_base); 444babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 445babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_request_irqs(pdev, camif); 446babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 447babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 448babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 449babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = pdata->gpio_get(); 450babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 451babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 452babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 453babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = s3c_camif_create_subdev(camif); 454babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 455babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_sd; 456babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 457babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_clk_get(camif); 458babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 459babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_clk; 460babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 461babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki platform_set_drvdata(pdev, camif); 462babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_set_rate(camif->clock[CLK_CAM], 463babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->pdata.sensor.clock_frequency); 464babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 465babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki dev_info(dev, "sensor clock frequency: %lu\n", 466babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_get_rate(camif->clock[CLK_CAM])); 467babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* 468babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Set initial pixel format, resolution and crop rectangle. 469babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Must be done before a sensor subdev is registered as some 470babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * settings are overrode with values from sensor subdev. 471babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */ 472babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki s3c_camif_set_defaults(camif); 473babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 474babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pm_runtime_enable(dev); 475babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 476babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = pm_runtime_get_sync(dev); 477babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 478babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_pm; 479babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 480babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* Initialize contiguous memory allocator */ 481babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif->alloc_ctx = vb2_dma_contig_init_ctx(dev); 482babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (IS_ERR(camif->alloc_ctx)) { 483babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = PTR_ERR(camif->alloc_ctx); 484babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_alloc; 485babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 486babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 487babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_media_dev_register(camif); 488babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 489babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_mdev; 490babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 491babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_register_sensor(camif); 492babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 493babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_sens; 494babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 495babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = v4l2_device_register_subdev(&camif->v4l2_dev, &camif->subdev); 496babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 497babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_sens; 498babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 499babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki mutex_lock(&camif->media_dev.graph_mutex); 500babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 501babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = v4l2_device_register_subdev_nodes(&camif->v4l2_dev); 502babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 503babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_unlock; 504babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 505babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_register_video_nodes(camif); 506babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 507babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_unlock; 508babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 509babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki ret = camif_create_media_links(camif); 510babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki if (ret < 0) 511babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki goto err_unlock; 512babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 513babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki mutex_unlock(&camif->media_dev.graph_mutex); 514babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pm_runtime_put(dev); 515babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 516babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 517babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_unlock: 518babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki mutex_unlock(&camif->media_dev.graph_mutex); 519babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_sens: 520babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_device_unregister(&camif->v4l2_dev); 521babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki media_device_unregister(&camif->media_dev); 522babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_unregister_media_entities(camif); 523babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_mdev: 524babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki vb2_dma_contig_cleanup_ctx(camif->alloc_ctx); 525babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_alloc: 526babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pm_runtime_put(dev); 527babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pm_runtime_disable(dev); 528babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_pm: 529babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_clk_put(camif); 530babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_clk: 531babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki s3c_camif_unregister_subdev(camif); 532babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_sd: 533babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pdata->gpio_put(); 534babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return ret; 535babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 536babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 5374c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int s3c_camif_remove(struct platform_device *pdev) 538babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 539babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_dev *camif = platform_get_drvdata(pdev); 540babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct s3c_camif_plat_data *pdata = &camif->pdata; 541babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 542babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki media_device_unregister(&camif->media_dev); 543babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_unregister_media_entities(camif); 544babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki v4l2_device_unregister(&camif->v4l2_dev); 545babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 546babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pm_runtime_disable(&pdev->dev); 547babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki camif_clk_put(camif); 548babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki pdata->gpio_put(); 549babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 550babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 551babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 552babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 553babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_runtime_resume(struct device *dev) 554babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 555babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_dev *camif = dev_get_drvdata(dev); 556babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 557babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_enable(camif->clock[CLK_GATE]); 558babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* null op on s3c244x */ 559babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_enable(camif->clock[CLK_CAM]); 560babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 561babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 562babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 563babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_runtime_suspend(struct device *dev) 564babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{ 565babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki struct camif_dev *camif = dev_get_drvdata(dev); 566babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 567babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki /* null op on s3c244x */ 568babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_disable(camif->clock[CLK_CAM]); 569babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 570babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki clk_disable(camif->clock[CLK_GATE]); 571babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki return 0; 572babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki} 573babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 574babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct s3c_camif_variant s3c244x_camif_variant = { 575babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .vp_pix_limits = { 576babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [VP_CODEC] = { 577babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_out_width = 4096, 578babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_sc_out_width = 2048, 579babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .out_width_align = 16, 580babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .min_out_width = 16, 581babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_height = 4096, 582babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 583babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [VP_PREVIEW] = { 584babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_out_width = 640, 585babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_sc_out_width = 640, 586babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .out_width_align = 16, 587babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .min_out_width = 16, 588babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_height = 480, 589babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 590babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 591babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .pix_limits = { 592babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .win_hor_offset_align = 8, 593babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 594babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ip_revision = S3C244X_CAMIF_IP_REV, 595babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 596babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 597babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct s3c_camif_drvdata s3c244x_camif_drvdata = { 598babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .variant = &s3c244x_camif_variant, 599babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .bus_clk_freq = 24000000UL, 600babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 601babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 602babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct s3c_camif_variant s3c6410_camif_variant = { 603babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .vp_pix_limits = { 604babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [VP_CODEC] = { 605babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_out_width = 4096, 606babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_sc_out_width = 2048, 607babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .out_width_align = 16, 608babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .min_out_width = 16, 609babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_height = 4096, 610babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 611babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki [VP_PREVIEW] = { 612babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_out_width = 4096, 613babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_sc_out_width = 720, 614babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .out_width_align = 16, 615babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .min_out_width = 16, 616babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .max_height = 4096, 617babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 618babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 619babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .pix_limits = { 620babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .win_hor_offset_align = 8, 621babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 622babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .ip_revision = S3C6410_CAMIF_IP_REV, 623babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .has_img_effect = 1, 624babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .vp_offset = 0x20, 625babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 626babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 627babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct s3c_camif_drvdata s3c6410_camif_drvdata = { 628babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .variant = &s3c6410_camif_variant, 629babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .bus_clk_freq = 133000000UL, 630babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 631babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 632babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct platform_device_id s3c_camif_driver_ids[] = { 633babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki { 634babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "s3c2440-camif", 635babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .driver_data = (unsigned long)&s3c244x_camif_drvdata, 636babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, { 637babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = "s3c6410-camif", 638babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .driver_data = (unsigned long)&s3c6410_camif_drvdata, 639babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki }, 640babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki { /* sentinel */ }, 641babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 642babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_DEVICE_TABLE(platform, s3c_camif_driver_ids); 643babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 644babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct dev_pm_ops s3c_camif_pm_ops = { 645babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .runtime_suspend = s3c_camif_runtime_suspend, 646babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .runtime_resume = s3c_camif_runtime_resume, 647babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 648babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 649babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct platform_driver s3c_camif_driver = { 650babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .probe = s3c_camif_probe, 6514c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman .remove = s3c_camif_remove, 652babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .id_table = s3c_camif_driver_ids, 653babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .driver = { 654babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .name = S3C_CAMIF_DRIVER_NAME, 655babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .owner = THIS_MODULE, 656babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki .pm = &s3c_camif_pm_ops, 657babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki } 658babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}; 659babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 660babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockimodule_platform_driver(s3c_camif_driver); 661babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki 662babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>"); 663babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>"); 664babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_DESCRIPTION("S3C24XX/S3C64XX SoC camera interface driver"); 665babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_LICENSE("GPL"); 666