mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"This series contains:
- Exynos s5p-mfc driver got support for VP8 encoder
- Some SoC drivers gained support for asynchronous registration
(needed for DT)
- The RC subsystem gained support for RC activity LED;
- New drivers added: a video decoder(adv7842), a video encoder
(adv7511), a new GSPCA driver (stk1135) and support for Renesas
R-Car (vsp1)
- the first SDR kernel driver: mirics msi3101. Due to some troubles
with the driver, and because the API is still under discussion, it
will be merged at staging for 3.12. Need to rework on it
- usual new boards additions, fixes, cleanups and driver
improvements"
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (242 commits)
[media] cx88: Fix regression: CX88_AUDIO_WM8775 can't be 0
[media] exynos4-is: Fix entity unregistration on error path
[media] exynos-gsc: Register v4l2 device
[media] exynos4-is: Fix fimc-lite bayer formats
[media] em28xx: fix assignment of the eeprom data
[media] hdpvr: fix iteration over uninitialized lists in hdpvr_probe()
[media] usbtv: Throw corrupted frames away
[media] usbtv: Fix deinterlacing
[media] v4l2: added missing mutex.h include to v4l2-ctrls.h
[media] DocBook: upgrade media_api DocBook version to 4.2
[media] ml86v7667: fix compile warning: 'ret' set but not used
[media] s5p-g2d: Fix registration failure
[media] media: coda: Fix DT driver data pointer for i.MX27
[media] s5p-mfc: Fix input/output format reporting
[media] v4l: vsp1: Fix mutex double lock at streamon time
[media] v4l: vsp1: Add support for RT clock
[media] v4l: vsp1: Initialize media device bus_info field
[media] davinci: vpif_capture: fix error return code in vpif_probe()
[media] davinci: vpif_display: fix error return code in vpif_probe()
[media] MAINTAINERS: add entries for adv7511 and adv7842
...
This commit is contained in:
commit
27c053aa8d
216 changed files with 18958 additions and 2632 deletions
|
|
@ -23,6 +23,8 @@ config SMS_SIANO_DEBUGFS
|
|||
depends on SMS_SIANO_MDTV
|
||||
depends on DEBUG_FS
|
||||
depends on SMS_USB_DRV
|
||||
depends on CONFIG_SMS_USB_DRV = CONFIG_SMS_SDIO_DRV
|
||||
|
||||
---help---
|
||||
Choose Y to enable visualizing a dump of the frontend
|
||||
statistics response packets via debugfs. Currently, works
|
||||
|
|
|
|||
|
|
@ -276,7 +276,8 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
|
|||
|
||||
/* Legacy PER/BER */
|
||||
tmp = p->ets_packets * 65535;
|
||||
do_div(tmp, p->ts_packets + p->ets_packets);
|
||||
if (p->ts_packets + p->ets_packets)
|
||||
do_div(tmp, p->ts_packets + p->ets_packets);
|
||||
client->legacy_per = tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -369,4 +369,6 @@
|
|||
#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500
|
||||
#define USB_PID_CPYTO_REDI_PC50A 0xa803
|
||||
#define USB_PID_CTVDIGDUAL_V2 0xe410
|
||||
#define USB_PID_PCTV_2002E 0x025c
|
||||
#define USB_PID_PCTV_2002E_SE 0x025d
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -157,7 +157,6 @@ static struct regdata mb86a20s_init2[] = {
|
|||
{ 0x45, 0x04 }, /* CN symbol 4 */
|
||||
{ 0x48, 0x04 }, /* CN manual mode */
|
||||
|
||||
{ 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */
|
||||
{ 0x50, 0xd6 }, { 0x51, 0x1f },
|
||||
{ 0x50, 0xd2 }, { 0x51, 0x03 },
|
||||
{ 0x50, 0xd7 }, { 0x51, 0xbf },
|
||||
|
|
@ -1860,16 +1859,15 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
|
|||
dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n",
|
||||
__func__, state->if_freq, (long long)pll);
|
||||
|
||||
if (!state->config->is_serial) {
|
||||
if (!state->config->is_serial)
|
||||
regD5 &= ~1;
|
||||
|
||||
rc = mb86a20s_writereg(state, 0x50, 0xd5);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
rc = mb86a20s_writereg(state, 0x51, regD5);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
}
|
||||
rc = mb86a20s_writereg(state, 0x50, 0xd5);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
rc = mb86a20s_writereg(state, 0x51, regD5);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
rc = mb86a20s_writeregdata(state, mb86a20s_init2);
|
||||
if (rc < 0)
|
||||
|
|
|
|||
|
|
@ -206,6 +206,18 @@ config VIDEO_ADV7604
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called adv7604.
|
||||
|
||||
config VIDEO_ADV7842
|
||||
tristate "Analog Devices ADV7842 decoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
---help---
|
||||
Support for the Analog Devices ADV7842 video decoder.
|
||||
|
||||
This is a Analog Devices Component/Graphics/SD Digitizer
|
||||
with 2:1 Multiplexed HDMI Receiver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adv7842.
|
||||
|
||||
config VIDEO_BT819
|
||||
tristate "BT819A VideoStream decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
|
@ -417,6 +429,17 @@ config VIDEO_ADV7393
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called adv7393.
|
||||
|
||||
config VIDEO_ADV7511
|
||||
tristate "Analog Devices ADV7511 encoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
---help---
|
||||
Support for the Analog Devices ADV7511 video encoder.
|
||||
|
||||
This is a Analog Devices HDMI transmitter.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adv7511.
|
||||
|
||||
config VIDEO_AD9389B
|
||||
tristate "Analog Devices AD9389B encoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
|
|||
obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
|
||||
obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
|
||||
obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
|
||||
obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
|
||||
obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
|
||||
obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o
|
||||
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
|
||||
obj-$(CONFIG_VIDEO_VS6624) += vs6624.o
|
||||
obj-$(CONFIG_VIDEO_BT819) += bt819.o
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/ad9389b.h>
|
||||
|
||||
|
|
@ -442,22 +443,11 @@ static int ad9389b_log_status(struct v4l2_subdev *sd)
|
|||
vic_detect, vic_sent);
|
||||
}
|
||||
}
|
||||
if (state->dv_timings.type == V4L2_DV_BT_656_1120) {
|
||||
struct v4l2_bt_timings *bt = bt = &state->dv_timings.bt;
|
||||
u32 frame_width = bt->width + bt->hfrontporch +
|
||||
bt->hsync + bt->hbackporch;
|
||||
u32 frame_height = bt->height + bt->vfrontporch +
|
||||
bt->vsync + bt->vbackporch;
|
||||
u32 frame_size = frame_width * frame_height;
|
||||
|
||||
v4l2_info(sd, "timings: %ux%u%s%u (%ux%u). Pix freq. = %u Hz. Polarities = 0x%x\n",
|
||||
bt->width, bt->height, bt->interlaced ? "i" : "p",
|
||||
frame_size > 0 ? (unsigned)bt->pixelclock / frame_size : 0,
|
||||
frame_width, frame_height,
|
||||
(unsigned)bt->pixelclock, bt->polarities);
|
||||
} else {
|
||||
if (state->dv_timings.type == V4L2_DV_BT_656_1120)
|
||||
v4l2_print_dv_timings(sd->name, "timings: ",
|
||||
&state->dv_timings, false);
|
||||
else
|
||||
v4l2_info(sd, "no timings set\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -636,95 +626,34 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_dv_timings ad9389b_timings[] = {
|
||||
V4L2_DV_BT_CEA_720X480P59_94,
|
||||
V4L2_DV_BT_CEA_720X576P50,
|
||||
V4L2_DV_BT_CEA_1280X720P24,
|
||||
V4L2_DV_BT_CEA_1280X720P25,
|
||||
V4L2_DV_BT_CEA_1280X720P30,
|
||||
V4L2_DV_BT_CEA_1280X720P50,
|
||||
V4L2_DV_BT_CEA_1280X720P60,
|
||||
V4L2_DV_BT_CEA_1920X1080P24,
|
||||
V4L2_DV_BT_CEA_1920X1080P25,
|
||||
V4L2_DV_BT_CEA_1920X1080P30,
|
||||
V4L2_DV_BT_CEA_1920X1080P50,
|
||||
V4L2_DV_BT_CEA_1920X1080P60,
|
||||
|
||||
V4L2_DV_BT_DMT_640X350P85,
|
||||
V4L2_DV_BT_DMT_640X400P85,
|
||||
V4L2_DV_BT_DMT_720X400P85,
|
||||
V4L2_DV_BT_DMT_640X480P60,
|
||||
V4L2_DV_BT_DMT_640X480P72,
|
||||
V4L2_DV_BT_DMT_640X480P75,
|
||||
V4L2_DV_BT_DMT_640X480P85,
|
||||
V4L2_DV_BT_DMT_800X600P56,
|
||||
V4L2_DV_BT_DMT_800X600P60,
|
||||
V4L2_DV_BT_DMT_800X600P72,
|
||||
V4L2_DV_BT_DMT_800X600P75,
|
||||
V4L2_DV_BT_DMT_800X600P85,
|
||||
V4L2_DV_BT_DMT_848X480P60,
|
||||
V4L2_DV_BT_DMT_1024X768P60,
|
||||
V4L2_DV_BT_DMT_1024X768P70,
|
||||
V4L2_DV_BT_DMT_1024X768P75,
|
||||
V4L2_DV_BT_DMT_1024X768P85,
|
||||
V4L2_DV_BT_DMT_1152X864P75,
|
||||
V4L2_DV_BT_DMT_1280X768P60_RB,
|
||||
V4L2_DV_BT_DMT_1280X768P60,
|
||||
V4L2_DV_BT_DMT_1280X768P75,
|
||||
V4L2_DV_BT_DMT_1280X768P85,
|
||||
V4L2_DV_BT_DMT_1280X800P60_RB,
|
||||
V4L2_DV_BT_DMT_1280X800P60,
|
||||
V4L2_DV_BT_DMT_1280X800P75,
|
||||
V4L2_DV_BT_DMT_1280X800P85,
|
||||
V4L2_DV_BT_DMT_1280X960P60,
|
||||
V4L2_DV_BT_DMT_1280X960P85,
|
||||
V4L2_DV_BT_DMT_1280X1024P60,
|
||||
V4L2_DV_BT_DMT_1280X1024P75,
|
||||
V4L2_DV_BT_DMT_1280X1024P85,
|
||||
V4L2_DV_BT_DMT_1360X768P60,
|
||||
V4L2_DV_BT_DMT_1400X1050P60_RB,
|
||||
V4L2_DV_BT_DMT_1400X1050P60,
|
||||
V4L2_DV_BT_DMT_1400X1050P75,
|
||||
V4L2_DV_BT_DMT_1400X1050P85,
|
||||
V4L2_DV_BT_DMT_1440X900P60_RB,
|
||||
V4L2_DV_BT_DMT_1440X900P60,
|
||||
V4L2_DV_BT_DMT_1600X1200P60,
|
||||
V4L2_DV_BT_DMT_1680X1050P60_RB,
|
||||
V4L2_DV_BT_DMT_1680X1050P60,
|
||||
V4L2_DV_BT_DMT_1792X1344P60,
|
||||
V4L2_DV_BT_DMT_1856X1392P60,
|
||||
V4L2_DV_BT_DMT_1920X1200P60_RB,
|
||||
V4L2_DV_BT_DMT_1366X768P60,
|
||||
V4L2_DV_BT_DMT_1920X1080P60,
|
||||
{},
|
||||
static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
|
||||
.type = V4L2_DV_BT_656_1120,
|
||||
.bt = {
|
||||
.max_width = 1920,
|
||||
.max_height = 1200,
|
||||
.min_pixelclock = 25000000,
|
||||
.max_pixelclock = 170000000,
|
||||
.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
|
||||
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM,
|
||||
},
|
||||
};
|
||||
|
||||
static int ad9389b_s_dv_timings(struct v4l2_subdev *sd,
|
||||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct ad9389b_state *state = get_ad9389b_state(sd);
|
||||
int i;
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s:\n", __func__);
|
||||
|
||||
/* quick sanity check */
|
||||
if (timings->type != V4L2_DV_BT_656_1120)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->bt.interlaced)
|
||||
return -EINVAL;
|
||||
if (timings->bt.pixelclock < 27000000 ||
|
||||
timings->bt.pixelclock > 170000000)
|
||||
if (!v4l2_valid_dv_timings(timings, &ad9389b_timings_cap, NULL, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
/* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
|
||||
if the format is listed in ad9389b_timings[] */
|
||||
for (i = 0; ad9389b_timings[i].bt.width; i++) {
|
||||
if (v4l_match_dv_timings(timings, &ad9389b_timings[i], 0)) {
|
||||
*timings = ad9389b_timings[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if the format is one of the CEA or DMT timings. */
|
||||
v4l2_find_dv_timings_cap(timings, &ad9389b_timings_cap, 0, NULL, NULL);
|
||||
|
||||
timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
|
||||
|
||||
|
|
@ -762,26 +691,14 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
|
|||
static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
|
||||
struct v4l2_enum_dv_timings *timings)
|
||||
{
|
||||
if (timings->index >= ARRAY_SIZE(ad9389b_timings))
|
||||
return -EINVAL;
|
||||
|
||||
memset(timings->reserved, 0, sizeof(timings->reserved));
|
||||
timings->timings = ad9389b_timings[timings->index];
|
||||
return 0;
|
||||
return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
|
||||
struct v4l2_dv_timings_cap *cap)
|
||||
{
|
||||
cap->type = V4L2_DV_BT_656_1120;
|
||||
cap->bt.max_width = 1920;
|
||||
cap->bt.max_height = 1200;
|
||||
cap->bt.min_pixelclock = 27000000;
|
||||
cap->bt.max_pixelclock = 170000000;
|
||||
cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT;
|
||||
cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
|
||||
V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM;
|
||||
*cap = ad9389b_timings_cap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -930,8 +847,10 @@ static void ad9389b_edid_handler(struct work_struct *work)
|
|||
* (DVI connectors are particularly prone to this problem). */
|
||||
if (state->edid.read_retries) {
|
||||
state->edid.read_retries--;
|
||||
/* EDID read failed, trigger a retry */
|
||||
ad9389b_wr(sd, 0xc9, 0xf);
|
||||
v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
|
||||
state->have_monitor = false;
|
||||
ad9389b_s_power(sd, false);
|
||||
ad9389b_s_power(sd, true);
|
||||
queue_delayed_work(state->work_queue,
|
||||
&state->edid_handler, EDID_DELAY);
|
||||
return;
|
||||
|
|
@ -967,11 +886,9 @@ static void ad9389b_setup(struct v4l2_subdev *sd)
|
|||
ad9389b_wr_and_or(sd, 0x15, 0xf1, 0x0);
|
||||
/* Output format: RGB 4:4:4 */
|
||||
ad9389b_wr_and_or(sd, 0x16, 0x3f, 0x0);
|
||||
/* CSC fixed point: +/-2, 1st order interpolation 4:2:2 -> 4:4:4 up
|
||||
conversion, Aspect ratio: 16:9 */
|
||||
ad9389b_wr_and_or(sd, 0x17, 0xe1, 0x0e);
|
||||
/* Disable pixel repetition and CSC */
|
||||
ad9389b_wr_and_or(sd, 0x3b, 0x9e, 0x0);
|
||||
/* 1st order interpolation 4:2:2 -> 4:4:4 up conversion,
|
||||
Aspect ratio: 16:9 */
|
||||
ad9389b_wr_and_or(sd, 0x17, 0xf9, 0x06);
|
||||
/* Output format: RGB 4:4:4, Active Format Information is valid. */
|
||||
ad9389b_wr_and_or(sd, 0x45, 0xc7, 0x08);
|
||||
/* Underscanned */
|
||||
|
|
@ -1056,12 +973,12 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
|
|||
|
||||
static bool edid_block_verify_crc(u8 *edid_block)
|
||||
{
|
||||
int i;
|
||||
u8 sum = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 127; i++)
|
||||
sum += *(edid_block + i);
|
||||
return ((255 - sum + 1) == edid_block[127]);
|
||||
for (i = 0; i < 128; i++)
|
||||
sum += edid_block[i];
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
|
||||
|
|
@ -1107,6 +1024,8 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
|
|||
}
|
||||
if (!edid_segment_verify_crc(sd, segment)) {
|
||||
/* edid crc error, force reread of edid segment */
|
||||
v4l2_err(sd, "%s: edid crc error\n", __func__);
|
||||
state->have_monitor = false;
|
||||
ad9389b_s_power(sd, false);
|
||||
ad9389b_s_power(sd, true);
|
||||
return false;
|
||||
|
|
@ -1190,27 +1109,27 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
|
||||
V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
|
||||
0, V4L2_DV_TX_MODE_DVI_D);
|
||||
state->hdmi_mode_ctrl->is_private = true;
|
||||
state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0);
|
||||
state->hotplug_ctrl->is_private = true;
|
||||
state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0);
|
||||
state->rx_sense_ctrl->is_private = true;
|
||||
state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0);
|
||||
state->have_edid0_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl =
|
||||
v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
|
||||
V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
|
||||
0, V4L2_DV_RGB_RANGE_AUTO);
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
sd->ctrl_handler = hdl;
|
||||
if (hdl->error) {
|
||||
err = hdl->error;
|
||||
|
||||
goto err_hdl;
|
||||
}
|
||||
state->hdmi_mode_ctrl->is_private = true;
|
||||
state->hotplug_ctrl->is_private = true;
|
||||
state->rx_sense_ctrl->is_private = true;
|
||||
state->have_edid0_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
|
||||
state->pad.flags = MEDIA_PAD_FL_SINK;
|
||||
err = media_entity_init(&sd->entity, 1, &state->pad, 0);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@
|
|||
#include <linux/uaccess.h>
|
||||
|
||||
#include <media/adv7343.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-of.h>
|
||||
|
||||
#include "adv7343_regs.h"
|
||||
|
||||
|
|
@ -226,12 +228,12 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
|
|||
else
|
||||
val = state->pdata->mode_config.sleep_mode << 0 |
|
||||
state->pdata->mode_config.pll_control << 1 |
|
||||
state->pdata->mode_config.dac_3 << 2 |
|
||||
state->pdata->mode_config.dac_2 << 3 |
|
||||
state->pdata->mode_config.dac_1 << 4 |
|
||||
state->pdata->mode_config.dac_6 << 5 |
|
||||
state->pdata->mode_config.dac_5 << 6 |
|
||||
state->pdata->mode_config.dac_4 << 7;
|
||||
state->pdata->mode_config.dac[2] << 2 |
|
||||
state->pdata->mode_config.dac[1] << 3 |
|
||||
state->pdata->mode_config.dac[0] << 4 |
|
||||
state->pdata->mode_config.dac[5] << 5 |
|
||||
state->pdata->mode_config.dac[4] << 6 |
|
||||
state->pdata->mode_config.dac[3] << 7;
|
||||
|
||||
err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
|
||||
if (err < 0)
|
||||
|
|
@ -250,15 +252,15 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
|
|||
/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
|
||||
val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
|
||||
|
||||
if (state->pdata && state->pdata->sd_config.sd_dac_out1)
|
||||
val = val | (state->pdata->sd_config.sd_dac_out1 << 1);
|
||||
else if (state->pdata && !state->pdata->sd_config.sd_dac_out1)
|
||||
val = val & ~(state->pdata->sd_config.sd_dac_out1 << 1);
|
||||
if (state->pdata && state->pdata->sd_config.sd_dac_out[0])
|
||||
val = val | (state->pdata->sd_config.sd_dac_out[0] << 1);
|
||||
else if (state->pdata && !state->pdata->sd_config.sd_dac_out[0])
|
||||
val = val & ~(state->pdata->sd_config.sd_dac_out[0] << 1);
|
||||
|
||||
if (state->pdata && state->pdata->sd_config.sd_dac_out2)
|
||||
val = val | (state->pdata->sd_config.sd_dac_out2 << 2);
|
||||
else if (state->pdata && !state->pdata->sd_config.sd_dac_out2)
|
||||
val = val & ~(state->pdata->sd_config.sd_dac_out2 << 2);
|
||||
if (state->pdata && state->pdata->sd_config.sd_dac_out[1])
|
||||
val = val | (state->pdata->sd_config.sd_dac_out[1] << 2);
|
||||
else if (state->pdata && !state->pdata->sd_config.sd_dac_out[1])
|
||||
val = val & ~(state->pdata->sd_config.sd_dac_out[1] << 2);
|
||||
|
||||
err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
|
||||
if (err < 0)
|
||||
|
|
@ -398,6 +400,40 @@ static int adv7343_initialize(struct v4l2_subdev *sd)
|
|||
return err;
|
||||
}
|
||||
|
||||
static struct adv7343_platform_data *
|
||||
adv7343_get_pdata(struct i2c_client *client)
|
||||
{
|
||||
struct adv7343_platform_data *pdata;
|
||||
struct device_node *np;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
goto done;
|
||||
|
||||
pdata->mode_config.sleep_mode =
|
||||
of_property_read_bool(np, "adi,power-mode-sleep-mode");
|
||||
|
||||
pdata->mode_config.pll_control =
|
||||
of_property_read_bool(np, "adi,power-mode-pll-ctrl");
|
||||
|
||||
of_property_read_u32_array(np, "adi,dac-enable",
|
||||
pdata->mode_config.dac, 6);
|
||||
|
||||
of_property_read_u32_array(np, "adi,sd-dac-enable",
|
||||
pdata->sd_config.sd_dac_out, 2);
|
||||
|
||||
done:
|
||||
of_node_put(np);
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static int adv7343_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
|
@ -416,7 +452,7 @@ static int adv7343_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
/* Copy board specific information here */
|
||||
state->pdata = client->dev.platform_data;
|
||||
state->pdata = adv7343_get_pdata(client);
|
||||
|
||||
state->reg00 = 0x80;
|
||||
state->reg01 = 0x00;
|
||||
|
|
@ -445,16 +481,21 @@ static int adv7343_probe(struct i2c_client *client,
|
|||
ADV7343_GAIN_DEF);
|
||||
state->sd.ctrl_handler = &state->hdl;
|
||||
if (state->hdl.error) {
|
||||
int err = state->hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
return err;
|
||||
err = state->hdl.error;
|
||||
goto done;
|
||||
}
|
||||
v4l2_ctrl_handler_setup(&state->hdl);
|
||||
|
||||
err = adv7343_initialize(&state->sd);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
err = v4l2_async_register_subdev(&state->sd);
|
||||
|
||||
done:
|
||||
if (err < 0)
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -463,6 +504,7 @@ static int adv7343_remove(struct i2c_client *client)
|
|||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
|
||||
v4l2_async_unregister_subdev(&state->sd);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
|
||||
|
|
@ -476,8 +518,17 @@ static const struct i2c_device_id adv7343_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, adv7343_id);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id adv7343_of_match[] = {
|
||||
{.compatible = "adi,adv7343", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adv7343_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver adv7343_driver = {
|
||||
.driver = {
|
||||
.of_match_table = of_match_ptr(adv7343_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7343",
|
||||
},
|
||||
|
|
|
|||
1198
drivers/media/i2c/adv7511.c
Normal file
1198
drivers/media/i2c/adv7511.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/adv7604.h>
|
||||
|
||||
static int debug;
|
||||
|
|
@ -76,6 +77,7 @@ struct adv7604_state {
|
|||
struct delayed_work delayed_work_enable_hotplug;
|
||||
bool connector_hdmi;
|
||||
bool restart_stdi_once;
|
||||
u32 prev_input_status;
|
||||
|
||||
/* i2c clients */
|
||||
struct i2c_client *i2c_avlink;
|
||||
|
|
@ -260,22 +262,22 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
|||
|
||||
static inline unsigned hblanking(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->hfrontporch + t->hsync + t->hbackporch;
|
||||
return V4L2_DV_BT_BLANKING_WIDTH(t);
|
||||
}
|
||||
|
||||
static inline unsigned htotal(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->width + t->hfrontporch + t->hsync + t->hbackporch;
|
||||
return V4L2_DV_BT_FRAME_WIDTH(t);
|
||||
}
|
||||
|
||||
static inline unsigned vblanking(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->vfrontporch + t->vsync + t->vbackporch;
|
||||
return V4L2_DV_BT_BLANKING_HEIGHT(t);
|
||||
}
|
||||
|
||||
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->height + t->vfrontporch + t->vsync + t->vbackporch;
|
||||
return V4L2_DV_BT_FRAME_HEIGHT(t);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
|
@ -761,7 +763,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
|
|||
int i;
|
||||
|
||||
for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
|
||||
if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings,
|
||||
if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
|
||||
DIGITAL_INPUT ? 250000 : 1000000))
|
||||
continue;
|
||||
io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
|
||||
|
|
@ -990,6 +992,11 @@ static inline bool no_lock_tmds(struct v4l2_subdev *sd)
|
|||
return (io_read(sd, 0x6a) & 0xe0) != 0xe0;
|
||||
}
|
||||
|
||||
static inline bool is_hdmi(struct v4l2_subdev *sd)
|
||||
{
|
||||
return hdmi_read(sd, 0x05) & 0x80;
|
||||
}
|
||||
|
||||
static inline bool no_lock_sspd(struct v4l2_subdev *sd)
|
||||
{
|
||||
/* TODO channel 2 */
|
||||
|
|
@ -1044,38 +1051,6 @@ static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void adv7604_print_timings(struct v4l2_subdev *sd,
|
||||
struct v4l2_dv_timings *timings, const char *txt, bool detailed)
|
||||
{
|
||||
struct v4l2_bt_timings *bt = &timings->bt;
|
||||
u32 htot, vtot;
|
||||
|
||||
if (timings->type != V4L2_DV_BT_656_1120)
|
||||
return;
|
||||
|
||||
htot = htotal(bt);
|
||||
vtot = vtotal(bt);
|
||||
|
||||
v4l2_info(sd, "%s %dx%d%s%d (%dx%d)",
|
||||
txt, bt->width, bt->height, bt->interlaced ? "i" : "p",
|
||||
(htot * vtot) > 0 ? ((u32)bt->pixelclock /
|
||||
(htot * vtot)) : 0,
|
||||
htot, vtot);
|
||||
|
||||
if (detailed) {
|
||||
v4l2_info(sd, " horizontal: fp = %d, %ssync = %d, bp = %d\n",
|
||||
bt->hfrontporch,
|
||||
(bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
|
||||
bt->hsync, bt->hbackporch);
|
||||
v4l2_info(sd, " vertical: fp = %d, %ssync = %d, bp = %d\n",
|
||||
bt->vfrontporch,
|
||||
(bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
|
||||
bt->vsync, bt->vbackporch);
|
||||
v4l2_info(sd, " pixelclock: %lld, flags: 0x%x, standards: 0x%x\n",
|
||||
bt->pixelclock, bt->flags, bt->standards);
|
||||
}
|
||||
}
|
||||
|
||||
struct stdi_readback {
|
||||
u16 bl, lcf, lcvs;
|
||||
u8 hs_pol, vs_pol;
|
||||
|
|
@ -1187,7 +1162,7 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
|
|||
cap->type = V4L2_DV_BT_656_1120;
|
||||
cap->bt.max_width = 1920;
|
||||
cap->bt.max_height = 1200;
|
||||
cap->bt.min_pixelclock = 27000000;
|
||||
cap->bt.min_pixelclock = 25000000;
|
||||
if (DIGITAL_INPUT)
|
||||
cap->bt.max_pixelclock = 225000000;
|
||||
else
|
||||
|
|
@ -1208,7 +1183,7 @@ static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
|
|||
int i;
|
||||
|
||||
for (i = 0; adv7604_timings[i].bt.width; i++) {
|
||||
if (v4l_match_dv_timings(timings, &adv7604_timings[i],
|
||||
if (v4l2_match_dv_timings(timings, &adv7604_timings[i],
|
||||
DIGITAL_INPUT ? 250000 : 1000000)) {
|
||||
*timings = adv7604_timings[i];
|
||||
break;
|
||||
|
|
@ -1242,12 +1217,21 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
|
|||
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
|
||||
|
||||
if (DIGITAL_INPUT) {
|
||||
uint32_t freq;
|
||||
|
||||
timings->type = V4L2_DV_BT_656_1120;
|
||||
|
||||
bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
|
||||
bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
|
||||
bt->pixelclock = (hdmi_read(sd, 0x06) * 1000000) +
|
||||
freq = (hdmi_read(sd, 0x06) * 1000000) +
|
||||
((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
|
||||
if (is_hdmi(sd)) {
|
||||
/* adjust for deep color mode */
|
||||
unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8;
|
||||
|
||||
freq = freq * 8 / bits_per_channel;
|
||||
}
|
||||
bt->pixelclock = freq;
|
||||
bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
|
||||
hdmi_read(sd, 0x21);
|
||||
bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 +
|
||||
|
|
@ -1329,8 +1313,8 @@ found:
|
|||
}
|
||||
|
||||
if (debug > 1)
|
||||
adv7604_print_timings(sd, timings,
|
||||
"adv7604_query_dv_timings:", true);
|
||||
v4l2_print_dv_timings(sd->name, "adv7604_query_dv_timings: ",
|
||||
timings, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1372,8 +1356,8 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
|
|||
|
||||
|
||||
if (debug > 1)
|
||||
adv7604_print_timings(sd, timings,
|
||||
"adv7604_s_dv_timings:", true);
|
||||
v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ",
|
||||
timings, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1534,6 +1518,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|||
{
|
||||
struct adv7604_state *state = to_state(sd);
|
||||
u8 fmt_change, fmt_change_digital, tx_5v;
|
||||
u32 input_status;
|
||||
|
||||
/* format change */
|
||||
fmt_change = io_read(sd, 0x43) & 0x98;
|
||||
|
|
@ -1544,9 +1529,18 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|||
io_write(sd, 0x6c, fmt_change_digital);
|
||||
if (fmt_change || fmt_change_digital) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"%s: ADV7604_FMT_CHANGE, fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
|
||||
"%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
|
||||
__func__, fmt_change, fmt_change_digital);
|
||||
v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
|
||||
|
||||
adv7604_g_input_status(sd, &input_status);
|
||||
if (input_status != state->prev_input_status) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"%s: input_status = 0x%x, prev_input_status = 0x%x\n",
|
||||
__func__, input_status, state->prev_input_status);
|
||||
state->prev_input_status = input_status;
|
||||
v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
|
||||
}
|
||||
|
||||
if (handled)
|
||||
*handled = true;
|
||||
}
|
||||
|
|
@ -1625,7 +1619,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
|
|||
u8 avi_len;
|
||||
u8 avi_ver;
|
||||
|
||||
if (!(hdmi_read(sd, 0x05) & 0x80)) {
|
||||
if (!is_hdmi(sd)) {
|
||||
v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1686,6 +1680,12 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
|
|||
"RGB limited range (16-235)",
|
||||
"RGB full range (0-255)",
|
||||
};
|
||||
char *deep_color_mode_txt[4] = {
|
||||
"8-bits per channel",
|
||||
"10-bits per channel",
|
||||
"12-bits per channel",
|
||||
"16-bits per channel (not supported)"
|
||||
};
|
||||
|
||||
v4l2_info(sd, "-----Chip status-----\n");
|
||||
v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on");
|
||||
|
|
@ -1723,8 +1723,13 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
|
|||
if (adv7604_query_dv_timings(sd, &timings))
|
||||
v4l2_info(sd, "No video detected\n");
|
||||
else
|
||||
adv7604_print_timings(sd, &timings, "Detected format:", true);
|
||||
adv7604_print_timings(sd, &state->timings, "Configured format:", true);
|
||||
v4l2_print_dv_timings(sd->name, "Detected format: ",
|
||||
&timings, true);
|
||||
v4l2_print_dv_timings(sd->name, "Configured format: ",
|
||||
&state->timings, true);
|
||||
|
||||
if (no_signal(sd))
|
||||
return 0;
|
||||
|
||||
v4l2_info(sd, "-----Color space-----\n");
|
||||
v4l2_info(sd, "RGB quantization range ctrl: %s\n",
|
||||
|
|
@ -1735,15 +1740,40 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
|
|||
(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
|
||||
(reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)",
|
||||
((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ?
|
||||
"enabled" : "disabled");
|
||||
"enabled" : "disabled");
|
||||
v4l2_info(sd, "Color space conversion: %s\n",
|
||||
csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]);
|
||||
|
||||
/* Digital video */
|
||||
if (DIGITAL_INPUT) {
|
||||
v4l2_info(sd, "-----HDMI status-----\n");
|
||||
v4l2_info(sd, "HDCP encrypted content: %s\n",
|
||||
hdmi_read(sd, 0x05) & 0x40 ? "true" : "false");
|
||||
if (!DIGITAL_INPUT)
|
||||
return 0;
|
||||
|
||||
v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D");
|
||||
v4l2_info(sd, "HDCP encrypted content: %s\n", (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false");
|
||||
v4l2_info(sd, "HDCP keys read: %s%s\n",
|
||||
(hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no",
|
||||
(hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : "");
|
||||
if (!is_hdmi(sd)) {
|
||||
bool audio_pll_locked = hdmi_read(sd, 0x04) & 0x01;
|
||||
bool audio_sample_packet_detect = hdmi_read(sd, 0x18) & 0x01;
|
||||
bool audio_mute = io_read(sd, 0x65) & 0x40;
|
||||
|
||||
v4l2_info(sd, "Audio: pll %s, samples %s, %s\n",
|
||||
audio_pll_locked ? "locked" : "not locked",
|
||||
audio_sample_packet_detect ? "detected" : "not detected",
|
||||
audio_mute ? "muted" : "enabled");
|
||||
if (audio_pll_locked && audio_sample_packet_detect) {
|
||||
v4l2_info(sd, "Audio format: %s\n",
|
||||
(hdmi_read(sd, 0x07) & 0x20) ? "multi-channel" : "stereo");
|
||||
}
|
||||
v4l2_info(sd, "Audio CTS: %u\n", (hdmi_read(sd, 0x5b) << 12) +
|
||||
(hdmi_read(sd, 0x5c) << 8) +
|
||||
(hdmi_read(sd, 0x5d) & 0xf0));
|
||||
v4l2_info(sd, "Audio N: %u\n", ((hdmi_read(sd, 0x5d) & 0x0f) << 16) +
|
||||
(hdmi_read(sd, 0x5e) << 8) +
|
||||
hdmi_read(sd, 0x5f));
|
||||
v4l2_info(sd, "AV Mute: %s\n", (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off");
|
||||
|
||||
v4l2_info(sd, "Deep color mode: %s\n", deep_color_mode_txt[(hdmi_read(sd, 0x0b) & 0x60) >> 5]);
|
||||
|
||||
print_avi_infoframe(sd);
|
||||
}
|
||||
|
|
@ -1952,6 +1982,10 @@ static int adv7604_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* initialize variables */
|
||||
state->restart_stdi_once = true;
|
||||
state->prev_input_status = ~0;
|
||||
|
||||
/* platform data */
|
||||
if (!pdata) {
|
||||
v4l_err(client, "No platform data!\n");
|
||||
|
|
@ -1987,29 +2021,30 @@ static int adv7604_probe(struct i2c_client *client,
|
|||
/* private controls */
|
||||
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
|
||||
state->detect_tx_5v_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl =
|
||||
v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops,
|
||||
V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
|
||||
0, V4L2_DV_RGB_RANGE_AUTO);
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
|
||||
/* custom controls */
|
||||
state->analog_sampling_phase_ctrl =
|
||||
v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL);
|
||||
state->analog_sampling_phase_ctrl->is_private = true;
|
||||
state->free_run_color_manual_ctrl =
|
||||
v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL);
|
||||
state->free_run_color_manual_ctrl->is_private = true;
|
||||
state->free_run_color_ctrl =
|
||||
v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color, NULL);
|
||||
state->free_run_color_ctrl->is_private = true;
|
||||
|
||||
sd->ctrl_handler = hdl;
|
||||
if (hdl->error) {
|
||||
err = hdl->error;
|
||||
goto err_hdl;
|
||||
}
|
||||
state->detect_tx_5v_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
state->analog_sampling_phase_ctrl->is_private = true;
|
||||
state->free_run_color_manual_ctrl->is_private = true;
|
||||
state->free_run_color_ctrl->is_private = true;
|
||||
|
||||
if (adv7604_s_detect_tx_5v_ctrl(sd)) {
|
||||
err = -ENODEV;
|
||||
goto err_hdl;
|
||||
|
|
@ -2035,7 +2070,6 @@ static int adv7604_probe(struct i2c_client *client,
|
|||
v4l2_err(sd, "failed to create all i2c clients\n");
|
||||
goto err_i2c;
|
||||
}
|
||||
state->restart_stdi_once = true;
|
||||
|
||||
/* work queues */
|
||||
state->work_queues = create_singlethread_workqueue(client->name);
|
||||
|
|
|
|||
2946
drivers/media/i2c/adv7842.c
Normal file
2946
drivers/media/i2c/adv7842.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -209,7 +209,8 @@ static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd,
|
|||
|
||||
fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
fmt->field = V4L2_FIELD_INTERLACED;
|
||||
/* The top field is always transferred first by the chip */
|
||||
fmt->field = V4L2_FIELD_INTERLACED_TB;
|
||||
fmt->width = 720;
|
||||
fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/log2.h>
|
||||
|
|
@ -135,6 +136,8 @@ struct mt9v032 {
|
|||
struct mutex power_lock;
|
||||
int power_count;
|
||||
|
||||
struct clk *clk;
|
||||
|
||||
struct mt9v032_platform_data *pdata;
|
||||
|
||||
u32 sysclk;
|
||||
|
|
@ -219,10 +222,9 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
|||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
||||
int ret;
|
||||
|
||||
if (mt9v032->pdata->set_clock) {
|
||||
mt9v032->pdata->set_clock(&mt9v032->subdev, mt9v032->sysclk);
|
||||
udelay(1);
|
||||
}
|
||||
clk_set_rate(mt9v032->clk, mt9v032->sysclk);
|
||||
clk_prepare_enable(mt9v032->clk);
|
||||
udelay(1);
|
||||
|
||||
/* Reset the chip and stop data read out */
|
||||
ret = mt9v032_write(client, MT9V032_RESET, 1);
|
||||
|
|
@ -238,8 +240,7 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
|||
|
||||
static void mt9v032_power_off(struct mt9v032 *mt9v032)
|
||||
{
|
||||
if (mt9v032->pdata->set_clock)
|
||||
mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
|
||||
clk_disable_unprepare(mt9v032->clk);
|
||||
}
|
||||
|
||||
static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
|
||||
|
|
@ -748,6 +749,10 @@ static int mt9v032_probe(struct i2c_client *client,
|
|||
if (!mt9v032)
|
||||
return -ENOMEM;
|
||||
|
||||
mt9v032->clk = devm_clk_get(&client->dev, NULL);
|
||||
if (IS_ERR(mt9v032->clk))
|
||||
return PTR_ERR(mt9v032->clk);
|
||||
|
||||
mutex_init(&mt9v032->power_lock);
|
||||
mt9v032->pdata = pdata;
|
||||
|
||||
|
|
|
|||
|
|
@ -1083,7 +1083,7 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
|
|||
{
|
||||
int i = ARRAY_SIZE(ov965x_formats);
|
||||
|
||||
if (fse->index > ARRAY_SIZE(ov965x_framesizes))
|
||||
if (fse->index >= ARRAY_SIZE(ov965x_framesizes))
|
||||
return -EINVAL;
|
||||
|
||||
while (--i)
|
||||
|
|
|
|||
|
|
@ -1111,6 +1111,11 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
|
|||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
mf = v4l2_subdev_get_try_format(fh, fmt->pad);
|
||||
*mf = fmt->format;
|
||||
if (fmt->pad == OIF_ISP_PAD) {
|
||||
mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD);
|
||||
mf->width = fmt->format.width;
|
||||
mf->height = fmt->format.height;
|
||||
}
|
||||
} else {
|
||||
switch (fmt->pad) {
|
||||
case OIF_ISP_PAD:
|
||||
|
|
|
|||
|
|
@ -1003,7 +1003,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
|
|||
const struct s5k6aa_interval *fi;
|
||||
int ret = 0;
|
||||
|
||||
if (fie->index > ARRAY_SIZE(s5k6aa_intervals))
|
||||
if (fie->index >= ARRAY_SIZE(s5k6aa_intervals))
|
||||
return -EINVAL;
|
||||
|
||||
v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
|
||||
|
|
|
|||
|
|
@ -225,19 +225,27 @@ static const unsigned char saa7111_init[] = {
|
|||
0x00, 0x00
|
||||
};
|
||||
|
||||
/* SAA7113/GM7113C init codes
|
||||
* It's important that R_14... R_17 == 0x00
|
||||
* for the gm7113c chip to deliver stable video
|
||||
/*
|
||||
* This table has one illegal value, and some values that are not
|
||||
* correct according to the datasheet initialization table.
|
||||
*
|
||||
* If you need a table with legal/default values tell the driver in
|
||||
* i2c_board_info.platform_data, and you will get the gm7113c_init
|
||||
* table instead.
|
||||
*/
|
||||
|
||||
/* SAA7113 Init codes */
|
||||
static const unsigned char saa7113_init[] = {
|
||||
R_01_INC_DELAY, 0x08,
|
||||
R_02_INPUT_CNTL_1, 0xc2,
|
||||
R_03_INPUT_CNTL_2, 0x30,
|
||||
R_04_INPUT_CNTL_3, 0x00,
|
||||
R_05_INPUT_CNTL_4, 0x00,
|
||||
R_06_H_SYNC_START, 0x89,
|
||||
R_06_H_SYNC_START, 0x89, /* Illegal value -119,
|
||||
* min. value = -108 (0x94) */
|
||||
R_07_H_SYNC_STOP, 0x0d,
|
||||
R_08_SYNC_CNTL, 0x88,
|
||||
R_08_SYNC_CNTL, 0x88, /* Not datasheet default.
|
||||
* HTC = VTR mode, should be 0x98 */
|
||||
R_09_LUMA_CNTL, 0x01,
|
||||
R_0A_LUMA_BRIGHT_CNTL, 0x80,
|
||||
R_0B_LUMA_CONTRAST_CNTL, 0x47,
|
||||
|
|
@ -245,9 +253,45 @@ static const unsigned char saa7113_init[] = {
|
|||
R_0D_CHROMA_HUE_CNTL, 0x00,
|
||||
R_0E_CHROMA_CNTL_1, 0x01,
|
||||
R_0F_CHROMA_GAIN_CNTL, 0x2a,
|
||||
R_10_CHROMA_CNTL_2, 0x08,
|
||||
R_10_CHROMA_CNTL_2, 0x08, /* Not datsheet default.
|
||||
* VRLN enabled, should be 0x00 */
|
||||
R_11_MODE_DELAY_CNTL, 0x0c,
|
||||
R_12_RT_SIGNAL_CNTL, 0x07,
|
||||
R_12_RT_SIGNAL_CNTL, 0x07, /* Not datasheet default,
|
||||
* should be 0x01 */
|
||||
R_13_RT_X_PORT_OUT_CNTL, 0x00,
|
||||
R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
|
||||
R_15_VGATE_START_FID_CHG, 0x00,
|
||||
R_16_VGATE_STOP, 0x00,
|
||||
R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* GM7113C is a clone of the SAA7113 chip
|
||||
* This init table is copied out of the saa7113 datasheet.
|
||||
* In R_08 we enable "Automatic Field Detection" [AUFD],
|
||||
* this is disabled when saa711x_set_v4lstd is called.
|
||||
*/
|
||||
static const unsigned char gm7113c_init[] = {
|
||||
R_01_INC_DELAY, 0x08,
|
||||
R_02_INPUT_CNTL_1, 0xc0,
|
||||
R_03_INPUT_CNTL_2, 0x33,
|
||||
R_04_INPUT_CNTL_3, 0x00,
|
||||
R_05_INPUT_CNTL_4, 0x00,
|
||||
R_06_H_SYNC_START, 0xe9,
|
||||
R_07_H_SYNC_STOP, 0x0d,
|
||||
R_08_SYNC_CNTL, 0x98,
|
||||
R_09_LUMA_CNTL, 0x01,
|
||||
R_0A_LUMA_BRIGHT_CNTL, 0x80,
|
||||
R_0B_LUMA_CONTRAST_CNTL, 0x47,
|
||||
R_0C_CHROMA_SAT_CNTL, 0x40,
|
||||
R_0D_CHROMA_HUE_CNTL, 0x00,
|
||||
R_0E_CHROMA_CNTL_1, 0x01,
|
||||
R_0F_CHROMA_GAIN_CNTL, 0x2a,
|
||||
R_10_CHROMA_CNTL_2, 0x00,
|
||||
R_11_MODE_DELAY_CNTL, 0x0c,
|
||||
R_12_RT_SIGNAL_CNTL, 0x01,
|
||||
R_13_RT_X_PORT_OUT_CNTL, 0x00,
|
||||
R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
|
||||
R_15_VGATE_START_FID_CHG, 0x00,
|
||||
|
|
@ -462,24 +506,6 @@ static const unsigned char saa7115_cfg_50hz_video[] = {
|
|||
|
||||
/* ============== SAA7715 VIDEO templates (end) ======= */
|
||||
|
||||
/* ============== GM7113C VIDEO templates ============= */
|
||||
static const unsigned char gm7113c_cfg_60hz_video[] = {
|
||||
R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
|
||||
R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
static const unsigned char gm7113c_cfg_50hz_video[] = {
|
||||
R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
|
||||
R_0E_CHROMA_CNTL_1, 0x07,
|
||||
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
/* ============== GM7113C VIDEO templates (end) ======= */
|
||||
|
||||
|
||||
static const unsigned char saa7115_cfg_vbi_on[] = {
|
||||
R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
|
||||
R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
|
||||
|
|
@ -964,17 +990,24 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
|
|||
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
|
||||
if (std & V4L2_STD_525_60) {
|
||||
v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
|
||||
if (state->ident == GM7113C)
|
||||
saa711x_writeregs(sd, gm7113c_cfg_60hz_video);
|
||||
else
|
||||
if (state->ident == GM7113C) {
|
||||
u8 reg = saa711x_read(sd, R_08_SYNC_CNTL);
|
||||
reg &= ~(SAA7113_R_08_FSEL | SAA7113_R_08_AUFD);
|
||||
reg |= SAA7113_R_08_FSEL;
|
||||
saa711x_write(sd, R_08_SYNC_CNTL, reg);
|
||||
} else {
|
||||
saa711x_writeregs(sd, saa7115_cfg_60hz_video);
|
||||
}
|
||||
saa711x_set_size(sd, 720, 480);
|
||||
} else {
|
||||
v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
|
||||
if (state->ident == GM7113C)
|
||||
saa711x_writeregs(sd, gm7113c_cfg_50hz_video);
|
||||
else
|
||||
if (state->ident == GM7113C) {
|
||||
u8 reg = saa711x_read(sd, R_08_SYNC_CNTL);
|
||||
reg &= ~(SAA7113_R_08_FSEL | SAA7113_R_08_AUFD);
|
||||
saa711x_write(sd, R_08_SYNC_CNTL, reg);
|
||||
} else {
|
||||
saa711x_writeregs(sd, saa7115_cfg_50hz_video);
|
||||
}
|
||||
saa711x_set_size(sd, 720, 576);
|
||||
}
|
||||
|
||||
|
|
@ -1596,6 +1629,65 @@ static const struct v4l2_subdev_ops saa711x_ops = {
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void saa711x_write_platform_data(struct saa711x_state *state,
|
||||
struct saa7115_platform_data *data)
|
||||
{
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
u8 work;
|
||||
|
||||
if (state->ident != GM7113C &&
|
||||
state->ident != SAA7113)
|
||||
return;
|
||||
|
||||
if (data->saa7113_r08_htc) {
|
||||
work = saa711x_read(sd, R_08_SYNC_CNTL);
|
||||
work &= ~SAA7113_R_08_HTC_MASK;
|
||||
work |= ((*data->saa7113_r08_htc) << SAA7113_R_08_HTC_OFFSET);
|
||||
saa711x_write(sd, R_08_SYNC_CNTL, work);
|
||||
}
|
||||
|
||||
if (data->saa7113_r10_vrln) {
|
||||
work = saa711x_read(sd, R_10_CHROMA_CNTL_2);
|
||||
work &= ~SAA7113_R_10_VRLN_MASK;
|
||||
if (*data->saa7113_r10_vrln)
|
||||
work |= (1 << SAA7113_R_10_VRLN_OFFSET);
|
||||
saa711x_write(sd, R_10_CHROMA_CNTL_2, work);
|
||||
}
|
||||
|
||||
if (data->saa7113_r10_ofts) {
|
||||
work = saa711x_read(sd, R_10_CHROMA_CNTL_2);
|
||||
work &= ~SAA7113_R_10_OFTS_MASK;
|
||||
work |= (*data->saa7113_r10_ofts << SAA7113_R_10_OFTS_OFFSET);
|
||||
saa711x_write(sd, R_10_CHROMA_CNTL_2, work);
|
||||
}
|
||||
|
||||
if (data->saa7113_r12_rts0) {
|
||||
work = saa711x_read(sd, R_12_RT_SIGNAL_CNTL);
|
||||
work &= ~SAA7113_R_12_RTS0_MASK;
|
||||
work |= (*data->saa7113_r12_rts0 << SAA7113_R_12_RTS0_OFFSET);
|
||||
|
||||
/* According to the datasheet,
|
||||
* SAA7113_RTS_DOT_IN should only be used on RTS1 */
|
||||
WARN_ON(*data->saa7113_r12_rts0 == SAA7113_RTS_DOT_IN);
|
||||
saa711x_write(sd, R_12_RT_SIGNAL_CNTL, work);
|
||||
}
|
||||
|
||||
if (data->saa7113_r12_rts1) {
|
||||
work = saa711x_read(sd, R_12_RT_SIGNAL_CNTL);
|
||||
work &= ~SAA7113_R_12_RTS1_MASK;
|
||||
work |= (*data->saa7113_r12_rts1 << SAA7113_R_12_RTS1_OFFSET);
|
||||
saa711x_write(sd, R_12_RT_SIGNAL_CNTL, work);
|
||||
}
|
||||
|
||||
if (data->saa7113_r13_adlsb) {
|
||||
work = saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL);
|
||||
work &= ~SAA7113_R_13_ADLSB_MASK;
|
||||
if (*data->saa7113_r13_adlsb)
|
||||
work |= (1 << SAA7113_R_13_ADLSB_OFFSET);
|
||||
saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL, work);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* saa711x_detect_chip - Detects the saa711x (or clone) variant
|
||||
* @client: I2C client structure.
|
||||
|
|
@ -1704,6 +1796,7 @@ static int saa711x_probe(struct i2c_client *client,
|
|||
struct saa711x_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
struct v4l2_ctrl_handler *hdl;
|
||||
struct saa7115_platform_data *pdata;
|
||||
int ident;
|
||||
char name[CHIP_VER_SIZE + 1];
|
||||
|
||||
|
|
@ -1767,21 +1860,31 @@ static int saa711x_probe(struct i2c_client *client,
|
|||
|
||||
/* init to 60hz/48khz */
|
||||
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
|
||||
pdata = client->dev.platform_data;
|
||||
switch (state->ident) {
|
||||
case SAA7111:
|
||||
case SAA7111A:
|
||||
saa711x_writeregs(sd, saa7111_init);
|
||||
break;
|
||||
case GM7113C:
|
||||
saa711x_writeregs(sd, gm7113c_init);
|
||||
break;
|
||||
case SAA7113:
|
||||
saa711x_writeregs(sd, saa7113_init);
|
||||
if (pdata && pdata->saa7113_force_gm7113c_init)
|
||||
saa711x_writeregs(sd, gm7113c_init);
|
||||
else
|
||||
saa711x_writeregs(sd, saa7113_init);
|
||||
break;
|
||||
default:
|
||||
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
|
||||
saa711x_writeregs(sd, saa7115_init_auto_input);
|
||||
}
|
||||
if (state->ident > SAA7111A)
|
||||
if (state->ident > SAA7111A && state->ident != GM7113C)
|
||||
saa711x_writeregs(sd, saa7115_init_misc);
|
||||
|
||||
if (pdata)
|
||||
saa711x_write_platform_data(state, pdata);
|
||||
|
||||
saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
|
||||
v4l2_ctrl_handler_setup(hdl);
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,25 @@
|
|||
#define R_FB_PULSE_C_POS_MSB 0xfb
|
||||
#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES 0xff
|
||||
|
||||
/* SAA7113 bit-masks */
|
||||
#define SAA7113_R_08_HTC_OFFSET 3
|
||||
#define SAA7113_R_08_HTC_MASK (0x3 << SAA7113_R_08_HTC_OFFSET)
|
||||
#define SAA7113_R_08_FSEL 0x40
|
||||
#define SAA7113_R_08_AUFD 0x80
|
||||
|
||||
#define SAA7113_R_10_VRLN_OFFSET 3
|
||||
#define SAA7113_R_10_VRLN_MASK (0x1 << SAA7113_R_10_VRLN_OFFSET)
|
||||
#define SAA7113_R_10_OFTS_OFFSET 6
|
||||
#define SAA7113_R_10_OFTS_MASK (0x3 << SAA7113_R_10_OFTS_OFFSET)
|
||||
|
||||
#define SAA7113_R_12_RTS0_OFFSET 0
|
||||
#define SAA7113_R_12_RTS0_MASK (0xf << SAA7113_R_12_RTS0_OFFSET)
|
||||
#define SAA7113_R_12_RTS1_OFFSET 4
|
||||
#define SAA7113_R_12_RTS1_MASK (0xf << SAA7113_R_12_RTS1_OFFSET)
|
||||
|
||||
#define SAA7113_R_13_ADLSB_OFFSET 7
|
||||
#define SAA7113_R_13_ADLSB_MASK (0x1 << SAA7113_R_13_ADLSB_OFFSET)
|
||||
|
||||
#if 0
|
||||
/* Those structs will be used in the future for debug purposes */
|
||||
struct saa711x_reg_descr {
|
||||
|
|
|
|||
|
|
@ -87,6 +87,17 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll)
|
|||
dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Heuristically guess the PLL tree for a given common multiplier and
|
||||
* divisor. Begin with the operational timing and continue to video
|
||||
* timing once operational timing has been verified.
|
||||
*
|
||||
* @mul is the PLL multiplier and @div is the common divisor
|
||||
* (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
|
||||
* multiplier will be a multiple of @mul.
|
||||
*
|
||||
* @return Zero on success, error code on error.
|
||||
*/
|
||||
static int __smiapp_pll_calculate(struct device *dev,
|
||||
const struct smiapp_pll_limits *limits,
|
||||
struct smiapp_pll *pll, uint32_t mul,
|
||||
|
|
@ -95,6 +106,12 @@ static int __smiapp_pll_calculate(struct device *dev,
|
|||
uint32_t sys_div;
|
||||
uint32_t best_pix_div = INT_MAX >> 1;
|
||||
uint32_t vt_op_binning_div;
|
||||
/*
|
||||
* Higher multipliers (and divisors) are often required than
|
||||
* necessitated by the external clock and the output clocks.
|
||||
* There are limits for all values in the clock tree. These
|
||||
* are the minimum and maximum multiplier for mul.
|
||||
*/
|
||||
uint32_t more_mul_min, more_mul_max;
|
||||
uint32_t more_mul_factor;
|
||||
uint32_t min_vt_div, max_vt_div, vt_div;
|
||||
|
|
|
|||
|
|
@ -1122,9 +1122,9 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
|
|||
rval = sensor->platform_data->set_xclk(
|
||||
&sensor->src->sd, sensor->platform_data->ext_clk);
|
||||
else
|
||||
rval = clk_enable(sensor->ext_clk);
|
||||
rval = clk_prepare_enable(sensor->ext_clk);
|
||||
if (rval < 0) {
|
||||
dev_dbg(&client->dev, "failed to set xclk\n");
|
||||
dev_dbg(&client->dev, "failed to enable xclk\n");
|
||||
goto out_xclk_fail;
|
||||
}
|
||||
usleep_range(1000, 1000);
|
||||
|
|
@ -1244,7 +1244,7 @@ out_cci_addr_fail:
|
|||
if (sensor->platform_data->set_xclk)
|
||||
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
|
||||
else
|
||||
clk_disable(sensor->ext_clk);
|
||||
clk_disable_unprepare(sensor->ext_clk);
|
||||
|
||||
out_xclk_fail:
|
||||
regulator_disable(sensor->vana);
|
||||
|
|
@ -1270,7 +1270,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
|
|||
if (sensor->platform_data->set_xclk)
|
||||
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
|
||||
else
|
||||
clk_disable(sensor->ext_clk);
|
||||
clk_disable_unprepare(sensor->ext_clk);
|
||||
usleep_range(5000, 5000);
|
||||
regulator_disable(sensor->vana);
|
||||
sensor->streaming = 0;
|
||||
|
|
@ -1835,12 +1835,12 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
|
|||
* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
|
||||
/ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
|
||||
|
||||
a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
|
||||
max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
|
||||
b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
|
||||
max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
|
||||
max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
|
||||
max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
|
||||
a = clamp(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
|
||||
sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
|
||||
b = clamp(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
|
||||
sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
|
||||
max_m = clamp(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
|
||||
sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
|
||||
|
||||
dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
|
||||
|
||||
|
|
@ -2363,11 +2363,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
|
|||
}
|
||||
|
||||
if (!sensor->platform_data->set_xclk) {
|
||||
sensor->ext_clk = devm_clk_get(&client->dev,
|
||||
sensor->platform_data->ext_clk_name);
|
||||
sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk");
|
||||
if (IS_ERR(sensor->ext_clk)) {
|
||||
dev_err(&client->dev, "could not get clock %s\n",
|
||||
sensor->platform_data->ext_clk_name);
|
||||
dev_err(&client->dev, "could not get clock\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -2375,8 +2373,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
|
|||
sensor->platform_data->ext_clk);
|
||||
if (rval < 0) {
|
||||
dev_err(&client->dev,
|
||||
"unable to set clock %s freq to %u\n",
|
||||
sensor->platform_data->ext_clk_name,
|
||||
"unable to set clock freq to %u\n",
|
||||
sensor->platform_data->ext_clk);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -2839,7 +2836,7 @@ static int smiapp_remove(struct i2c_client *client)
|
|||
if (sensor->platform_data->set_xclk)
|
||||
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
|
||||
else
|
||||
clk_disable(sensor->ext_clk);
|
||||
clk_disable_unprepare(sensor->ext_clk);
|
||||
sensor->power_count = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -946,6 +946,10 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
if (!mt9m111)
|
||||
return -ENOMEM;
|
||||
|
||||
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
|
||||
if (IS_ERR(mt9m111->clk))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
/* Default HIGHPOWER context */
|
||||
mt9m111->ctx = &context_b;
|
||||
|
||||
|
|
@ -963,8 +967,10 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
&mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
|
||||
V4L2_EXPOSURE_AUTO);
|
||||
mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
|
||||
if (mt9m111->hdl.error)
|
||||
return mt9m111->hdl.error;
|
||||
if (mt9m111->hdl.error) {
|
||||
ret = mt9m111->hdl.error;
|
||||
goto out_clkput;
|
||||
}
|
||||
|
||||
/* Second stage probe - when a capture adapter is there */
|
||||
mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
|
||||
|
|
@ -975,18 +981,25 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
mt9m111->lastpage = -1;
|
||||
mutex_init(&mt9m111->power_lock);
|
||||
|
||||
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
|
||||
if (IS_ERR(mt9m111->clk)) {
|
||||
ret = PTR_ERR(mt9m111->clk);
|
||||
goto eclkget;
|
||||
}
|
||||
ret = soc_camera_power_init(&client->dev, ssdd);
|
||||
if (ret < 0)
|
||||
goto out_hdlfree;
|
||||
|
||||
ret = mt9m111_video_probe(client);
|
||||
if (ret) {
|
||||
v4l2_clk_put(mt9m111->clk);
|
||||
eclkget:
|
||||
v4l2_ctrl_handler_free(&mt9m111->hdl);
|
||||
}
|
||||
if (ret < 0)
|
||||
goto out_hdlfree;
|
||||
|
||||
mt9m111->subdev.dev = &client->dev;
|
||||
ret = v4l2_async_register_subdev(&mt9m111->subdev);
|
||||
if (ret < 0)
|
||||
goto out_hdlfree;
|
||||
|
||||
return 0;
|
||||
|
||||
out_hdlfree:
|
||||
v4l2_ctrl_handler_free(&mt9m111->hdl);
|
||||
out_clkput:
|
||||
v4l2_clk_put(mt9m111->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -995,6 +1008,7 @@ static int mt9m111_remove(struct i2c_client *client)
|
|||
{
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
|
||||
v4l2_async_unregister_subdev(&mt9m111->subdev);
|
||||
v4l2_clk_put(mt9m111->clk);
|
||||
v4l2_device_unregister_subdev(&mt9m111->subdev);
|
||||
v4l2_ctrl_handler_free(&mt9m111->hdl);
|
||||
|
|
|
|||
|
|
@ -594,9 +594,12 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
|
|||
ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
vdev->dev.type = &mt9t031_dev_type;
|
||||
if (vdev)
|
||||
/* Not needed during probing, when vdev isn't available yet */
|
||||
vdev->dev.type = &mt9t031_dev_type;
|
||||
} else {
|
||||
vdev->dev.type = NULL;
|
||||
if (vdev)
|
||||
vdev->dev.type = NULL;
|
||||
soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,10 +291,8 @@ static int ths7303_log_status(struct v4l2_subdev *sd)
|
|||
struct v4l2_bt_timings *bt = bt = &state->bt;
|
||||
u32 frame_width, frame_height;
|
||||
|
||||
frame_width = bt->width + bt->hfrontporch +
|
||||
bt->hsync + bt->hbackporch;
|
||||
frame_height = bt->height + bt->vfrontporch +
|
||||
bt->vsync + bt->vbackporch;
|
||||
frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
|
||||
frame_height = V4L2_DV_BT_FRAME_HEIGHT(bt);
|
||||
v4l2_info(sd,
|
||||
"timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n",
|
||||
bt->width, bt->height, bt->interlaced ? "i" : "p",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
#include "ths8200_regs.h"
|
||||
|
|
@ -42,18 +44,16 @@ struct ths8200_state {
|
|||
struct v4l2_dv_timings dv_timings;
|
||||
};
|
||||
|
||||
static const struct v4l2_dv_timings ths8200_timings[] = {
|
||||
V4L2_DV_BT_CEA_720X480P59_94,
|
||||
V4L2_DV_BT_CEA_1280X720P24,
|
||||
V4L2_DV_BT_CEA_1280X720P25,
|
||||
V4L2_DV_BT_CEA_1280X720P30,
|
||||
V4L2_DV_BT_CEA_1280X720P50,
|
||||
V4L2_DV_BT_CEA_1280X720P60,
|
||||
V4L2_DV_BT_CEA_1920X1080P24,
|
||||
V4L2_DV_BT_CEA_1920X1080P25,
|
||||
V4L2_DV_BT_CEA_1920X1080P30,
|
||||
V4L2_DV_BT_CEA_1920X1080P50,
|
||||
V4L2_DV_BT_CEA_1920X1080P60,
|
||||
static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
|
||||
.type = V4L2_DV_BT_656_1120,
|
||||
.bt = {
|
||||
.max_width = 1920,
|
||||
.max_height = 1080,
|
||||
.min_pixelclock = 25000000,
|
||||
.max_pixelclock = 148500000,
|
||||
.standards = V4L2_DV_BT_STD_CEA861,
|
||||
.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE,
|
||||
},
|
||||
};
|
||||
|
||||
static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
|
||||
|
|
@ -63,22 +63,22 @@ static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
|
|||
|
||||
static inline unsigned hblanking(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->hfrontporch + t->hsync + t->hbackporch;
|
||||
return V4L2_DV_BT_BLANKING_WIDTH(t);
|
||||
}
|
||||
|
||||
static inline unsigned htotal(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->width + t->hfrontporch + t->hsync + t->hbackporch;
|
||||
return V4L2_DV_BT_FRAME_WIDTH(t);
|
||||
}
|
||||
|
||||
static inline unsigned vblanking(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->vfrontporch + t->vsync + t->vbackporch;
|
||||
return V4L2_DV_BT_BLANKING_HEIGHT(t);
|
||||
}
|
||||
|
||||
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
|
||||
{
|
||||
return t->height + t->vfrontporch + t->vsync + t->vbackporch;
|
||||
return V4L2_DV_BT_FRAME_HEIGHT(t);
|
||||
}
|
||||
|
||||
static int ths8200_read(struct v4l2_subdev *sd, u8 reg)
|
||||
|
|
@ -133,39 +133,6 @@ static int ths8200_s_register(struct v4l2_subdev *sd,
|
|||
}
|
||||
#endif
|
||||
|
||||
static void ths8200_print_timings(struct v4l2_subdev *sd,
|
||||
struct v4l2_dv_timings *timings,
|
||||
const char *txt, bool detailed)
|
||||
{
|
||||
struct v4l2_bt_timings *bt = &timings->bt;
|
||||
u32 htot, vtot;
|
||||
|
||||
if (timings->type != V4L2_DV_BT_656_1120)
|
||||
return;
|
||||
|
||||
htot = htotal(bt);
|
||||
vtot = vtotal(bt);
|
||||
|
||||
v4l2_info(sd, "%s %dx%d%s%d (%dx%d)",
|
||||
txt, bt->width, bt->height, bt->interlaced ? "i" : "p",
|
||||
(htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0,
|
||||
htot, vtot);
|
||||
|
||||
if (detailed) {
|
||||
v4l2_info(sd, " horizontal: fp = %d, %ssync = %d, bp = %d\n",
|
||||
bt->hfrontporch,
|
||||
(bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
|
||||
bt->hsync, bt->hbackporch);
|
||||
v4l2_info(sd, " vertical: fp = %d, %ssync = %d, bp = %d\n",
|
||||
bt->vfrontporch,
|
||||
(bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
|
||||
bt->vsync, bt->vbackporch);
|
||||
v4l2_info(sd,
|
||||
" pixelclock: %lld, flags: 0x%x, standards: 0x%x\n",
|
||||
bt->pixelclock, bt->flags, bt->standards);
|
||||
}
|
||||
}
|
||||
|
||||
static int ths8200_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct ths8200_state *state = to_state(sd);
|
||||
|
|
@ -182,9 +149,8 @@ static int ths8200_log_status(struct v4l2_subdev *sd)
|
|||
ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_LSB),
|
||||
(ths8200_read(sd, THS8200_DTG2_LINE_CNT_MSB) & 0x07) * 256 +
|
||||
ths8200_read(sd, THS8200_DTG2_LINE_CNT_LSB));
|
||||
ths8200_print_timings(sd, &state->dv_timings,
|
||||
"Configured format:", true);
|
||||
|
||||
v4l2_print_dv_timings(sd->name, "Configured format:",
|
||||
&state->dv_timings, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -409,25 +375,15 @@ static int ths8200_s_dv_timings(struct v4l2_subdev *sd,
|
|||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct ths8200_state *state = to_state(sd);
|
||||
int i;
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s:\n", __func__);
|
||||
|
||||
if (timings->type != V4L2_DV_BT_656_1120)
|
||||
if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap,
|
||||
NULL, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO Support interlaced formats */
|
||||
if (timings->bt.interlaced) {
|
||||
v4l2_dbg(1, debug, sd, "TODO Support interlaced formats\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ths8200_timings); i++) {
|
||||
if (v4l_match_dv_timings(&ths8200_timings[i], timings, 10))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(ths8200_timings)) {
|
||||
if (!v4l2_find_dv_timings_cap(timings, &ths8200_timings_cap, 10,
|
||||
NULL, NULL)) {
|
||||
v4l2_dbg(1, debug, sd, "Unsupported format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -457,26 +413,14 @@ static int ths8200_g_dv_timings(struct v4l2_subdev *sd,
|
|||
static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
|
||||
struct v4l2_enum_dv_timings *timings)
|
||||
{
|
||||
/* Check requested format index is within range */
|
||||
if (timings->index >= ARRAY_SIZE(ths8200_timings))
|
||||
return -EINVAL;
|
||||
|
||||
timings->timings = ths8200_timings[timings->index];
|
||||
|
||||
return 0;
|
||||
return v4l2_enum_dv_timings_cap(timings, &ths8200_timings_cap,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static int ths8200_dv_timings_cap(struct v4l2_subdev *sd,
|
||||
struct v4l2_dv_timings_cap *cap)
|
||||
{
|
||||
cap->type = V4L2_DV_BT_656_1120;
|
||||
cap->bt.max_width = 1920;
|
||||
cap->bt.max_height = 1080;
|
||||
cap->bt.min_pixelclock = 27000000;
|
||||
cap->bt.max_pixelclock = 148500000;
|
||||
cap->bt.standards = V4L2_DV_BT_STD_CEA861;
|
||||
cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE;
|
||||
|
||||
*cap = ths8200_timings_cap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -500,6 +444,7 @@ static int ths8200_probe(struct i2c_client *client,
|
|||
{
|
||||
struct ths8200_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
int error;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
|
|
@ -517,6 +462,10 @@ static int ths8200_probe(struct i2c_client *client,
|
|||
|
||||
ths8200_core_init(sd);
|
||||
|
||||
error = v4l2_async_register_subdev(&state->sd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
|
|
@ -526,12 +475,13 @@ static int ths8200_probe(struct i2c_client *client,
|
|||
static int ths8200_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ths8200_state *decoder = to_state(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
ths8200_s_power(sd, false);
|
||||
|
||||
v4l2_async_unregister_subdev(&decoder->sd);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
|
||||
return 0;
|
||||
|
|
@ -543,10 +493,19 @@ static struct i2c_device_id ths8200_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ths8200_id);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id ths8200_of_match[] = {
|
||||
{ .compatible = "ti,ths8200", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ths8200_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver ths8200_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ths8200",
|
||||
.of_match_table = of_match_ptr(ths8200_of_match),
|
||||
},
|
||||
.probe = ths8200_probe,
|
||||
.remove = ths8200_remove,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/v4l2-mediabus.h>
|
||||
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-mediabus.h>
|
||||
|
|
@ -1175,16 +1176,22 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
sd->ctrl_handler = &decoder->hdl;
|
||||
if (decoder->hdl.error) {
|
||||
ret = decoder->hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&decoder->hdl);
|
||||
return ret;
|
||||
goto done;
|
||||
}
|
||||
v4l2_ctrl_handler_setup(&decoder->hdl);
|
||||
|
||||
v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
|
||||
|
||||
return 0;
|
||||
ret = v4l2_async_register_subdev(&decoder->sd);
|
||||
if (!ret)
|
||||
v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
|
||||
|
||||
done:
|
||||
if (ret < 0) {
|
||||
v4l2_ctrl_handler_free(&decoder->hdl);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&decoder->sd.entity);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1199,6 +1206,7 @@ static int tvp514x_remove(struct i2c_client *client)
|
|||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct tvp514x_decoder *decoder = to_decoder(sd);
|
||||
|
||||
v4l2_async_unregister_subdev(&decoder->sd);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&decoder->sd.entity);
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <media/tvp7002.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-of.h>
|
||||
|
||||
#include "tvp7002_reg.h"
|
||||
|
||||
MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
|
||||
|
|
@ -942,6 +945,48 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
|
|||
.pad = &tvp7002_pad_ops,
|
||||
};
|
||||
|
||||
static struct tvp7002_config *
|
||||
tvp7002_get_pdata(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_of_endpoint bus_cfg;
|
||||
struct tvp7002_config *pdata;
|
||||
struct device_node *endpoint;
|
||||
unsigned int flags;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!endpoint)
|
||||
return NULL;
|
||||
|
||||
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
goto done;
|
||||
|
||||
v4l2_of_parse_endpoint(endpoint, &bus_cfg);
|
||||
flags = bus_cfg.bus.parallel.flags;
|
||||
|
||||
if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
|
||||
pdata->hs_polarity = 1;
|
||||
|
||||
if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
|
||||
pdata->vs_polarity = 1;
|
||||
|
||||
if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
|
||||
pdata->clk_polarity = 1;
|
||||
|
||||
if (flags & V4L2_MBUS_FIELD_EVEN_HIGH)
|
||||
pdata->fid_polarity = 1;
|
||||
|
||||
if (flags & V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH)
|
||||
pdata->sog_polarity = 1;
|
||||
|
||||
done:
|
||||
of_node_put(endpoint);
|
||||
return pdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* tvp7002_probe - Probe a TVP7002 device
|
||||
* @c: ptr to i2c_client struct
|
||||
|
|
@ -953,32 +998,32 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
|
|||
*/
|
||||
static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
|
||||
{
|
||||
struct tvp7002_config *pdata = tvp7002_get_pdata(c);
|
||||
struct v4l2_subdev *sd;
|
||||
struct tvp7002 *device;
|
||||
struct v4l2_dv_timings timings;
|
||||
int polarity_a;
|
||||
int polarity_b;
|
||||
u8 revision;
|
||||
|
||||
int error;
|
||||
|
||||
if (pdata == NULL) {
|
||||
dev_err(&c->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(c->adapter,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
if (!c->dev.platform_data) {
|
||||
v4l_err(c, "No platform data!!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
device = devm_kzalloc(&c->dev, sizeof(struct tvp7002), GFP_KERNEL);
|
||||
|
||||
if (!device)
|
||||
return -ENOMEM;
|
||||
|
||||
sd = &device->sd;
|
||||
device->pdata = c->dev.platform_data;
|
||||
device->pdata = pdata;
|
||||
device->current_timings = tvp7002_timings;
|
||||
|
||||
/* Tell v4l2 the device is ready */
|
||||
|
|
@ -1039,6 +1084,10 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
|
|||
}
|
||||
v4l2_ctrl_handler_setup(&device->hdl);
|
||||
|
||||
error = v4l2_async_register_subdev(&device->sd);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
@ -1063,6 +1112,7 @@ static int tvp7002_remove(struct i2c_client *c)
|
|||
|
||||
v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
|
||||
"on address 0x%x\n", c->addr);
|
||||
v4l2_async_unregister_subdev(&device->sd);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&device->sd.entity);
|
||||
#endif
|
||||
|
|
@ -1078,9 +1128,18 @@ static const struct i2c_device_id tvp7002_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tvp7002_id);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id tvp7002_of_match[] = {
|
||||
{ .compatible = "ti,tvp7002", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tvp7002_of_match);
|
||||
#endif
|
||||
|
||||
/* I2C driver data */
|
||||
static struct i2c_driver tvp7002_driver = {
|
||||
.driver = {
|
||||
.of_match_table = of_match_ptr(tvp7002_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
.name = TVP7002_MODULE_NAME,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/media-entity.h>
|
||||
|
|
@ -121,7 +122,6 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph)
|
|||
return entity;
|
||||
}
|
||||
|
||||
#define stack_peek(en) ((en)->stack[(en)->top - 1].entity)
|
||||
#define link_top(en) ((en)->stack[(en)->top].link)
|
||||
#define stack_top(en) ((en)->stack[(en)->top].entity)
|
||||
|
||||
|
|
@ -140,6 +140,12 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
|
|||
{
|
||||
graph->top = 0;
|
||||
graph->stack[graph->top].entity = NULL;
|
||||
bitmap_zero(graph->entities, MEDIA_ENTITY_ENUM_MAX_ID);
|
||||
|
||||
if (WARN_ON(entity->id >= MEDIA_ENTITY_ENUM_MAX_ID))
|
||||
return;
|
||||
|
||||
__set_bit(entity->id, graph->entities);
|
||||
stack_push(graph, entity);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
|
||||
|
|
@ -180,9 +186,11 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
|
|||
|
||||
/* Get the entity in the other end of the link . */
|
||||
next = media_entity_other(entity, link);
|
||||
if (WARN_ON(next->id >= MEDIA_ENTITY_ENUM_MAX_ID))
|
||||
return NULL;
|
||||
|
||||
/* Was it the entity we came here from? */
|
||||
if (next == stack_peek(graph)) {
|
||||
/* Has the entity already been visited? */
|
||||
if (__test_and_set_bit(next->id, graph->entities)) {
|
||||
link_top(graph)++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4441,9 +4441,7 @@ static void tibetCS16_init(struct bttv *btv)
|
|||
* is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
|
||||
* unit 3, the second (which is the master) is logical unit 0, etc.
|
||||
* We need to maintain the status of the analog switch (which of the 16
|
||||
* cameras is connected to which of the 4 controllers). Rather than
|
||||
* add to the bttv structure for this, we use the data reserved for
|
||||
* the mbox (unused for this card type).
|
||||
* cameras is connected to which of the 4 controllers) in sw_status array.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
@ -4478,7 +4476,6 @@ static void kodicom4400r_write(struct bttv *btv,
|
|||
*/
|
||||
static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
|
||||
{
|
||||
char *sw_status;
|
||||
int xaddr, yaddr;
|
||||
struct bttv *mctlr;
|
||||
static unsigned char map[4] = {3, 0, 2, 1};
|
||||
|
|
@ -4489,14 +4486,13 @@ static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
|
|||
}
|
||||
yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
|
||||
yaddr = map[yaddr];
|
||||
sw_status = (char *)(&mctlr->mbox_we);
|
||||
xaddr = input & 0xf;
|
||||
/* Check if the controller/camera pair has changed, else ignore */
|
||||
if (sw_status[yaddr] != xaddr)
|
||||
if (mctlr->sw_status[yaddr] != xaddr)
|
||||
{
|
||||
/* "open" the old switch, "close" the new one, save the new */
|
||||
kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
|
||||
sw_status[yaddr] = xaddr;
|
||||
kodicom4400r_write(mctlr, mctlr->sw_status[yaddr], yaddr, 0);
|
||||
mctlr->sw_status[yaddr] = xaddr;
|
||||
kodicom4400r_write(mctlr, xaddr, yaddr, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -4509,7 +4505,6 @@ static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
|
|||
*/
|
||||
static void kodicom4400r_init(struct bttv *btv)
|
||||
{
|
||||
char *sw_status = (char *)(&btv->mbox_we);
|
||||
int ix;
|
||||
|
||||
gpio_inout(0x0003ff, 0x0003ff);
|
||||
|
|
@ -4517,7 +4512,7 @@ static void kodicom4400r_init(struct bttv *btv)
|
|||
gpio_write(0);
|
||||
/* Preset camera 0 to the 4 controllers */
|
||||
for (ix = 0; ix < 4; ix++) {
|
||||
sw_status[ix] = ix;
|
||||
btv->sw_status[ix] = ix;
|
||||
kodicom4400r_write(btv, ix, ix, 1);
|
||||
}
|
||||
/*
|
||||
|
|
@ -4794,7 +4789,6 @@ static void gv800s_write(struct bttv *btv,
|
|||
static void gv800s_muxsel(struct bttv *btv, unsigned int input)
|
||||
{
|
||||
struct bttv *mctlr;
|
||||
char *sw_status;
|
||||
int xaddr, yaddr;
|
||||
static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
|
||||
{ 0x1, 0x5, 0xb, 0x7 },
|
||||
|
|
@ -4807,14 +4801,13 @@ static void gv800s_muxsel(struct bttv *btv, unsigned int input)
|
|||
return;
|
||||
}
|
||||
yaddr = (btv->c.nr - mctlr->c.nr) & 3;
|
||||
sw_status = (char *)(&mctlr->mbox_we);
|
||||
xaddr = map[yaddr][input] & 0xf;
|
||||
|
||||
/* Check if the controller/camera pair has changed, ignore otherwise */
|
||||
if (sw_status[yaddr] != xaddr) {
|
||||
if (mctlr->sw_status[yaddr] != xaddr) {
|
||||
/* disable the old switch, enable the new one and save status */
|
||||
gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
|
||||
sw_status[yaddr] = xaddr;
|
||||
gv800s_write(mctlr, mctlr->sw_status[yaddr], yaddr, 0);
|
||||
mctlr->sw_status[yaddr] = xaddr;
|
||||
gv800s_write(mctlr, xaddr, yaddr, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -4822,7 +4815,6 @@ static void gv800s_muxsel(struct bttv *btv, unsigned int input)
|
|||
/* GeoVision GV-800(S) "master" chip init */
|
||||
static void gv800s_init(struct bttv *btv)
|
||||
{
|
||||
char *sw_status = (char *)(&btv->mbox_we);
|
||||
int ix;
|
||||
|
||||
gpio_inout(0xf107f, 0xf107f);
|
||||
|
|
@ -4831,7 +4823,7 @@ static void gv800s_init(struct bttv *btv)
|
|||
|
||||
/* Preset camera 0 to the 4 controllers */
|
||||
for (ix = 0; ix < 4; ix++) {
|
||||
sw_status[ix] = ix;
|
||||
btv->sw_status[ix] = ix;
|
||||
gv800s_write(btv, ix, ix, 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,6 +459,9 @@ struct bttv {
|
|||
int mbox_iow;
|
||||
int mbox_csel;
|
||||
|
||||
/* switch status for multi-controller cards */
|
||||
char sw_status[4];
|
||||
|
||||
/* risc memory management data
|
||||
- must acquire s_lock before changing these
|
||||
- only the irq handler is supported to touch top + bottom + vcurr */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ config VIDEO_CX23885
|
|||
select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "cx23885.h"
|
||||
#include "cx23885-av.h"
|
||||
#include "cx23885-video.h"
|
||||
|
||||
void cx23885_av_work_handler(struct work_struct *work)
|
||||
{
|
||||
|
|
@ -32,5 +33,17 @@ void cx23885_av_work_handler(struct work_struct *work)
|
|||
|
||||
v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
|
||||
PCI_MSK_AV_CORE, &handled);
|
||||
|
||||
/* Getting here with the interrupt not handled
|
||||
then probbaly flatiron does have pending interrupts.
|
||||
*/
|
||||
if (!handled) {
|
||||
/* clear left and right adc channel interrupt request flag */
|
||||
cx23885_flatiron_write(dev, 0x1f,
|
||||
cx23885_flatiron_read(dev, 0x1f) | 0x80);
|
||||
cx23885_flatiron_write(dev, 0x23,
|
||||
cx23885_flatiron_read(dev, 0x23) | 0x80);
|
||||
}
|
||||
|
||||
cx23885_irq_enable(dev, PCI_MSK_AV_CORE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -528,11 +528,12 @@ struct cx23885_board cx23885_boards[] = {
|
|||
} },
|
||||
},
|
||||
[CX23885_BOARD_MYGICA_X8507] = {
|
||||
.name = "Mygica X8507",
|
||||
.name = "Mygica X8502/X8507 ISDB-T",
|
||||
.tuner_type = TUNER_XC5000,
|
||||
.tuner_addr = 0x61,
|
||||
.tuner_bus = 1,
|
||||
.porta = CX23885_ANALOG_VIDEO,
|
||||
.portb = CX23885_MPEG_DVB,
|
||||
.input = {
|
||||
{
|
||||
.type = CX23885_VMUX_TELEVISION,
|
||||
|
|
@ -1281,7 +1282,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
|
|||
case CX23885_BOARD_MYGICA_X8507:
|
||||
/* GPIO-0 (0)Analog / (1)Digital TV */
|
||||
/* GPIO-1 reset XC5000 */
|
||||
/* GPIO-2 reset LGS8GL5 / LGS8G75 */
|
||||
/* GPIO-2 demod reset */
|
||||
cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1);
|
||||
cx23885_gpio_clear(dev, GPIO_1 | GPIO_2);
|
||||
mdelay(100);
|
||||
|
|
@ -1677,6 +1678,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
|
|||
break;
|
||||
case CX23885_BOARD_MYGICA_X8506:
|
||||
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
|
||||
case CX23885_BOARD_MYGICA_X8507:
|
||||
ts1->gen_ctrl_val = 0x5; /* Parallel */
|
||||
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
||||
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
|
||||
|
|
|
|||
|
|
@ -1941,10 +1941,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
|
|||
|
||||
if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) {
|
||||
cx23885_irq_disable(dev, PCI_MSK_AV_CORE);
|
||||
if (!schedule_work(&dev->cx25840_work))
|
||||
printk(KERN_ERR "%s: failed to set up deferred work for"
|
||||
" AV Core/IR interrupt. Interrupt is disabled"
|
||||
" and won't be re-enabled\n", dev->name);
|
||||
schedule_work(&dev->cx25840_work);
|
||||
handled++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
#include "stb6100_cfg.h"
|
||||
#include "tda10071.h"
|
||||
#include "a8293.h"
|
||||
#include "mb86a20s.h"
|
||||
|
||||
static unsigned int debug;
|
||||
|
||||
|
|
@ -119,8 +120,6 @@ static void dvb_buf_release(struct videobuf_queue *q,
|
|||
cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
|
||||
}
|
||||
|
||||
static int cx23885_dvb_set_frontend(struct dvb_frontend *fe);
|
||||
|
||||
static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
|
||||
{
|
||||
struct videobuf_dvb_frontends *f;
|
||||
|
|
@ -135,12 +134,6 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
|
|||
|
||||
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
|
||||
|
||||
/*
|
||||
* FIXME: Improve this path to avoid calling the
|
||||
* cx23885_dvb_set_frontend() every time it passes here.
|
||||
*/
|
||||
cx23885_dvb_set_frontend(fe->dvb.frontend);
|
||||
}
|
||||
|
||||
static struct videobuf_queue_ops dvb_qops = {
|
||||
|
|
@ -500,6 +493,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
|
|||
.if_khz = 5380,
|
||||
};
|
||||
|
||||
static struct mb86a20s_config mygica_x8507_mb86a20s_config = {
|
||||
.demod_address = 0x10,
|
||||
};
|
||||
|
||||
static struct xc5000_config mygica_x8507_xc5000_config = {
|
||||
.i2c_address = 0x61,
|
||||
.if_khz = 4000,
|
||||
};
|
||||
|
||||
static struct stv090x_config prof_8000_stv090x_config = {
|
||||
.device = STV0903,
|
||||
.demod_mode = STV090x_SINGLE,
|
||||
|
|
@ -556,14 +558,27 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
|
|||
}
|
||||
break;
|
||||
case CX23885_BOARD_MYGICA_X8506:
|
||||
case CX23885_BOARD_MYGICA_X8507:
|
||||
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
|
||||
/* Select Digital TV */
|
||||
cx23885_gpio_set(dev, GPIO_0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Call the real set_frontend */
|
||||
if (port->set_frontend)
|
||||
return port->set_frontend(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx23885_set_frontend_hook(struct cx23885_tsport *port,
|
||||
struct dvb_frontend *fe)
|
||||
{
|
||||
port->set_frontend = fe->ops.set_frontend;
|
||||
fe->ops.set_frontend = cx23885_dvb_set_frontend;
|
||||
}
|
||||
|
||||
static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
|
||||
.prod = LGS8GXX_PROD_LGS8G75,
|
||||
.demod_address = 0x19,
|
||||
|
|
@ -771,6 +786,8 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
0x60, &dev->i2c_bus[1].i2c_adap,
|
||||
&hauppauge_hvr127x_config);
|
||||
}
|
||||
if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1275)
|
||||
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1255:
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
|
||||
|
|
@ -1106,6 +1123,21 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
&i2c_bus2->i2c_adap,
|
||||
&mygica_x8506_xc5000_config);
|
||||
}
|
||||
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
|
||||
break;
|
||||
case CX23885_BOARD_MYGICA_X8507:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
i2c_bus2 = &dev->i2c_bus[1];
|
||||
fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
|
||||
&mygica_x8507_mb86a20s_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(xc5000_attach,
|
||||
fe0->dvb.frontend,
|
||||
&i2c_bus2->i2c_adap,
|
||||
&mygica_x8507_xc5000_config);
|
||||
}
|
||||
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
|
||||
break;
|
||||
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
|
|
@ -1119,6 +1151,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
&i2c_bus2->i2c_adap,
|
||||
&magicpro_prohdtve2_xc5000_config);
|
||||
}
|
||||
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1850:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
|
|
@ -1249,6 +1282,10 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
fe0->dvb.frontend = dvb_attach(ds3000_attach,
|
||||
&tevii_ds3000_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(ts2020_attach, fe0->dvb.frontend,
|
||||
&tevii_ts2020_config, &i2c_bus->i2c_adap);
|
||||
}
|
||||
break;
|
||||
case CX23885_BOARD_PROF_8000:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <asm/div64.h>
|
||||
|
||||
#include "cx23885.h"
|
||||
#include "cx23885-video.h"
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include "cx23885-ioctl.h"
|
||||
|
|
@ -417,7 +418,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
|
|||
mutex_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
|
||||
int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
|
||||
{
|
||||
/* 8 bit registers, 8 bit values */
|
||||
u8 buf[] = { reg, data };
|
||||
|
|
@ -428,7 +429,7 @@ static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
|
|||
return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
|
||||
}
|
||||
|
||||
static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
|
||||
u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
|
||||
{
|
||||
/* 8 bit registers, 8 bit values */
|
||||
int ret;
|
||||
|
|
|
|||
26
drivers/media/pci/cx23885/cx23885-video.h
Normal file
26
drivers/media/pci/cx23885/cx23885-video.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Driver for the Conexant CX23885/7/8 PCIe bridge
|
||||
*
|
||||
* Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _CX23885_VIDEO_H_
|
||||
#define _CX23885_VIDEO_H_
|
||||
int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data);
|
||||
u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg);
|
||||
#endif
|
||||
|
|
@ -320,6 +320,8 @@ struct cx23885_tsport {
|
|||
|
||||
/* Workaround for a temp dvb_frontend that the tuner can attached to */
|
||||
struct dvb_frontend analog_fe;
|
||||
|
||||
int (*set_frontend)(struct dvb_frontend *fe);
|
||||
};
|
||||
|
||||
struct cx23885_kernel_ir {
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ config VIDEO_CX88_DVB
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called cx88-dvb.
|
||||
|
||||
config VIDEO_CX88_VP3054
|
||||
tristate "VP-3054 Secondary I2C Bus Support"
|
||||
default m
|
||||
config VIDEO_CX88_ENABLE_VP3054
|
||||
bool "VP-3054 Secondary I2C Bus Support"
|
||||
default y
|
||||
depends on VIDEO_CX88_DVB && DVB_MT352
|
||||
---help---
|
||||
This adds DVB-T support for cards based on the
|
||||
|
|
@ -82,6 +82,11 @@ config VIDEO_CX88_VP3054
|
|||
which also require support for the VP-3054
|
||||
Secondary I2C bus, such at DNTV Live! DVB-T Pro.
|
||||
|
||||
config VIDEO_CX88_VP3054
|
||||
tristate
|
||||
depends on VIDEO_CX88_DVB && VIDEO_CX88_ENABLE_VP3054
|
||||
default y
|
||||
|
||||
config VIDEO_CX88_MPEG
|
||||
tristate
|
||||
depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ struct cx88_input {
|
|||
};
|
||||
|
||||
enum cx88_audio_chip {
|
||||
CX88_AUDIO_WM8775,
|
||||
CX88_AUDIO_WM8775 = 1,
|
||||
CX88_AUDIO_TVAUDIO,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -203,13 +203,23 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
|
|||
|
||||
config VIDEO_SH_VEU
|
||||
tristate "SuperH VEU mem2mem video processing driver"
|
||||
depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS
|
||||
depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS && HAS_DMA
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select V4L2_MEM2MEM_DEV
|
||||
help
|
||||
Support for the Video Engine Unit (VEU) on SuperH and
|
||||
SH-Mobile SoCs.
|
||||
|
||||
config VIDEO_RENESAS_VSP1
|
||||
tristate "Renesas VSP1 Video Processing Engine"
|
||||
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
---help---
|
||||
This is a V4L2 driver for the Renesas VSP1 video processing engine.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called vsp1.
|
||||
|
||||
endif # V4L_MEM2MEM_DRIVERS
|
||||
|
||||
menuconfig V4L_TEST_DRIVERS
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o
|
|||
|
||||
obj-$(CONFIG_SOC_CAMERA) += soc_camera/
|
||||
|
||||
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
|
||||
|
||||
obj-y += davinci/
|
||||
|
||||
obj-$(CONFIG_ARCH_OMAP) += omap/
|
||||
|
|
|
|||
|
|
@ -388,13 +388,8 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
|
||||
params.hdelay = bt->hsync + bt->hbackporch;
|
||||
params.vdelay = bt->vsync + bt->vbackporch;
|
||||
params.line = bt->hfrontporch + bt->hsync
|
||||
+ bt->hbackporch + bt->width;
|
||||
params.frame = bt->vfrontporch + bt->vsync
|
||||
+ bt->vbackporch + bt->height;
|
||||
if (bt->interlaced)
|
||||
params.frame += bt->il_vfrontporch + bt->il_vsync
|
||||
+ bt->il_vbackporch;
|
||||
params.line = V4L2_DV_BT_FRAME_WIDTH(bt);
|
||||
params.frame = V4L2_DV_BT_FRAME_HEIGHT(bt);
|
||||
} else if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities
|
||||
& V4L2_IN_CAP_STD) {
|
||||
params.hdelay = 0;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -43,14 +43,26 @@
|
|||
#define CODA_STREAM_ENDIAN_SELECT (1 << 0)
|
||||
#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110
|
||||
#define CODA_IMAGE_ENDIAN_SELECT (1 << 0)
|
||||
#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114
|
||||
#define CODA_BIT_STREAM_END_FLAG (1 << 2)
|
||||
#define CODA_BIT_DEC_SEQ_INIT_ESCAPE (1 << 0)
|
||||
#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118
|
||||
#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x))
|
||||
#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x))
|
||||
#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x))
|
||||
#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140
|
||||
#define CODA7_REG_BIT_AXI_SRAM_USE 0x140
|
||||
#define CODA7_USE_BIT_ENABLE (1 << 0)
|
||||
#define CODA7_USE_HOST_ME_ENABLE (1 << 11)
|
||||
#define CODA7_USE_HOST_OVL_ENABLE (1 << 10)
|
||||
#define CODA7_USE_HOST_DBK_ENABLE (1 << 9)
|
||||
#define CODA7_USE_HOST_IP_ENABLE (1 << 8)
|
||||
#define CODA7_USE_HOST_BIT_ENABLE (1 << 7)
|
||||
#define CODA7_USE_ME_ENABLE (1 << 4)
|
||||
#define CODA7_USE_HOST_ME_ENABLE (1 << 11)
|
||||
#define CODA7_USE_OVL_ENABLE (1 << 3)
|
||||
#define CODA7_USE_DBK_ENABLE (1 << 2)
|
||||
#define CODA7_USE_IP_ENABLE (1 << 1)
|
||||
#define CODA7_USE_BIT_ENABLE (1 << 0)
|
||||
|
||||
#define CODA_REG_BIT_BUSY 0x160
|
||||
#define CODA_REG_BIT_BUSY_FLAG 1
|
||||
#define CODA_REG_BIT_RUN_COMMAND 0x164
|
||||
|
|
@ -84,6 +96,15 @@
|
|||
#define CODA_MODE_INVALID 0xffff
|
||||
#define CODA_REG_BIT_INT_ENABLE 0x170
|
||||
#define CODA_INT_INTERRUPT_ENABLE (1 << 3)
|
||||
#define CODA_REG_BIT_INT_REASON 0x174
|
||||
#define CODA7_REG_BIT_RUN_AUX_STD 0x178
|
||||
#define CODA_MP4_AUX_MPEG4 0
|
||||
#define CODA_MP4_AUX_DIVX3 1
|
||||
#define CODA_VPX_AUX_THO 0
|
||||
#define CODA_VPX_AUX_VP6 1
|
||||
#define CODA_VPX_AUX_VP8 2
|
||||
#define CODA_H264_AUX_AVC 0
|
||||
#define CODA_H264_AUX_MVC 1
|
||||
|
||||
/*
|
||||
* Commands' mailbox:
|
||||
|
|
@ -92,15 +113,89 @@
|
|||
* issued.
|
||||
*/
|
||||
|
||||
/* Decoder Sequence Initialization */
|
||||
#define CODA_CMD_DEC_SEQ_BB_START 0x180
|
||||
#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184
|
||||
#define CODA_CMD_DEC_SEQ_OPTION 0x188
|
||||
#define CODA_REORDER_ENABLE (1 << 1)
|
||||
#define CODADX6_QP_REPORT (1 << 0)
|
||||
#define CODA7_MP4_DEBLK_ENABLE (1 << 0)
|
||||
#define CODA_CMD_DEC_SEQ_SRC_SIZE 0x18c
|
||||
#define CODA_CMD_DEC_SEQ_START_BYTE 0x190
|
||||
#define CODA_CMD_DEC_SEQ_PS_BB_START 0x194
|
||||
#define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198
|
||||
#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c
|
||||
#define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c
|
||||
#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0
|
||||
|
||||
#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0
|
||||
#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0
|
||||
#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */
|
||||
#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4
|
||||
#define CODA_RET_DEC_SEQ_SRC_F_RATE 0x1c8
|
||||
#define CODA9_RET_DEC_SEQ_ASPECT 0x1c8
|
||||
#define CODA_RET_DEC_SEQ_FRAME_NEED 0x1cc
|
||||
#define CODA_RET_DEC_SEQ_FRAME_DELAY 0x1d0
|
||||
#define CODA_RET_DEC_SEQ_INFO 0x1d4
|
||||
#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT 0x1d8
|
||||
#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM 0x1dc
|
||||
#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM 0x1e0
|
||||
#define CODA_RET_DEC_SEQ_ERR_REASON 0x1e0
|
||||
#define CODA_RET_DEC_SEQ_FRATE_NR 0x1e4
|
||||
#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8
|
||||
#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4
|
||||
#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8
|
||||
|
||||
/* Decoder Picture Run */
|
||||
#define CODA_CMD_DEC_PIC_ROT_MODE 0x180
|
||||
#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184
|
||||
#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188
|
||||
#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c
|
||||
#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190
|
||||
|
||||
#define CODA_CMD_DEC_PIC_OPTION 0x194
|
||||
#define CODA_PRE_SCAN_EN (1 << 0)
|
||||
#define CODA_PRE_SCAN_MODE_DECODE (0 << 1)
|
||||
#define CODA_PRE_SCAN_MODE_RETURN (1 << 1)
|
||||
#define CODA_IFRAME_SEARCH_EN (1 << 2)
|
||||
#define CODA_SKIP_FRAME_MODE (0x3 << 3)
|
||||
#define CODA_CMD_DEC_PIC_SKIP_NUM 0x198
|
||||
#define CODA_CMD_DEC_PIC_CHUNK_SIZE 0x19c
|
||||
#define CODA_CMD_DEC_PIC_BB_START 0x1a0
|
||||
#define CODA_CMD_DEC_PIC_START_BYTE 0x1a4
|
||||
#define CODA_RET_DEC_PIC_SIZE 0x1bc
|
||||
#define CODA_RET_DEC_PIC_FRAME_NUM 0x1c0
|
||||
#define CODA_RET_DEC_PIC_FRAME_IDX 0x1c4
|
||||
#define CODA_RET_DEC_PIC_ERR_MB 0x1c8
|
||||
#define CODA_RET_DEC_PIC_TYPE 0x1cc
|
||||
#define CODA_PIC_TYPE_MASK 0x7
|
||||
#define CODA_PIC_TYPE_MASK_VC1 0x3f
|
||||
#define CODA9_PIC_TYPE_FIRST_MASK (0x7 << 3)
|
||||
#define CODA9_PIC_TYPE_IDR_MASK (0x3 << 6)
|
||||
#define CODA7_PIC_TYPE_H264_NPF_MASK (0x3 << 16)
|
||||
#define CODA7_PIC_TYPE_INTERLACED (1 << 18)
|
||||
#define CODA_RET_DEC_PIC_POST 0x1d0
|
||||
#define CODA_RET_DEC_PIC_MVC_REPORT 0x1d0
|
||||
#define CODA_RET_DEC_PIC_OPTION 0x1d4
|
||||
#define CODA_RET_DEC_PIC_SUCCESS 0x1d8
|
||||
#define CODA_RET_DEC_PIC_CUR_IDX 0x1dc
|
||||
#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT 0x1e0
|
||||
#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4
|
||||
#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec
|
||||
|
||||
/* Encoder Sequence Initialization */
|
||||
#define CODA_CMD_ENC_SEQ_BB_START 0x180
|
||||
#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184
|
||||
#define CODA_CMD_ENC_SEQ_OPTION 0x188
|
||||
#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9
|
||||
#define CODA7_OPTION_GAMMA_OFFSET 8
|
||||
#define CODA7_OPTION_RCQPMAX_OFFSET 7
|
||||
#define CODADX6_OPTION_GAMMA_OFFSET 7
|
||||
#define CODA7_OPTION_RCQPMIN_OFFSET 6
|
||||
#define CODA_OPTION_LIMITQP_OFFSET 6
|
||||
#define CODA_OPTION_RCINTRAQP_OFFSET 5
|
||||
#define CODA_OPTION_FMO_OFFSET 4
|
||||
#define CODA_OPTION_AVC_AUD_OFFSET 2
|
||||
#define CODA_OPTION_SLICEREPORT_OFFSET 1
|
||||
#define CODA_CMD_ENC_SEQ_COD_STD 0x18c
|
||||
#define CODA_STD_MPEG4 0
|
||||
|
|
@ -169,8 +264,10 @@
|
|||
#define CODA_FMOPARAM_TYPE_MASK 1
|
||||
#define CODA_FMOPARAM_SLICENUM_OFFSET 0
|
||||
#define CODA_FMOPARAM_SLICENUM_MASK 0x0f
|
||||
#define CODADX6_CMD_ENC_SEQ_INTRA_QP 0x1bc
|
||||
#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8
|
||||
#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc
|
||||
#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4
|
||||
#define CODA_CMD_ENC_SEQ_RC_QP_MAX 0x1c8
|
||||
#define CODA_QPMAX_OFFSET 0
|
||||
#define CODA_QPMAX_MASK 0x3f
|
||||
|
|
@ -197,18 +294,24 @@
|
|||
#define CODA_CMD_ENC_PIC_OPTION 0x194
|
||||
#define CODA_CMD_ENC_PIC_BB_START 0x198
|
||||
#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c
|
||||
#define CODA_RET_ENC_FRAME_NUM 0x1c0
|
||||
#define CODA_RET_ENC_PIC_TYPE 0x1c4
|
||||
#define CODA_RET_ENC_PIC_FRAME_IDX 0x1c8
|
||||
#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc
|
||||
#define CODA_RET_ENC_PIC_FLAG 0x1d0
|
||||
#define CODA_RET_ENC_PIC_SUCCESS 0x1d8
|
||||
|
||||
/* Set Frame Buffer */
|
||||
#define CODA_CMD_SET_FRAME_BUF_NUM 0x180
|
||||
#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184
|
||||
#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188
|
||||
#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c
|
||||
#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190
|
||||
#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194
|
||||
#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198
|
||||
#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c
|
||||
#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0
|
||||
#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4
|
||||
#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8
|
||||
|
||||
/* Encoder Header */
|
||||
|
|
|
|||
|
|
@ -1743,11 +1743,10 @@ static int vpbe_display_probe(struct platform_device *pdev)
|
|||
|
||||
printk(KERN_DEBUG "vpbe_display_probe\n");
|
||||
/* Allocate memory for vpbe_display */
|
||||
disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
|
||||
if (!disp_dev) {
|
||||
printk(KERN_ERR "ran out of memory\n");
|
||||
disp_dev = devm_kzalloc(&pdev->dev, sizeof(struct vpbe_display),
|
||||
GFP_KERNEL);
|
||||
if (!disp_dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&disp_dev->dma_queue_lock);
|
||||
/*
|
||||
|
|
@ -1786,26 +1785,24 @@ static int vpbe_display_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = res->start;
|
||||
if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
|
||||
disp_dev)) {
|
||||
err = devm_request_irq(&pdev->dev, irq, venc_isr, IRQF_DISABLED,
|
||||
VPBE_DISPLAY_DRIVER, disp_dev);
|
||||
if (err) {
|
||||
v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
|
||||
"Unable to request interrupt\n");
|
||||
err = -ENODEV;
|
||||
goto probe_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
|
||||
if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
|
||||
err = -ENODEV;
|
||||
goto probe_out_irq;
|
||||
goto probe_out;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
|
||||
return 0;
|
||||
|
||||
probe_out_irq:
|
||||
free_irq(res->start, disp_dev);
|
||||
probe_out:
|
||||
for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
|
||||
/* Get the pointer to the layer object */
|
||||
|
|
@ -1817,7 +1814,6 @@ probe_out:
|
|||
kfree(disp_dev->dev[k]);
|
||||
}
|
||||
}
|
||||
kfree(disp_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1830,15 +1826,10 @@ static int vpbe_display_remove(struct platform_device *pdev)
|
|||
struct vpbe_layer *vpbe_display_layer;
|
||||
struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
|
||||
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
|
||||
|
||||
/* unregister irq */
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
free_irq(res->start, disp_dev);
|
||||
|
||||
/* deinitialize the vpbe display controller */
|
||||
if (NULL != vpbe_dev->ops.deinitialize)
|
||||
vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
|
||||
|
|
|
|||
|
|
@ -1547,61 +1547,36 @@ static int osd_probe(struct platform_device *pdev)
|
|||
const struct platform_device_id *pdev_id;
|
||||
struct osd_state *osd;
|
||||
struct resource *res;
|
||||
int ret = 0;
|
||||
|
||||
osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL);
|
||||
pdev_id = platform_get_device_id(pdev);
|
||||
if (!pdev_id)
|
||||
return -EINVAL;
|
||||
|
||||
osd = devm_kzalloc(&pdev->dev, sizeof(struct osd_state), GFP_KERNEL);
|
||||
if (osd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev_id = platform_get_device_id(pdev);
|
||||
if (!pdev_id) {
|
||||
ret = -EINVAL;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
osd->dev = &pdev->dev;
|
||||
osd->vpbe_type = pdev_id->driver_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(osd->dev, "Unable to get OSD register address map\n");
|
||||
ret = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
osd->osd_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(osd->osd_base))
|
||||
return PTR_ERR(osd->osd_base);
|
||||
|
||||
osd->osd_base_phys = res->start;
|
||||
osd->osd_size = resource_size(res);
|
||||
if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
|
||||
MODULE_NAME)) {
|
||||
dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
|
||||
ret = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
osd->osd_base = ioremap_nocache(res->start, osd->osd_size);
|
||||
if (!osd->osd_base) {
|
||||
dev_err(osd->dev, "Unable to map the OSD region\n");
|
||||
ret = -ENODEV;
|
||||
goto release_mem_region;
|
||||
}
|
||||
spin_lock_init(&osd->lock);
|
||||
osd->ops = osd_ops;
|
||||
platform_set_drvdata(pdev, osd);
|
||||
dev_notice(osd->dev, "OSD sub device probe success\n");
|
||||
return ret;
|
||||
|
||||
release_mem_region:
|
||||
release_mem_region(osd->osd_base_phys, osd->osd_size);
|
||||
free_mem:
|
||||
kfree(osd);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int osd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct osd_state *osd = platform_get_drvdata(pdev);
|
||||
|
||||
iounmap((void *)osd->osd_base);
|
||||
release_mem_region(osd->osd_base_phys, osd->osd_size);
|
||||
kfree(osd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -639,105 +639,46 @@ static int venc_probe(struct platform_device *pdev)
|
|||
const struct platform_device_id *pdev_id;
|
||||
struct venc_state *venc;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL);
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "No platform data for VENC sub device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdev_id = platform_get_device_id(pdev);
|
||||
if (!pdev_id)
|
||||
return -EINVAL;
|
||||
|
||||
venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL);
|
||||
if (venc == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev_id = platform_get_device_id(pdev);
|
||||
if (!pdev_id) {
|
||||
ret = -EINVAL;
|
||||
goto free_mem;
|
||||
}
|
||||
venc->venc_type = pdev_id->driver_data;
|
||||
venc->pdev = &pdev->dev;
|
||||
venc->pdata = pdev->dev.platform_data;
|
||||
if (NULL == venc->pdata) {
|
||||
dev_err(venc->pdev, "Unable to get platform data for"
|
||||
" VENC sub device");
|
||||
ret = -ENOENT;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(venc->pdev,
|
||||
"Unable to get VENC register address map\n");
|
||||
ret = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res), "venc")) {
|
||||
dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n");
|
||||
ret = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
venc->venc_base = ioremap_nocache(res->start, resource_size(res));
|
||||
if (!venc->venc_base) {
|
||||
dev_err(venc->pdev, "Unable to map VENC IO space\n");
|
||||
ret = -ENODEV;
|
||||
goto release_venc_mem_region;
|
||||
}
|
||||
venc->venc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(venc->venc_base))
|
||||
return PTR_ERR(venc->venc_base);
|
||||
|
||||
if (venc->venc_type != VPBE_VERSION_1) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(venc->pdev,
|
||||
"Unable to get VDAC_CONFIG address map\n");
|
||||
ret = -ENODEV;
|
||||
goto unmap_venc_io;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start,
|
||||
resource_size(res), "venc")) {
|
||||
dev_err(venc->pdev,
|
||||
"Unable to reserve VDAC_CONFIG MMIO region\n");
|
||||
ret = -ENODEV;
|
||||
goto unmap_venc_io;
|
||||
}
|
||||
|
||||
venc->vdaccfg_reg = ioremap_nocache(res->start,
|
||||
resource_size(res));
|
||||
if (!venc->vdaccfg_reg) {
|
||||
dev_err(venc->pdev,
|
||||
"Unable to map VDAC_CONFIG IO space\n");
|
||||
ret = -ENODEV;
|
||||
goto release_vdaccfg_mem_region;
|
||||
}
|
||||
venc->vdaccfg_reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(venc->vdaccfg_reg))
|
||||
return PTR_ERR(venc->vdaccfg_reg);
|
||||
}
|
||||
spin_lock_init(&venc->lock);
|
||||
platform_set_drvdata(pdev, venc);
|
||||
dev_notice(venc->pdev, "VENC sub device probe success\n");
|
||||
return 0;
|
||||
|
||||
release_vdaccfg_mem_region:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
unmap_venc_io:
|
||||
iounmap(venc->venc_base);
|
||||
release_venc_mem_region:
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
free_mem:
|
||||
kfree(venc);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct venc_state *venc = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
iounmap((void *)venc->venc_base);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
if (venc->venc_type != VPBE_VERSION_1) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
iounmap((void *)venc->vdaccfg_reg);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
}
|
||||
kfree(venc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1799,19 +1799,15 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
|
|||
|
||||
/* Configure video port timings */
|
||||
|
||||
std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
|
||||
bt->hsync - 8;
|
||||
std_info->eav2sav = V4L2_DV_BT_BLANKING_WIDTH(bt) - 8;
|
||||
std_info->sav2eav = bt->width;
|
||||
|
||||
std_info->l1 = 1;
|
||||
std_info->l3 = bt->vsync + bt->vbackporch + 1;
|
||||
|
||||
std_info->vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);
|
||||
if (bt->interlaced) {
|
||||
if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
|
||||
std_info->vsize = bt->height * 2 +
|
||||
bt->vfrontporch + bt->vsync + bt->vbackporch +
|
||||
bt->il_vfrontporch + bt->il_vsync +
|
||||
bt->il_vbackporch;
|
||||
std_info->l5 = std_info->vsize/2 -
|
||||
(bt->vfrontporch - 1);
|
||||
std_info->l7 = std_info->vsize/2 + 1;
|
||||
|
|
@ -1825,8 +1821,6 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
|
|||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
std_info->vsize = bt->height + bt->vfrontporch +
|
||||
bt->vsync + bt->vbackporch;
|
||||
std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
|
||||
}
|
||||
strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
|
||||
|
|
@ -1979,6 +1973,76 @@ vpif_init_free_channel_objects:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int vpif_async_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vpif_obj.config->subdev_count; i++)
|
||||
if (!strcmp(vpif_obj.config->subdev_info[i].name,
|
||||
subdev->name)) {
|
||||
vpif_obj.sd[i] = subdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vpif_probe_complete(void)
|
||||
{
|
||||
struct common_obj *common;
|
||||
struct channel_obj *ch;
|
||||
int i, j, err, k;
|
||||
|
||||
for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
|
||||
ch = vpif_obj.dev[j];
|
||||
ch->channel_id = j;
|
||||
common = &(ch->common[VPIF_VIDEO_INDEX]);
|
||||
spin_lock_init(&common->irqlock);
|
||||
mutex_init(&common->lock);
|
||||
ch->video_dev->lock = &common->lock;
|
||||
/* Initialize prio member of channel object */
|
||||
v4l2_prio_init(&ch->prio);
|
||||
video_set_drvdata(ch->video_dev, ch);
|
||||
|
||||
/* select input 0 */
|
||||
err = vpif_set_input(vpif_obj.config, ch, 0);
|
||||
if (err)
|
||||
goto probe_out;
|
||||
|
||||
err = video_register_device(ch->video_dev,
|
||||
VFL_TYPE_GRABBER, (j ? 1 : 0));
|
||||
if (err)
|
||||
goto probe_out;
|
||||
}
|
||||
|
||||
v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
|
||||
return 0;
|
||||
|
||||
probe_out:
|
||||
for (k = 0; k < j; k++) {
|
||||
/* Get the pointer to the channel object */
|
||||
ch = vpif_obj.dev[k];
|
||||
/* Unregister video device */
|
||||
video_unregister_device(ch->video_dev);
|
||||
}
|
||||
kfree(vpif_obj.sd);
|
||||
for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
|
||||
ch = vpif_obj.dev[i];
|
||||
/* Note: does nothing if ch->video_dev == NULL */
|
||||
video_device_release(ch->video_dev);
|
||||
}
|
||||
v4l2_device_unregister(&vpif_obj.v4l2_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vpif_async_complete(struct v4l2_async_notifier *notifier)
|
||||
{
|
||||
return vpif_probe_complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* vpif_probe : This function probes the vpif capture driver
|
||||
* @pdev: platform device pointer
|
||||
|
|
@ -1989,12 +2053,10 @@ vpif_init_free_channel_objects:
|
|||
static __init int vpif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vpif_subdev_info *subdevdata;
|
||||
struct vpif_capture_config *config;
|
||||
int i, j, k, err;
|
||||
int i, j, err;
|
||||
int res_idx = 0;
|
||||
struct i2c_adapter *i2c_adap;
|
||||
struct channel_obj *ch;
|
||||
struct common_obj *common;
|
||||
struct video_device *vfd;
|
||||
struct resource *res;
|
||||
int subdev_count;
|
||||
|
|
@ -2068,10 +2130,9 @@ static __init int vpif_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
i2c_adap = i2c_get_adapter(1);
|
||||
config = pdev->dev.platform_data;
|
||||
vpif_obj.config = pdev->dev.platform_data;
|
||||
|
||||
subdev_count = config->subdev_count;
|
||||
subdev_count = vpif_obj.config->subdev_count;
|
||||
vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
|
||||
GFP_KERNEL);
|
||||
if (vpif_obj.sd == NULL) {
|
||||
|
|
@ -2080,54 +2141,43 @@ static __init int vpif_probe(struct platform_device *pdev)
|
|||
goto vpif_sd_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < subdev_count; i++) {
|
||||
subdevdata = &config->subdev_info[i];
|
||||
vpif_obj.sd[i] =
|
||||
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
|
||||
i2c_adap,
|
||||
&subdevdata->board_info,
|
||||
NULL);
|
||||
if (!vpif_obj.config->asd_sizes) {
|
||||
i2c_adap = i2c_get_adapter(1);
|
||||
for (i = 0; i < subdev_count; i++) {
|
||||
subdevdata = &vpif_obj.config->subdev_info[i];
|
||||
vpif_obj.sd[i] =
|
||||
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
|
||||
i2c_adap,
|
||||
&subdevdata->
|
||||
board_info,
|
||||
NULL);
|
||||
|
||||
if (!vpif_obj.sd[i]) {
|
||||
vpif_err("Error registering v4l2 subdevice\n");
|
||||
err = -ENODEV;
|
||||
if (!vpif_obj.sd[i]) {
|
||||
vpif_err("Error registering v4l2 subdevice\n");
|
||||
err = -ENOMEM;
|
||||
goto probe_subdev_out;
|
||||
}
|
||||
v4l2_info(&vpif_obj.v4l2_dev,
|
||||
"registered sub device %s\n",
|
||||
subdevdata->name);
|
||||
}
|
||||
vpif_probe_complete();
|
||||
} else {
|
||||
vpif_obj.notifier.subdevs = vpif_obj.config->asd;
|
||||
vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
|
||||
vpif_obj.notifier.bound = vpif_async_bound;
|
||||
vpif_obj.notifier.complete = vpif_async_complete;
|
||||
err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
|
||||
&vpif_obj.notifier);
|
||||
if (err) {
|
||||
vpif_err("Error registering async notifier\n");
|
||||
err = -EINVAL;
|
||||
goto probe_subdev_out;
|
||||
}
|
||||
v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
|
||||
subdevdata->name);
|
||||
}
|
||||
|
||||
for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
|
||||
ch = vpif_obj.dev[j];
|
||||
ch->channel_id = j;
|
||||
common = &(ch->common[VPIF_VIDEO_INDEX]);
|
||||
spin_lock_init(&common->irqlock);
|
||||
mutex_init(&common->lock);
|
||||
ch->video_dev->lock = &common->lock;
|
||||
/* Initialize prio member of channel object */
|
||||
v4l2_prio_init(&ch->prio);
|
||||
video_set_drvdata(ch->video_dev, ch);
|
||||
|
||||
/* select input 0 */
|
||||
err = vpif_set_input(config, ch, 0);
|
||||
if (err)
|
||||
goto probe_out;
|
||||
|
||||
err = video_register_device(ch->video_dev,
|
||||
VFL_TYPE_GRABBER, (j ? 1 : 0));
|
||||
if (err)
|
||||
goto probe_out;
|
||||
}
|
||||
v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
|
||||
return 0;
|
||||
|
||||
probe_out:
|
||||
for (k = 0; k < j; k++) {
|
||||
/* Get the pointer to the channel object */
|
||||
ch = vpif_obj.dev[k];
|
||||
/* Unregister video device */
|
||||
video_unregister_device(ch->video_dev);
|
||||
}
|
||||
probe_subdev_out:
|
||||
/* free sub devices memory */
|
||||
kfree(vpif_obj.sd);
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ struct vpif_device {
|
|||
struct v4l2_device v4l2_dev;
|
||||
struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
struct v4l2_subdev **sd;
|
||||
struct v4l2_async_notifier notifier;
|
||||
struct vpif_capture_config *config;
|
||||
};
|
||||
|
||||
struct vpif_config_params {
|
||||
|
|
|
|||
|
|
@ -1436,19 +1436,15 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
|
|||
|
||||
/* Configure video port timings */
|
||||
|
||||
std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
|
||||
bt->hsync - 8;
|
||||
std_info->eav2sav = V4L2_DV_BT_BLANKING_WIDTH(bt) - 8;
|
||||
std_info->sav2eav = bt->width;
|
||||
|
||||
std_info->l1 = 1;
|
||||
std_info->l3 = bt->vsync + bt->vbackporch + 1;
|
||||
|
||||
std_info->vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);
|
||||
if (bt->interlaced) {
|
||||
if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
|
||||
std_info->vsize = bt->height * 2 +
|
||||
bt->vfrontporch + bt->vsync + bt->vbackporch +
|
||||
bt->il_vfrontporch + bt->il_vsync +
|
||||
bt->il_vbackporch;
|
||||
std_info->l5 = std_info->vsize/2 -
|
||||
(bt->vfrontporch - 1);
|
||||
std_info->l7 = std_info->vsize/2 + 1;
|
||||
|
|
@ -1462,8 +1458,6 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
|
|||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
std_info->vsize = bt->height + bt->vfrontporch +
|
||||
bt->vsync + bt->vbackporch;
|
||||
std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
|
||||
}
|
||||
strncpy(std_info->name, "Custom timings BT656/1120",
|
||||
|
|
@ -1618,6 +1612,102 @@ vpif_init_free_channel_objects:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int vpif_async_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vpif_obj.config->subdev_count; i++)
|
||||
if (!strcmp(vpif_obj.config->subdevinfo[i].name,
|
||||
subdev->name)) {
|
||||
vpif_obj.sd[i] = subdev;
|
||||
vpif_obj.sd[i]->grp_id = 1 << i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vpif_probe_complete(void)
|
||||
{
|
||||
struct common_obj *common;
|
||||
struct channel_obj *ch;
|
||||
int j, err, k;
|
||||
|
||||
for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
|
||||
ch = vpif_obj.dev[j];
|
||||
/* Initialize field of the channel objects */
|
||||
atomic_set(&ch->usrs, 0);
|
||||
for (k = 0; k < VPIF_NUMOBJECTS; k++) {
|
||||
ch->common[k].numbuffers = 0;
|
||||
common = &ch->common[k];
|
||||
common->io_usrs = 0;
|
||||
common->started = 0;
|
||||
spin_lock_init(&common->irqlock);
|
||||
mutex_init(&common->lock);
|
||||
common->numbuffers = 0;
|
||||
common->set_addr = NULL;
|
||||
common->ytop_off = 0;
|
||||
common->ybtm_off = 0;
|
||||
common->ctop_off = 0;
|
||||
common->cbtm_off = 0;
|
||||
common->cur_frm = NULL;
|
||||
common->next_frm = NULL;
|
||||
memset(&common->fmt, 0, sizeof(common->fmt));
|
||||
common->numbuffers = config_params.numbuffers[k];
|
||||
}
|
||||
ch->initialized = 0;
|
||||
if (vpif_obj.config->subdev_count)
|
||||
ch->sd = vpif_obj.sd[0];
|
||||
ch->channel_id = j;
|
||||
if (j < 2)
|
||||
ch->common[VPIF_VIDEO_INDEX].numbuffers =
|
||||
config_params.numbuffers[ch->channel_id];
|
||||
else
|
||||
ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
|
||||
|
||||
memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
|
||||
|
||||
/* Initialize prio member of channel object */
|
||||
v4l2_prio_init(&ch->prio);
|
||||
ch->common[VPIF_VIDEO_INDEX].fmt.type =
|
||||
V4L2_BUF_TYPE_VIDEO_OUTPUT;
|
||||
ch->video_dev->lock = &common->lock;
|
||||
video_set_drvdata(ch->video_dev, ch);
|
||||
|
||||
/* select output 0 */
|
||||
err = vpif_set_output(vpif_obj.config, ch, 0);
|
||||
if (err)
|
||||
goto probe_out;
|
||||
|
||||
/* register video device */
|
||||
vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
|
||||
(int)ch, (int)&ch->video_dev);
|
||||
|
||||
err = video_register_device(ch->video_dev,
|
||||
VFL_TYPE_GRABBER, (j ? 3 : 2));
|
||||
if (err < 0)
|
||||
goto probe_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
probe_out:
|
||||
for (k = 0; k < j; k++) {
|
||||
ch = vpif_obj.dev[k];
|
||||
video_unregister_device(ch->video_dev);
|
||||
video_device_release(ch->video_dev);
|
||||
ch->video_dev = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vpif_async_complete(struct v4l2_async_notifier *notifier)
|
||||
{
|
||||
return vpif_probe_complete();
|
||||
}
|
||||
|
||||
/*
|
||||
* vpif_probe: This function creates device entries by register itself to the
|
||||
* V4L2 driver and initializes fields of each channel objects
|
||||
|
|
@ -1625,11 +1715,9 @@ vpif_init_free_channel_objects:
|
|||
static __init int vpif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vpif_subdev_info *subdevdata;
|
||||
struct vpif_display_config *config;
|
||||
int i, j = 0, k, err = 0;
|
||||
int i, j = 0, err = 0;
|
||||
int res_idx = 0;
|
||||
struct i2c_adapter *i2c_adap;
|
||||
struct common_obj *common;
|
||||
struct channel_obj *ch;
|
||||
struct video_device *vfd;
|
||||
struct resource *res;
|
||||
|
|
@ -1708,11 +1796,9 @@ static __init int vpif_probe(struct platform_device *pdev)
|
|||
size/2;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_adap = i2c_get_adapter(1);
|
||||
config = pdev->dev.platform_data;
|
||||
subdev_count = config->subdev_count;
|
||||
subdevdata = config->subdevinfo;
|
||||
vpif_obj.config = pdev->dev.platform_data;
|
||||
subdev_count = vpif_obj.config->subdev_count;
|
||||
subdevdata = vpif_obj.config->subdevinfo;
|
||||
vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
|
||||
GFP_KERNEL);
|
||||
if (vpif_obj.sd == NULL) {
|
||||
|
|
@ -1721,86 +1807,41 @@ static __init int vpif_probe(struct platform_device *pdev)
|
|||
goto vpif_sd_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < subdev_count; i++) {
|
||||
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
|
||||
i2c_adap,
|
||||
&subdevdata[i].board_info,
|
||||
NULL);
|
||||
if (!vpif_obj.sd[i]) {
|
||||
vpif_err("Error registering v4l2 subdevice\n");
|
||||
err = -ENODEV;
|
||||
if (!vpif_obj.config->asd_sizes) {
|
||||
i2c_adap = i2c_get_adapter(1);
|
||||
for (i = 0; i < subdev_count; i++) {
|
||||
vpif_obj.sd[i] =
|
||||
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
|
||||
i2c_adap,
|
||||
&subdevdata[i].
|
||||
board_info,
|
||||
NULL);
|
||||
if (!vpif_obj.sd[i]) {
|
||||
vpif_err("Error registering v4l2 subdevice\n");
|
||||
err = -ENODEV;
|
||||
goto probe_subdev_out;
|
||||
}
|
||||
|
||||
if (vpif_obj.sd[i])
|
||||
vpif_obj.sd[i]->grp_id = 1 << i;
|
||||
}
|
||||
vpif_probe_complete();
|
||||
} else {
|
||||
vpif_obj.notifier.subdevs = vpif_obj.config->asd;
|
||||
vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
|
||||
vpif_obj.notifier.bound = vpif_async_bound;
|
||||
vpif_obj.notifier.complete = vpif_async_complete;
|
||||
err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
|
||||
&vpif_obj.notifier);
|
||||
if (err) {
|
||||
vpif_err("Error registering async notifier\n");
|
||||
err = -EINVAL;
|
||||
goto probe_subdev_out;
|
||||
}
|
||||
|
||||
if (vpif_obj.sd[i])
|
||||
vpif_obj.sd[i]->grp_id = 1 << i;
|
||||
}
|
||||
|
||||
for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
|
||||
ch = vpif_obj.dev[j];
|
||||
/* Initialize field of the channel objects */
|
||||
atomic_set(&ch->usrs, 0);
|
||||
for (k = 0; k < VPIF_NUMOBJECTS; k++) {
|
||||
ch->common[k].numbuffers = 0;
|
||||
common = &ch->common[k];
|
||||
common->io_usrs = 0;
|
||||
common->started = 0;
|
||||
spin_lock_init(&common->irqlock);
|
||||
mutex_init(&common->lock);
|
||||
common->numbuffers = 0;
|
||||
common->set_addr = NULL;
|
||||
common->ytop_off = common->ybtm_off = 0;
|
||||
common->ctop_off = common->cbtm_off = 0;
|
||||
common->cur_frm = common->next_frm = NULL;
|
||||
memset(&common->fmt, 0, sizeof(common->fmt));
|
||||
common->numbuffers = config_params.numbuffers[k];
|
||||
|
||||
}
|
||||
ch->initialized = 0;
|
||||
if (subdev_count)
|
||||
ch->sd = vpif_obj.sd[0];
|
||||
ch->channel_id = j;
|
||||
if (j < 2)
|
||||
ch->common[VPIF_VIDEO_INDEX].numbuffers =
|
||||
config_params.numbuffers[ch->channel_id];
|
||||
else
|
||||
ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
|
||||
|
||||
memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
|
||||
|
||||
/* Initialize prio member of channel object */
|
||||
v4l2_prio_init(&ch->prio);
|
||||
ch->common[VPIF_VIDEO_INDEX].fmt.type =
|
||||
V4L2_BUF_TYPE_VIDEO_OUTPUT;
|
||||
ch->video_dev->lock = &common->lock;
|
||||
video_set_drvdata(ch->video_dev, ch);
|
||||
|
||||
/* select output 0 */
|
||||
err = vpif_set_output(config, ch, 0);
|
||||
if (err)
|
||||
goto probe_out;
|
||||
|
||||
/* register video device */
|
||||
vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
|
||||
(int)ch, (int)&ch->video_dev);
|
||||
|
||||
err = video_register_device(ch->video_dev,
|
||||
VFL_TYPE_GRABBER, (j ? 3 : 2));
|
||||
if (err < 0)
|
||||
goto probe_out;
|
||||
}
|
||||
|
||||
v4l2_info(&vpif_obj.v4l2_dev,
|
||||
" VPIF display driver initialized\n");
|
||||
return 0;
|
||||
|
||||
probe_out:
|
||||
for (k = 0; k < j; k++) {
|
||||
ch = vpif_obj.dev[k];
|
||||
video_unregister_device(ch->video_dev);
|
||||
video_device_release(ch->video_dev);
|
||||
ch->video_dev = NULL;
|
||||
}
|
||||
probe_subdev_out:
|
||||
kfree(vpif_obj.sd);
|
||||
vpif_sd_error:
|
||||
|
|
|
|||
|
|
@ -148,7 +148,8 @@ struct vpif_device {
|
|||
struct v4l2_device v4l2_dev;
|
||||
struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
|
||||
struct v4l2_subdev **sd;
|
||||
|
||||
struct v4l2_async_notifier notifier;
|
||||
struct vpif_display_config *config;
|
||||
};
|
||||
|
||||
struct vpif_config_params {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <media/davinci/vpss.h>
|
||||
|
||||
|
|
@ -404,9 +405,8 @@ EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
|
|||
|
||||
static int vpss_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r1, *r2;
|
||||
struct resource *res;
|
||||
char *platform_name;
|
||||
int status;
|
||||
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
|
|
@ -427,38 +427,19 @@ static int vpss_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
|
||||
r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r1)
|
||||
return -ENOENT;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
|
||||
if (!r1)
|
||||
return -EBUSY;
|
||||
|
||||
oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
|
||||
if (!oper_cfg.vpss_regs_base0) {
|
||||
status = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
oper_cfg.vpss_regs_base0 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(oper_cfg.vpss_regs_base0))
|
||||
return PTR_ERR(oper_cfg.vpss_regs_base0);
|
||||
|
||||
if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
|
||||
r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!r2) {
|
||||
status = -ENOENT;
|
||||
goto fail2;
|
||||
}
|
||||
r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
|
||||
if (!r2) {
|
||||
status = -EBUSY;
|
||||
goto fail2;
|
||||
}
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
|
||||
oper_cfg.vpss_regs_base1 = ioremap(r2->start,
|
||||
resource_size(r2));
|
||||
if (!oper_cfg.vpss_regs_base1) {
|
||||
status = -EBUSY;
|
||||
goto fail3;
|
||||
}
|
||||
oper_cfg.vpss_regs_base1 = devm_ioremap_resource(&pdev->dev,
|
||||
res);
|
||||
if (IS_ERR(oper_cfg.vpss_regs_base1))
|
||||
return PTR_ERR(oper_cfg.vpss_regs_base1);
|
||||
}
|
||||
|
||||
if (oper_cfg.platform == DM355) {
|
||||
|
|
@ -493,30 +474,13 @@ static int vpss_probe(struct platform_device *pdev)
|
|||
|
||||
spin_lock_init(&oper_cfg.vpss_lock);
|
||||
dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
release_mem_region(r2->start, resource_size(r2));
|
||||
fail2:
|
||||
iounmap(oper_cfg.vpss_regs_base0);
|
||||
fail1:
|
||||
release_mem_region(r1->start, resource_size(r1));
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpss_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
iounmap(oper_cfg.vpss_regs_base0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
|
||||
iounmap(oper_cfg.vpss_regs_base1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1122,10 +1122,14 @@ static int gsc_probe(struct platform_device *pdev)
|
|||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = gsc_register_m2m_device(gsc);
|
||||
ret = v4l2_device_register(dev, &gsc->v4l2_dev);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
ret = gsc_register_m2m_device(gsc);
|
||||
if (ret)
|
||||
goto err_v4l2;
|
||||
|
||||
platform_set_drvdata(pdev, gsc);
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
|
|
@ -1147,6 +1151,8 @@ err_pm:
|
|||
pm_runtime_put(dev);
|
||||
err_m2m:
|
||||
gsc_unregister_m2m_device(gsc);
|
||||
err_v4l2:
|
||||
v4l2_device_unregister(&gsc->v4l2_dev);
|
||||
err_clk:
|
||||
gsc_clk_put(gsc);
|
||||
return ret;
|
||||
|
|
@ -1157,6 +1163,7 @@ static int gsc_remove(struct platform_device *pdev)
|
|||
struct gsc_dev *gsc = platform_get_drvdata(pdev);
|
||||
|
||||
gsc_unregister_m2m_device(gsc);
|
||||
v4l2_device_unregister(&gsc->v4l2_dev);
|
||||
|
||||
vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
@ -1210,12 +1217,12 @@ static int gsc_resume(struct device *dev)
|
|||
spin_unlock_irqrestore(&gsc->slock, flags);
|
||||
return 0;
|
||||
}
|
||||
gsc_hw_set_sw_reset(gsc);
|
||||
gsc_wait_reset(gsc);
|
||||
|
||||
spin_unlock_irqrestore(&gsc->slock, flags);
|
||||
|
||||
return gsc_m2m_resume(gsc);
|
||||
if (!pm_runtime_suspended(dev))
|
||||
return gsc_runtime_resume(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gsc_suspend(struct device *dev)
|
||||
|
|
@ -1227,7 +1234,10 @@ static int gsc_suspend(struct device *dev)
|
|||
if (test_and_set_bit(ST_SUSPEND, &gsc->state))
|
||||
return 0;
|
||||
|
||||
return gsc_m2m_suspend(gsc);
|
||||
if (!pm_runtime_suspended(dev))
|
||||
return gsc_runtime_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops gsc_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -343,6 +343,7 @@ struct gsc_dev {
|
|||
unsigned long state;
|
||||
struct vb2_alloc_ctx *alloc_ctx;
|
||||
struct video_device vdev;
|
||||
struct v4l2_device v4l2_dev;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -751,6 +751,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
|
|||
gsc->vdev.release = video_device_release_empty;
|
||||
gsc->vdev.lock = &gsc->lock;
|
||||
gsc->vdev.vfl_dir = VFL_DIR_M2M;
|
||||
gsc->vdev.v4l2_dev = &gsc->v4l2_dev;
|
||||
snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
|
||||
GSC_MODULE_NAME, gsc->id);
|
||||
|
||||
|
|
|
|||
|
|
@ -1110,6 +1110,8 @@ static int fimc_remove(struct platform_device *pdev)
|
|||
struct fimc_dev *fimc = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
clk_disable(fimc->clock[CLK_GATE]);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
fimc_unregister_capture_subdev(fimc);
|
||||
|
|
|
|||
|
|
@ -81,21 +81,46 @@ static int fimc_is_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_is_i2c_suspend(struct device *dev)
|
||||
#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
|
||||
static int fimc_is_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(isp_i2c->clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_is_i2c_resume(struct device *dev)
|
||||
static int fimc_is_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
|
||||
|
||||
return clk_prepare_enable(isp_i2c->clock);
|
||||
}
|
||||
#endif
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
|
||||
fimc_is_i2c_resume, NULL);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int fimc_is_i2c_suspend(struct device *dev)
|
||||
{
|
||||
if (pm_runtime_suspended(dev))
|
||||
return 0;
|
||||
|
||||
return fimc_is_i2c_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int fimc_is_i2c_resume(struct device *dev)
|
||||
{
|
||||
if (pm_runtime_suspended(dev))
|
||||
return 0;
|
||||
|
||||
return fimc_is_i2c_runtime_resume(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct dev_pm_ops fimc_is_i2c_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(fimc_is_i2c_runtime_suspend,
|
||||
fimc_is_i2c_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(fimc_is_i2c_suspend, fimc_is_i2c_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id fimc_is_i2c_of_match[] = {
|
||||
{ .compatible = FIMC_IS_I2C_COMPATIBLE },
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
|
|||
__hw_param_copy(dst, src);
|
||||
}
|
||||
|
||||
int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset)
|
||||
static int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset)
|
||||
{
|
||||
struct is_param_region *par = &is->is_p_region->parameter;
|
||||
struct chain_config *cfg = &is->config[is->config_index];
|
||||
|
|
@ -287,7 +287,7 @@ void __is_set_sensor(struct fimc_is *is, int fps)
|
|||
fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
|
||||
}
|
||||
|
||||
void __is_set_init_isp_aa(struct fimc_is *is)
|
||||
static void __maybe_unused __is_set_init_isp_aa(struct fimc_is *is)
|
||||
{
|
||||
struct isp_param *isp;
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ int fimc_is_hw_set_param(struct fimc_is *is)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fimc_is_hw_set_tune(struct fimc_is *is)
|
||||
static int __maybe_unused fimc_is_hw_set_tune(struct fimc_is *is)
|
||||
{
|
||||
fimc_is_hw_wait_intmsr0_intmsd0(is);
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ int fimc_is_itf_mode_change(struct fimc_is *is)
|
|||
fimc_is_hw_change_mode(is);
|
||||
ret = fimc_is_wait_event(is, IS_ST_CHANGE_MODE, 1,
|
||||
FIMC_IS_CONFIG_TIMEOUT);
|
||||
if (!ret < 0)
|
||||
if (ret < 0)
|
||||
dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n",
|
||||
__func__, is->config_index);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -993,3 +993,4 @@ module_exit(fimc_is_module_exit);
|
|||
MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME);
|
||||
MODULE_AUTHOR("Younghwan Joo <[email protected]>");
|
||||
MODULE_AUTHOR("Sylwester Nawrocki <[email protected]>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -672,6 +672,8 @@ int fimc_isp_subdev_create(struct fimc_isp *isp)
|
|||
mutex_init(&isp->subdev_lock);
|
||||
|
||||
v4l2_subdev_init(sd, &fimc_is_subdev_ops);
|
||||
|
||||
sd->owner = THIS_MODULE;
|
||||
sd->grp_id = GRP_ID_FIMC_IS;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
|
|||
.name = "RAW10 (GRBG)",
|
||||
.fourcc = V4L2_PIX_FMT_SGRBG10,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.depth = { 10 },
|
||||
.depth = { 16 },
|
||||
.color = FIMC_FMT_RAW10,
|
||||
.memplanes = 1,
|
||||
.mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
|
||||
|
|
@ -99,7 +99,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
|
|||
.name = "RAW12 (GRBG)",
|
||||
.fourcc = V4L2_PIX_FMT_SGRBG12,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.depth = { 12 },
|
||||
.depth = { 16 },
|
||||
.color = FIMC_FMT_RAW12,
|
||||
.memplanes = 1,
|
||||
.mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
|
||||
|
|
@ -1504,16 +1504,17 @@ static int fimc_lite_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL);
|
||||
if (!fimc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dev->of_node) {
|
||||
of_id = of_match_node(flite_of_match, dev->of_node);
|
||||
if (of_id)
|
||||
drv_data = (struct flite_drvdata *)of_id->data;
|
||||
fimc->index = of_alias_get_id(dev->of_node, "fimc-lite");
|
||||
}
|
||||
of_id = of_match_node(flite_of_match, dev->of_node);
|
||||
if (of_id)
|
||||
drv_data = (struct flite_drvdata *)of_id->data;
|
||||
fimc->index = of_alias_get_id(dev->of_node, "fimc-lite");
|
||||
|
||||
if (!drv_data || fimc->index >= drv_data->num_instances ||
|
||||
fimc->index < 0) {
|
||||
|
|
|
|||
|
|
@ -1149,7 +1149,6 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
|
|||
while (--i >= 0) {
|
||||
if (IS_ERR(fmd->camclk[i].clock))
|
||||
continue;
|
||||
clk_unprepare(fmd->camclk[i].clock);
|
||||
clk_put(fmd->camclk[i].clock);
|
||||
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
@ -1168,7 +1167,7 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
|
|||
struct device *dev = NULL;
|
||||
char clk_name[32];
|
||||
struct clk *clock;
|
||||
int ret, i;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < FIMC_MAX_CAMCLKS; i++)
|
||||
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
|
||||
|
|
@ -1186,12 +1185,6 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
|
|||
ret = PTR_ERR(clock);
|
||||
break;
|
||||
}
|
||||
ret = clk_prepare(clock);
|
||||
if (ret < 0) {
|
||||
clk_put(clock);
|
||||
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
|
||||
break;
|
||||
}
|
||||
fmd->camclk[i].clock = clock;
|
||||
}
|
||||
if (ret)
|
||||
|
|
@ -1248,7 +1241,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
|
|||
ret = pm_runtime_get_sync(fmd->pmf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = clk_enable(camclk->clock);
|
||||
ret = clk_prepare_enable(camclk->clock);
|
||||
dbg("Enabled camclk %d: f: %lu", si->clk_id,
|
||||
clk_get_rate(camclk->clock));
|
||||
}
|
||||
|
|
@ -1259,7 +1252,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
|
|||
return 0;
|
||||
|
||||
if (--camclk->use_count == 0) {
|
||||
clk_disable(camclk->clock);
|
||||
clk_disable_unprepare(camclk->clock);
|
||||
pm_runtime_put(fmd->pmf);
|
||||
dbg("Disabled camclk %d", si->clk_id);
|
||||
}
|
||||
|
|
@ -1529,9 +1522,9 @@ static int fimc_md_probe(struct platform_device *pdev)
|
|||
err_unlock:
|
||||
mutex_unlock(&fmd->media_dev.graph_mutex);
|
||||
err_clk:
|
||||
media_device_unregister(&fmd->media_dev);
|
||||
fimc_md_put_clocks(fmd);
|
||||
fimc_md_unregister_entities(fmd);
|
||||
media_device_unregister(&fmd->media_dev);
|
||||
err_md:
|
||||
v4l2_device_unregister(&fmd->v4l2_dev);
|
||||
return ret;
|
||||
|
|
@ -1543,6 +1536,8 @@ static int fimc_md_remove(struct platform_device *pdev)
|
|||
|
||||
if (!fmd)
|
||||
return 0;
|
||||
|
||||
v4l2_device_unregister(&fmd->v4l2_dev);
|
||||
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
|
||||
fimc_md_unregister_entities(fmd);
|
||||
fimc_md_pipelines_free(fmd);
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ static void cafe_ctlr_init(struct mcam_camera *mcam)
|
|||
}
|
||||
|
||||
|
||||
static void cafe_ctlr_power_up(struct mcam_camera *mcam)
|
||||
static int cafe_ctlr_power_up(struct mcam_camera *mcam)
|
||||
{
|
||||
/*
|
||||
* Part one of the sensor dance: turn the global
|
||||
|
|
@ -414,6 +414,8 @@ static void cafe_ctlr_power_up(struct mcam_camera *mcam)
|
|||
*/
|
||||
mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
|
||||
mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cafe_ctlr_power_down(struct mcam_camera *mcam)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
|
|
@ -93,6 +94,9 @@ MODULE_PARM_DESC(buffer_mode,
|
|||
#define CF_CONFIG_NEEDED 4 /* Must configure hardware */
|
||||
#define CF_SINGLE_BUFFER 5 /* Running with a single buffer */
|
||||
#define CF_SG_RESTART 6 /* SG restart needed */
|
||||
#define CF_FRAME_SOF0 7 /* Frame 0 started */
|
||||
#define CF_FRAME_SOF1 8
|
||||
#define CF_FRAME_SOF2 9
|
||||
|
||||
#define sensor_call(cam, o, f, args...) \
|
||||
v4l2_subdev_call(cam->sensor, o, f, ##args)
|
||||
|
|
@ -101,6 +105,7 @@ static struct mcam_format_struct {
|
|||
__u8 *desc;
|
||||
__u32 pixelformat;
|
||||
int bpp; /* Bytes per pixel */
|
||||
bool planar;
|
||||
enum v4l2_mbus_pixelcode mbus_code;
|
||||
} mcam_formats[] = {
|
||||
{
|
||||
|
|
@ -108,24 +113,56 @@ static struct mcam_format_struct {
|
|||
.pixelformat = V4L2_PIX_FMT_YUYV,
|
||||
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
.planar = false,
|
||||
},
|
||||
{
|
||||
.desc = "UYVY 4:2:2",
|
||||
.pixelformat = V4L2_PIX_FMT_UYVY,
|
||||
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
.planar = false,
|
||||
},
|
||||
{
|
||||
.desc = "YUV 4:2:2 PLANAR",
|
||||
.pixelformat = V4L2_PIX_FMT_YUV422P,
|
||||
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
.planar = true,
|
||||
},
|
||||
{
|
||||
.desc = "YUV 4:2:0 PLANAR",
|
||||
.pixelformat = V4L2_PIX_FMT_YUV420,
|
||||
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
.planar = true,
|
||||
},
|
||||
{
|
||||
.desc = "YVU 4:2:0 PLANAR",
|
||||
.pixelformat = V4L2_PIX_FMT_YVU420,
|
||||
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
.planar = true,
|
||||
},
|
||||
{
|
||||
.desc = "RGB 444",
|
||||
.pixelformat = V4L2_PIX_FMT_RGB444,
|
||||
.mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
|
||||
.bpp = 2,
|
||||
.planar = false,
|
||||
},
|
||||
{
|
||||
.desc = "RGB 565",
|
||||
.pixelformat = V4L2_PIX_FMT_RGB565,
|
||||
.mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
|
||||
.bpp = 2,
|
||||
.planar = false,
|
||||
},
|
||||
{
|
||||
.desc = "Raw RGB Bayer",
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
|
||||
.bpp = 1
|
||||
.bpp = 1,
|
||||
.planar = false,
|
||||
},
|
||||
};
|
||||
#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)
|
||||
|
|
@ -168,6 +205,12 @@ struct mcam_dma_desc {
|
|||
u32 segment_len;
|
||||
};
|
||||
|
||||
struct yuv_pointer_t {
|
||||
dma_addr_t y;
|
||||
dma_addr_t u;
|
||||
dma_addr_t v;
|
||||
};
|
||||
|
||||
/*
|
||||
* Our buffer type for working with videobuf2. Note that the vb2
|
||||
* developers have decreed that struct vb2_buffer must be at the
|
||||
|
|
@ -179,6 +222,7 @@ struct mcam_vb_buffer {
|
|||
struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
|
||||
dma_addr_t dma_desc_pa; /* Descriptor physical address */
|
||||
int dma_desc_nent; /* Number of mapped descriptors */
|
||||
struct yuv_pointer_t yuv_p;
|
||||
};
|
||||
|
||||
static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
|
||||
|
|
@ -219,8 +263,10 @@ static void mcam_reset_buffers(struct mcam_camera *cam)
|
|||
int i;
|
||||
|
||||
cam->next_buf = -1;
|
||||
for (i = 0; i < cam->nbufs; i++)
|
||||
for (i = 0; i < cam->nbufs; i++) {
|
||||
clear_bit(i, &cam->flags);
|
||||
clear_bit(CF_FRAME_SOF0 + i, &cam->flags);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int mcam_needs_config(struct mcam_camera *cam)
|
||||
|
|
@ -253,6 +299,45 @@ static void mcam_ctlr_stop(struct mcam_camera *cam)
|
|||
mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
|
||||
}
|
||||
|
||||
static void mcam_enable_mipi(struct mcam_camera *mcam)
|
||||
{
|
||||
/* Using MIPI mode and enable MIPI */
|
||||
cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n",
|
||||
mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY5, mcam->dphy[1]);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY6, mcam->dphy[2]);
|
||||
|
||||
if (!mcam->mipi_enabled) {
|
||||
if (mcam->lane > 4 || mcam->lane <= 0) {
|
||||
cam_warn(mcam, "lane number error\n");
|
||||
mcam->lane = 1; /* set the default value */
|
||||
}
|
||||
/*
|
||||
* 0x41 actives 1 lane
|
||||
* 0x43 actives 2 lanes
|
||||
* 0x45 actives 3 lanes (never happen)
|
||||
* 0x47 actives 4 lanes
|
||||
*/
|
||||
mcam_reg_write(mcam, REG_CSI2_CTRL0,
|
||||
CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane));
|
||||
mcam_reg_write(mcam, REG_CLKCTRL,
|
||||
(mcam->mclk_src << 29) | mcam->mclk_div);
|
||||
|
||||
mcam->mipi_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void mcam_disable_mipi(struct mcam_camera *mcam)
|
||||
{
|
||||
/* Using Parallel mode or disable MIPI */
|
||||
mcam_reg_write(mcam, REG_CSI2_CTRL0, 0x0);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY3, 0x0);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY5, 0x0);
|
||||
mcam_reg_write(mcam, REG_CSI2_DPHY6, 0x0);
|
||||
mcam->mipi_enabled = false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
#ifdef MCAM_MODE_VMALLOC
|
||||
|
|
@ -425,6 +510,15 @@ static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
|
|||
/*
|
||||
* DMA-contiguous code.
|
||||
*/
|
||||
|
||||
static bool mcam_fmt_is_planar(__u32 pfmt)
|
||||
{
|
||||
struct mcam_format_struct *f;
|
||||
|
||||
f = mcam_find_format(pfmt);
|
||||
return f->planar;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a contiguous buffer for the given frame. Here also is where
|
||||
* the underrun strategy is set: if there is no buffer available, reuse
|
||||
|
|
@ -436,27 +530,58 @@ static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
|
|||
static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
|
||||
{
|
||||
struct mcam_vb_buffer *buf;
|
||||
struct v4l2_pix_format *fmt = &cam->pix_format;
|
||||
dma_addr_t dma_handle;
|
||||
u32 pixel_count = fmt->width * fmt->height;
|
||||
struct vb2_buffer *vb;
|
||||
|
||||
/*
|
||||
* If there are no available buffers, go into single mode
|
||||
*/
|
||||
if (list_empty(&cam->buffers)) {
|
||||
buf = cam->vb_bufs[frame ^ 0x1];
|
||||
cam->vb_bufs[frame] = buf;
|
||||
mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
|
||||
vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
|
||||
set_bit(CF_SINGLE_BUFFER, &cam->flags);
|
||||
cam->frame_state.singles++;
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* OK, we have a buffer we can use.
|
||||
*/
|
||||
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
|
||||
queue);
|
||||
list_del_init(&buf->queue);
|
||||
clear_bit(CF_SINGLE_BUFFER, &cam->flags);
|
||||
}
|
||||
/*
|
||||
* OK, we have a buffer we can use.
|
||||
*/
|
||||
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
|
||||
list_del_init(&buf->queue);
|
||||
mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
|
||||
vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
|
||||
|
||||
cam->vb_bufs[frame] = buf;
|
||||
clear_bit(CF_SINGLE_BUFFER, &cam->flags);
|
||||
vb = &buf->vb_buf;
|
||||
|
||||
dma_handle = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
buf->yuv_p.y = dma_handle;
|
||||
|
||||
switch (cam->pix_format.pixelformat) {
|
||||
case V4L2_PIX_FMT_YUV422P:
|
||||
buf->yuv_p.u = buf->yuv_p.y + pixel_count;
|
||||
buf->yuv_p.v = buf->yuv_p.u + pixel_count / 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
buf->yuv_p.u = buf->yuv_p.y + pixel_count;
|
||||
buf->yuv_p.v = buf->yuv_p.u + pixel_count / 4;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YVU420:
|
||||
buf->yuv_p.v = buf->yuv_p.y + pixel_count;
|
||||
buf->yuv_p.u = buf->yuv_p.v + pixel_count / 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, buf->yuv_p.y);
|
||||
if (mcam_fmt_is_planar(fmt->pixelformat)) {
|
||||
mcam_reg_write(cam, frame == 0 ?
|
||||
REG_U0BAR : REG_U1BAR, buf->yuv_p.u);
|
||||
mcam_reg_write(cam, frame == 0 ?
|
||||
REG_V0BAR : REG_V1BAR, buf->yuv_p.v);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -614,48 +739,90 @@ static inline void mcam_sg_restart(struct mcam_camera *cam)
|
|||
*/
|
||||
static void mcam_ctlr_image(struct mcam_camera *cam)
|
||||
{
|
||||
int imgsz;
|
||||
struct v4l2_pix_format *fmt = &cam->pix_format;
|
||||
u32 widthy = 0, widthuv = 0, imgsz_h, imgsz_w;
|
||||
|
||||
cam_dbg(cam, "camera: bytesperline = %d; height = %d\n",
|
||||
fmt->bytesperline, fmt->sizeimage / fmt->bytesperline);
|
||||
imgsz_h = (fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK;
|
||||
imgsz_w = (fmt->width * 2) & IMGSZ_H_MASK;
|
||||
|
||||
switch (fmt->pixelformat) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
case V4L2_PIX_FMT_UYVY:
|
||||
widthy = fmt->width * 2;
|
||||
widthuv = 0;
|
||||
break;
|
||||
case V4L2_PIX_FMT_JPEG:
|
||||
imgsz_h = (fmt->sizeimage / fmt->bytesperline) << IMGSZ_V_SHIFT;
|
||||
widthy = fmt->bytesperline;
|
||||
widthuv = 0;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV422P:
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
case V4L2_PIX_FMT_YVU420:
|
||||
widthy = fmt->width;
|
||||
widthuv = fmt->width / 2;
|
||||
break;
|
||||
default:
|
||||
widthy = fmt->bytesperline;
|
||||
widthuv = 0;
|
||||
}
|
||||
|
||||
mcam_reg_write_mask(cam, REG_IMGPITCH, widthuv << 16 | widthy,
|
||||
IMGP_YP_MASK | IMGP_UVP_MASK);
|
||||
mcam_reg_write(cam, REG_IMGSIZE, imgsz_h | imgsz_w);
|
||||
mcam_reg_write(cam, REG_IMGOFFSET, 0x0);
|
||||
|
||||
imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
|
||||
(fmt->bytesperline & IMGSZ_H_MASK);
|
||||
mcam_reg_write(cam, REG_IMGSIZE, imgsz);
|
||||
mcam_reg_write(cam, REG_IMGOFFSET, 0);
|
||||
/* YPITCH just drops the last two bits */
|
||||
mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
|
||||
IMGP_YP_MASK);
|
||||
/*
|
||||
* Tell the controller about the image format we are using.
|
||||
*/
|
||||
switch (cam->pix_format.pixelformat) {
|
||||
switch (fmt->pixelformat) {
|
||||
case V4L2_PIX_FMT_YUV422P:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV | C0_YUV_PLANAR | C0_YUVE_YVYU, C0_DF_MASK);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
case V4L2_PIX_FMT_YVU420:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV | C0_YUV_420PL | C0_YUVE_YVYU, C0_DF_MASK);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
|
||||
C0_DF_MASK);
|
||||
break;
|
||||
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_UYVY, C0_DF_MASK);
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK);
|
||||
break;
|
||||
case V4L2_PIX_FMT_JPEG:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK);
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB444:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
|
||||
C0_DF_MASK);
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XRGB, C0_DF_MASK);
|
||||
/* Alpha value? */
|
||||
break;
|
||||
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
|
||||
C0_DF_MASK);
|
||||
break;
|
||||
|
||||
mcam_reg_write_mask(cam, REG_CTRL0,
|
||||
C0_DF_RGB | C0_RGBF_565 | C0_RGB5_BGGR, C0_DF_MASK);
|
||||
break;
|
||||
default:
|
||||
cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
|
||||
break;
|
||||
cam_err(cam, "camera: unknown format: %#x\n", fmt->pixelformat);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure it knows we want to use hsync/vsync.
|
||||
*/
|
||||
mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
|
||||
C0_SIFM_MASK);
|
||||
mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);
|
||||
/*
|
||||
* This field controls the generation of EOF(DVP only)
|
||||
*/
|
||||
if (cam->bus_type != V4L2_MBUS_CSI2)
|
||||
mcam_reg_set_bit(cam, REG_CTRL0,
|
||||
C0_EOF_VSYNC | C0_VEDGE_CTRL);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -753,15 +920,21 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
|
|||
/*
|
||||
* Power up and down.
|
||||
*/
|
||||
static void mcam_ctlr_power_up(struct mcam_camera *cam)
|
||||
static int mcam_ctlr_power_up(struct mcam_camera *cam)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
cam->plat_power_up(cam);
|
||||
ret = cam->plat_power_up(cam);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
msleep(5); /* Just to be sure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mcam_ctlr_power_down(struct mcam_camera *cam)
|
||||
|
|
@ -869,6 +1042,17 @@ static int mcam_read_setup(struct mcam_camera *cam)
|
|||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
clear_bit(CF_DMA_ACTIVE, &cam->flags);
|
||||
mcam_reset_buffers(cam);
|
||||
/*
|
||||
* Update CSI2_DPHY value
|
||||
*/
|
||||
if (cam->calc_dphy)
|
||||
cam->calc_dphy(cam);
|
||||
cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
|
||||
cam->dphy[0], cam->dphy[1], cam->dphy[2]);
|
||||
if (cam->bus_type == V4L2_MBUS_CSI2)
|
||||
mcam_enable_mipi(cam);
|
||||
else
|
||||
mcam_disable_mipi(cam);
|
||||
mcam_ctlr_irq_enable(cam);
|
||||
cam->state = S_STREAMING;
|
||||
if (!test_bit(CF_SG_RESTART, &cam->flags))
|
||||
|
|
@ -943,6 +1127,7 @@ static void mcam_vb_wait_finish(struct vb2_queue *vq)
|
|||
static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||
{
|
||||
struct mcam_camera *cam = vb2_get_drv_priv(vq);
|
||||
unsigned int frame;
|
||||
|
||||
if (cam->state != S_IDLE) {
|
||||
INIT_LIST_HEAD(&cam->buffers);
|
||||
|
|
@ -960,6 +1145,14 @@ static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
cam->state = S_BUFWAIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure clear the left over frame flags
|
||||
* before every really start streaming
|
||||
*/
|
||||
for (frame = 0; frame < cam->nbufs; frame++)
|
||||
clear_bit(CF_FRAME_SOF0 + frame, &cam->flags);
|
||||
|
||||
return mcam_read_setup(cam);
|
||||
}
|
||||
|
||||
|
|
@ -976,6 +1169,12 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq)
|
|||
if (cam->state != S_STREAMING)
|
||||
return -EINVAL;
|
||||
mcam_ctlr_stop_dma(cam);
|
||||
/*
|
||||
* Reset the CCIC PHY after stopping streaming,
|
||||
* otherwise, the CCIC may be unstable.
|
||||
*/
|
||||
if (cam->ctlr_reset)
|
||||
cam->ctlr_reset(cam);
|
||||
/*
|
||||
* VB2 reclaims the buffers, so we need to forget
|
||||
* about them.
|
||||
|
|
@ -1087,6 +1286,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
|
|||
#ifdef MCAM_MODE_DMA_CONTIG
|
||||
vq->ops = &mcam_vb2_ops;
|
||||
vq->mem_ops = &vb2_dma_contig_memops;
|
||||
vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
|
||||
cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
|
||||
vq->io_modes = VB2_MMAP | VB2_USERPTR;
|
||||
cam->dma_setup = mcam_ctlr_dma_contig;
|
||||
|
|
@ -1097,6 +1297,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
|
|||
#ifdef MCAM_MODE_DMA_SG
|
||||
vq->ops = &mcam_vb2_sg_ops;
|
||||
vq->mem_ops = &vb2_dma_sg_memops;
|
||||
vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
|
||||
vq->io_modes = VB2_MMAP | VB2_USERPTR;
|
||||
cam->dma_setup = mcam_ctlr_dma_sg;
|
||||
cam->frame_complete = mcam_dma_sg_done;
|
||||
|
|
@ -1247,7 +1448,15 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
|
|||
ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
v4l2_fill_pix_format(pix, &mbus_fmt);
|
||||
pix->bytesperline = pix->width * f->bpp;
|
||||
switch (f->pixelformat) {
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
case V4L2_PIX_FMT_YVU420:
|
||||
pix->bytesperline = pix->width * 3 / 2;
|
||||
break;
|
||||
default:
|
||||
pix->bytesperline = pix->width * f->bpp;
|
||||
break;
|
||||
}
|
||||
pix->sizeimage = pix->height * pix->bytesperline;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1475,7 +1684,9 @@ static int mcam_v4l_open(struct file *filp)
|
|||
ret = mcam_setup_vb2(cam);
|
||||
if (ret)
|
||||
goto out;
|
||||
mcam_ctlr_power_up(cam);
|
||||
ret = mcam_ctlr_power_up(cam);
|
||||
if (ret)
|
||||
goto out;
|
||||
__mcam_cam_reset(cam);
|
||||
mcam_set_config_needed(cam, 1);
|
||||
}
|
||||
|
|
@ -1498,10 +1709,12 @@ static int mcam_v4l_release(struct file *filp)
|
|||
if (cam->users == 0) {
|
||||
mcam_ctlr_stop_dma(cam);
|
||||
mcam_cleanup_vb2(cam);
|
||||
mcam_disable_mipi(cam);
|
||||
mcam_ctlr_power_down(cam);
|
||||
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
|
||||
mcam_free_dma_bufs(cam);
|
||||
}
|
||||
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1617,9 +1830,11 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
|
|||
* each time.
|
||||
*/
|
||||
for (frame = 0; frame < cam->nbufs; frame++)
|
||||
if (irqs & (IRQ_EOF0 << frame)) {
|
||||
if (irqs & (IRQ_EOF0 << frame) &&
|
||||
test_bit(CF_FRAME_SOF0 + frame, &cam->flags)) {
|
||||
mcam_frame_complete(cam, frame);
|
||||
handled = 1;
|
||||
clear_bit(CF_FRAME_SOF0 + frame, &cam->flags);
|
||||
if (cam->buffer_mode == B_DMA_sg)
|
||||
break;
|
||||
}
|
||||
|
|
@ -1628,9 +1843,15 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
|
|||
* code assumes that we won't get multiple frame interrupts
|
||||
* at once; may want to rethink that.
|
||||
*/
|
||||
if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
|
||||
for (frame = 0; frame < cam->nbufs; frame++) {
|
||||
if (irqs & (IRQ_SOF0 << frame)) {
|
||||
set_bit(CF_FRAME_SOF0 + frame, &cam->flags);
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled == IRQ_HANDLED) {
|
||||
set_bit(CF_DMA_ACTIVE, &cam->flags);
|
||||
handled = 1;
|
||||
if (cam->buffer_mode == B_DMA_sg)
|
||||
mcam_ctlr_stop(cam);
|
||||
}
|
||||
|
|
@ -1787,7 +2008,11 @@ int mccic_resume(struct mcam_camera *cam)
|
|||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
if (cam->users > 0) {
|
||||
mcam_ctlr_power_up(cam);
|
||||
ret = mcam_ctlr_power_up(cam);
|
||||
if (ret) {
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
__mcam_cam_reset(cam);
|
||||
} else {
|
||||
mcam_ctlr_power_down(cam);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ struct mcam_frame_state {
|
|||
unsigned int delivered;
|
||||
};
|
||||
|
||||
#define NR_MCAM_CLK 3
|
||||
|
||||
/*
|
||||
* A description of one of our devices.
|
||||
* Locking: controlled by s_mutex. Certain fields, however, require
|
||||
|
|
@ -108,11 +110,33 @@ struct mcam_camera {
|
|||
short int clock_speed; /* Sensor clock speed, default 30 */
|
||||
short int use_smbus; /* SMBUS or straight I2c? */
|
||||
enum mcam_buffer_mode buffer_mode;
|
||||
|
||||
int mclk_min; /* The minimal value of mclk */
|
||||
int mclk_src; /* which clock source the mclk derives from */
|
||||
int mclk_div; /* Clock Divider Value for MCLK */
|
||||
|
||||
int ccic_id;
|
||||
enum v4l2_mbus_type bus_type;
|
||||
/* MIPI support */
|
||||
/* The dphy config value, allocated in board file
|
||||
* dphy[0]: DPHY3
|
||||
* dphy[1]: DPHY5
|
||||
* dphy[2]: DPHY6
|
||||
*/
|
||||
int *dphy;
|
||||
bool mipi_enabled; /* flag whether mipi is enabled already */
|
||||
int lane; /* lane number */
|
||||
|
||||
/* clock tree support */
|
||||
struct clk *clk[NR_MCAM_CLK];
|
||||
|
||||
/*
|
||||
* Callbacks from the core to the platform code.
|
||||
*/
|
||||
void (*plat_power_up) (struct mcam_camera *cam);
|
||||
int (*plat_power_up) (struct mcam_camera *cam);
|
||||
void (*plat_power_down) (struct mcam_camera *cam);
|
||||
void (*calc_dphy) (struct mcam_camera *cam);
|
||||
void (*ctlr_reset) (struct mcam_camera *cam);
|
||||
|
||||
/*
|
||||
* Everything below here is private to the mcam core and
|
||||
|
|
@ -225,6 +249,23 @@ int mccic_resume(struct mcam_camera *cam);
|
|||
#define REG_Y0BAR 0x00
|
||||
#define REG_Y1BAR 0x04
|
||||
#define REG_Y2BAR 0x08
|
||||
#define REG_U0BAR 0x0c
|
||||
#define REG_U1BAR 0x10
|
||||
#define REG_U2BAR 0x14
|
||||
#define REG_V0BAR 0x18
|
||||
#define REG_V1BAR 0x1C
|
||||
#define REG_V2BAR 0x20
|
||||
|
||||
/*
|
||||
* register definitions for MIPI support
|
||||
*/
|
||||
#define REG_CSI2_CTRL0 0x100
|
||||
#define CSI2_C0_MIPI_EN (0x1 << 0)
|
||||
#define CSI2_C0_ACT_LANE(n) ((n-1) << 1)
|
||||
#define REG_CSI2_DPHY3 0x12c
|
||||
#define REG_CSI2_DPHY5 0x134
|
||||
#define REG_CSI2_DPHY6 0x138
|
||||
|
||||
/* ... */
|
||||
|
||||
#define REG_IMGPITCH 0x24 /* Image pitch register */
|
||||
|
|
@ -293,13 +334,16 @@ int mccic_resume(struct mcam_camera *cam);
|
|||
#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */
|
||||
#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */
|
||||
/* Bayer bits 18,19 if needed */
|
||||
#define C0_EOF_VSYNC 0x00400000 /* Generate EOF by VSYNC */
|
||||
#define C0_VEDGE_CTRL 0x00800000 /* Detect falling edge of VSYNC */
|
||||
#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */
|
||||
#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */
|
||||
#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */
|
||||
#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */
|
||||
#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */
|
||||
/* SIFMODE */
|
||||
#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */
|
||||
#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */
|
||||
#define C0_SOF_NOSYNC 0x40000000 /* Use inband active signaling */
|
||||
#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */
|
||||
|
||||
/* Bits below C1_444ALPHA are not present in Cafe */
|
||||
#define REG_CTRL1 0x40 /* Control 1 */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "mcam-core.h"
|
||||
|
||||
|
|
@ -33,11 +34,14 @@ MODULE_ALIAS("platform:mmp-camera");
|
|||
MODULE_AUTHOR("Jonathan Corbet <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"};
|
||||
|
||||
struct mmp_camera {
|
||||
void *power_regs;
|
||||
struct platform_device *pdev;
|
||||
struct mcam_camera mcam;
|
||||
struct list_head devlist;
|
||||
struct clk *mipi_clk;
|
||||
int irq;
|
||||
};
|
||||
|
||||
|
|
@ -101,6 +105,27 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
|
|||
#define CPU_SUBSYS_PMU_BASE 0xd4282800
|
||||
#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */
|
||||
#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */
|
||||
#define REG_CCIC2_CRCR 0xf4 /* CCIC2 clk reset ctrl reg */
|
||||
|
||||
static void mcam_clk_enable(struct mcam_camera *mcam)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NR_MCAM_CLK; i++) {
|
||||
if (!IS_ERR(mcam->clk[i]))
|
||||
clk_prepare_enable(mcam->clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void mcam_clk_disable(struct mcam_camera *mcam)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
|
||||
if (!IS_ERR(mcam->clk[i]))
|
||||
clk_disable_unprepare(mcam->clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Power control.
|
||||
|
|
@ -112,10 +137,17 @@ static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
|
|||
mdelay(1);
|
||||
}
|
||||
|
||||
static void mmpcam_power_up(struct mcam_camera *mcam)
|
||||
static int mmpcam_power_up(struct mcam_camera *mcam)
|
||||
{
|
||||
struct mmp_camera *cam = mcam_to_cam(mcam);
|
||||
struct mmp_camera_platform_data *pdata;
|
||||
|
||||
if (mcam->bus_type == V4L2_MBUS_CSI2) {
|
||||
cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
|
||||
if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
|
||||
return PTR_ERR(cam->mipi_clk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn on power and clocks to the controller.
|
||||
*/
|
||||
|
|
@ -132,6 +164,10 @@ static void mmpcam_power_up(struct mcam_camera *mcam)
|
|||
mdelay(5);
|
||||
gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
|
||||
mdelay(5);
|
||||
|
||||
mcam_clk_enable(mcam);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmpcam_power_down(struct mcam_camera *mcam)
|
||||
|
|
@ -149,8 +185,133 @@ static void mmpcam_power_down(struct mcam_camera *mcam)
|
|||
pdata = cam->pdev->dev.platform_data;
|
||||
gpio_set_value(pdata->sensor_power_gpio, 0);
|
||||
gpio_set_value(pdata->sensor_reset_gpio, 0);
|
||||
|
||||
if (mcam->bus_type == V4L2_MBUS_CSI2 && !IS_ERR(cam->mipi_clk)) {
|
||||
if (cam->mipi_clk)
|
||||
devm_clk_put(mcam->dev, cam->mipi_clk);
|
||||
cam->mipi_clk = NULL;
|
||||
}
|
||||
|
||||
mcam_clk_disable(mcam);
|
||||
}
|
||||
|
||||
void mcam_ctlr_reset(struct mcam_camera *mcam)
|
||||
{
|
||||
unsigned long val;
|
||||
struct mmp_camera *cam = mcam_to_cam(mcam);
|
||||
|
||||
if (mcam->ccic_id) {
|
||||
/*
|
||||
* Using CCIC2
|
||||
*/
|
||||
val = ioread32(cam->power_regs + REG_CCIC2_CRCR);
|
||||
iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR);
|
||||
iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR);
|
||||
} else {
|
||||
/*
|
||||
* Using CCIC1
|
||||
*/
|
||||
val = ioread32(cam->power_regs + REG_CCIC_CRCR);
|
||||
iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR);
|
||||
iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* calc the dphy register values
|
||||
* There are three dphy registers being used.
|
||||
* dphy[0] - CSI2_DPHY3
|
||||
* dphy[1] - CSI2_DPHY5
|
||||
* dphy[2] - CSI2_DPHY6
|
||||
* CSI2_DPHY3 and CSI2_DPHY6 can be set with a default value
|
||||
* or be calculated dynamically
|
||||
*/
|
||||
void mmpcam_calc_dphy(struct mcam_camera *mcam)
|
||||
{
|
||||
struct mmp_camera *cam = mcam_to_cam(mcam);
|
||||
struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data;
|
||||
struct device *dev = &cam->pdev->dev;
|
||||
unsigned long tx_clk_esc;
|
||||
|
||||
/*
|
||||
* If CSI2_DPHY3 is calculated dynamically,
|
||||
* pdata->lane_clk should be already set
|
||||
* either in the board driver statically
|
||||
* or in the sensor driver dynamically.
|
||||
*/
|
||||
/*
|
||||
* dphy[0] - CSI2_DPHY3:
|
||||
* bit 0 ~ bit 7: HS Term Enable.
|
||||
* defines the time that the DPHY
|
||||
* wait before enabling the data
|
||||
* lane termination after detecting
|
||||
* that the sensor has driven the data
|
||||
* lanes to the LP00 bridge state.
|
||||
* The value is calculated by:
|
||||
* (Max T(D_TERM_EN)/Period(DDR)) - 1
|
||||
* bit 8 ~ bit 15: HS_SETTLE
|
||||
* Time interval during which the HS
|
||||
* receiver shall ignore any Data Lane
|
||||
* HS transistions.
|
||||
* The vaule has been calibrated on
|
||||
* different boards. It seems to work well.
|
||||
*
|
||||
* More detail please refer
|
||||
* MIPI Alliance Spectification for D-PHY
|
||||
* document for explanation of HS-SETTLE
|
||||
* and D-TERM-EN.
|
||||
*/
|
||||
switch (pdata->dphy3_algo) {
|
||||
case DPHY3_ALGO_PXA910:
|
||||
/*
|
||||
* Calculate CSI2_DPHY3 algo for PXA910
|
||||
*/
|
||||
pdata->dphy[0] =
|
||||
(((1 + (pdata->lane_clk * 80) / 1000) & 0xff) << 8)
|
||||
| (1 + pdata->lane_clk * 35 / 1000);
|
||||
break;
|
||||
case DPHY3_ALGO_PXA2128:
|
||||
/*
|
||||
* Calculate CSI2_DPHY3 algo for PXA2128
|
||||
*/
|
||||
pdata->dphy[0] =
|
||||
(((2 + (pdata->lane_clk * 110) / 1000) & 0xff) << 8)
|
||||
| (1 + pdata->lane_clk * 35 / 1000);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Use default CSI2_DPHY3 value for PXA688/PXA988
|
||||
*/
|
||||
dev_dbg(dev, "camera: use the default CSI2_DPHY3 value\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* mipi_clk will never be changed, it is a fixed value on MMP
|
||||
*/
|
||||
if (IS_ERR(cam->mipi_clk))
|
||||
return;
|
||||
|
||||
/* get the escape clk, this is hard coded */
|
||||
tx_clk_esc = (clk_get_rate(cam->mipi_clk) / 1000000) / 12;
|
||||
|
||||
/*
|
||||
* dphy[2] - CSI2_DPHY6:
|
||||
* bit 0 ~ bit 7: CK Term Enable
|
||||
* Time for the Clock Lane receiver to enable the HS line
|
||||
* termination. The value is calculated similarly with
|
||||
* HS Term Enable
|
||||
* bit 8 ~ bit 15: CK Settle
|
||||
* Time interval during which the HS receiver shall ignore
|
||||
* any Clock Lane HS transitions.
|
||||
* The value is calibrated on the boards.
|
||||
*/
|
||||
pdata->dphy[2] =
|
||||
((((534 * tx_clk_esc) / 2000 - 1) & 0xff) << 8)
|
||||
| (((38 * tx_clk_esc) / 1000 - 1) & 0xff);
|
||||
|
||||
dev_dbg(dev, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
|
||||
pdata->dphy[0], pdata->dphy[1], pdata->dphy[2]);
|
||||
}
|
||||
|
||||
static irqreturn_t mmpcam_irq(int irq, void *data)
|
||||
{
|
||||
|
|
@ -164,6 +325,35 @@ static irqreturn_t mmpcam_irq(int irq, void *data)
|
|||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static void mcam_deinit_clk(struct mcam_camera *mcam)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NR_MCAM_CLK; i++) {
|
||||
if (!IS_ERR(mcam->clk[i])) {
|
||||
if (mcam->clk[i])
|
||||
devm_clk_put(mcam->dev, mcam->clk[i]);
|
||||
}
|
||||
mcam->clk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mcam_init_clk(struct mcam_camera *mcam)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NR_MCAM_CLK; i++) {
|
||||
if (mcam_clks[i] != NULL) {
|
||||
/* Some clks are not necessary on some boards
|
||||
* We still try to run even it fails getting clk
|
||||
*/
|
||||
mcam->clk[i] = devm_clk_get(mcam->dev, mcam_clks[i]);
|
||||
if (IS_ERR(mcam->clk[i]))
|
||||
dev_warn(mcam->dev, "Could not get clk: %s\n",
|
||||
mcam_clks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mmpcam_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -173,17 +363,32 @@ static int mmpcam_probe(struct platform_device *pdev)
|
|||
struct mmp_camera_platform_data *pdata;
|
||||
int ret;
|
||||
|
||||
cam = kzalloc(sizeof(*cam), GFP_KERNEL);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
|
||||
cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
|
||||
if (cam == NULL)
|
||||
return -ENOMEM;
|
||||
cam->pdev = pdev;
|
||||
cam->mipi_clk = NULL;
|
||||
INIT_LIST_HEAD(&cam->devlist);
|
||||
|
||||
mcam = &cam->mcam;
|
||||
mcam->plat_power_up = mmpcam_power_up;
|
||||
mcam->plat_power_down = mmpcam_power_down;
|
||||
mcam->ctlr_reset = mcam_ctlr_reset;
|
||||
mcam->calc_dphy = mmpcam_calc_dphy;
|
||||
mcam->dev = &pdev->dev;
|
||||
mcam->use_smbus = 0;
|
||||
mcam->ccic_id = pdev->id;
|
||||
mcam->mclk_min = pdata->mclk_min;
|
||||
mcam->mclk_src = pdata->mclk_src;
|
||||
mcam->mclk_div = pdata->mclk_div;
|
||||
mcam->bus_type = pdata->bus_type;
|
||||
mcam->dphy = pdata->dphy;
|
||||
mcam->mipi_enabled = false;
|
||||
mcam->lane = pdata->lane;
|
||||
mcam->chip_id = MCAM_ARMADA610;
|
||||
mcam->buffer_mode = B_DMA_sg;
|
||||
spin_lock_init(&mcam->dev_lock);
|
||||
|
|
@ -191,69 +396,58 @@ static int mmpcam_probe(struct platform_device *pdev)
|
|||
* Get our I/O memory.
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "no iomem resource!\n");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
}
|
||||
mcam->regs = ioremap(res->start, resource_size(res));
|
||||
if (mcam->regs == NULL) {
|
||||
dev_err(&pdev->dev, "MMIO ioremap fail\n");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
}
|
||||
mcam->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mcam->regs))
|
||||
return PTR_ERR(mcam->regs);
|
||||
mcam->regs_size = resource_size(res);
|
||||
/*
|
||||
* Power/clock memory is elsewhere; get it too. Perhaps this
|
||||
* should really be managed outside of this driver?
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "no power resource!\n");
|
||||
ret = -ENODEV;
|
||||
goto out_unmap1;
|
||||
}
|
||||
cam->power_regs = ioremap(res->start, resource_size(res));
|
||||
if (cam->power_regs == NULL) {
|
||||
dev_err(&pdev->dev, "power MMIO ioremap fail\n");
|
||||
ret = -ENODEV;
|
||||
goto out_unmap1;
|
||||
}
|
||||
cam->power_regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(cam->power_regs))
|
||||
return PTR_ERR(cam->power_regs);
|
||||
/*
|
||||
* Find the i2c adapter. This assumes, of course, that the
|
||||
* i2c bus is already up and functioning.
|
||||
*/
|
||||
pdata = pdev->dev.platform_data;
|
||||
mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
|
||||
if (mcam->i2c_adapter == NULL) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "No i2c adapter\n");
|
||||
goto out_unmap2;
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* Sensor GPIO pins.
|
||||
*/
|
||||
ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
|
||||
ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio,
|
||||
"cam-power");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't get sensor power gpio %d",
|
||||
pdata->sensor_power_gpio);
|
||||
goto out_unmap2;
|
||||
return ret;
|
||||
}
|
||||
gpio_direction_output(pdata->sensor_power_gpio, 0);
|
||||
ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
|
||||
ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio,
|
||||
"cam-reset");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
|
||||
pdata->sensor_reset_gpio);
|
||||
goto out_gpio;
|
||||
return ret;
|
||||
}
|
||||
gpio_direction_output(pdata->sensor_reset_gpio, 0);
|
||||
|
||||
mcam_init_clk(mcam);
|
||||
|
||||
/*
|
||||
* Power the device up and hand it off to the core.
|
||||
*/
|
||||
mmpcam_power_up(mcam);
|
||||
ret = mmpcam_power_up(mcam);
|
||||
if (ret)
|
||||
goto out_deinit_clk;
|
||||
ret = mccic_register(mcam);
|
||||
if (ret)
|
||||
goto out_gpio2;
|
||||
goto out_power_down;
|
||||
/*
|
||||
* Finally, set up our IRQ now that the core is ready to
|
||||
* deal with it.
|
||||
|
|
@ -264,8 +458,8 @@ static int mmpcam_probe(struct platform_device *pdev)
|
|||
goto out_unregister;
|
||||
}
|
||||
cam->irq = res->start;
|
||||
ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
|
||||
"mmp-camera", mcam);
|
||||
ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
|
||||
"mmp-camera", mcam);
|
||||
if (ret == 0) {
|
||||
mmpcam_add_device(cam);
|
||||
return 0;
|
||||
|
|
@ -273,17 +467,10 @@ static int mmpcam_probe(struct platform_device *pdev)
|
|||
|
||||
out_unregister:
|
||||
mccic_shutdown(mcam);
|
||||
out_gpio2:
|
||||
out_power_down:
|
||||
mmpcam_power_down(mcam);
|
||||
gpio_free(pdata->sensor_reset_gpio);
|
||||
out_gpio:
|
||||
gpio_free(pdata->sensor_power_gpio);
|
||||
out_unmap2:
|
||||
iounmap(cam->power_regs);
|
||||
out_unmap1:
|
||||
iounmap(mcam->regs);
|
||||
out_free:
|
||||
kfree(cam);
|
||||
out_deinit_clk:
|
||||
mcam_deinit_clk(mcam);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +487,7 @@ static int mmpcam_remove(struct mmp_camera *cam)
|
|||
pdata = cam->pdev->dev.platform_data;
|
||||
gpio_free(pdata->sensor_reset_gpio);
|
||||
gpio_free(pdata->sensor_power_gpio);
|
||||
mcam_deinit_clk(mcam);
|
||||
iounmap(cam->power_regs);
|
||||
iounmap(mcam->regs);
|
||||
kfree(cam);
|
||||
|
|
|
|||
|
|
@ -106,15 +106,15 @@ static const u32 src_pixfmt_map[8][2] = {
|
|||
void camif_hw_set_source_format(struct camif_dev *camif)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
|
||||
unsigned int i = ARRAY_SIZE(src_pixfmt_map);
|
||||
int i;
|
||||
u32 cfg;
|
||||
|
||||
while (i-- >= 0) {
|
||||
for (i = ARRAY_SIZE(src_pixfmt_map) - 1; i >= 0; i--) {
|
||||
if (src_pixfmt_map[i][0] == mf->code)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0 && src_pixfmt_map[i][0] != mf->code) {
|
||||
if (i < 0) {
|
||||
i = 0;
|
||||
dev_err(camif->dev,
|
||||
"Unsupported pixel code, falling back to %#08x\n",
|
||||
src_pixfmt_map[i][0]);
|
||||
|
|
|
|||
|
|
@ -374,9 +374,9 @@
|
|||
#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16
|
||||
|
||||
/* Buffer size requirements defined by hardware */
|
||||
#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 1) * 8)
|
||||
#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 3) * 8)
|
||||
#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \
|
||||
((DIV_ROUND_UP(imw, 64) * DIV_ROUND_UP(imh, 64) * 256) + \
|
||||
(((((imw + 127) / 64) * 16) * DIV_ROUND_UP(imh, 64) * 256) + \
|
||||
(DIV_ROUND_UP((mbw) * (mbh), 32) * 16))
|
||||
#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64)
|
||||
#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \
|
||||
|
|
|
|||
61
drivers/media/platform/s5p-mfc/regs-mfc-v7.h
Normal file
61
drivers/media/platform/s5p-mfc/regs-mfc-v7.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Register definition file for Samsung MFC V7.x Interface (FIMV) driver
|
||||
*
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _REGS_MFC_V7_H
|
||||
#define _REGS_MFC_V7_H
|
||||
|
||||
#include "regs-mfc-v6.h"
|
||||
|
||||
/* Additional features of v7 */
|
||||
#define S5P_FIMV_CODEC_VP8_ENC_V7 25
|
||||
|
||||
/* Additional registers for v7 */
|
||||
#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V7 0xf47c
|
||||
|
||||
#define S5P_FIMV_E_SOURCE_FIRST_ADDR_V7 0xf9e0
|
||||
#define S5P_FIMV_E_SOURCE_SECOND_ADDR_V7 0xf9e4
|
||||
#define S5P_FIMV_E_SOURCE_THIRD_ADDR_V7 0xf9e8
|
||||
#define S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7 0xf9ec
|
||||
#define S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7 0xf9f0
|
||||
#define S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7 0xf9f4
|
||||
|
||||
#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7 0xfa70
|
||||
#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7 0xfa74
|
||||
|
||||
#define S5P_FIMV_E_VP8_OPTIONS_V7 0xfdb0
|
||||
#define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7 0xfdb4
|
||||
#define S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION_V7 0xfdb8
|
||||
#define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4
|
||||
|
||||
/* MFCv7 variant defines */
|
||||
#define MAX_FW_SIZE_V7 (SZ_1M) /* 1MB */
|
||||
#define MAX_CPB_SIZE_V7 (3 * SZ_1M) /* 3MB */
|
||||
#define MFC_VERSION_V7 0x72
|
||||
#define MFC_NUM_PORTS_V7 1
|
||||
|
||||
#define MFC_LUMA_PAD_BYTES_V7 256
|
||||
#define MFC_CHROMA_PAD_BYTES_V7 128
|
||||
|
||||
/* MFCv7 Context buffer sizes */
|
||||
#define MFC_CTX_BUF_SIZE_V7 (30 * SZ_1K) /* 30KB */
|
||||
#define MFC_H264_DEC_CTX_BUF_SIZE_V7 (2 * SZ_1M) /* 2MB */
|
||||
#define MFC_OTHER_DEC_CTX_BUF_SIZE_V7 (20 * SZ_1K) /* 20KB */
|
||||
#define MFC_H264_ENC_CTX_BUF_SIZE_V7 (100 * SZ_1K) /* 100KB */
|
||||
#define MFC_OTHER_ENC_CTX_BUF_SIZE_V7 (10 * SZ_1K) /* 10KB */
|
||||
|
||||
/* Buffer size defines */
|
||||
#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(w, h) \
|
||||
(SZ_1M + ((w) * 144) + (8192 * (h)) + 49216)
|
||||
|
||||
#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(w, h) \
|
||||
(((w) * 48) + (((w) + 1) / 2 * 128) + 144 + 8192)
|
||||
|
||||
#endif /*_REGS_MFC_V7_H*/
|
||||
|
|
@ -1391,6 +1391,32 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = {
|
|||
.fw_name = "s5p-mfc-v6.fw",
|
||||
};
|
||||
|
||||
struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
|
||||
.dev_ctx = MFC_CTX_BUF_SIZE_V7,
|
||||
.h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7,
|
||||
.other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7,
|
||||
.h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V7,
|
||||
.other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7,
|
||||
};
|
||||
|
||||
struct s5p_mfc_buf_size buf_size_v7 = {
|
||||
.fw = MAX_FW_SIZE_V7,
|
||||
.cpb = MAX_CPB_SIZE_V7,
|
||||
.priv = &mfc_buf_size_v7,
|
||||
};
|
||||
|
||||
struct s5p_mfc_buf_align mfc_buf_align_v7 = {
|
||||
.base = 0,
|
||||
};
|
||||
|
||||
static struct s5p_mfc_variant mfc_drvdata_v7 = {
|
||||
.version = MFC_VERSION_V7,
|
||||
.port_num = MFC_NUM_PORTS_V7,
|
||||
.buf_size = &buf_size_v7,
|
||||
.buf_align = &mfc_buf_align_v7,
|
||||
.fw_name = "s5p-mfc-v7.fw",
|
||||
};
|
||||
|
||||
static struct platform_device_id mfc_driver_ids[] = {
|
||||
{
|
||||
.name = "s5p-mfc",
|
||||
|
|
@ -1401,6 +1427,9 @@ static struct platform_device_id mfc_driver_ids[] = {
|
|||
}, {
|
||||
.name = "s5p-mfc-v6",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v6,
|
||||
}, {
|
||||
.name = "s5p-mfc-v7",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v7,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
@ -1413,6 +1442,9 @@ static const struct of_device_id exynos_mfc_match[] = {
|
|||
}, {
|
||||
.compatible = "samsung,mfc-v6",
|
||||
.data = &mfc_drvdata_v6,
|
||||
}, {
|
||||
.compatible = "samsung,mfc-v7",
|
||||
.data = &mfc_drvdata_v7,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ static struct s5p_mfc_hw_cmds *s5p_mfc_cmds;
|
|||
|
||||
void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev)
|
||||
{
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6();
|
||||
else
|
||||
s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5();
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
|
|||
case S5P_MFC_CODEC_H263_ENC:
|
||||
codec_type = S5P_FIMV_CODEC_H263_ENC_V6;
|
||||
break;
|
||||
case S5P_MFC_CODEC_VP8_ENC:
|
||||
codec_type = S5P_FIMV_CODEC_VP8_ENC_V7;
|
||||
break;
|
||||
default:
|
||||
codec_type = S5P_FIMV_CODEC_NONE_V6;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <media/videobuf2-core.h>
|
||||
#include "regs-mfc.h"
|
||||
#include "regs-mfc-v6.h"
|
||||
#include "regs-mfc-v7.h"
|
||||
|
||||
/* Definitions related to MFC memory */
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
|
|||
#define MFC_ENC_CAP_PLANE_COUNT 1
|
||||
#define MFC_ENC_OUT_PLANE_COUNT 2
|
||||
#define STUFF_BYTE 4
|
||||
#define MFC_MAX_CTRLS 70
|
||||
#define MFC_MAX_CTRLS 77
|
||||
|
||||
#define S5P_MFC_CODEC_NONE -1
|
||||
#define S5P_MFC_CODEC_H264_DEC 0
|
||||
|
|
@ -80,6 +81,7 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
|
|||
#define S5P_MFC_CODEC_H264_MVC_ENC 21
|
||||
#define S5P_MFC_CODEC_MPEG4_ENC 22
|
||||
#define S5P_MFC_CODEC_H263_ENC 23
|
||||
#define S5P_MFC_CODEC_VP8_ENC 24
|
||||
|
||||
#define S5P_MFC_R2H_CMD_EMPTY 0
|
||||
#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1
|
||||
|
|
@ -407,6 +409,21 @@ struct s5p_mfc_mpeg4_enc_params {
|
|||
int level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s5p_mfc_vp8_enc_params - encoding parameters for vp8
|
||||
*/
|
||||
struct s5p_mfc_vp8_enc_params {
|
||||
u8 imd_4x4;
|
||||
enum v4l2_vp8_num_partitions num_partitions;
|
||||
enum v4l2_vp8_num_ref_frames num_ref;
|
||||
u8 filter_level;
|
||||
u8 filter_sharpness;
|
||||
u32 golden_frame_ref_period;
|
||||
enum v4l2_vp8_golden_frame_sel golden_frame_sel;
|
||||
u8 hier_layer;
|
||||
u8 hier_layer_qp[3];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s5p_mfc_enc_params - general encoding parameters
|
||||
*/
|
||||
|
|
@ -441,6 +458,7 @@ struct s5p_mfc_enc_params {
|
|||
struct {
|
||||
struct s5p_mfc_h264_enc_params h264;
|
||||
struct s5p_mfc_mpeg4_enc_params mpeg4;
|
||||
struct s5p_mfc_vp8_enc_params vp8;
|
||||
} codec;
|
||||
|
||||
};
|
||||
|
|
@ -683,6 +701,7 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
|
|||
#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \
|
||||
(dev->variant->port_num ? 1 : 0) : 0) : 0)
|
||||
#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0)
|
||||
#define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0)
|
||||
#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0)
|
||||
#define IS_MFCV7(dev) (dev->variant->version >= 0x70 ? 1 : 0)
|
||||
|
||||
#endif /* S5P_MFC_COMMON_H_ */
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
|
|||
|
||||
mfc_debug_enter();
|
||||
|
||||
if (IS_MFCV6(dev)) {
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
/* Reset IP */
|
||||
/* except RISC, reset */
|
||||
mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6);
|
||||
|
|
@ -213,7 +213,7 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
|
|||
|
||||
static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
|
||||
{
|
||||
if (IS_MFCV6(dev)) {
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
|
||||
mfc_debug(2, "Base Address : %08x\n", dev->bank1);
|
||||
} else {
|
||||
|
|
@ -226,7 +226,7 @@ static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
|
|||
|
||||
static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
|
||||
{
|
||||
if (IS_MFCV6(dev)) {
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
/* Zero initialization should be done before RESET.
|
||||
* Nothing to do here. */
|
||||
} else {
|
||||
|
|
@ -264,7 +264,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
|
|||
s5p_mfc_clear_cmds(dev);
|
||||
/* 3. Release reset signal to the RISC */
|
||||
s5p_mfc_clean_dev_int_flags(dev);
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
|
||||
else
|
||||
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
|
||||
|
|
@ -301,7 +301,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
|
|||
s5p_mfc_clock_off();
|
||||
return -EIO;
|
||||
}
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6);
|
||||
else
|
||||
ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
|
||||
|
|
@ -380,7 +380,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
|
|||
return ret;
|
||||
}
|
||||
/* 4. Release reset signal to the RISC */
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
|
||||
else
|
||||
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|||
mfc_err("Unknown codec\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!IS_MFCV6(dev)) {
|
||||
if (!IS_MFCV6_PLUS(dev)) {
|
||||
if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
|
||||
mfc_err("Not supported format.\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -398,10 +398,11 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|||
mfc_err("Unsupported format for destination.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
|
||||
if (IS_MFCV6_PLUS(dev) &&
|
||||
(fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
|
||||
mfc_err("Not supported format.\n");
|
||||
return -EINVAL;
|
||||
} else if (!IS_MFCV6(dev) &&
|
||||
} else if (!IS_MFCV6_PLUS(dev) &&
|
||||
(fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
|
||||
mfc_err("Not supported format.\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -925,7 +926,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
|
|||
psize[0] = ctx->luma_size;
|
||||
psize[1] = ctx->chroma_size;
|
||||
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
allocators[0] =
|
||||
ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
|
||||
else
|
||||
|
|
@ -1050,7 +1051,7 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q)
|
|||
ctx->dpb_flush_flag = 1;
|
||||
ctx->dec_dst_flag = 0;
|
||||
spin_unlock_irqrestore(&dev->irqlock, flags);
|
||||
if (IS_MFCV6(dev) && (ctx->state == MFCINST_RUNNING)) {
|
||||
if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) {
|
||||
ctx->state = MFCINST_FLUSH;
|
||||
set_work_bit_irqsave(ctx);
|
||||
s5p_mfc_clean_ctx_int_flags(ctx);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,13 @@ static struct s5p_mfc_fmt formats[] = {
|
|||
.type = MFC_FMT_ENC,
|
||||
.num_planes = 1,
|
||||
},
|
||||
{
|
||||
.name = "VP8 Encoded Stream",
|
||||
.fourcc = V4L2_PIX_FMT_VP8,
|
||||
.codec_mode = S5P_MFC_CODEC_VP8_ENC,
|
||||
.type = MFC_FMT_ENC,
|
||||
.num_planes = 1,
|
||||
},
|
||||
};
|
||||
|
||||
#define NUM_FORMATS ARRAY_SIZE(formats)
|
||||
|
|
@ -557,6 +564,60 @@ static struct mfc_control controls[] = {
|
|||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
|
||||
.maximum = V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS,
|
||||
.default_value = V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION,
|
||||
.menu_skip_mask = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
|
||||
.maximum = V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME,
|
||||
.default_value = V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME,
|
||||
.menu_skip_mask = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.minimum = 0,
|
||||
.maximum = 63,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.minimum = 0,
|
||||
.maximum = 7,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.minimum = 0,
|
||||
.maximum = (1 << 16) - 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL,
|
||||
.type = V4L2_CTRL_TYPE_MENU,
|
||||
.minimum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV,
|
||||
.maximum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD,
|
||||
.default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV,
|
||||
.menu_skip_mask = 0,
|
||||
},
|
||||
};
|
||||
|
||||
#define NUM_CTRLS ARRAY_SIZE(controls)
|
||||
|
|
@ -663,7 +724,7 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
|
|||
spin_unlock_irqrestore(&dev->irqlock, flags);
|
||||
}
|
||||
|
||||
if (!IS_MFCV6(dev)) {
|
||||
if (!IS_MFCV6_PLUS(dev)) {
|
||||
ctx->state = MFCINST_RUNNING;
|
||||
if (s5p_mfc_ctx_ready(ctx))
|
||||
set_work_bit_irqsave(ctx);
|
||||
|
|
@ -917,6 +978,11 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IS_MFCV7(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
|
||||
mfc_err("VP8 is supported only in MFC v7\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
|
||||
mfc_err("must be set encoding output size\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -931,12 +997,12 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IS_MFCV6(dev)) {
|
||||
if (!IS_MFCV6_PLUS(dev)) {
|
||||
if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
|
||||
mfc_err("Not supported format.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (IS_MFCV6(dev)) {
|
||||
} else if (IS_MFCV6_PLUS(dev)) {
|
||||
if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
|
||||
mfc_err("Not supported format.\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -1060,7 +1126,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_MFCV6(dev)) {
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
/* Check for min encoder buffers */
|
||||
if (ctx->pb_count &&
|
||||
(reqbufs->count < ctx->pb_count)) {
|
||||
|
|
@ -1341,7 +1407,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
S5P_FIMV_ENC_PROFILE_H264_BASELINE;
|
||||
break;
|
||||
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
|
||||
if (IS_MFCV6(dev))
|
||||
if (IS_MFCV6_PLUS(dev))
|
||||
p->codec.h264.profile =
|
||||
S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE;
|
||||
else
|
||||
|
|
@ -1470,6 +1536,27 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
|
||||
p->codec.mpeg4.quarter_pixel = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
|
||||
p->codec.vp8.num_partitions = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4:
|
||||
p->codec.vp8.imd_4x4 = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
|
||||
p->codec.vp8.num_ref = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL:
|
||||
p->codec.vp8.filter_level = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS:
|
||||
p->codec.vp8.filter_sharpness = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD:
|
||||
p->codec.vp8.golden_frame_ref_period = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
|
||||
p->codec.vp8.golden_frame_sel = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
|
||||
ctrl->id, ctrl->val);
|
||||
|
|
@ -1650,9 +1737,11 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
|
|||
*buf_count = 1;
|
||||
if (*buf_count > MFC_MAX_BUFFERS)
|
||||
*buf_count = MFC_MAX_BUFFERS;
|
||||
|
||||
psize[0] = ctx->luma_size;
|
||||
psize[1] = ctx->chroma_size;
|
||||
if (IS_MFCV6(dev)) {
|
||||
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
allocators[0] =
|
||||
ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
|
||||
allocators[1] =
|
||||
|
|
@ -1761,7 +1850,8 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
|
|||
struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
|
||||
struct s5p_mfc_dev *dev = ctx->dev;
|
||||
|
||||
if (IS_MFCV6(dev) && (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
|
||||
if (IS_MFCV6_PLUS(dev) &&
|
||||
(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
|
||||
|
||||
if ((ctx->state == MFCINST_GOT_INST) &&
|
||||
(dev->curr_ctx == ctx->num) && dev->hw_lock) {
|
||||
|
|
@ -1915,7 +2005,9 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
|
|||
ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
|
||||
&cfg, NULL);
|
||||
} else {
|
||||
if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
|
||||
if ((controls[i].type == V4L2_CTRL_TYPE_MENU) ||
|
||||
(controls[i].type ==
|
||||
V4L2_CTRL_TYPE_INTEGER_MENU)) {
|
||||
ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
|
||||
&ctx->ctrl_handler,
|
||||
&s5p_mfc_enc_ctrl_ops, controls[i].id,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static struct s5p_mfc_hw_ops *s5p_mfc_ops;
|
|||
|
||||
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev)
|
||||
{
|
||||
if (IS_MFCV6(dev)) {
|
||||
if (IS_MFCV6_PLUS(dev)) {
|
||||
s5p_mfc_ops = s5p_mfc_init_hw_ops_v6();
|
||||
dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
|
|||
ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
|
||||
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height),
|
||||
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
|
||||
|
||||
ctx->luma_dpb_size = ALIGN((mb_width * mb_height) *
|
||||
S5P_FIMV_LUMA_MB_TO_PIXEL_V6,
|
||||
S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6);
|
||||
|
|
@ -112,10 +113,18 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
|
|||
(ctx->mv_count * ctx->mv_size);
|
||||
break;
|
||||
case S5P_MFC_CODEC_MPEG4_DEC:
|
||||
ctx->scratch_buf_size =
|
||||
S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(
|
||||
mb_width,
|
||||
mb_height);
|
||||
if (IS_MFCV7(dev)) {
|
||||
ctx->scratch_buf_size =
|
||||
S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(
|
||||
mb_width,
|
||||
mb_height);
|
||||
} else {
|
||||
ctx->scratch_buf_size =
|
||||
S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(
|
||||
mb_width,
|
||||
mb_height);
|
||||
}
|
||||
|
||||
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
|
||||
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
|
||||
ctx->bank1.size = ctx->scratch_buf_size;
|
||||
|
|
@ -179,6 +188,19 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
|
|||
ctx->chroma_dpb_size + ctx->me_buffer_size));
|
||||
ctx->bank2.size = 0;
|
||||
break;
|
||||
case S5P_MFC_CODEC_VP8_ENC:
|
||||
ctx->scratch_buf_size =
|
||||
S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(
|
||||
mb_width,
|
||||
mb_height);
|
||||
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
|
||||
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
|
||||
ctx->bank1.size =
|
||||
ctx->scratch_buf_size + ctx->tmv_buffer_size +
|
||||
(ctx->pb_count * (ctx->luma_dpb_size +
|
||||
ctx->chroma_dpb_size + ctx->me_buffer_size));
|
||||
ctx->bank2.size = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -228,6 +250,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
|
|||
break;
|
||||
case S5P_MFC_CODEC_MPEG4_ENC:
|
||||
case S5P_MFC_CODEC_H263_ENC:
|
||||
case S5P_MFC_CODEC_VP8_ENC:
|
||||
ctx->ctx.size = buf_size->other_enc_ctx;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -329,6 +352,12 @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
|
|||
ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
|
||||
ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
|
||||
ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
|
||||
|
||||
/* MFCv7 needs pad bytes for Luma and Chroma */
|
||||
if (IS_MFCV7(ctx->dev)) {
|
||||
ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
|
||||
ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set registers for decoding stream buffer */
|
||||
|
|
@ -453,8 +482,13 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
|
|||
{
|
||||
struct s5p_mfc_dev *dev = ctx->dev;
|
||||
|
||||
WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */
|
||||
WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6);
|
||||
if (IS_MFCV7(dev)) {
|
||||
WRITEL(y_addr, S5P_FIMV_E_SOURCE_FIRST_ADDR_V7);
|
||||
WRITEL(c_addr, S5P_FIMV_E_SOURCE_SECOND_ADDR_V7);
|
||||
} else {
|
||||
WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6);
|
||||
WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6);
|
||||
}
|
||||
|
||||
mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
|
||||
mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
|
||||
|
|
@ -466,8 +500,13 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
|
|||
struct s5p_mfc_dev *dev = ctx->dev;
|
||||
unsigned long enc_recon_y_addr, enc_recon_c_addr;
|
||||
|
||||
*y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6);
|
||||
*c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6);
|
||||
if (IS_MFCV7(dev)) {
|
||||
*y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
|
||||
*c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
|
||||
} else {
|
||||
*y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6);
|
||||
*c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6);
|
||||
}
|
||||
|
||||
enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6);
|
||||
enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6);
|
||||
|
|
@ -1140,6 +1179,80 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
|
||||
{
|
||||
struct s5p_mfc_dev *dev = ctx->dev;
|
||||
struct s5p_mfc_enc_params *p = &ctx->enc_params;
|
||||
struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8;
|
||||
unsigned int reg = 0;
|
||||
unsigned int val = 0;
|
||||
|
||||
mfc_debug_enter();
|
||||
|
||||
s5p_mfc_set_enc_params(ctx);
|
||||
|
||||
/* pictype : number of B */
|
||||
reg = READL(S5P_FIMV_E_GOP_CONFIG_V6);
|
||||
reg &= ~(0x3 << 16);
|
||||
reg |= ((p->num_b_frame & 0x3) << 16);
|
||||
WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
|
||||
|
||||
/* profile & level */
|
||||
reg = 0;
|
||||
/** profile */
|
||||
reg |= (0x1 << 4);
|
||||
WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
|
||||
|
||||
/* rate control config. */
|
||||
reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
|
||||
/** macroblock level rate control */
|
||||
reg &= ~(0x1 << 8);
|
||||
reg |= ((p->rc_mb & 0x1) << 8);
|
||||
WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
|
||||
|
||||
/* frame rate */
|
||||
if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
|
||||
reg = 0;
|
||||
reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
|
||||
reg |= p->rc_framerate_denom & 0xFFFF;
|
||||
WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
|
||||
}
|
||||
|
||||
/* vbv buffer size */
|
||||
if (p->frame_skip_mode ==
|
||||
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
|
||||
WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
|
||||
|
||||
if (p->rc_frame)
|
||||
WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
|
||||
}
|
||||
|
||||
/* VP8 specific params */
|
||||
reg = 0;
|
||||
reg |= (p_vp8->imd_4x4 & 0x1) << 10;
|
||||
switch (p_vp8->num_partitions) {
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION:
|
||||
val = 0;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS:
|
||||
val = 2;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS:
|
||||
val = 4;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS:
|
||||
val = 8;
|
||||
break;
|
||||
}
|
||||
reg |= (val & 0xF) << 3;
|
||||
reg |= (p_vp8->num_ref & 0x2);
|
||||
WRITEL(reg, S5P_FIMV_E_VP8_OPTIONS_V7);
|
||||
|
||||
mfc_debug_leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize decoding */
|
||||
static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
|
||||
{
|
||||
|
|
@ -1166,6 +1279,12 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
|
|||
reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
|
||||
WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6);
|
||||
}
|
||||
|
||||
if (IS_MFCV7(dev)) {
|
||||
WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6);
|
||||
reg = 0;
|
||||
}
|
||||
|
||||
/* Setup loop filter, for decoding this is only valid for MPEG4 */
|
||||
if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) {
|
||||
mfc_debug(2, "Set loop filter to: %d\n",
|
||||
|
|
@ -1176,7 +1295,10 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
|
|||
if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)
|
||||
reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
|
||||
|
||||
WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6);
|
||||
if (IS_MFCV7(dev))
|
||||
WRITEL(reg, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V7);
|
||||
else
|
||||
WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6);
|
||||
|
||||
/* 0: NV12(CbCr), 1: NV21(CrCb) */
|
||||
if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
|
||||
|
|
@ -1184,6 +1306,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
|
|||
else
|
||||
WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6);
|
||||
|
||||
|
||||
/* sei parse */
|
||||
WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6);
|
||||
|
||||
|
|
@ -1248,12 +1371,20 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
|
|||
s5p_mfc_set_enc_params_mpeg4(ctx);
|
||||
else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC)
|
||||
s5p_mfc_set_enc_params_h263(ctx);
|
||||
else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC)
|
||||
s5p_mfc_set_enc_params_vp8(ctx);
|
||||
else {
|
||||
mfc_err("Unknown codec for encoding (%x).\n",
|
||||
ctx->codec_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set stride lengths */
|
||||
if (IS_MFCV7(dev)) {
|
||||
WRITEL(ctx->img_width, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7);
|
||||
WRITEL(ctx->img_width, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7);
|
||||
}
|
||||
|
||||
WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
|
||||
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
|
||||
S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
|
||||
#include "regs-hdmi.h"
|
||||
|
||||
|
|
@ -625,7 +626,7 @@ static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
|
||||
if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings,
|
||||
if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings,
|
||||
timings, 0))
|
||||
break;
|
||||
if (i == ARRAY_SIZE(hdmi_timings)) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ config VIDEO_PXA27x
|
|||
---help---
|
||||
This is a v4l2 driver for the PXA27x Quick Capture Interface
|
||||
|
||||
config VIDEO_RCAR_VIN
|
||||
tristate "R-Car Video Input (VIN) support"
|
||||
depends on VIDEO_DEV && SOC_CAMERA
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select SOC_CAMERA_SCALE_CROP
|
||||
---help---
|
||||
This is a v4l2 driver for the R-Car VIN Interface
|
||||
|
||||
config VIDEO_SH_MOBILE_CSI2
|
||||
tristate "SuperH Mobile MIPI CSI-2 Interface driver"
|
||||
depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
|
|||
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
|
||||
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
|
||||
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
|
||||
obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar_vin.o
|
||||
|
|
|
|||
|
|
@ -672,7 +672,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
|
|||
fmt = soc_mbus_get_fmtdesc(code);
|
||||
if (!fmt) {
|
||||
dev_warn(icd->parent,
|
||||
"Unsupported format code #%u: %d\n", idx, code);
|
||||
"Unsupported format code #%u: 0x%x\n", idx, code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -688,7 +688,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
|
|||
xlate->host_fmt = &mx3_camera_formats[0];
|
||||
xlate->code = code;
|
||||
xlate++;
|
||||
dev_dbg(dev, "Providing format %s using code %d\n",
|
||||
dev_dbg(dev, "Providing format %s using code 0x%x\n",
|
||||
mx3_camera_formats[0].name, code);
|
||||
}
|
||||
break;
|
||||
|
|
@ -698,7 +698,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
|
|||
xlate->host_fmt = &mx3_camera_formats[1];
|
||||
xlate->code = code;
|
||||
xlate++;
|
||||
dev_dbg(dev, "Providing format %s using code %d\n",
|
||||
dev_dbg(dev, "Providing format %s using code 0x%x\n",
|
||||
mx3_camera_formats[1].name, code);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1144,6 +1144,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
|
|||
|
||||
static int mx3_camera_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mx3_camera_pdata *pdata = pdev->dev.platform_data;
|
||||
struct mx3_camera_dev *mx3_cam;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
|
|
@ -1151,26 +1152,25 @@ static int mx3_camera_probe(struct platform_device *pdev)
|
|||
struct soc_camera_host *soc_host;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
err = -ENODEV;
|
||||
goto egetres;
|
||||
}
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
mx3_cam = vzalloc(sizeof(*mx3_cam));
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
mx3_cam = devm_kzalloc(&pdev->dev, sizeof(*mx3_cam), GFP_KERNEL);
|
||||
if (!mx3_cam) {
|
||||
dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
|
||||
err = -ENOMEM;
|
||||
goto ealloc;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mx3_cam->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(mx3_cam->clk)) {
|
||||
err = PTR_ERR(mx3_cam->clk);
|
||||
goto eclkget;
|
||||
}
|
||||
mx3_cam->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(mx3_cam->clk))
|
||||
return PTR_ERR(mx3_cam->clk);
|
||||
|
||||
mx3_cam->pdata = pdev->dev.platform_data;
|
||||
mx3_cam->platform_flags = mx3_cam->pdata->flags;
|
||||
mx3_cam->pdata = pdata;
|
||||
mx3_cam->platform_flags = pdata->flags;
|
||||
if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) {
|
||||
/*
|
||||
* Platform hasn't set available data widths. This is bad.
|
||||
|
|
@ -1189,7 +1189,7 @@ static int mx3_camera_probe(struct platform_device *pdev)
|
|||
if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
|
||||
mx3_cam->width_flags |= 1 << 14;
|
||||
|
||||
mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
|
||||
mx3_cam->mclk = pdata->mclk_10khz * 10000;
|
||||
if (!mx3_cam->mclk) {
|
||||
dev_warn(&pdev->dev,
|
||||
"mclk_10khz == 0! Please, fix your platform data. "
|
||||
|
|
@ -1201,13 +1201,6 @@ static int mx3_camera_probe(struct platform_device *pdev)
|
|||
INIT_LIST_HEAD(&mx3_cam->capture);
|
||||
spin_lock_init(&mx3_cam->lock);
|
||||
|
||||
base = ioremap(res->start, resource_size(res));
|
||||
if (!base) {
|
||||
pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
|
||||
err = -ENOMEM;
|
||||
goto eioremap;
|
||||
}
|
||||
|
||||
mx3_cam->base = base;
|
||||
|
||||
soc_host = &mx3_cam->soc_host;
|
||||
|
|
@ -1218,9 +1211,12 @@ static int mx3_camera_probe(struct platform_device *pdev)
|
|||
soc_host->nr = pdev->id;
|
||||
|
||||
mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
|
||||
if (IS_ERR(mx3_cam->alloc_ctx)) {
|
||||
err = PTR_ERR(mx3_cam->alloc_ctx);
|
||||
goto eallocctx;
|
||||
if (IS_ERR(mx3_cam->alloc_ctx))
|
||||
return PTR_ERR(mx3_cam->alloc_ctx);
|
||||
|
||||
if (pdata->asd_sizes) {
|
||||
soc_host->asd = pdata->asd;
|
||||
soc_host->asd_sizes = pdata->asd_sizes;
|
||||
}
|
||||
|
||||
err = soc_camera_host_register(soc_host);
|
||||
|
|
@ -1234,14 +1230,6 @@ static int mx3_camera_probe(struct platform_device *pdev)
|
|||
|
||||
ecamhostreg:
|
||||
vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
|
||||
eallocctx:
|
||||
iounmap(base);
|
||||
eioremap:
|
||||
clk_put(mx3_cam->clk);
|
||||
eclkget:
|
||||
vfree(mx3_cam);
|
||||
ealloc:
|
||||
egetres:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1251,12 +1239,8 @@ static int mx3_camera_remove(struct platform_device *pdev)
|
|||
struct mx3_camera_dev *mx3_cam = container_of(soc_host,
|
||||
struct mx3_camera_dev, soc_host);
|
||||
|
||||
clk_put(mx3_cam->clk);
|
||||
|
||||
soc_camera_host_unregister(soc_host);
|
||||
|
||||
iounmap(mx3_cam->base);
|
||||
|
||||
/*
|
||||
* The channel has either not been allocated,
|
||||
* or should have been released
|
||||
|
|
@ -1266,8 +1250,6 @@ static int mx3_camera_remove(struct platform_device *pdev)
|
|||
|
||||
vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
|
||||
|
||||
vfree(mx3_cam);
|
||||
|
||||
dmaengine_put();
|
||||
|
||||
return 0;
|
||||
|
|
@ -1276,6 +1258,7 @@ static int mx3_camera_remove(struct platform_device *pdev)
|
|||
static struct platform_driver mx3_camera_driver = {
|
||||
.driver = {
|
||||
.name = MX3_CAM_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mx3_camera_probe,
|
||||
.remove = mx3_camera_remove,
|
||||
|
|
|
|||
1486
drivers/media/platform/soc_camera/rcar_vin.c
Normal file
1486
drivers/media/platform/soc_camera/rcar_vin.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -610,13 +610,12 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
|
|||
static int sh_mobile_ceu_clock_start(struct soc_camera_host *ici)
|
||||
{
|
||||
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(ici->v4l2_dev.dev);
|
||||
|
||||
pcdev->buf_total = 0;
|
||||
|
||||
ret = sh_mobile_ceu_soft_reset(pcdev);
|
||||
sh_mobile_ceu_soft_reset(pcdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1837,9 +1836,9 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
|
|||
for (j = 0; pcdev->pdata->asd_sizes[j]; j++) {
|
||||
for (i = 0; i < pcdev->pdata->asd_sizes[j]; i++, asd++) {
|
||||
dev_dbg(&pdev->dev, "%s(): subdev #%d, type %u\n",
|
||||
__func__, i, (*asd)->bus_type);
|
||||
if ((*asd)->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
|
||||
!strncmp(name, (*asd)->match.platform.name,
|
||||
__func__, i, (*asd)->match_type);
|
||||
if ((*asd)->match_type == V4L2_ASYNC_MATCH_DEVNAME &&
|
||||
!strncmp(name, (*asd)->match.device_name.name,
|
||||
sizeof(name) - 1)) {
|
||||
pcdev->csi2_asd = *asd;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ EXPORT_SYMBOL(soc_camera_power_off);
|
|||
|
||||
int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
|
||||
{
|
||||
|
||||
/* Should not have any effect in synchronous case */
|
||||
return devm_regulator_bulk_get(dev, ssdd->num_regulators,
|
||||
ssdd->regulators);
|
||||
}
|
||||
|
|
@ -1311,6 +1311,7 @@ eusrfmt:
|
|||
static int soc_camera_i2c_init(struct soc_camera_device *icd,
|
||||
struct soc_camera_desc *sdesc)
|
||||
{
|
||||
struct soc_camera_subdev_desc *ssdd;
|
||||
struct i2c_client *client;
|
||||
struct soc_camera_host *ici;
|
||||
struct soc_camera_host_desc *shd = &sdesc->host_desc;
|
||||
|
|
@ -1333,7 +1334,21 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
shd->board_info->platform_data = &sdesc->subdev_desc;
|
||||
ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL);
|
||||
if (!ssdd) {
|
||||
ret = -ENOMEM;
|
||||
goto ealloc;
|
||||
}
|
||||
|
||||
memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd));
|
||||
/*
|
||||
* In synchronous case we request regulators ourselves in
|
||||
* soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
|
||||
* to allocate them again.
|
||||
*/
|
||||
ssdd->num_regulators = 0;
|
||||
ssdd->regulators = NULL;
|
||||
shd->board_info->platform_data = ssdd;
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "%d-%04x",
|
||||
shd->i2c_adapter_id, shd->board_info->addr);
|
||||
|
|
@ -1359,8 +1374,10 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
|
|||
return 0;
|
||||
ei2cnd:
|
||||
v4l2_clk_unregister(icd->clk);
|
||||
eclkreg:
|
||||
icd->clk = NULL;
|
||||
eclkreg:
|
||||
kfree(ssdd);
|
||||
ealloc:
|
||||
i2c_put_adapter(adap);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1370,15 +1387,18 @@ static void soc_camera_i2c_free(struct soc_camera_device *icd)
|
|||
struct i2c_client *client =
|
||||
to_i2c_client(to_soc_camera_control(icd));
|
||||
struct i2c_adapter *adap;
|
||||
struct soc_camera_subdev_desc *ssdd;
|
||||
|
||||
icd->control = NULL;
|
||||
if (icd->sasc)
|
||||
return;
|
||||
|
||||
adap = client->adapter;
|
||||
ssdd = client->dev.platform_data;
|
||||
v4l2_device_unregister_subdev(i2c_get_clientdata(client));
|
||||
i2c_unregister_device(client);
|
||||
i2c_put_adapter(adap);
|
||||
kfree(ssdd);
|
||||
v4l2_clk_unregister(icd->clk);
|
||||
icd->clk = NULL;
|
||||
}
|
||||
|
|
@ -1466,7 +1486,8 @@ static int scan_async_group(struct soc_camera_host *ici,
|
|||
struct soc_camera_device *icd;
|
||||
struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
|
||||
char clk_name[V4L2_SUBDEV_NAME_SIZE];
|
||||
int ret, i;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* First look for a sensor */
|
||||
for (i = 0; i < size; i++) {
|
||||
|
|
@ -1475,7 +1496,7 @@ static int scan_async_group(struct soc_camera_host *ici,
|
|||
break;
|
||||
}
|
||||
|
||||
if (i == size || asd[i]->bus_type != V4L2_ASYNC_BUS_I2C) {
|
||||
if (i >= size || asd[i]->match_type != V4L2_ASYNC_MATCH_I2C) {
|
||||
/* All useless */
|
||||
dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n");
|
||||
return -ENODEV;
|
||||
|
|
@ -1501,7 +1522,7 @@ static int scan_async_group(struct soc_camera_host *ici,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sasc->notifier.subdev = asd;
|
||||
sasc->notifier.subdevs = asd;
|
||||
sasc->notifier.num_subdevs = size;
|
||||
sasc->notifier.bound = soc_camera_async_bound;
|
||||
sasc->notifier.unbind = soc_camera_async_unbind;
|
||||
|
|
@ -1994,9 +2015,10 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
|
|||
|
||||
/*
|
||||
* In the asynchronous case ssdd->num_regulators == 0 yet, so, the below
|
||||
* regulator allocation is a dummy. They will be really requested later
|
||||
* in soc_camera_async_bind(). Also note, that in that case regulators
|
||||
* are attached to the I2C device and not to the camera platform device.
|
||||
* regulator allocation is a dummy. They are actually requested by the
|
||||
* subdevice driver, using soc_camera_power_init(). Also note, that in
|
||||
* that case regulators are attached to the I2C device and not to the
|
||||
* camera platform device.
|
||||
*/
|
||||
ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators,
|
||||
ssdd->regulators);
|
||||
|
|
|
|||
5
drivers/media/platform/vsp1/Makefile
Normal file
5
drivers/media/platform/vsp1/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
|
||||
vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
|
||||
vsp1-y += vsp1_lif.o vsp1_uds.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
|
||||
74
drivers/media/platform/vsp1/vsp1.h
Normal file
74
drivers/media/platform/vsp1/vsp1.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* vsp1.h -- R-Car VSP1 Driver
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_H__
|
||||
#define __VSP1_H__
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_data/vsp1.h>
|
||||
|
||||
#include <media/media-device.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_regs.h"
|
||||
|
||||
struct clk;
|
||||
struct device;
|
||||
|
||||
struct vsp1_platform_data;
|
||||
struct vsp1_lif;
|
||||
struct vsp1_rwpf;
|
||||
struct vsp1_uds;
|
||||
|
||||
#define VPS1_MAX_RPF 5
|
||||
#define VPS1_MAX_UDS 3
|
||||
#define VPS1_MAX_WPF 4
|
||||
|
||||
struct vsp1_device {
|
||||
struct device *dev;
|
||||
struct vsp1_platform_data *pdata;
|
||||
|
||||
void __iomem *mmio;
|
||||
struct clk *clock;
|
||||
struct clk *rt_clock;
|
||||
|
||||
struct mutex lock;
|
||||
int ref_count;
|
||||
|
||||
struct vsp1_lif *lif;
|
||||
struct vsp1_rwpf *rpf[VPS1_MAX_RPF];
|
||||
struct vsp1_uds *uds[VPS1_MAX_UDS];
|
||||
struct vsp1_rwpf *wpf[VPS1_MAX_WPF];
|
||||
|
||||
struct list_head entities;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct media_device media_dev;
|
||||
};
|
||||
|
||||
struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1);
|
||||
void vsp1_device_put(struct vsp1_device *vsp1);
|
||||
|
||||
static inline u32 vsp1_read(struct vsp1_device *vsp1, u32 reg)
|
||||
{
|
||||
return ioread32(vsp1->mmio + reg);
|
||||
}
|
||||
|
||||
static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data)
|
||||
{
|
||||
iowrite32(data, vsp1->mmio + reg);
|
||||
}
|
||||
|
||||
#endif /* __VSP1_H__ */
|
||||
527
drivers/media/platform/vsp1/vsp1_drv.c
Normal file
527
drivers/media/platform/vsp1/vsp1_drv.c
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
* vsp1_drv.c -- R-Car VSP1 Driver
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_lif.h"
|
||||
#include "vsp1_rwpf.h"
|
||||
#include "vsp1_uds.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Interrupt Handling
|
||||
*/
|
||||
|
||||
static irqreturn_t vsp1_irq_handler(int irq, void *data)
|
||||
{
|
||||
u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
|
||||
struct vsp1_device *vsp1 = data;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
|
||||
struct vsp1_rwpf *wpf = vsp1->wpf[i];
|
||||
struct vsp1_pipeline *pipe;
|
||||
u32 status;
|
||||
|
||||
if (wpf == NULL)
|
||||
continue;
|
||||
|
||||
pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
|
||||
status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
|
||||
vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
|
||||
|
||||
if (status & VI6_WFP_IRQ_STA_FRE) {
|
||||
vsp1_pipeline_frame_end(pipe);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Entities
|
||||
*/
|
||||
|
||||
/*
|
||||
* vsp1_create_links - Create links from all sources to the given sink
|
||||
*
|
||||
* This function creates media links from all valid sources to the given sink
|
||||
* pad. Links that would be invalid according to the VSP1 hardware capabilities
|
||||
* are skipped. Those include all links
|
||||
*
|
||||
* - from a UDS to a UDS (UDS entities can't be chained)
|
||||
* - from an entity to itself (no loops are allowed)
|
||||
*/
|
||||
static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink)
|
||||
{
|
||||
struct media_entity *entity = &sink->subdev.entity;
|
||||
struct vsp1_entity *source;
|
||||
unsigned int pad;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(source, &vsp1->entities, list_dev) {
|
||||
u32 flags;
|
||||
|
||||
if (source->type == sink->type)
|
||||
continue;
|
||||
|
||||
if (source->type == VSP1_ENTITY_LIF ||
|
||||
source->type == VSP1_ENTITY_WPF)
|
||||
continue;
|
||||
|
||||
flags = source->type == VSP1_ENTITY_RPF &&
|
||||
sink->type == VSP1_ENTITY_WPF &&
|
||||
source->index == sink->index
|
||||
? MEDIA_LNK_FL_ENABLED : 0;
|
||||
|
||||
for (pad = 0; pad < entity->num_pads; ++pad) {
|
||||
if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
|
||||
continue;
|
||||
|
||||
ret = media_entity_create_link(&source->subdev.entity,
|
||||
source->source_pad,
|
||||
entity, pad, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (flags & MEDIA_LNK_FL_ENABLED)
|
||||
source->sink = entity;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vsp1_destroy_entities(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct vsp1_entity *entity;
|
||||
struct vsp1_entity *next;
|
||||
|
||||
list_for_each_entry_safe(entity, next, &vsp1->entities, list_dev) {
|
||||
list_del(&entity->list_dev);
|
||||
vsp1_entity_destroy(entity);
|
||||
}
|
||||
|
||||
v4l2_device_unregister(&vsp1->v4l2_dev);
|
||||
media_device_unregister(&vsp1->media_dev);
|
||||
}
|
||||
|
||||
static int vsp1_create_entities(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct media_device *mdev = &vsp1->media_dev;
|
||||
struct v4l2_device *vdev = &vsp1->v4l2_dev;
|
||||
struct vsp1_entity *entity;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
mdev->dev = vsp1->dev;
|
||||
strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
|
||||
snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
|
||||
dev_name(mdev->dev));
|
||||
ret = media_device_register(mdev);
|
||||
if (ret < 0) {
|
||||
dev_err(vsp1->dev, "media device registration failed (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vdev->mdev = mdev;
|
||||
ret = v4l2_device_register(vsp1->dev, vdev);
|
||||
if (ret < 0) {
|
||||
dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
|
||||
ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Instantiate all the entities. */
|
||||
if (vsp1->pdata->features & VSP1_HAS_LIF) {
|
||||
vsp1->lif = vsp1_lif_create(vsp1);
|
||||
if (IS_ERR(vsp1->lif)) {
|
||||
ret = PTR_ERR(vsp1->lif);
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
for (i = 0; i < vsp1->pdata->rpf_count; ++i) {
|
||||
struct vsp1_rwpf *rpf;
|
||||
|
||||
rpf = vsp1_rpf_create(vsp1, i);
|
||||
if (IS_ERR(rpf)) {
|
||||
ret = PTR_ERR(rpf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
vsp1->rpf[i] = rpf;
|
||||
list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
for (i = 0; i < vsp1->pdata->uds_count; ++i) {
|
||||
struct vsp1_uds *uds;
|
||||
|
||||
uds = vsp1_uds_create(vsp1, i);
|
||||
if (IS_ERR(uds)) {
|
||||
ret = PTR_ERR(uds);
|
||||
goto done;
|
||||
}
|
||||
|
||||
vsp1->uds[i] = uds;
|
||||
list_add_tail(&uds->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
|
||||
struct vsp1_rwpf *wpf;
|
||||
|
||||
wpf = vsp1_wpf_create(vsp1, i);
|
||||
if (IS_ERR(wpf)) {
|
||||
ret = PTR_ERR(wpf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
vsp1->wpf[i] = wpf;
|
||||
list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
|
||||
}
|
||||
|
||||
/* Create links. */
|
||||
list_for_each_entry(entity, &vsp1->entities, list_dev) {
|
||||
if (entity->type == VSP1_ENTITY_LIF ||
|
||||
entity->type == VSP1_ENTITY_RPF)
|
||||
continue;
|
||||
|
||||
ret = vsp1_create_links(vsp1, entity);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (vsp1->pdata->features & VSP1_HAS_LIF) {
|
||||
ret = media_entity_create_link(
|
||||
&vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE,
|
||||
&vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register all subdevs. */
|
||||
list_for_each_entry(entity, &vsp1->entities, list_dev) {
|
||||
ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
|
||||
&entity->subdev);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
|
||||
|
||||
done:
|
||||
if (ret < 0)
|
||||
vsp1_destroy_entities(vsp1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vsp1_device_init(struct vsp1_device *vsp1)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 status;
|
||||
|
||||
/* Reset any channel that might be running. */
|
||||
status = vsp1_read(vsp1, VI6_STATUS);
|
||||
|
||||
for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
|
||||
unsigned int timeout;
|
||||
|
||||
if (!(status & VI6_STATUS_SYS_ACT(i)))
|
||||
continue;
|
||||
|
||||
vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(i));
|
||||
for (timeout = 10; timeout > 0; --timeout) {
|
||||
status = vsp1_read(vsp1, VI6_STATUS);
|
||||
if (!(status & VI6_STATUS_SYS_ACT(i)))
|
||||
break;
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(vsp1->dev, "failed to reset wpf.%u\n", i);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
|
||||
(8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
|
||||
|
||||
for (i = 0; i < vsp1->pdata->rpf_count; ++i)
|
||||
vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
|
||||
|
||||
for (i = 0; i < vsp1->pdata->uds_count; ++i)
|
||||
vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
|
||||
|
||||
vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
|
||||
|
||||
vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
|
||||
(VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
|
||||
vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
|
||||
(VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsp1_clocks_enable(struct vsp1_device *vsp1)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(vsp1->clock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (IS_ERR(vsp1->rt_clock))
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(vsp1->rt_clock);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vsp1_clocks_disable(struct vsp1_device *vsp1)
|
||||
{
|
||||
if (!IS_ERR(vsp1->rt_clock))
|
||||
clk_disable_unprepare(vsp1->rt_clock);
|
||||
clk_disable_unprepare(vsp1->clock);
|
||||
}
|
||||
|
||||
/*
|
||||
* vsp1_device_get - Acquire the VSP1 device
|
||||
*
|
||||
* Increment the VSP1 reference count and initialize the device if the first
|
||||
* reference is taken.
|
||||
*
|
||||
* Return a pointer to the VSP1 device or NULL if an error occured.
|
||||
*/
|
||||
struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct vsp1_device *__vsp1 = vsp1;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&vsp1->lock);
|
||||
if (vsp1->ref_count > 0)
|
||||
goto done;
|
||||
|
||||
ret = vsp1_clocks_enable(vsp1);
|
||||
if (ret < 0) {
|
||||
__vsp1 = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = vsp1_device_init(vsp1);
|
||||
if (ret < 0) {
|
||||
vsp1_clocks_disable(vsp1);
|
||||
__vsp1 = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (__vsp1)
|
||||
vsp1->ref_count++;
|
||||
|
||||
mutex_unlock(&vsp1->lock);
|
||||
return __vsp1;
|
||||
}
|
||||
|
||||
/*
|
||||
* vsp1_device_put - Release the VSP1 device
|
||||
*
|
||||
* Decrement the VSP1 reference count and cleanup the device if the last
|
||||
* reference is released.
|
||||
*/
|
||||
void vsp1_device_put(struct vsp1_device *vsp1)
|
||||
{
|
||||
mutex_lock(&vsp1->lock);
|
||||
|
||||
if (--vsp1->ref_count == 0)
|
||||
vsp1_clocks_disable(vsp1);
|
||||
|
||||
mutex_unlock(&vsp1->lock);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Power Management
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int vsp1_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
|
||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
||||
|
||||
if (vsp1->ref_count == 0)
|
||||
return 0;
|
||||
|
||||
vsp1_clocks_disable(vsp1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsp1_pm_resume(struct device *dev)
|
||||
{
|
||||
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
|
||||
|
||||
WARN_ON(mutex_is_locked(&vsp1->lock));
|
||||
|
||||
if (vsp1->ref_count)
|
||||
return 0;
|
||||
|
||||
return vsp1_clocks_enable(vsp1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops vsp1_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Platform Driver
|
||||
*/
|
||||
|
||||
static struct vsp1_platform_data *
|
||||
vsp1_get_platform_data(struct platform_device *pdev)
|
||||
{
|
||||
struct vsp1_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "missing platform data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) {
|
||||
dev_err(&pdev->dev, "invalid number of RPF (%u)\n",
|
||||
pdata->rpf_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) {
|
||||
dev_err(&pdev->dev, "invalid number of UDS (%u)\n",
|
||||
pdata->uds_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) {
|
||||
dev_err(&pdev->dev, "invalid number of WPF (%u)\n",
|
||||
pdata->wpf_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static int vsp1_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vsp1_device *vsp1;
|
||||
struct resource *irq;
|
||||
struct resource *io;
|
||||
int ret;
|
||||
|
||||
vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
|
||||
if (vsp1 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
vsp1->dev = &pdev->dev;
|
||||
mutex_init(&vsp1->lock);
|
||||
INIT_LIST_HEAD(&vsp1->entities);
|
||||
|
||||
vsp1->pdata = vsp1_get_platform_data(pdev);
|
||||
if (vsp1->pdata == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* I/O, IRQ and clock resources */
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
|
||||
if (IS_ERR(vsp1->mmio))
|
||||
return PTR_ERR(vsp1->mmio);
|
||||
|
||||
vsp1->clock = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(vsp1->clock)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
return PTR_ERR(vsp1->clock);
|
||||
}
|
||||
|
||||
/* The RT clock is optional */
|
||||
vsp1->rt_clock = devm_clk_get(&pdev->dev, "rt");
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "missing IRQ\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
|
||||
IRQF_SHARED, dev_name(&pdev->dev), vsp1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Instanciate entities */
|
||||
ret = vsp1_create_entities(vsp1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create entities\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, vsp1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsp1_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
|
||||
|
||||
vsp1_destroy_entities(vsp1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vsp1_platform_driver = {
|
||||
.probe = vsp1_probe,
|
||||
.remove = vsp1_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "vsp1",
|
||||
.pm = &vsp1_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(vsp1_platform_driver);
|
||||
|
||||
MODULE_ALIAS("vsp1");
|
||||
MODULE_AUTHOR("Laurent Pinchart <[email protected]>");
|
||||
MODULE_DESCRIPTION("Renesas VSP1 Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
181
drivers/media/platform/vsp1/vsp1_entity.c
Normal file
181
drivers/media/platform/vsp1/vsp1_entity.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* vsp1_entity.c -- R-Car VSP1 Base Entity
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
struct v4l2_mbus_framefmt *
|
||||
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
unsigned int pad, u32 which)
|
||||
{
|
||||
switch (which) {
|
||||
case V4L2_SUBDEV_FORMAT_TRY:
|
||||
return v4l2_subdev_get_try_format(fh, pad);
|
||||
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||
return &entity->formats[pad];
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* vsp1_entity_init_formats - Initialize formats on all pads
|
||||
* @subdev: V4L2 subdevice
|
||||
* @fh: V4L2 subdev file handle
|
||||
*
|
||||
* Initialize all pad formats with default values. If fh is not NULL, try
|
||||
* formats are initialized on the file handle. Otherwise active formats are
|
||||
* initialized on the device.
|
||||
*/
|
||||
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct v4l2_subdev_format format;
|
||||
unsigned int pad;
|
||||
|
||||
for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
|
||||
memset(&format, 0, sizeof(format));
|
||||
|
||||
format.pad = pad;
|
||||
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY
|
||||
: V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
|
||||
v4l2_subdev_call(subdev, pad, set_fmt, fh, &format);
|
||||
}
|
||||
}
|
||||
|
||||
static int vsp1_entity_open(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
vsp1_entity_init_formats(subdev, fh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
|
||||
.open = vsp1_entity_open,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Media Operations
|
||||
*/
|
||||
|
||||
static int vsp1_entity_link_setup(struct media_entity *entity,
|
||||
const struct media_pad *local,
|
||||
const struct media_pad *remote, u32 flags)
|
||||
{
|
||||
struct vsp1_entity *source;
|
||||
|
||||
if (!(local->flags & MEDIA_PAD_FL_SOURCE))
|
||||
return 0;
|
||||
|
||||
source = container_of(local->entity, struct vsp1_entity, subdev.entity);
|
||||
|
||||
if (!source->route)
|
||||
return 0;
|
||||
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (source->sink)
|
||||
return -EBUSY;
|
||||
source->sink = remote->entity;
|
||||
} else {
|
||||
source->sink = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct media_entity_operations vsp1_media_ops = {
|
||||
.link_setup = vsp1_entity_link_setup,
|
||||
.link_validate = v4l2_subdev_link_validate,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization
|
||||
*/
|
||||
|
||||
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
||||
unsigned int num_pads)
|
||||
{
|
||||
static const struct {
|
||||
unsigned int id;
|
||||
unsigned int reg;
|
||||
} routes[] = {
|
||||
{ VI6_DPR_NODE_LIF, 0 },
|
||||
{ VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) },
|
||||
{ VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) },
|
||||
{ VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) },
|
||||
{ VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) },
|
||||
{ VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) },
|
||||
{ VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) },
|
||||
{ VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) },
|
||||
{ VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) },
|
||||
{ VI6_DPR_NODE_WPF(0), 0 },
|
||||
{ VI6_DPR_NODE_WPF(1), 0 },
|
||||
{ VI6_DPR_NODE_WPF(2), 0 },
|
||||
{ VI6_DPR_NODE_WPF(3), 0 },
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(routes); ++i) {
|
||||
if (routes[i].id == entity->id) {
|
||||
entity->route = routes[i].reg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(routes))
|
||||
return -EINVAL;
|
||||
|
||||
entity->vsp1 = vsp1;
|
||||
entity->source_pad = num_pads - 1;
|
||||
|
||||
/* Allocate formats and pads. */
|
||||
entity->formats = devm_kzalloc(vsp1->dev,
|
||||
num_pads * sizeof(*entity->formats),
|
||||
GFP_KERNEL);
|
||||
if (entity->formats == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
|
||||
GFP_KERNEL);
|
||||
if (entity->pads == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize pads. */
|
||||
for (i = 0; i < num_pads - 1; ++i)
|
||||
entity->pads[i].flags = MEDIA_PAD_FL_SINK;
|
||||
|
||||
entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
/* Initialize the media entity. */
|
||||
return media_entity_init(&entity->subdev.entity, num_pads,
|
||||
entity->pads, 0);
|
||||
}
|
||||
|
||||
void vsp1_entity_destroy(struct vsp1_entity *entity)
|
||||
{
|
||||
media_entity_cleanup(&entity->subdev.entity);
|
||||
}
|
||||
68
drivers/media/platform/vsp1/vsp1_entity.h
Normal file
68
drivers/media/platform/vsp1/vsp1_entity.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* vsp1_entity.h -- R-Car VSP1 Base Entity
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_ENTITY_H__
|
||||
#define __VSP1_ENTITY_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
struct vsp1_device;
|
||||
|
||||
enum vsp1_entity_type {
|
||||
VSP1_ENTITY_LIF,
|
||||
VSP1_ENTITY_RPF,
|
||||
VSP1_ENTITY_UDS,
|
||||
VSP1_ENTITY_WPF,
|
||||
};
|
||||
|
||||
struct vsp1_entity {
|
||||
struct vsp1_device *vsp1;
|
||||
|
||||
enum vsp1_entity_type type;
|
||||
unsigned int index;
|
||||
unsigned int id;
|
||||
unsigned int route;
|
||||
|
||||
struct list_head list_dev;
|
||||
struct list_head list_pipe;
|
||||
|
||||
struct media_pad *pads;
|
||||
unsigned int source_pad;
|
||||
|
||||
struct media_entity *sink;
|
||||
|
||||
struct v4l2_subdev subdev;
|
||||
struct v4l2_mbus_framefmt *formats;
|
||||
};
|
||||
|
||||
static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_entity, subdev);
|
||||
}
|
||||
|
||||
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
||||
unsigned int num_pads);
|
||||
void vsp1_entity_destroy(struct vsp1_entity *entity);
|
||||
|
||||
extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
|
||||
extern const struct media_entity_operations vsp1_media_ops;
|
||||
|
||||
struct v4l2_mbus_framefmt *
|
||||
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
unsigned int pad, u32 which);
|
||||
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh);
|
||||
|
||||
#endif /* __VSP1_ENTITY_H__ */
|
||||
238
drivers/media/platform/vsp1/vsp1_lif.c
Normal file
238
drivers/media/platform/vsp1/vsp1_lif.c
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_lif.h"
|
||||
|
||||
#define LIF_MIN_SIZE 2U
|
||||
#define LIF_MAX_SIZE 2048U
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Device Access
|
||||
*/
|
||||
|
||||
static inline u32 vsp1_lif_read(struct vsp1_lif *lif, u32 reg)
|
||||
{
|
||||
return vsp1_read(lif->entity.vsp1, reg);
|
||||
}
|
||||
|
||||
static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
|
||||
{
|
||||
vsp1_write(lif->entity.vsp1, reg, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
*/
|
||||
|
||||
static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct vsp1_lif *lif = to_lif(subdev);
|
||||
unsigned int hbth = 1300;
|
||||
unsigned int obth = 400;
|
||||
unsigned int lbth = 200;
|
||||
|
||||
if (!enable) {
|
||||
vsp1_lif_write(lif, VI6_LIF_CTRL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
format = &lif->entity.formats[LIF_PAD_SOURCE];
|
||||
|
||||
obth = min(obth, (format->width + 1) / 2 * format->height - 4);
|
||||
|
||||
vsp1_lif_write(lif, VI6_LIF_CSBTH,
|
||||
(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
|
||||
(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
|
||||
|
||||
vsp1_lif_write(lif, VI6_LIF_CTRL,
|
||||
(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
|
||||
(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
|
||||
VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
||||
static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
static const unsigned int codes[] = {
|
||||
V4L2_MBUS_FMT_ARGB8888_1X32,
|
||||
V4L2_MBUS_FMT_AYUV8_1X32,
|
||||
};
|
||||
|
||||
if (code->pad == LIF_PAD_SINK) {
|
||||
if (code->index >= ARRAY_SIZE(codes))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = codes[code->index];
|
||||
} else {
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/* The LIF can't perform format conversion, the sink format is
|
||||
* always identical to the source format.
|
||||
*/
|
||||
if (code->index)
|
||||
return -EINVAL;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK);
|
||||
code->code = format->code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lif_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK);
|
||||
|
||||
if (fse->index || fse->code != format->code)
|
||||
return -EINVAL;
|
||||
|
||||
if (fse->pad == LIF_PAD_SINK) {
|
||||
fse->min_width = LIF_MIN_SIZE;
|
||||
fse->max_width = LIF_MAX_SIZE;
|
||||
fse->min_height = LIF_MIN_SIZE;
|
||||
fse->max_height = LIF_MAX_SIZE;
|
||||
} else {
|
||||
fse->min_width = format->width;
|
||||
fse->max_width = format->width;
|
||||
fse->min_height = format->height;
|
||||
fse->max_height = format->height;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_lif *lif = to_lif(subdev);
|
||||
|
||||
fmt->format = *vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_lif *lif = to_lif(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/* Default to YUV if the requested format is not supported. */
|
||||
if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||
fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
|
||||
fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
if (fmt->pad == LIF_PAD_SOURCE) {
|
||||
/* The LIF source format is always identical to its sink
|
||||
* format.
|
||||
*/
|
||||
fmt->format = *format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
format->code = fmt->format.code;
|
||||
format->width = clamp_t(unsigned int, fmt->format.width,
|
||||
LIF_MIN_SIZE, LIF_MAX_SIZE);
|
||||
format->height = clamp_t(unsigned int, fmt->format.height,
|
||||
LIF_MIN_SIZE, LIF_MAX_SIZE);
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
format->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
|
||||
fmt->format = *format;
|
||||
|
||||
/* Propagate the format to the source pad. */
|
||||
format = vsp1_entity_get_pad_format(&lif->entity, fh, LIF_PAD_SOURCE,
|
||||
fmt->which);
|
||||
*format = fmt->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_video_ops lif_video_ops = {
|
||||
.s_stream = lif_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops lif_pad_ops = {
|
||||
.enum_mbus_code = lif_enum_mbus_code,
|
||||
.enum_frame_size = lif_enum_frame_size,
|
||||
.get_fmt = lif_get_format,
|
||||
.set_fmt = lif_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops lif_ops = {
|
||||
.video = &lif_video_ops,
|
||||
.pad = &lif_pad_ops,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization and Cleanup
|
||||
*/
|
||||
|
||||
struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
struct vsp1_lif *lif;
|
||||
int ret;
|
||||
|
||||
lif = devm_kzalloc(vsp1->dev, sizeof(*lif), GFP_KERNEL);
|
||||
if (lif == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
lif->entity.type = VSP1_ENTITY_LIF;
|
||||
lif->entity.id = VI6_DPR_NODE_LIF;
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &lif->entity, 2);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the V4L2 subdev. */
|
||||
subdev = &lif->entity.subdev;
|
||||
v4l2_subdev_init(subdev, &lif_ops);
|
||||
|
||||
subdev->entity.ops = &vsp1_media_ops;
|
||||
subdev->internal_ops = &vsp1_subdev_internal_ops;
|
||||
snprintf(subdev->name, sizeof(subdev->name), "%s lif",
|
||||
dev_name(vsp1->dev));
|
||||
v4l2_set_subdevdata(subdev, lif);
|
||||
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
vsp1_entity_init_formats(subdev, NULL);
|
||||
|
||||
return lif;
|
||||
}
|
||||
37
drivers/media/platform/vsp1/vsp1_lif.h
Normal file
37
drivers/media/platform/vsp1/vsp1_lif.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* vsp1_lif.h -- R-Car VSP1 LCD Controller Interface
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_LIF_H__
|
||||
#define __VSP1_LIF_H__
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
struct vsp1_device;
|
||||
|
||||
#define LIF_PAD_SINK 0
|
||||
#define LIF_PAD_SOURCE 1
|
||||
|
||||
struct vsp1_lif {
|
||||
struct vsp1_entity entity;
|
||||
};
|
||||
|
||||
static inline struct vsp1_lif *to_lif(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_lif, entity.subdev);
|
||||
}
|
||||
|
||||
struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1);
|
||||
|
||||
#endif /* __VSP1_LIF_H__ */
|
||||
581
drivers/media/platform/vsp1/vsp1_regs.h
Normal file
581
drivers/media/platform/vsp1/vsp1_regs.h
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
/*
|
||||
* vsp1_regs.h -- R-Car VSP1 Registers Definitions
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Electronics Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __VSP1_REGS_H__
|
||||
#define __VSP1_REGS_H__
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* General Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_CMD(n) (0x0000 + (n) * 4)
|
||||
#define VI6_CMD_STRCMD (1 << 0)
|
||||
|
||||
#define VI6_CLK_DCSWT 0x0018
|
||||
#define VI6_CLK_DCSWT_CSTPW_MASK (0xff << 8)
|
||||
#define VI6_CLK_DCSWT_CSTPW_SHIFT 8
|
||||
#define VI6_CLK_DCSWT_CSTRW_MASK (0xff << 0)
|
||||
#define VI6_CLK_DCSWT_CSTRW_SHIFT 0
|
||||
|
||||
#define VI6_SRESET 0x0028
|
||||
#define VI6_SRESET_SRTS(n) (1 << (n))
|
||||
|
||||
#define VI6_STATUS 0x0038
|
||||
#define VI6_STATUS_SYS_ACT(n) (1 << ((n) + 8))
|
||||
|
||||
#define VI6_WPF_IRQ_ENB(n) (0x0048 + (n) * 12)
|
||||
#define VI6_WFP_IRQ_ENB_DFEE (1 << 1)
|
||||
#define VI6_WFP_IRQ_ENB_FREE (1 << 0)
|
||||
|
||||
#define VI6_WPF_IRQ_STA(n) (0x004c + (n) * 12)
|
||||
#define VI6_WFP_IRQ_STA_DFE (1 << 1)
|
||||
#define VI6_WFP_IRQ_STA_FRE (1 << 0)
|
||||
|
||||
#define VI6_DISP_IRQ_ENB 0x0078
|
||||
#define VI6_DISP_IRQ_ENB_DSTE (1 << 8)
|
||||
#define VI6_DISP_IRQ_ENB_MAEE (1 << 5)
|
||||
#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << ((n) + 4))
|
||||
|
||||
#define VI6_DISP_IRQ_STA 0x007c
|
||||
#define VI6_DISP_IRQ_STA_DSE (1 << 8)
|
||||
#define VI6_DISP_IRQ_STA_MAE (1 << 5)
|
||||
#define VI6_DISP_IRQ_STA_LNE(n) (1 << ((n) + 4))
|
||||
|
||||
#define VI6_WPF_LINE_COUNT(n) (0x0084 + (n) * 4)
|
||||
#define VI6_WPF_LINE_COUNT_MASK (0x1fffff << 0)
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Display List Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_DL_CTRL 0x0100
|
||||
#define VI6_DL_CTRL_AR_WAIT_MASK (0xffff << 16)
|
||||
#define VI6_DL_CTRL_AR_WAIT_SHIFT 16
|
||||
#define VI6_DL_CTRL_DC2 (1 << 12)
|
||||
#define VI6_DL_CTRL_DC1 (1 << 8)
|
||||
#define VI6_DL_CTRL_DC0 (1 << 4)
|
||||
#define VI6_DL_CTRL_CFM0 (1 << 2)
|
||||
#define VI6_DL_CTRL_NH0 (1 << 1)
|
||||
#define VI6_DL_CTRL_DLE (1 << 0)
|
||||
|
||||
#define VI6_DL_HDR_ADDR(n) (0x0104 + (n) * 4)
|
||||
|
||||
#define VI6_DL_SWAP 0x0114
|
||||
#define VI6_DL_SWAP_LWS (1 << 2)
|
||||
#define VI6_DL_SWAP_WDS (1 << 1)
|
||||
#define VI6_DL_SWAP_BTS (1 << 0)
|
||||
|
||||
#define VI6_DL_EXT_CTRL 0x011c
|
||||
#define VI6_DL_EXT_CTRL_NWE (1 << 16)
|
||||
#define VI6_DL_EXT_CTRL_POLINT_MASK (0x3f << 8)
|
||||
#define VI6_DL_EXT_CTRL_POLINT_SHIFT 8
|
||||
#define VI6_DL_EXT_CTRL_DLPRI (1 << 5)
|
||||
#define VI6_DL_EXT_CTRL_EXPRI (1 << 4)
|
||||
#define VI6_DL_EXT_CTRL_EXT (1 << 0)
|
||||
|
||||
#define VI6_DL_BODY_SIZE 0x0120
|
||||
#define VI6_DL_BODY_SIZE_UPD (1 << 24)
|
||||
#define VI6_DL_BODY_SIZE_BS_MASK (0x1ffff << 0)
|
||||
#define VI6_DL_BODY_SIZE_BS_SHIFT 0
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* RPF Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_RPF_OFFSET 0x100
|
||||
|
||||
#define VI6_RPF_SRC_BSIZE 0x0300
|
||||
#define VI6_RPF_SRC_BSIZE_BHSIZE_MASK (0x1fff << 16)
|
||||
#define VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT 16
|
||||
#define VI6_RPF_SRC_BSIZE_BVSIZE_MASK (0x1fff << 0)
|
||||
#define VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT 0
|
||||
|
||||
#define VI6_RPF_SRC_ESIZE 0x0304
|
||||
#define VI6_RPF_SRC_ESIZE_EHSIZE_MASK (0x1fff << 16)
|
||||
#define VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT 16
|
||||
#define VI6_RPF_SRC_ESIZE_EVSIZE_MASK (0x1fff << 0)
|
||||
#define VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT 0
|
||||
|
||||
#define VI6_RPF_INFMT 0x0308
|
||||
#define VI6_RPF_INFMT_VIR (1 << 28)
|
||||
#define VI6_RPF_INFMT_CIPM (1 << 16)
|
||||
#define VI6_RPF_INFMT_SPYCS (1 << 15)
|
||||
#define VI6_RPF_INFMT_SPUVS (1 << 14)
|
||||
#define VI6_RPF_INFMT_CEXT_ZERO (0 << 12)
|
||||
#define VI6_RPF_INFMT_CEXT_EXT (1 << 12)
|
||||
#define VI6_RPF_INFMT_CEXT_ONE (2 << 12)
|
||||
#define VI6_RPF_INFMT_CEXT_MASK (3 << 12)
|
||||
#define VI6_RPF_INFMT_RDTM_BT601 (0 << 9)
|
||||
#define VI6_RPF_INFMT_RDTM_BT601_EXT (1 << 9)
|
||||
#define VI6_RPF_INFMT_RDTM_BT709 (2 << 9)
|
||||
#define VI6_RPF_INFMT_RDTM_BT709_EXT (3 << 9)
|
||||
#define VI6_RPF_INFMT_RDTM_MASK (7 << 9)
|
||||
#define VI6_RPF_INFMT_CSC (1 << 8)
|
||||
#define VI6_RPF_INFMT_RDFMT_MASK (0x7f << 0)
|
||||
#define VI6_RPF_INFMT_RDFMT_SHIFT 0
|
||||
|
||||
#define VI6_RPF_DSWAP 0x030c
|
||||
#define VI6_RPF_DSWAP_A_LLS (1 << 11)
|
||||
#define VI6_RPF_DSWAP_A_LWS (1 << 10)
|
||||
#define VI6_RPF_DSWAP_A_WDS (1 << 9)
|
||||
#define VI6_RPF_DSWAP_A_BTS (1 << 8)
|
||||
#define VI6_RPF_DSWAP_P_LLS (1 << 3)
|
||||
#define VI6_RPF_DSWAP_P_LWS (1 << 2)
|
||||
#define VI6_RPF_DSWAP_P_WDS (1 << 1)
|
||||
#define VI6_RPF_DSWAP_P_BTS (1 << 0)
|
||||
|
||||
#define VI6_RPF_LOC 0x0310
|
||||
#define VI6_RPF_LOC_HCOORD_MASK (0x1fff << 16)
|
||||
#define VI6_RPF_LOC_HCOORD_SHIFT 16
|
||||
#define VI6_RPF_LOC_VCOORD_MASK (0x1fff << 0)
|
||||
#define VI6_RPF_LOC_VCOORD_SHIFT 0
|
||||
|
||||
#define VI6_RPF_ALPH_SEL 0x0314
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_PACKED (0 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_8B_PLANE (1 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_SELECT (2 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_1B_PLANE (3 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_FIXED (4 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_MASK (7 << 28)
|
||||
#define VI6_RPF_ALPH_SEL_ASEL_SHIFT 28
|
||||
#define VI6_RPF_ALPH_SEL_IROP_MASK (0xf << 24)
|
||||
#define VI6_RPF_ALPH_SEL_IROP_SHIFT 24
|
||||
#define VI6_RPF_ALPH_SEL_BSEL (1 << 23)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_ZERO (0 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_AEXT_MASK (3 << 18)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 8)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 8
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 0)
|
||||
#define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 0
|
||||
|
||||
#define VI6_RPF_VRTCOL_SET 0x0318
|
||||
#define VI6_RPF_VRTCOL_SET_LAYA_MASK (0xff << 24)
|
||||
#define VI6_RPF_VRTCOL_SET_LAYA_SHIFT 24
|
||||
#define VI6_RPF_VRTCOL_SET_LAYR_MASK (0xff << 16)
|
||||
#define VI6_RPF_VRTCOL_SET_LAYR_SHIFT 16
|
||||
#define VI6_RPF_VRTCOL_SET_LAYG_MASK (0xff << 8)
|
||||
#define VI6_RPF_VRTCOL_SET_LAYG_SHIFT 8
|
||||
#define VI6_RPF_VRTCOL_SET_LAYB_MASK (0xff << 0)
|
||||
#define VI6_RPF_VRTCOL_SET_LAYB_SHIFT 0
|
||||
|
||||
#define VI6_RPF_MSK_CTRL 0x031c
|
||||
#define VI6_RPF_MSK_CTRL_MSK_EN (1 << 24)
|
||||
#define VI6_RPF_MSK_CTRL_MGR_MASK (0xff << 16)
|
||||
#define VI6_RPF_MSK_CTRL_MGR_SHIFT 16
|
||||
#define VI6_RPF_MSK_CTRL_MGG_MASK (0xff << 8)
|
||||
#define VI6_RPF_MSK_CTRL_MGG_SHIFT 8
|
||||
#define VI6_RPF_MSK_CTRL_MGB_MASK (0xff << 0)
|
||||
#define VI6_RPF_MSK_CTRL_MGB_SHIFT 0
|
||||
|
||||
#define VI6_RPF_MSK_SET0 0x0320
|
||||
#define VI6_RPF_MSK_SET1 0x0324
|
||||
#define VI6_RPF_MSK_SET_MSA_MASK (0xff << 24)
|
||||
#define VI6_RPF_MSK_SET_MSA_SHIFT 24
|
||||
#define VI6_RPF_MSK_SET_MSR_MASK (0xff << 16)
|
||||
#define VI6_RPF_MSK_SET_MSR_SHIFT 16
|
||||
#define VI6_RPF_MSK_SET_MSG_MASK (0xff << 8)
|
||||
#define VI6_RPF_MSK_SET_MSG_SHIFT 8
|
||||
#define VI6_RPF_MSK_SET_MSB_MASK (0xff << 0)
|
||||
#define VI6_RPF_MSK_SET_MSB_SHIFT 0
|
||||
|
||||
#define VI6_RPF_CKEY_CTRL 0x0328
|
||||
#define VI6_RPF_CKEY_CTRL_CV (1 << 4)
|
||||
#define VI6_RPF_CKEY_CTRL_SAPE1 (1 << 1)
|
||||
#define VI6_RPF_CKEY_CTRL_SAPE0 (1 << 0)
|
||||
|
||||
#define VI6_RPF_CKEY_SET0 0x032c
|
||||
#define VI6_RPF_CKEY_SET1 0x0330
|
||||
#define VI6_RPF_CKEY_SET_AP_MASK (0xff << 24)
|
||||
#define VI6_RPF_CKEY_SET_AP_SHIFT 24
|
||||
#define VI6_RPF_CKEY_SET_R_MASK (0xff << 16)
|
||||
#define VI6_RPF_CKEY_SET_R_SHIFT 16
|
||||
#define VI6_RPF_CKEY_SET_GY_MASK (0xff << 8)
|
||||
#define VI6_RPF_CKEY_SET_GY_SHIFT 8
|
||||
#define VI6_RPF_CKEY_SET_B_MASK (0xff << 0)
|
||||
#define VI6_RPF_CKEY_SET_B_SHIFT 0
|
||||
|
||||
#define VI6_RPF_SRCM_PSTRIDE 0x0334
|
||||
#define VI6_RPF_SRCM_PSTRIDE_Y_SHIFT 16
|
||||
#define VI6_RPF_SRCM_PSTRIDE_C_SHIFT 0
|
||||
|
||||
#define VI6_RPF_SRCM_ASTRIDE 0x0338
|
||||
#define VI6_RPF_SRCM_PSTRIDE_A_SHIFT 0
|
||||
|
||||
#define VI6_RPF_SRCM_ADDR_Y 0x033c
|
||||
#define VI6_RPF_SRCM_ADDR_C0 0x0340
|
||||
#define VI6_RPF_SRCM_ADDR_C1 0x0344
|
||||
#define VI6_RPF_SRCM_ADDR_AI 0x0348
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* WPF Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_WPF_OFFSET 0x100
|
||||
|
||||
#define VI6_WPF_SRCRPF 0x1000
|
||||
#define VI6_WPF_SRCRPF_VIRACT_DIS (0 << 28)
|
||||
#define VI6_WPF_SRCRPF_VIRACT_SUB (1 << 28)
|
||||
#define VI6_WPF_SRCRPF_VIRACT_MST (2 << 28)
|
||||
#define VI6_WPF_SRCRPF_VIRACT_MASK (3 << 28)
|
||||
#define VI6_WPF_SRCRPF_RPF_ACT_DIS(n) (0 << ((n) * 2))
|
||||
#define VI6_WPF_SRCRPF_RPF_ACT_SUB(n) (1 << ((n) * 2))
|
||||
#define VI6_WPF_SRCRPF_RPF_ACT_MST(n) (2 << ((n) * 2))
|
||||
#define VI6_WPF_SRCRPF_RPF_ACT_MASK(n) (3 << ((n) * 2))
|
||||
|
||||
#define VI6_WPF_HSZCLIP 0x1004
|
||||
#define VI6_WPF_VSZCLIP 0x1008
|
||||
#define VI6_WPF_SZCLIP_EN (1 << 28)
|
||||
#define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16)
|
||||
#define VI6_WPF_SZCLIP_OFST_SHIFT 16
|
||||
#define VI6_WPF_SZCLIP_SIZE_MASK (0x1fff << 0)
|
||||
#define VI6_WPF_SZCLIP_SIZE_SHIFT 0
|
||||
|
||||
#define VI6_WPF_OUTFMT 0x100c
|
||||
#define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24)
|
||||
#define VI6_WPF_OUTFMT_PDV_SHIFT 24
|
||||
#define VI6_WPF_OUTFMT_PXA (1 << 23)
|
||||
#define VI6_WPF_OUTFMT_FLP (1 << 16)
|
||||
#define VI6_WPF_OUTFMT_SPYCS (1 << 15)
|
||||
#define VI6_WPF_OUTFMT_SPUVS (1 << 14)
|
||||
#define VI6_WPF_OUTFMT_DITH_DIS (0 << 12)
|
||||
#define VI6_WPF_OUTFMT_DITH_EN (3 << 12)
|
||||
#define VI6_WPF_OUTFMT_DITH_MASK (3 << 12)
|
||||
#define VI6_WPF_OUTFMT_WRTM_BT601 (0 << 9)
|
||||
#define VI6_WPF_OUTFMT_WRTM_BT601_EXT (1 << 9)
|
||||
#define VI6_WPF_OUTFMT_WRTM_BT709 (2 << 9)
|
||||
#define VI6_WPF_OUTFMT_WRTM_BT709_EXT (3 << 9)
|
||||
#define VI6_WPF_OUTFMT_WRTM_MASK (7 << 9)
|
||||
#define VI6_WPF_OUTFMT_CSC (1 << 8)
|
||||
#define VI6_WPF_OUTFMT_WRFMT_MASK (0x7f << 0)
|
||||
#define VI6_WPF_OUTFMT_WRFMT_SHIFT 0
|
||||
|
||||
#define VI6_WPF_DSWAP 0x1010
|
||||
#define VI6_WPF_DSWAP_P_LLS (1 << 3)
|
||||
#define VI6_WPF_DSWAP_P_LWS (1 << 2)
|
||||
#define VI6_WPF_DSWAP_P_WDS (1 << 1)
|
||||
#define VI6_WPF_DSWAP_P_BTS (1 << 0)
|
||||
|
||||
#define VI6_WPF_RNDCTRL 0x1014
|
||||
#define VI6_WPF_RNDCTRL_CBRM (1 << 28)
|
||||
#define VI6_WPF_RNDCTRL_ABRM_TRUNC (0 << 24)
|
||||
#define VI6_WPF_RNDCTRL_ABRM_ROUND (1 << 24)
|
||||
#define VI6_WPF_RNDCTRL_ABRM_THRESH (2 << 24)
|
||||
#define VI6_WPF_RNDCTRL_ABRM_MASK (3 << 24)
|
||||
#define VI6_WPF_RNDCTRL_ATHRESH_MASK (0xff << 16)
|
||||
#define VI6_WPF_RNDCTRL_ATHRESH_SHIFT 16
|
||||
#define VI6_WPF_RNDCTRL_CLMD_FULL (0 << 12)
|
||||
#define VI6_WPF_RNDCTRL_CLMD_CLIP (1 << 12)
|
||||
#define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12)
|
||||
#define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12)
|
||||
|
||||
#define VI6_WPF_DSTM_STRIDE_Y 0x101c
|
||||
#define VI6_WPF_DSTM_STRIDE_C 0x1020
|
||||
#define VI6_WPF_DSTM_ADDR_Y 0x1024
|
||||
#define VI6_WPF_DSTM_ADDR_C0 0x1028
|
||||
#define VI6_WPF_DSTM_ADDR_C1 0x102c
|
||||
|
||||
#define VI6_WPF_WRBCK_CTRL 0x1034
|
||||
#define VI6_WPF_WRBCK_CTRL_WBMD (1 << 0)
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* DPR Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_DPR_RPF_ROUTE(n) (0x2000 + (n) * 4)
|
||||
|
||||
#define VI6_DPR_WPF_FPORCH(n) (0x2014 + (n) * 4)
|
||||
#define VI6_DPR_WPF_FPORCH_FP_WPFN (5 << 8)
|
||||
|
||||
#define VI6_DPR_SRU_ROUTE 0x2024
|
||||
#define VI6_DPR_UDS_ROUTE(n) (0x2028 + (n) * 4)
|
||||
#define VI6_DPR_LUT_ROUTE 0x203c
|
||||
#define VI6_DPR_CLU_ROUTE 0x2040
|
||||
#define VI6_DPR_HST_ROUTE 0x2044
|
||||
#define VI6_DPR_HSI_ROUTE 0x2048
|
||||
#define VI6_DPR_BRU_ROUTE 0x204c
|
||||
#define VI6_DPR_ROUTE_FXA_MASK (0xff << 8)
|
||||
#define VI6_DPR_ROUTE_FXA_SHIFT 16
|
||||
#define VI6_DPR_ROUTE_FP_MASK (0xff << 8)
|
||||
#define VI6_DPR_ROUTE_FP_SHIFT 8
|
||||
#define VI6_DPR_ROUTE_RT_MASK (0x3f << 0)
|
||||
#define VI6_DPR_ROUTE_RT_SHIFT 0
|
||||
|
||||
#define VI6_DPR_HGO_SMPPT 0x2050
|
||||
#define VI6_DPR_HGT_SMPPT 0x2054
|
||||
#define VI6_DPR_SMPPT_TGW_MASK (7 << 8)
|
||||
#define VI6_DPR_SMPPT_TGW_SHIFT 8
|
||||
#define VI6_DPR_SMPPT_PT_MASK (0x3f << 0)
|
||||
#define VI6_DPR_SMPPT_PT_SHIFT 0
|
||||
|
||||
#define VI6_DPR_NODE_RPF(n) (n)
|
||||
#define VI6_DPR_NODE_SRU 16
|
||||
#define VI6_DPR_NODE_UDS(n) (17 + (n))
|
||||
#define VI6_DPR_NODE_LUT 22
|
||||
#define VI6_DPR_NODE_BRU_IN(n) (23 + (n))
|
||||
#define VI6_DPR_NODE_BRU_OUT 27
|
||||
#define VI6_DPR_NODE_CLU 29
|
||||
#define VI6_DPR_NODE_HST 30
|
||||
#define VI6_DPR_NODE_HSI 31
|
||||
#define VI6_DPR_NODE_LIF 55
|
||||
#define VI6_DPR_NODE_WPF(n) (56 + (n))
|
||||
#define VI6_DPR_NODE_UNUSED 63
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* SRU Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_SRU_CTRL0 0x2200
|
||||
#define VI6_SRU_CTRL1 0x2204
|
||||
#define VI6_SRU_CTRL2 0x2208
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* UDS Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_UDS_OFFSET 0x100
|
||||
|
||||
#define VI6_UDS_CTRL 0x2300
|
||||
#define VI6_UDS_CTRL_AMD (1 << 30)
|
||||
#define VI6_UDS_CTRL_FMD (1 << 29)
|
||||
#define VI6_UDS_CTRL_BLADV (1 << 28)
|
||||
#define VI6_UDS_CTRL_AON (1 << 25)
|
||||
#define VI6_UDS_CTRL_ATHON (1 << 24)
|
||||
#define VI6_UDS_CTRL_BC (1 << 20)
|
||||
#define VI6_UDS_CTRL_NE_A (1 << 19)
|
||||
#define VI6_UDS_CTRL_NE_RCR (1 << 18)
|
||||
#define VI6_UDS_CTRL_NE_GY (1 << 17)
|
||||
#define VI6_UDS_CTRL_NE_BCB (1 << 16)
|
||||
#define VI6_UDS_CTRL_TDIPC (1 << 1)
|
||||
|
||||
#define VI6_UDS_SCALE 0x2304
|
||||
#define VI6_UDS_SCALE_HMANT_MASK (0xf << 28)
|
||||
#define VI6_UDS_SCALE_HMANT_SHIFT 28
|
||||
#define VI6_UDS_SCALE_HFRAC_MASK (0xfff << 16)
|
||||
#define VI6_UDS_SCALE_HFRAC_SHIFT 16
|
||||
#define VI6_UDS_SCALE_VMANT_MASK (0xf << 12)
|
||||
#define VI6_UDS_SCALE_VMANT_SHIFT 12
|
||||
#define VI6_UDS_SCALE_VFRAC_MASK (0xfff << 0)
|
||||
#define VI6_UDS_SCALE_VFRAC_SHIFT 0
|
||||
|
||||
#define VI6_UDS_ALPTH 0x2308
|
||||
#define VI6_UDS_ALPTH_TH1_MASK (0xff << 8)
|
||||
#define VI6_UDS_ALPTH_TH1_SHIFT 8
|
||||
#define VI6_UDS_ALPTH_TH0_MASK (0xff << 0)
|
||||
#define VI6_UDS_ALPTH_TH0_SHIFT 0
|
||||
|
||||
#define VI6_UDS_ALPVAL 0x230c
|
||||
#define VI6_UDS_ALPVAL_VAL2_MASK (0xff << 16)
|
||||
#define VI6_UDS_ALPVAL_VAL2_SHIFT 16
|
||||
#define VI6_UDS_ALPVAL_VAL1_MASK (0xff << 8)
|
||||
#define VI6_UDS_ALPVAL_VAL1_SHIFT 8
|
||||
#define VI6_UDS_ALPVAL_VAL0_MASK (0xff << 0)
|
||||
#define VI6_UDS_ALPVAL_VAL0_SHIFT 0
|
||||
|
||||
#define VI6_UDS_PASS_BWIDTH 0x2310
|
||||
#define VI6_UDS_PASS_BWIDTH_H_MASK (0x7f << 16)
|
||||
#define VI6_UDS_PASS_BWIDTH_H_SHIFT 16
|
||||
#define VI6_UDS_PASS_BWIDTH_V_MASK (0x7f << 0)
|
||||
#define VI6_UDS_PASS_BWIDTH_V_SHIFT 0
|
||||
|
||||
#define VI6_UDS_IPC 0x2318
|
||||
#define VI6_UDS_IPC_FIELD (1 << 27)
|
||||
#define VI6_UDS_IPC_VEDP_MASK (0xfff << 0)
|
||||
#define VI6_UDS_IPC_VEDP_SHIFT 0
|
||||
|
||||
#define VI6_UDS_CLIP_SIZE 0x2324
|
||||
#define VI6_UDS_CLIP_SIZE_HSIZE_MASK (0x1fff << 16)
|
||||
#define VI6_UDS_CLIP_SIZE_HSIZE_SHIFT 16
|
||||
#define VI6_UDS_CLIP_SIZE_VSIZE_MASK (0x1fff << 0)
|
||||
#define VI6_UDS_CLIP_SIZE_VSIZE_SHIFT 0
|
||||
|
||||
#define VI6_UDS_FILL_COLOR 0x2328
|
||||
#define VI6_UDS_FILL_COLOR_RFILC_MASK (0xff << 16)
|
||||
#define VI6_UDS_FILL_COLOR_RFILC_SHIFT 16
|
||||
#define VI6_UDS_FILL_COLOR_GFILC_MASK (0xff << 8)
|
||||
#define VI6_UDS_FILL_COLOR_GFILC_SHIFT 8
|
||||
#define VI6_UDS_FILL_COLOR_BFILC_MASK (0xff << 0)
|
||||
#define VI6_UDS_FILL_COLOR_BFILC_SHIFT 0
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* LUT Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_LUT_CTRL 0x2800
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* CLU Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_CLU_CTRL 0x2900
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HST Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_HST_CTRL 0x2a00
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HSI Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_HSI_CTRL 0x2b00
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* BRU Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_BRU_INCTRL 0x2c00
|
||||
#define VI6_BRU_VIRRPF_SIZE 0x2c04
|
||||
#define VI6_BRU_VIRRPF_LOC 0x2c08
|
||||
#define VI6_BRU_VIRRPF_COL 0x2c0c
|
||||
#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8)
|
||||
#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8)
|
||||
#define VI6_BRU_ROP 0x2c30
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HGO Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_HGO_OFFSET 0x3000
|
||||
#define VI6_HGO_SIZE 0x3004
|
||||
#define VI6_HGO_MODE 0x3008
|
||||
#define VI6_HGO_LB_TH 0x300c
|
||||
#define VI6_HGO_LBn_H(n) (0x3010 + (n) * 8)
|
||||
#define VI6_HGO_LBn_V(n) (0x3014 + (n) * 8)
|
||||
#define VI6_HGO_R_HISTO 0x3030
|
||||
#define VI6_HGO_R_MAXMIN 0x3130
|
||||
#define VI6_HGO_R_SUM 0x3134
|
||||
#define VI6_HGO_R_LB_DET 0x3138
|
||||
#define VI6_HGO_G_HISTO 0x3140
|
||||
#define VI6_HGO_G_MAXMIN 0x3240
|
||||
#define VI6_HGO_G_SUM 0x3244
|
||||
#define VI6_HGO_G_LB_DET 0x3248
|
||||
#define VI6_HGO_B_HISTO 0x3250
|
||||
#define VI6_HGO_B_MAXMIN 0x3350
|
||||
#define VI6_HGO_B_SUM 0x3354
|
||||
#define VI6_HGO_B_LB_DET 0x3358
|
||||
#define VI6_HGO_REGRST 0x33fc
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* HGT Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_HGT_OFFSET 0x3400
|
||||
#define VI6_HGT_SIZE 0x3404
|
||||
#define VI6_HGT_MODE 0x3408
|
||||
#define VI6_HGT_HUE_AREA(n) (0x340c + (n) * 4)
|
||||
#define VI6_HGT_LB_TH 0x3424
|
||||
#define VI6_HGT_LBn_H(n) (0x3438 + (n) * 8)
|
||||
#define VI6_HGT_LBn_V(n) (0x342c + (n) * 8)
|
||||
#define VI6_HGT_HISTO(m, n) (0x3450 + (m) * 128 + (n) * 4)
|
||||
#define VI6_HGT_MAXMIN 0x3750
|
||||
#define VI6_HGT_SUM 0x3754
|
||||
#define VI6_HGT_LB_DET 0x3758
|
||||
#define VI6_HGT_REGRST 0x37fc
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* LIF Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_LIF_CTRL 0x3b00
|
||||
#define VI6_LIF_CTRL_OBTH_MASK (0x7ff << 16)
|
||||
#define VI6_LIF_CTRL_OBTH_SHIFT 16
|
||||
#define VI6_LIF_CTRL_CFMT (1 << 4)
|
||||
#define VI6_LIF_CTRL_REQSEL (1 << 1)
|
||||
#define VI6_LIF_CTRL_LIF_EN (1 << 0)
|
||||
|
||||
#define VI6_LIF_CSBTH 0x3b04
|
||||
#define VI6_LIF_CSBTH_HBTH_MASK (0x7ff << 16)
|
||||
#define VI6_LIF_CSBTH_HBTH_SHIFT 16
|
||||
#define VI6_LIF_CSBTH_LBTH_MASK (0x7ff << 0)
|
||||
#define VI6_LIF_CSBTH_LBTH_SHIFT 0
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Security Control Registers
|
||||
*/
|
||||
|
||||
#define VI6_SECURITY_CTRL0 0x3d00
|
||||
#define VI6_SECURITY_CTRL1 0x3d04
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* RPF CLUT Registers
|
||||
*/
|
||||
|
||||
#define VI6_CLUT_TABLE 0x4000
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* 1D LUT Registers
|
||||
*/
|
||||
|
||||
#define VI6_LUT_TABLE 0x7000
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* 3D LUT Registers
|
||||
*/
|
||||
|
||||
#define VI6_CLU_ADDR 0x7400
|
||||
#define VI6_CLU_DATA 0x7404
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Formats
|
||||
*/
|
||||
|
||||
#define VI6_FMT_RGB_332 0x00
|
||||
#define VI6_FMT_XRGB_4444 0x01
|
||||
#define VI6_FMT_RGBX_4444 0x02
|
||||
#define VI6_FMT_XRGB_1555 0x04
|
||||
#define VI6_FMT_RGBX_5551 0x05
|
||||
#define VI6_FMT_RGB_565 0x06
|
||||
#define VI6_FMT_AXRGB_86666 0x07
|
||||
#define VI6_FMT_RGBXA_66668 0x08
|
||||
#define VI6_FMT_XRGBA_66668 0x09
|
||||
#define VI6_FMT_ARGBX_86666 0x0a
|
||||
#define VI6_FMT_AXRXGXB_8262626 0x0b
|
||||
#define VI6_FMT_XRXGXBA_2626268 0x0c
|
||||
#define VI6_FMT_ARXGXBX_8626262 0x0d
|
||||
#define VI6_FMT_RXGXBXA_6262628 0x0e
|
||||
#define VI6_FMT_XRGB_6666 0x0f
|
||||
#define VI6_FMT_RGBX_6666 0x10
|
||||
#define VI6_FMT_XRXGXB_262626 0x11
|
||||
#define VI6_FMT_RXGXBX_626262 0x12
|
||||
#define VI6_FMT_ARGB_8888 0x13
|
||||
#define VI6_FMT_RGBA_8888 0x14
|
||||
#define VI6_FMT_RGB_888 0x15
|
||||
#define VI6_FMT_XRGXGB_763763 0x16
|
||||
#define VI6_FMT_XXRGB_86666 0x17
|
||||
#define VI6_FMT_BGR_888 0x18
|
||||
#define VI6_FMT_ARGB_4444 0x19
|
||||
#define VI6_FMT_RGBA_4444 0x1a
|
||||
#define VI6_FMT_ARGB_1555 0x1b
|
||||
#define VI6_FMT_RGBA_5551 0x1c
|
||||
#define VI6_FMT_ABGR_4444 0x1d
|
||||
#define VI6_FMT_BGRA_4444 0x1e
|
||||
#define VI6_FMT_ABGR_1555 0x1f
|
||||
#define VI6_FMT_BGRA_5551 0x20
|
||||
#define VI6_FMT_XBXGXR_262626 0x21
|
||||
#define VI6_FMT_ABGR_8888 0x22
|
||||
#define VI6_FMT_XXRGB_88565 0x23
|
||||
|
||||
#define VI6_FMT_Y_UV_444 0x40
|
||||
#define VI6_FMT_Y_UV_422 0x41
|
||||
#define VI6_FMT_Y_UV_420 0x42
|
||||
#define VI6_FMT_YUV_444 0x46
|
||||
#define VI6_FMT_YUYV_422 0x47
|
||||
#define VI6_FMT_YYUV_422 0x48
|
||||
#define VI6_FMT_YUV_420 0x49
|
||||
#define VI6_FMT_Y_U_V_444 0x4a
|
||||
#define VI6_FMT_Y_U_V_422 0x4b
|
||||
#define VI6_FMT_Y_U_V_420 0x4c
|
||||
|
||||
#endif /* __VSP1_REGS_H__ */
|
||||
209
drivers/media/platform/vsp1/vsp1_rpf.c
Normal file
209
drivers/media/platform/vsp1/vsp1_rpf.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_rwpf.h"
|
||||
#include "vsp1_video.h"
|
||||
|
||||
#define RPF_MAX_WIDTH 8190
|
||||
#define RPF_MAX_HEIGHT 8190
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Device Access
|
||||
*/
|
||||
|
||||
static inline u32 vsp1_rpf_read(struct vsp1_rwpf *rpf, u32 reg)
|
||||
{
|
||||
return vsp1_read(rpf->entity.vsp1,
|
||||
reg + rpf->entity.index * VI6_RPF_OFFSET);
|
||||
}
|
||||
|
||||
static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
|
||||
{
|
||||
vsp1_write(rpf->entity.vsp1,
|
||||
reg + rpf->entity.index * VI6_RPF_OFFSET, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
*/
|
||||
|
||||
static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
struct vsp1_rwpf *rpf = to_rwpf(subdev);
|
||||
const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
|
||||
const struct v4l2_pix_format_mplane *format = &rpf->video.format;
|
||||
u32 pstride;
|
||||
u32 infmt;
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
/* Source size and stride. Cropping isn't supported yet. */
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
|
||||
(format->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
|
||||
(format->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
|
||||
(format->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
|
||||
(format->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
|
||||
|
||||
pstride = format->plane_fmt[0].bytesperline
|
||||
<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
|
||||
if (format->num_planes > 1)
|
||||
pstride |= format->plane_fmt[1].bytesperline
|
||||
<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
|
||||
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
|
||||
|
||||
/* Format */
|
||||
infmt = VI6_RPF_INFMT_CIPM
|
||||
| (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
|
||||
|
||||
if (fmtinfo->swap_yc)
|
||||
infmt |= VI6_RPF_INFMT_SPYCS;
|
||||
if (fmtinfo->swap_uv)
|
||||
infmt |= VI6_RPF_INFMT_SPUVS;
|
||||
|
||||
if (rpf->entity.formats[RWPF_PAD_SINK].code !=
|
||||
rpf->entity.formats[RWPF_PAD_SOURCE].code)
|
||||
infmt |= VI6_RPF_INFMT_CSC;
|
||||
|
||||
vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
|
||||
vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
|
||||
|
||||
/* Output location. Composing isn't supported yet. */
|
||||
vsp1_rpf_write(rpf, VI6_RPF_LOC, 0);
|
||||
|
||||
/* Disable alpha, mask and color key. Set the alpha channel to a fixed
|
||||
* value of 255.
|
||||
*/
|
||||
vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_ASEL_FIXED);
|
||||
vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
|
||||
255 << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
|
||||
vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
|
||||
vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_video_ops rpf_video_ops = {
|
||||
.s_stream = rpf_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops rpf_pad_ops = {
|
||||
.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
|
||||
.enum_frame_size = vsp1_rwpf_enum_frame_size,
|
||||
.get_fmt = vsp1_rwpf_get_format,
|
||||
.set_fmt = vsp1_rwpf_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops rpf_ops = {
|
||||
.video = &rpf_video_ops,
|
||||
.pad = &rpf_pad_ops,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Video Device Operations
|
||||
*/
|
||||
|
||||
static void rpf_vdev_queue(struct vsp1_video *video,
|
||||
struct vsp1_video_buffer *buf)
|
||||
{
|
||||
struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
|
||||
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0]);
|
||||
if (buf->buf.num_planes > 1)
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, buf->addr[1]);
|
||||
if (buf->buf.num_planes > 2)
|
||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, buf->addr[2]);
|
||||
}
|
||||
|
||||
static const struct vsp1_video_operations rpf_vdev_ops = {
|
||||
.queue = rpf_vdev_queue,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization and Cleanup
|
||||
*/
|
||||
|
||||
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
struct vsp1_video *video;
|
||||
struct vsp1_rwpf *rpf;
|
||||
int ret;
|
||||
|
||||
rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
|
||||
if (rpf == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rpf->max_width = RPF_MAX_WIDTH;
|
||||
rpf->max_height = RPF_MAX_HEIGHT;
|
||||
|
||||
rpf->entity.type = VSP1_ENTITY_RPF;
|
||||
rpf->entity.index = index;
|
||||
rpf->entity.id = VI6_DPR_NODE_RPF(index);
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the V4L2 subdev. */
|
||||
subdev = &rpf->entity.subdev;
|
||||
v4l2_subdev_init(subdev, &rpf_ops);
|
||||
|
||||
subdev->entity.ops = &vsp1_media_ops;
|
||||
subdev->internal_ops = &vsp1_subdev_internal_ops;
|
||||
snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
|
||||
dev_name(vsp1->dev), index);
|
||||
v4l2_set_subdevdata(subdev, rpf);
|
||||
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
vsp1_entity_init_formats(subdev, NULL);
|
||||
|
||||
/* Initialize the video device. */
|
||||
video = &rpf->video;
|
||||
|
||||
video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
video->vsp1 = vsp1;
|
||||
video->ops = &rpf_vdev_ops;
|
||||
|
||||
ret = vsp1_video_init(video, &rpf->entity);
|
||||
if (ret < 0)
|
||||
goto error_video;
|
||||
|
||||
/* Connect the video device to the RPF. */
|
||||
ret = media_entity_create_link(&rpf->video.video.entity, 0,
|
||||
&rpf->entity.subdev.entity,
|
||||
RWPF_PAD_SINK,
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (ret < 0)
|
||||
goto error_link;
|
||||
|
||||
return rpf;
|
||||
|
||||
error_link:
|
||||
vsp1_video_cleanup(video);
|
||||
error_video:
|
||||
media_entity_cleanup(&rpf->entity.subdev.entity);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
124
drivers/media/platform/vsp1/vsp1_rwpf.c
Normal file
124
drivers/media/platform/vsp1/vsp1_rwpf.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* vsp1_rwpf.c -- R-Car VSP1 Read and Write Pixel Formatters
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_rwpf.h"
|
||||
#include "vsp1_video.h"
|
||||
|
||||
#define RWPF_MIN_WIDTH 1
|
||||
#define RWPF_MIN_HEIGHT 1
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
||||
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
static const unsigned int codes[] = {
|
||||
V4L2_MBUS_FMT_ARGB8888_1X32,
|
||||
V4L2_MBUS_FMT_AYUV8_1X32,
|
||||
};
|
||||
|
||||
if (code->index >= ARRAY_SIZE(codes))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = codes[code->index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, fse->pad);
|
||||
|
||||
if (fse->index || fse->code != format->code)
|
||||
return -EINVAL;
|
||||
|
||||
if (fse->pad == RWPF_PAD_SINK) {
|
||||
fse->min_width = RWPF_MIN_WIDTH;
|
||||
fse->max_width = rwpf->max_width;
|
||||
fse->min_height = RWPF_MIN_HEIGHT;
|
||||
fse->max_height = rwpf->max_height;
|
||||
} else {
|
||||
/* The size on the source pad are fixed and always identical to
|
||||
* the size on the sink pad.
|
||||
*/
|
||||
fse->min_width = format->width;
|
||||
fse->max_width = format->width;
|
||||
fse->min_height = format->height;
|
||||
fse->max_height = format->height;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||
|
||||
fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/* Default to YUV if the requested format is not supported. */
|
||||
if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||
fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
|
||||
fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
|
||||
|
||||
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
if (fmt->pad == RWPF_PAD_SOURCE) {
|
||||
/* The RWPF performs format conversion but can't scale, only the
|
||||
* format code can be changed on the source pad.
|
||||
*/
|
||||
format->code = fmt->format.code;
|
||||
fmt->format = *format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
format->code = fmt->format.code;
|
||||
format->width = clamp_t(unsigned int, fmt->format.width,
|
||||
RWPF_MIN_WIDTH, rwpf->max_width);
|
||||
format->height = clamp_t(unsigned int, fmt->format.height,
|
||||
RWPF_MIN_HEIGHT, rwpf->max_height);
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
format->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
|
||||
fmt->format = *format;
|
||||
|
||||
/* Propagate the format to the source pad. */
|
||||
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
|
||||
fmt->which);
|
||||
*format = fmt->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
53
drivers/media/platform/vsp1/vsp1_rwpf.h
Normal file
53
drivers/media/platform/vsp1/vsp1_rwpf.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* vsp1_rwpf.h -- R-Car VSP1 Read and Write Pixel Formatters
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_RWPF_H__
|
||||
#define __VSP1_RWPF_H__
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_entity.h"
|
||||
#include "vsp1_video.h"
|
||||
|
||||
#define RWPF_PAD_SINK 0
|
||||
#define RWPF_PAD_SOURCE 1
|
||||
|
||||
struct vsp1_rwpf {
|
||||
struct vsp1_entity entity;
|
||||
struct vsp1_video video;
|
||||
|
||||
unsigned int max_width;
|
||||
unsigned int max_height;
|
||||
};
|
||||
|
||||
static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_rwpf, entity.subdev);
|
||||
}
|
||||
|
||||
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
|
||||
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_mbus_code_enum *code);
|
||||
int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_frame_size_enum *fse);
|
||||
int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt);
|
||||
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt);
|
||||
|
||||
#endif /* __VSP1_RWPF_H__ */
|
||||
346
drivers/media/platform/vsp1/vsp1_uds.c
Normal file
346
drivers/media/platform/vsp1/vsp1_uds.c
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* vsp1_uds.c -- R-Car VSP1 Up and Down Scaler
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1.h"
|
||||
#include "vsp1_uds.h"
|
||||
|
||||
#define UDS_MIN_SIZE 4U
|
||||
#define UDS_MAX_SIZE 8190U
|
||||
|
||||
#define UDS_MIN_FACTOR 0x0100
|
||||
#define UDS_MAX_FACTOR 0xffff
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Device Access
|
||||
*/
|
||||
|
||||
static inline u32 vsp1_uds_read(struct vsp1_uds *uds, u32 reg)
|
||||
{
|
||||
return vsp1_read(uds->entity.vsp1,
|
||||
reg + uds->entity.index * VI6_UDS_OFFSET);
|
||||
}
|
||||
|
||||
static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
|
||||
{
|
||||
vsp1_write(uds->entity.vsp1,
|
||||
reg + uds->entity.index * VI6_UDS_OFFSET, data);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Scaling Computation
|
||||
*/
|
||||
|
||||
/*
|
||||
* uds_output_size - Return the output size for an input size and scaling ratio
|
||||
* @input: input size in pixels
|
||||
* @ratio: scaling ratio in U4.12 fixed-point format
|
||||
*/
|
||||
static unsigned int uds_output_size(unsigned int input, unsigned int ratio)
|
||||
{
|
||||
if (ratio > 4096) {
|
||||
/* Down-scaling */
|
||||
unsigned int mp;
|
||||
|
||||
mp = ratio / 4096;
|
||||
mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4);
|
||||
|
||||
return (input - 1) / mp * mp * 4096 / ratio + 1;
|
||||
} else {
|
||||
/* Up-scaling */
|
||||
return (input - 1) * 4096 / ratio + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* uds_output_limits - Return the min and max output sizes for an input size
|
||||
* @input: input size in pixels
|
||||
* @minimum: minimum output size (returned)
|
||||
* @maximum: maximum output size (returned)
|
||||
*/
|
||||
static void uds_output_limits(unsigned int input,
|
||||
unsigned int *minimum, unsigned int *maximum)
|
||||
{
|
||||
*minimum = max(uds_output_size(input, UDS_MAX_FACTOR), UDS_MIN_SIZE);
|
||||
*maximum = min(uds_output_size(input, UDS_MIN_FACTOR), UDS_MAX_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* uds_passband_width - Return the passband filter width for a scaling ratio
|
||||
* @ratio: scaling ratio in U4.12 fixed-point format
|
||||
*/
|
||||
static unsigned int uds_passband_width(unsigned int ratio)
|
||||
{
|
||||
if (ratio >= 4096) {
|
||||
/* Down-scaling */
|
||||
unsigned int mp;
|
||||
|
||||
mp = ratio / 4096;
|
||||
mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4);
|
||||
|
||||
return 64 * 4096 * mp / ratio;
|
||||
} else {
|
||||
/* Up-scaling */
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
|
||||
{
|
||||
/* TODO: This is an approximation that will need to be refined. */
|
||||
return (input - 1) * 4096 / (output - 1);
|
||||
}
|
||||
|
||||
static void uds_compute_ratios(struct vsp1_uds *uds)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *input = &uds->entity.formats[UDS_PAD_SINK];
|
||||
struct v4l2_mbus_framefmt *output =
|
||||
&uds->entity.formats[UDS_PAD_SOURCE];
|
||||
|
||||
uds->hscale = uds_compute_ratio(input->width, output->width);
|
||||
uds->vscale = uds_compute_ratio(input->height, output->height);
|
||||
|
||||
dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n",
|
||||
uds->hscale, uds->vscale);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Core Operations
|
||||
*/
|
||||
|
||||
static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct vsp1_uds *uds = to_uds(subdev);
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
/* Enable multi-tap scaling. */
|
||||
vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_BC);
|
||||
|
||||
vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
|
||||
(uds_passband_width(uds->hscale)
|
||||
<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
|
||||
(uds_passband_width(uds->vscale)
|
||||
<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
|
||||
|
||||
|
||||
/* Set the scaling ratios and the output size. */
|
||||
format = &uds->entity.formats[UDS_PAD_SOURCE];
|
||||
|
||||
vsp1_uds_write(uds, VI6_UDS_SCALE,
|
||||
(uds->hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
|
||||
(uds->vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
|
||||
vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
|
||||
(format->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
|
||||
(format->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Pad Operations
|
||||
*/
|
||||
|
||||
static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
static const unsigned int codes[] = {
|
||||
V4L2_MBUS_FMT_ARGB8888_1X32,
|
||||
V4L2_MBUS_FMT_AYUV8_1X32,
|
||||
};
|
||||
|
||||
if (code->pad == UDS_PAD_SINK) {
|
||||
if (code->index >= ARRAY_SIZE(codes))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = codes[code->index];
|
||||
} else {
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/* The UDS can't perform format conversion, the sink format is
|
||||
* always identical to the source format.
|
||||
*/
|
||||
if (code->index)
|
||||
return -EINVAL;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK);
|
||||
code->code = format->code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uds_enum_frame_size(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK);
|
||||
|
||||
if (fse->index || fse->code != format->code)
|
||||
return -EINVAL;
|
||||
|
||||
if (fse->pad == UDS_PAD_SINK) {
|
||||
fse->min_width = UDS_MIN_SIZE;
|
||||
fse->max_width = UDS_MAX_SIZE;
|
||||
fse->min_height = UDS_MIN_SIZE;
|
||||
fse->max_height = UDS_MAX_SIZE;
|
||||
} else {
|
||||
uds_output_limits(format->width, &fse->min_width,
|
||||
&fse->max_width);
|
||||
uds_output_limits(format->height, &fse->min_height,
|
||||
&fse->max_height);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_uds *uds = to_uds(subdev);
|
||||
|
||||
fmt->format = *vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh,
|
||||
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
|
||||
enum v4l2_subdev_format_whence which)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
unsigned int minimum;
|
||||
unsigned int maximum;
|
||||
|
||||
switch (pad) {
|
||||
case UDS_PAD_SINK:
|
||||
/* Default to YUV if the requested format is not supported. */
|
||||
if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||
fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
|
||||
fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
|
||||
|
||||
fmt->width = clamp(fmt->width, UDS_MIN_SIZE, UDS_MAX_SIZE);
|
||||
fmt->height = clamp(fmt->height, UDS_MIN_SIZE, UDS_MAX_SIZE);
|
||||
break;
|
||||
|
||||
case UDS_PAD_SOURCE:
|
||||
/* The UDS scales but can't perform format conversion. */
|
||||
format = vsp1_entity_get_pad_format(&uds->entity, fh,
|
||||
UDS_PAD_SINK, which);
|
||||
fmt->code = format->code;
|
||||
|
||||
uds_output_limits(format->width, &minimum, &maximum);
|
||||
fmt->width = clamp(fmt->width, minimum, maximum);
|
||||
uds_output_limits(format->height, &minimum, &maximum);
|
||||
fmt->height = clamp(fmt->height, minimum, maximum);
|
||||
break;
|
||||
}
|
||||
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
}
|
||||
|
||||
static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vsp1_uds *uds = to_uds(subdev);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
uds_try_format(uds, fh, fmt->pad, &fmt->format, fmt->which);
|
||||
|
||||
format = vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad,
|
||||
fmt->which);
|
||||
*format = fmt->format;
|
||||
|
||||
if (fmt->pad == UDS_PAD_SINK) {
|
||||
/* Propagate the format to the source pad. */
|
||||
format = vsp1_entity_get_pad_format(&uds->entity, fh,
|
||||
UDS_PAD_SOURCE, fmt->which);
|
||||
*format = fmt->format;
|
||||
|
||||
uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which);
|
||||
}
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
uds_compute_ratios(uds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdevice Operations
|
||||
*/
|
||||
|
||||
static struct v4l2_subdev_video_ops uds_video_ops = {
|
||||
.s_stream = uds_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops uds_pad_ops = {
|
||||
.enum_mbus_code = uds_enum_mbus_code,
|
||||
.enum_frame_size = uds_enum_frame_size,
|
||||
.get_fmt = uds_get_format,
|
||||
.set_fmt = uds_set_format,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops uds_ops = {
|
||||
.video = &uds_video_ops,
|
||||
.pad = &uds_pad_ops,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization and Cleanup
|
||||
*/
|
||||
|
||||
struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
struct vsp1_uds *uds;
|
||||
int ret;
|
||||
|
||||
uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL);
|
||||
if (uds == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
uds->entity.type = VSP1_ENTITY_UDS;
|
||||
uds->entity.index = index;
|
||||
uds->entity.id = VI6_DPR_NODE_UDS(index);
|
||||
|
||||
ret = vsp1_entity_init(vsp1, &uds->entity, 2);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Initialize the V4L2 subdev. */
|
||||
subdev = &uds->entity.subdev;
|
||||
v4l2_subdev_init(subdev, &uds_ops);
|
||||
|
||||
subdev->entity.ops = &vsp1_media_ops;
|
||||
subdev->internal_ops = &vsp1_subdev_internal_ops;
|
||||
snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u",
|
||||
dev_name(vsp1->dev), index);
|
||||
v4l2_set_subdevdata(subdev, uds);
|
||||
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
vsp1_entity_init_formats(subdev, NULL);
|
||||
|
||||
return uds;
|
||||
}
|
||||
40
drivers/media/platform/vsp1/vsp1_uds.h
Normal file
40
drivers/media/platform/vsp1/vsp1_uds.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* vsp1_uds.h -- R-Car VSP1 Up and Down Scaler
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Corporation
|
||||
*
|
||||
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef __VSP1_UDS_H__
|
||||
#define __VSP1_UDS_H__
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "vsp1_entity.h"
|
||||
|
||||
struct vsp1_device;
|
||||
|
||||
#define UDS_PAD_SINK 0
|
||||
#define UDS_PAD_SOURCE 1
|
||||
|
||||
struct vsp1_uds {
|
||||
struct vsp1_entity entity;
|
||||
|
||||
unsigned int hscale;
|
||||
unsigned int vscale;
|
||||
};
|
||||
|
||||
static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct vsp1_uds, entity.subdev);
|
||||
}
|
||||
|
||||
struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
|
||||
|
||||
#endif /* __VSP1_UDS_H__ */
|
||||
1069
drivers/media/platform/vsp1/vsp1_video.c
Normal file
1069
drivers/media/platform/vsp1/vsp1_video.c
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue