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: "The main set of series of patches for media subsystem, including: - document RC sysfs class - added an API to setup scancode to allow waking up systems using the Remote Controller - add API for SDR devices. Drivers are still on staging - some API improvements for getting EDID data from media inputs/outputs - new DVB frontend driver for drx-j (ATSC) - one driver (it913x/it9137) got removed, in favor of an improvement on another driver (af9035) - added a skeleton V4L2 PCI driver at documentation - added a dual flash driver (lm3646) - added a new IR driver (img-ir) - added an IR scancode decoder for the Sharp protocol - some improvements at the usbtv driver, to allow its core to be reused. - added a new SDR driver (rtl2832u_sdr) - added a new tuner driver (msi001) - several improvements at em28xx driver to fix PM support, device removal and to split the V4L2 specific bits into a separate sub-driver - one driver got converted to videobuf2 (s2255drv) - the e4000 tuner driver now follows an improved binding model - some fixes at V4L2 compat32 code - several fixes and enhancements at videobuf2 code - some cleanups at V4L2 API documentation - usual driver enhancements, new board additions and misc fixups" [ NOTE! This merge effective drops commit4329b93b28
("of: Reduce indentation in of_graph_get_next_endpoint"). The of_graph_get_next_endpoint() function was moved and renamed by commitfd9fdb78a9
("[media] of: move graph helpers from drivers/media/v4l2-core to drivers/of"). It was originally called v4l2_of_get_next_endpoint() and lived in the file drivers/media/v4l2-core/v4l2-of.c. In that original location, it was then fixed to support empty port nodes by commitb9db140c1e
("[media] v4l: of: Support empty port nodes"), and that commit clashes badly with the dropped "Reduce intendation" commit. I had to choose one or the other, and decided that the "Support empty port nodes" commit was more important ] * 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (426 commits) [media] em28xx-dvb: fix PCTV 461e tuner I2C binding Revert "[media] em28xx-dvb: fix PCTV 461e tuner I2C binding" [media] em28xx: fix PCTV 290e LNA oops [media] em28xx-dvb: fix PCTV 461e tuner I2C binding [media] m88ds3103: fix bug on .set_tone() [media] saa7134: fix WARN_ON during resume [media] v4l2-dv-timings: add module name, description, license [media] videodev2.h: add parenthesis around macro arguments [media] saa6752hs: depends on CRC32 [media] si4713: fix Kconfig dependencies [media] Sensoray 2255 uses videobuf2 [media] adv7180: free an interrupt on failure paths in init_device() [media] e4000: make VIDEO_V4L2 dependency optional [media] af9033: Don't export functions for the hardware filter [media] af9035: use af9033 PID filters [media] af9033: implement PID filter [media] rtl2832_sdr: do not use dynamic stack allocation [media] e4000: fix 32-bit build error [media] em28xx-audio: make sure audio is unmuted on open() [media] DocBook media: v4l2_format_sdr was renamed to v4l2_sdr_format ...
This commit is contained in:
@@ -196,7 +196,7 @@ config VIDEO_ADV7183
|
||||
|
||||
config VIDEO_ADV7604
|
||||
tristate "Analog Devices ADV7604 decoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
|
||||
---help---
|
||||
Support for the Analog Devices ADV7604 video decoder.
|
||||
|
||||
@@ -208,7 +208,7 @@ config VIDEO_ADV7604
|
||||
|
||||
config VIDEO_ADV7842
|
||||
tristate "Analog Devices ADV7842 decoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
|
||||
---help---
|
||||
Support for the Analog Devices ADV7842 video decoder.
|
||||
|
||||
@@ -431,7 +431,7 @@ config VIDEO_ADV7393
|
||||
|
||||
config VIDEO_ADV7511
|
||||
tristate "Analog Devices ADV7511 encoder"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
|
||||
---help---
|
||||
Support for the Analog Devices ADV7511 video encoder.
|
||||
|
||||
@@ -629,6 +629,15 @@ config VIDEO_LM3560
|
||||
This is a driver for the lm3560 dual flash controllers. It controls
|
||||
flash, torch LEDs.
|
||||
|
||||
config VIDEO_LM3646
|
||||
tristate "LM3646 dual flash driver support"
|
||||
depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
select REGMAP_I2C
|
||||
---help---
|
||||
This is a driver for the lm3646 dual flash controllers. It controls
|
||||
flash, torch LEDs.
|
||||
|
||||
comment "Video improvement chips"
|
||||
|
||||
config VIDEO_UPD64031A
|
||||
@@ -659,6 +668,7 @@ comment "Audio/Video compression chips"
|
||||
config VIDEO_SAA6752HS
|
||||
tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
select CRC32
|
||||
---help---
|
||||
Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3
|
||||
audio encoder with multiplexer.
|
||||
|
@@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
|
||||
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
|
||||
obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
|
||||
obj-$(CONFIG_VIDEO_LM3560) += lm3560.o
|
||||
obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
|
||||
obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
|
||||
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
|
||||
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
|
||||
|
@@ -573,7 +573,7 @@ static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
|
||||
|
||||
/* ------------------------------ PAD OPS ------------------------------ */
|
||||
|
||||
static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
|
||||
static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct ad9389b_state *state = get_ad9389b_state(sd);
|
||||
|
||||
|
@@ -123,11 +123,11 @@
|
||||
struct adv7180_state {
|
||||
struct v4l2_ctrl_handler ctrl_hdl;
|
||||
struct v4l2_subdev sd;
|
||||
struct work_struct work;
|
||||
struct mutex mutex; /* mutual excl. when accessing chip */
|
||||
int irq;
|
||||
v4l2_std_id curr_norm;
|
||||
bool autodetect;
|
||||
bool powered;
|
||||
u8 input;
|
||||
};
|
||||
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
|
||||
@@ -312,6 +312,37 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_set_power(struct adv7180_state *state,
|
||||
struct i2c_client *client, bool on)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (on)
|
||||
val = ADV7180_PWR_MAN_ON;
|
||||
else
|
||||
val = ADV7180_PWR_MAN_OFF;
|
||||
|
||||
return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
|
||||
}
|
||||
|
||||
static int adv7180_s_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adv7180_set_power(state, client, on);
|
||||
if (ret == 0)
|
||||
state->powered = on;
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
|
||||
@@ -442,6 +473,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
|
||||
.s_std = adv7180_s_std,
|
||||
.s_power = adv7180_s_power,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
@@ -449,10 +481,9 @@ static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
.video = &adv7180_video_ops,
|
||||
};
|
||||
|
||||
static void adv7180_work(struct work_struct *work)
|
||||
static irqreturn_t adv7180_irq(int irq, void *devid)
|
||||
{
|
||||
struct adv7180_state *state = container_of(work, struct adv7180_state,
|
||||
work);
|
||||
struct adv7180_state *state = devid;
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
|
||||
u8 isr3;
|
||||
|
||||
@@ -468,17 +499,6 @@ static void adv7180_work(struct work_struct *work)
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t adv7180_irq(int irq, void *devid)
|
||||
{
|
||||
struct adv7180_state *state = devid;
|
||||
|
||||
schedule_work(&state->work);
|
||||
|
||||
disable_irq_nosync(state->irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -533,48 +553,52 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
|
||||
|
||||
/* register for interrupts */
|
||||
if (state->irq > 0) {
|
||||
ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME,
|
||||
state);
|
||||
ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
|
||||
IRQF_ONESHOT, KBUILD_MODNAME, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
ADV7180_ADI_CTRL_IRQ_SPACE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
/* config the Interrupt pin to be active low */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
|
||||
ADV7180_ICONF1_ACTIVE_LOW |
|
||||
ADV7180_ICONF1_PSYNC_ONLY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
/* enable AD change interrupts interrupts */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
|
||||
ADV7180_IRQ3_AD_CHANGE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free_irq(state->irq, state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_probe(struct i2c_client *client,
|
||||
@@ -598,9 +622,9 @@ static int adv7180_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
state->irq = client->irq;
|
||||
INIT_WORK(&state->work, adv7180_work);
|
||||
mutex_init(&state->mutex);
|
||||
state->autodetect = true;
|
||||
state->powered = true;
|
||||
state->input = 0;
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
|
||||
@@ -611,15 +635,21 @@ static int adv7180_probe(struct i2c_client *client,
|
||||
ret = init_device(client, state);
|
||||
if (ret)
|
||||
goto err_free_ctrl;
|
||||
|
||||
ret = v4l2_async_register_subdev(sd);
|
||||
if (ret)
|
||||
goto err_free_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
if (state->irq > 0)
|
||||
free_irq(client->irq, state);
|
||||
err_free_ctrl:
|
||||
adv7180_exit_controls(state);
|
||||
err_unreg_subdev:
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
err:
|
||||
printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -628,20 +658,14 @@ static int adv7180_remove(struct i2c_client *client)
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
if (state->irq > 0) {
|
||||
free_irq(client->irq, state);
|
||||
if (cancel_work_sync(&state->work)) {
|
||||
/*
|
||||
* Work was pending, therefore we need to enable
|
||||
* IRQ here to balance the disable_irq() done in the
|
||||
* interrupt handler.
|
||||
*/
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
}
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
|
||||
if (state->irq > 0)
|
||||
free_irq(client->irq, state);
|
||||
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
adv7180_exit_controls(state);
|
||||
mutex_destroy(&state->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -654,13 +678,10 @@ static const struct i2c_device_id adv7180_id[] = {
|
||||
static int adv7180_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
|
||||
ADV7180_PWR_MAN_OFF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
return adv7180_set_power(state, client, false);
|
||||
}
|
||||
|
||||
static int adv7180_resume(struct device *dev)
|
||||
@@ -670,10 +691,11 @@ static int adv7180_resume(struct device *dev)
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
|
||||
ADV7180_PWR_MAN_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (state->powered) {
|
||||
ret = adv7180_set_power(state, client, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = init_device(client, state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@@ -597,7 +597,7 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
|
||||
static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct adv7511_state *state = get_adv7511_state(sd);
|
||||
|
||||
|
@@ -1658,7 +1658,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
|
||||
static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct adv7604_state *state = to_state(sd);
|
||||
u8 *data = NULL;
|
||||
@@ -1728,7 +1728,7 @@ static int get_edid_spa_location(const u8 *edid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
|
||||
static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct adv7604_state *state = to_state(sd);
|
||||
int spa_loc;
|
||||
|
@@ -546,6 +546,14 @@ static void main_reset(struct v4l2_subdev *sd)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline bool is_analog_input(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
|
||||
return ((state->mode == ADV7842_MODE_RGB) ||
|
||||
(state->mode == ADV7842_MODE_COMP));
|
||||
}
|
||||
|
||||
static inline bool is_digital_input(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
@@ -1027,12 +1035,72 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
|
||||
cp_write(sd, 0xac, (height & 0x0f) << 4);
|
||||
}
|
||||
|
||||
static void adv7842_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
u8 offset_buf[4];
|
||||
|
||||
if (auto_offset) {
|
||||
offset_a = 0x3ff;
|
||||
offset_b = 0x3ff;
|
||||
offset_c = 0x3ff;
|
||||
}
|
||||
|
||||
v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n",
|
||||
__func__, auto_offset ? "Auto" : "Manual",
|
||||
offset_a, offset_b, offset_c);
|
||||
|
||||
offset_buf[0]= (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4);
|
||||
offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6);
|
||||
offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8);
|
||||
offset_buf[3] = offset_c & 0x0ff;
|
||||
|
||||
/* Registers must be written in this order with no i2c access in between */
|
||||
if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf))
|
||||
v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
|
||||
}
|
||||
|
||||
static void adv7842_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
u8 gain_buf[4];
|
||||
u8 gain_man = 1;
|
||||
u8 agc_mode_man = 1;
|
||||
|
||||
if (auto_gain) {
|
||||
gain_man = 0;
|
||||
agc_mode_man = 0;
|
||||
gain_a = 0x100;
|
||||
gain_b = 0x100;
|
||||
gain_c = 0x100;
|
||||
}
|
||||
|
||||
v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n",
|
||||
__func__, auto_gain ? "Auto" : "Manual",
|
||||
gain_a, gain_b, gain_c);
|
||||
|
||||
gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4));
|
||||
gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6));
|
||||
gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8));
|
||||
gain_buf[3] = ((gain_c & 0x0ff));
|
||||
|
||||
/* Registers must be written in this order with no i2c access in between */
|
||||
if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf))
|
||||
v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
|
||||
}
|
||||
|
||||
static void set_rgb_quantization_range(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
bool rgb_output = io_read(sd, 0x02) & 0x02;
|
||||
bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
|
||||
|
||||
v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n",
|
||||
__func__, state->rgb_quantization_range);
|
||||
v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",
|
||||
__func__, state->rgb_quantization_range,
|
||||
rgb_output, hdmi_signal);
|
||||
|
||||
adv7842_set_gain(sd, true, 0x0, 0x0, 0x0);
|
||||
adv7842_set_offset(sd, true, 0x0, 0x0, 0x0);
|
||||
|
||||
switch (state->rgb_quantization_range) {
|
||||
case V4L2_DV_RGB_RANGE_AUTO:
|
||||
@@ -1050,7 +1118,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdmi_read(sd, 0x05) & 0x80) {
|
||||
if (hdmi_signal) {
|
||||
/* Receiving HDMI signal
|
||||
* Set automode */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0xf0);
|
||||
@@ -1066,24 +1134,45 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
|
||||
} else {
|
||||
/* RGB full range (0-255) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x10);
|
||||
|
||||
if (is_digital_input(sd) && rgb_output) {
|
||||
adv7842_set_offset(sd, false, 0x40, 0x40, 0x40);
|
||||
} else {
|
||||
adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
|
||||
adv7842_set_offset(sd, false, 0x70, 0x70, 0x70);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case V4L2_DV_RGB_RANGE_LIMITED:
|
||||
if (state->mode == ADV7842_MODE_COMP) {
|
||||
/* YCrCb limited range (16-235) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x20);
|
||||
} else {
|
||||
/* RGB limited range (16-235) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
/* RGB limited range (16-235) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x00);
|
||||
|
||||
break;
|
||||
case V4L2_DV_RGB_RANGE_FULL:
|
||||
if (state->mode == ADV7842_MODE_COMP) {
|
||||
/* YCrCb full range (0-255) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x60);
|
||||
break;
|
||||
}
|
||||
|
||||
/* RGB full range (0-255) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x10);
|
||||
|
||||
if (is_analog_input(sd) || hdmi_signal)
|
||||
break;
|
||||
|
||||
/* Adjust gain/offset for DVI-D signals only */
|
||||
if (rgb_output) {
|
||||
adv7842_set_offset(sd, false, 0x40, 0x40, 0x40);
|
||||
} else {
|
||||
/* RGB full range (0-255) */
|
||||
io_write_and_or(sd, 0x02, 0x0f, 0x10);
|
||||
adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
|
||||
adv7842_set_offset(sd, false, 0x70, 0x70, 0x70);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1360,12 +1449,11 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
|
||||
|
||||
bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
|
||||
bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
|
||||
freq = (hdmi_read(sd, 0x06) * 1000000) +
|
||||
((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
|
||||
|
||||
freq = ((hdmi_read(sd, 0x51) << 1) + (hdmi_read(sd, 0x52) >> 7)) * 1000000;
|
||||
freq += ((hdmi_read(sd, 0x52) & 0x7f) * 7813);
|
||||
if (is_hdmi(sd)) {
|
||||
/* adjust for deep color mode */
|
||||
freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8);
|
||||
freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 6) * 2 + 8);
|
||||
}
|
||||
bt->pixelclock = freq;
|
||||
bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
|
||||
@@ -1717,8 +1805,8 @@ static void select_input(struct v4l2_subdev *sd,
|
||||
* (rev. 2.5, June 2010)" p. 17. */
|
||||
afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */
|
||||
afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */
|
||||
cp_write(sd, 0x3e, 0x80); /* CP core pre-gain control,
|
||||
enable color control */
|
||||
cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */
|
||||
|
||||
/* CP coast control */
|
||||
cp_write(sd, 0xc3, 0x33); /* Component mode */
|
||||
|
||||
@@ -1926,7 +2014,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
|
||||
static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
u8 *data = NULL;
|
||||
@@ -1966,7 +2054,7 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e)
|
||||
static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
|
||||
{
|
||||
struct adv7842_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
@@ -2103,7 +2191,8 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
|
||||
{
|
||||
int i;
|
||||
uint8_t buf[14];
|
||||
uint8_t avi_inf_len;
|
||||
u8 avi_len;
|
||||
u8 avi_ver;
|
||||
struct avi_info_frame avi;
|
||||
|
||||
if (!(hdmi_read(sd, 0x05) & 0x80)) {
|
||||
@@ -2116,18 +2205,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
|
||||
}
|
||||
|
||||
if (io_read(sd, 0x88) & 0x10) {
|
||||
/* Note: the ADV7842 calculated incorrect checksums for InfoFrames
|
||||
with a length of 14 or 15. See the ADV7842 Register Settings
|
||||
Recommendations document for more details. */
|
||||
v4l2_info(sd, "AVI infoframe checksum error\n");
|
||||
return;
|
||||
v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n");
|
||||
io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
|
||||
if (io_read(sd, 0x88) & 0x10) {
|
||||
v4l2_info(sd, "AVI infoframe checksum error still present\n");
|
||||
io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
|
||||
}
|
||||
}
|
||||
|
||||
avi_inf_len = infoframe_read(sd, 0xe2);
|
||||
avi_len = infoframe_read(sd, 0xe2);
|
||||
avi_ver = infoframe_read(sd, 0xe1);
|
||||
v4l2_info(sd, "AVI infoframe version %d (%d byte)\n",
|
||||
infoframe_read(sd, 0xe1), avi_inf_len);
|
||||
avi_ver, avi_len);
|
||||
|
||||
if (infoframe_read(sd, 0xe1) != 0x02)
|
||||
if (avi_ver != 0x02)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
@@ -2602,9 +2693,15 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
|
||||
/* disable I2C access to internal EDID ram from HDMI DDC ports */
|
||||
rep_write_and_or(sd, 0x77, 0xf3, 0x00);
|
||||
|
||||
hdmi_write(sd, 0x69, 0xa3); /* HPA manual */
|
||||
/* HPA disable on port A and B */
|
||||
io_write_and_or(sd, 0x20, 0xcf, 0x00);
|
||||
if (pdata->hpa_auto) {
|
||||
/* HPA auto, HPA 0.5s after Edid set and Cable detect */
|
||||
hdmi_write(sd, 0x69, 0x5c);
|
||||
} else {
|
||||
/* HPA manual */
|
||||
hdmi_write(sd, 0x69, 0xa3);
|
||||
/* HPA disable on port A and B */
|
||||
io_write_and_or(sd, 0x20, 0xcf, 0x00);
|
||||
}
|
||||
|
||||
/* LLC */
|
||||
io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase);
|
||||
|
@@ -431,8 +431,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
* Initialize the other fields of rc_dev
|
||||
*/
|
||||
rc->map_name = ir->ir_codes;
|
||||
rc->allowed_protos = rc_type;
|
||||
rc->enabled_protocols = rc_type;
|
||||
rc_set_allowed_protocols(rc, rc_type);
|
||||
rc_set_enabled_protocols(rc, rc_type);
|
||||
if (!rc->driver_name)
|
||||
rc->driver_name = MODULE_NAME;
|
||||
|
||||
|
@@ -15,12 +15,6 @@
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@@ -42,7 +36,7 @@
|
||||
#define REG_FLAG 0xd0
|
||||
#define REG_CONFIG1 0xe0
|
||||
|
||||
/* Fault Mask */
|
||||
/* fault mask */
|
||||
#define FAULT_TIMEOUT (1<<0)
|
||||
#define FAULT_OVERTEMP (1<<1)
|
||||
#define FAULT_SHORT_CIRCUIT (1<<2)
|
||||
@@ -53,7 +47,8 @@ enum led_enable {
|
||||
MODE_FLASH = 0x3,
|
||||
};
|
||||
|
||||
/* struct lm3560_flash
|
||||
/**
|
||||
* struct lm3560_flash
|
||||
*
|
||||
* @pdata: platform data
|
||||
* @regmap: reg. map for i2c
|
||||
@@ -98,7 +93,7 @@ static int lm3560_mode_ctrl(struct lm3560_flash *flash)
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* led1/2 enable/disable */
|
||||
/* led1/2 enable/disable */
|
||||
static int lm3560_enable_ctrl(struct lm3560_flash *flash,
|
||||
enum lm3560_led_id led_no, bool on)
|
||||
{
|
||||
@@ -168,7 +163,7 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* V4L2 controls */
|
||||
/* v4l2 controls */
|
||||
static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
|
||||
{
|
||||
struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
|
||||
@@ -297,6 +292,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash,
|
||||
const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no];
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 8);
|
||||
|
||||
/* flash mode */
|
||||
v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
|
||||
V4L2_FLASH_LED_MODE_TORCH, ~0x7,
|
||||
@@ -309,6 +305,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash,
|
||||
|
||||
/* flash strobe */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
|
||||
|
||||
/* flash strobe stop */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
|
||||
|
||||
@@ -395,7 +392,7 @@ static int lm3560_init_device(struct lm3560_flash *flash)
|
||||
rval = lm3560_mode_ctrl(flash);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
/* Reset faults */
|
||||
/* reset faults */
|
||||
rval = regmap_read(flash->regmap, REG_FLAG, ®_val);
|
||||
return rval;
|
||||
}
|
||||
@@ -419,8 +416,7 @@ static int lm3560_probe(struct i2c_client *client,
|
||||
|
||||
/* if there is no platform data, use chip default value */
|
||||
if (pdata == NULL) {
|
||||
pdata =
|
||||
kzalloc(sizeof(struct lm3560_platform_data), GFP_KERNEL);
|
||||
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (pdata == NULL)
|
||||
return -ENODEV;
|
||||
pdata->peak = LM3560_PEAK_3600mA;
|
||||
|
414
drivers/media/i2c/lm3646.c
Normal file
414
drivers/media/i2c/lm3646.c
Normal file
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* drivers/media/i2c/lm3646.c
|
||||
* General device driver for TI lm3646, Dual FLASH LED Driver
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments
|
||||
*
|
||||
* Contact: Daniel Jeong <gshark.jeong@gmail.com>
|
||||
* Ldd-Mlp <ldd-mlp@list.ti.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.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/lm3646.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
/* registers definitions */
|
||||
#define REG_ENABLE 0x01
|
||||
#define REG_TORCH_BR 0x05
|
||||
#define REG_FLASH_BR 0x05
|
||||
#define REG_FLASH_TOUT 0x04
|
||||
#define REG_FLAG 0x08
|
||||
#define REG_STROBE_SRC 0x06
|
||||
#define REG_LED1_FLASH_BR 0x06
|
||||
#define REG_LED1_TORCH_BR 0x07
|
||||
|
||||
#define MASK_ENABLE 0x03
|
||||
#define MASK_TORCH_BR 0x70
|
||||
#define MASK_FLASH_BR 0x0F
|
||||
#define MASK_FLASH_TOUT 0x07
|
||||
#define MASK_FLAG 0xFF
|
||||
#define MASK_STROBE_SRC 0x80
|
||||
|
||||
/* Fault Mask */
|
||||
#define FAULT_TIMEOUT (1<<0)
|
||||
#define FAULT_SHORT_CIRCUIT (1<<1)
|
||||
#define FAULT_UVLO (1<<2)
|
||||
#define FAULT_IVFM (1<<3)
|
||||
#define FAULT_OCP (1<<4)
|
||||
#define FAULT_OVERTEMP (1<<5)
|
||||
#define FAULT_NTC_TRIP (1<<6)
|
||||
#define FAULT_OVP (1<<7)
|
||||
|
||||
enum led_mode {
|
||||
MODE_SHDN = 0x0,
|
||||
MODE_TORCH = 0x2,
|
||||
MODE_FLASH = 0x3,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lm3646_flash
|
||||
*
|
||||
* @pdata: platform data
|
||||
* @regmap: reg. map for i2c
|
||||
* @lock: muxtex for serial access.
|
||||
* @led_mode: V4L2 LED mode
|
||||
* @ctrls_led: V4L2 contols
|
||||
* @subdev_led: V4L2 subdev
|
||||
* @mode_reg : mode register value
|
||||
*/
|
||||
struct lm3646_flash {
|
||||
struct device *dev;
|
||||
struct lm3646_platform_data *pdata;
|
||||
struct regmap *regmap;
|
||||
|
||||
struct v4l2_ctrl_handler ctrls_led;
|
||||
struct v4l2_subdev subdev_led;
|
||||
|
||||
u8 mode_reg;
|
||||
};
|
||||
|
||||
#define to_lm3646_flash(_ctrl) \
|
||||
container_of(_ctrl->handler, struct lm3646_flash, ctrls_led)
|
||||
|
||||
/* enable mode control */
|
||||
static int lm3646_mode_ctrl(struct lm3646_flash *flash,
|
||||
enum v4l2_flash_led_mode led_mode)
|
||||
{
|
||||
switch (led_mode) {
|
||||
case V4L2_FLASH_LED_MODE_NONE:
|
||||
return regmap_write(flash->regmap,
|
||||
REG_ENABLE, flash->mode_reg | MODE_SHDN);
|
||||
case V4L2_FLASH_LED_MODE_TORCH:
|
||||
return regmap_write(flash->regmap,
|
||||
REG_ENABLE, flash->mode_reg | MODE_TORCH);
|
||||
case V4L2_FLASH_LED_MODE_FLASH:
|
||||
return regmap_write(flash->regmap,
|
||||
REG_ENABLE, flash->mode_reg | MODE_FLASH);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* V4L2 controls */
|
||||
static int lm3646_get_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct lm3646_flash *flash = to_lm3646_flash(ctrl);
|
||||
unsigned int reg_val;
|
||||
int rval;
|
||||
|
||||
if (ctrl->id != V4L2_CID_FLASH_FAULT)
|
||||
return -EINVAL;
|
||||
|
||||
rval = regmap_read(flash->regmap, REG_FLAG, ®_val);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
ctrl->val = 0;
|
||||
if (reg_val & FAULT_TIMEOUT)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_TIMEOUT;
|
||||
if (reg_val & FAULT_SHORT_CIRCUIT)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
|
||||
if (reg_val & FAULT_UVLO)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_UNDER_VOLTAGE;
|
||||
if (reg_val & FAULT_IVFM)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_INPUT_VOLTAGE;
|
||||
if (reg_val & FAULT_OCP)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_OVER_CURRENT;
|
||||
if (reg_val & FAULT_OVERTEMP)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
|
||||
if (reg_val & FAULT_NTC_TRIP)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE;
|
||||
if (reg_val & FAULT_OVP)
|
||||
ctrl->val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm3646_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct lm3646_flash *flash = to_lm3646_flash(ctrl);
|
||||
unsigned int reg_val;
|
||||
int rval = -EINVAL;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_FLASH_LED_MODE:
|
||||
|
||||
if (ctrl->val != V4L2_FLASH_LED_MODE_FLASH)
|
||||
return lm3646_mode_ctrl(flash, ctrl->val);
|
||||
/* switch to SHDN mode before flash strobe on */
|
||||
return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
|
||||
|
||||
case V4L2_CID_FLASH_STROBE_SOURCE:
|
||||
return regmap_update_bits(flash->regmap,
|
||||
REG_STROBE_SRC, MASK_STROBE_SRC,
|
||||
(ctrl->val) << 7);
|
||||
|
||||
case V4L2_CID_FLASH_STROBE:
|
||||
|
||||
/* read and check current mode of chip to start flash */
|
||||
rval = regmap_read(flash->regmap, REG_ENABLE, ®_val);
|
||||
if (rval < 0 || ((reg_val & MASK_ENABLE) != MODE_SHDN))
|
||||
return rval;
|
||||
/* flash on */
|
||||
return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_FLASH);
|
||||
|
||||
case V4L2_CID_FLASH_STROBE_STOP:
|
||||
|
||||
/*
|
||||
* flash mode will be turned automatically
|
||||
* from FLASH mode to SHDN mode after flash duration timeout
|
||||
* read and check current mode of chip to stop flash
|
||||
*/
|
||||
rval = regmap_read(flash->regmap, REG_ENABLE, ®_val);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
if ((reg_val & MASK_ENABLE) == MODE_FLASH)
|
||||
return lm3646_mode_ctrl(flash,
|
||||
V4L2_FLASH_LED_MODE_NONE);
|
||||
return rval;
|
||||
|
||||
case V4L2_CID_FLASH_TIMEOUT:
|
||||
return regmap_update_bits(flash->regmap,
|
||||
REG_FLASH_TOUT, MASK_FLASH_TOUT,
|
||||
LM3646_FLASH_TOUT_ms_TO_REG
|
||||
(ctrl->val));
|
||||
|
||||
case V4L2_CID_FLASH_INTENSITY:
|
||||
return regmap_update_bits(flash->regmap,
|
||||
REG_FLASH_BR, MASK_FLASH_BR,
|
||||
LM3646_TOTAL_FLASH_BRT_uA_TO_REG
|
||||
(ctrl->val));
|
||||
|
||||
case V4L2_CID_FLASH_TORCH_INTENSITY:
|
||||
return regmap_update_bits(flash->regmap,
|
||||
REG_TORCH_BR, MASK_TORCH_BR,
|
||||
LM3646_TOTAL_TORCH_BRT_uA_TO_REG
|
||||
(ctrl->val) << 4);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops lm3646_led_ctrl_ops = {
|
||||
.g_volatile_ctrl = lm3646_get_ctrl,
|
||||
.s_ctrl = lm3646_set_ctrl,
|
||||
};
|
||||
|
||||
static int lm3646_init_controls(struct lm3646_flash *flash)
|
||||
{
|
||||
struct v4l2_ctrl *fault;
|
||||
struct v4l2_ctrl_handler *hdl = &flash->ctrls_led;
|
||||
const struct v4l2_ctrl_ops *ops = &lm3646_led_ctrl_ops;
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 8);
|
||||
/* flash mode */
|
||||
v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
|
||||
V4L2_FLASH_LED_MODE_TORCH, ~0x7,
|
||||
V4L2_FLASH_LED_MODE_NONE);
|
||||
|
||||
/* flash source */
|
||||
v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE,
|
||||
0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
|
||||
|
||||
/* flash strobe */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
|
||||
/* flash strobe stop */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
|
||||
|
||||
/* flash strobe timeout */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,
|
||||
LM3646_FLASH_TOUT_MIN,
|
||||
LM3646_FLASH_TOUT_MAX,
|
||||
LM3646_FLASH_TOUT_STEP, flash->pdata->flash_timeout);
|
||||
|
||||
/* max flash current */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY,
|
||||
LM3646_TOTAL_FLASH_BRT_MIN,
|
||||
LM3646_TOTAL_FLASH_BRT_MAX,
|
||||
LM3646_TOTAL_FLASH_BRT_STEP,
|
||||
LM3646_TOTAL_FLASH_BRT_MAX);
|
||||
|
||||
/* max torch current */
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY,
|
||||
LM3646_TOTAL_TORCH_BRT_MIN,
|
||||
LM3646_TOTAL_TORCH_BRT_MAX,
|
||||
LM3646_TOTAL_TORCH_BRT_STEP,
|
||||
LM3646_TOTAL_TORCH_BRT_MAX);
|
||||
|
||||
/* fault */
|
||||
fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,
|
||||
V4L2_FLASH_FAULT_OVER_VOLTAGE
|
||||
| V4L2_FLASH_FAULT_OVER_TEMPERATURE
|
||||
| V4L2_FLASH_FAULT_SHORT_CIRCUIT
|
||||
| V4L2_FLASH_FAULT_TIMEOUT, 0, 0);
|
||||
if (fault != NULL)
|
||||
fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
|
||||
|
||||
if (hdl->error)
|
||||
return hdl->error;
|
||||
|
||||
flash->subdev_led.ctrl_handler = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize device */
|
||||
static const struct v4l2_subdev_ops lm3646_ops = {
|
||||
.core = NULL,
|
||||
};
|
||||
|
||||
static const struct regmap_config lm3646_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xFF,
|
||||
};
|
||||
|
||||
static int lm3646_subdev_init(struct lm3646_flash *flash)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(flash->dev);
|
||||
int rval;
|
||||
|
||||
v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops);
|
||||
flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
strcpy(flash->subdev_led.name, LM3646_NAME);
|
||||
rval = lm3646_init_controls(flash);
|
||||
if (rval)
|
||||
goto err_out;
|
||||
rval = media_entity_init(&flash->subdev_led.entity, 0, NULL, 0);
|
||||
if (rval < 0)
|
||||
goto err_out;
|
||||
flash->subdev_led.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
|
||||
return rval;
|
||||
|
||||
err_out:
|
||||
v4l2_ctrl_handler_free(&flash->ctrls_led);
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int lm3646_init_device(struct lm3646_flash *flash)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
int rval;
|
||||
|
||||
/* read the value of mode register to reduce redundant i2c accesses */
|
||||
rval = regmap_read(flash->regmap, REG_ENABLE, ®_val);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
flash->mode_reg = reg_val & 0xfc;
|
||||
|
||||
/* output disable */
|
||||
rval = lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
/*
|
||||
* LED1 flash current setting
|
||||
* LED2 flash current = Total(Max) flash current - LED1 flash current
|
||||
*/
|
||||
rval = regmap_update_bits(flash->regmap,
|
||||
REG_LED1_FLASH_BR, 0x7F,
|
||||
LM3646_LED1_FLASH_BRT_uA_TO_REG
|
||||
(flash->pdata->led1_flash_brt));
|
||||
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
/*
|
||||
* LED1 torch current setting
|
||||
* LED2 torch current = Total(Max) torch current - LED1 torch current
|
||||
*/
|
||||
rval = regmap_update_bits(flash->regmap,
|
||||
REG_LED1_TORCH_BR, 0x7F,
|
||||
LM3646_LED1_TORCH_BRT_uA_TO_REG
|
||||
(flash->pdata->led1_torch_brt));
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
/* Reset flag register */
|
||||
return regmap_read(flash->regmap, REG_FLAG, ®_val);
|
||||
}
|
||||
|
||||
static int lm3646_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *devid)
|
||||
{
|
||||
struct lm3646_flash *flash;
|
||||
struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
int rval;
|
||||
|
||||
flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (flash == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
flash->regmap = devm_regmap_init_i2c(client, &lm3646_regmap);
|
||||
if (IS_ERR(flash->regmap))
|
||||
return PTR_ERR(flash->regmap);
|
||||
|
||||
/* check device tree if there is no platform data */
|
||||
if (pdata == NULL) {
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct lm3646_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (pdata == NULL)
|
||||
return -ENOMEM;
|
||||
/* use default data in case of no platform data */
|
||||
pdata->flash_timeout = LM3646_FLASH_TOUT_MAX;
|
||||
pdata->led1_torch_brt = LM3646_LED1_TORCH_BRT_MAX;
|
||||
pdata->led1_flash_brt = LM3646_LED1_FLASH_BRT_MAX;
|
||||
}
|
||||
flash->pdata = pdata;
|
||||
flash->dev = &client->dev;
|
||||
|
||||
rval = lm3646_subdev_init(flash);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
rval = lm3646_init_device(flash);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
i2c_set_clientdata(client, flash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm3646_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm3646_flash *flash = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(&flash->subdev_led);
|
||||
v4l2_ctrl_handler_free(&flash->ctrls_led);
|
||||
media_entity_cleanup(&flash->subdev_led.entity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm3646_id_table[] = {
|
||||
{LM3646_NAME, 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, lm3646_id_table);
|
||||
|
||||
static struct i2c_driver lm3646_i2c_driver = {
|
||||
.driver = {
|
||||
.name = LM3646_NAME,
|
||||
},
|
||||
.probe = lm3646_probe,
|
||||
.remove = lm3646_remove,
|
||||
.id_table = lm3646_id_table,
|
||||
};
|
||||
|
||||
module_i2c_driver(lm3646_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
|
||||
MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
|
||||
MODULE_DESCRIPTION("Texas Instruments LM3646 Dual Flash LED driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -78,6 +78,9 @@
|
||||
#define MT9P031_PLL_CONFIG_1 0x11
|
||||
#define MT9P031_PLL_CONFIG_2 0x12
|
||||
#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
|
||||
#define MT9P031_PIXEL_CLOCK_INVERT (1 << 15)
|
||||
#define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8)
|
||||
#define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0)
|
||||
#define MT9P031_FRAME_RESTART 0x0b
|
||||
#define MT9P031_SHUTTER_DELAY 0x0c
|
||||
#define MT9P031_RST 0x0d
|
||||
@@ -130,6 +133,8 @@ struct mt9p031 {
|
||||
|
||||
enum mt9p031_model model;
|
||||
struct aptina_pll pll;
|
||||
unsigned int clk_div;
|
||||
bool use_pll;
|
||||
int reset;
|
||||
|
||||
struct v4l2_ctrl_handler ctrls;
|
||||
@@ -198,6 +203,11 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
|
||||
MT9P031_PIXEL_CLOCK_DIVIDE(mt9p031->clk_div));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
|
||||
0);
|
||||
}
|
||||
@@ -222,15 +232,34 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
|
||||
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
||||
struct mt9p031_platform_data *pdata = mt9p031->pdata;
|
||||
int ret;
|
||||
|
||||
mt9p031->clk = devm_clk_get(&client->dev, NULL);
|
||||
if (IS_ERR(mt9p031->clk))
|
||||
return PTR_ERR(mt9p031->clk);
|
||||
|
||||
clk_set_rate(mt9p031->clk, pdata->ext_freq);
|
||||
ret = clk_set_rate(mt9p031->clk, pdata->ext_freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* If the external clock frequency is out of bounds for the PLL use the
|
||||
* pixel clock divider only and disable the PLL.
|
||||
*/
|
||||
if (pdata->ext_freq > limits.ext_clock_max) {
|
||||
unsigned int div;
|
||||
|
||||
div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq);
|
||||
div = roundup_pow_of_two(div) / 2;
|
||||
|
||||
mt9p031->clk_div = max_t(unsigned int, div, 64);
|
||||
mt9p031->use_pll = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
mt9p031->pll.ext_clock = pdata->ext_freq;
|
||||
mt9p031->pll.pix_clock = pdata->target_freq;
|
||||
mt9p031->use_pll = true;
|
||||
|
||||
return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
|
||||
}
|
||||
@@ -240,6 +269,9 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
||||
int ret;
|
||||
|
||||
if (!mt9p031->use_pll)
|
||||
return 0;
|
||||
|
||||
ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
|
||||
MT9P031_PLL_CONTROL_PWRON);
|
||||
if (ret < 0)
|
||||
@@ -265,6 +297,9 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
||||
|
||||
if (!mt9p031->use_pll)
|
||||
return 0;
|
||||
|
||||
return mt9p031_write(client, MT9P031_PLL_CONTROL,
|
||||
MT9P031_PLL_CONTROL_PWROFF);
|
||||
}
|
||||
@@ -285,9 +320,15 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Emable clock */
|
||||
if (mt9p031->clk)
|
||||
clk_prepare_enable(mt9p031->clk);
|
||||
/* Enable clock */
|
||||
if (mt9p031->clk) {
|
||||
ret = clk_prepare_enable(mt9p031->clk);
|
||||
if (ret) {
|
||||
regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
|
||||
mt9p031->regulators);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now RESET_BAR must be high */
|
||||
if (gpio_is_valid(mt9p031->reset)) {
|
||||
|
@@ -12,9 +12,11 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/v4l2-mediabus.h>
|
||||
@@ -55,6 +57,7 @@
|
||||
#define MT9T001_OUTPUT_CONTROL_SYNC (1 << 0)
|
||||
#define MT9T001_OUTPUT_CONTROL_CHIP_ENABLE (1 << 1)
|
||||
#define MT9T001_OUTPUT_CONTROL_TEST_DATA (1 << 6)
|
||||
#define MT9T001_OUTPUT_CONTROL_DEF 0x0002
|
||||
#define MT9T001_SHUTTER_WIDTH_HIGH 0x08
|
||||
#define MT9T001_SHUTTER_WIDTH_LOW 0x09
|
||||
#define MT9T001_SHUTTER_WIDTH_MIN 1
|
||||
@@ -116,6 +119,12 @@ struct mt9t001 {
|
||||
struct v4l2_subdev subdev;
|
||||
struct media_pad pad;
|
||||
|
||||
struct clk *clk;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
|
||||
struct mutex power_lock; /* lock to protect power_count */
|
||||
int power_count;
|
||||
|
||||
struct v4l2_mbus_framefmt format;
|
||||
struct v4l2_rect crop;
|
||||
|
||||
@@ -159,6 +168,77 @@ static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9t001_reset(struct mt9t001 *mt9t001)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
|
||||
int ret;
|
||||
|
||||
/* Reset the chip and stop data read out */
|
||||
ret = mt9t001_write(client, MT9T001_RESET, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt9t001_write(client, MT9T001_RESET, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
|
||||
|
||||
return mt9t001_set_output_control(mt9t001,
|
||||
MT9T001_OUTPUT_CONTROL_CHIP_ENABLE,
|
||||
0);
|
||||
}
|
||||
|
||||
static int mt9t001_power_on(struct mt9t001 *mt9t001)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Bring up the supplies */
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(mt9t001->regulators),
|
||||
mt9t001->regulators);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable clock */
|
||||
ret = clk_prepare_enable(mt9t001->clk);
|
||||
if (ret < 0)
|
||||
regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
|
||||
mt9t001->regulators);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mt9t001_power_off(struct mt9t001 *mt9t001)
|
||||
{
|
||||
regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
|
||||
mt9t001->regulators);
|
||||
|
||||
clk_disable_unprepare(mt9t001->clk);
|
||||
}
|
||||
|
||||
static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
|
||||
int ret;
|
||||
|
||||
if (!on) {
|
||||
mt9t001_power_off(mt9t001);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = mt9t001_power_on(mt9t001);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt9t001_reset(mt9t001);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failed to reset the camera\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return v4l2_ctrl_handler_setup(&mt9t001->ctrls);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 subdev video operations
|
||||
*/
|
||||
@@ -195,6 +275,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE;
|
||||
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
||||
struct mt9t001_platform_data *pdata = client->dev.platform_data;
|
||||
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
|
||||
struct v4l2_mbus_framefmt *format = &mt9t001->format;
|
||||
struct v4l2_rect *crop = &mt9t001->crop;
|
||||
@@ -205,6 +286,14 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
if (!enable)
|
||||
return mt9t001_set_output_control(mt9t001, mode, 0);
|
||||
|
||||
/* Configure the pixel clock polarity */
|
||||
if (pdata->clk_pol) {
|
||||
ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
|
||||
MT9T001_PIXEL_CLOCK_INVERT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure the window size and row/column bin */
|
||||
hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
|
||||
vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
|
||||
@@ -629,10 +718,68 @@ static const struct v4l2_ctrl_config mt9t001_gains[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 subdev core operations
|
||||
*/
|
||||
|
||||
static int mt9t001_set_power(struct v4l2_subdev *subdev, int on)
|
||||
{
|
||||
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&mt9t001->power_lock);
|
||||
|
||||
/* If the power count is modified from 0 to != 0 or from != 0 to 0,
|
||||
* update the power state.
|
||||
*/
|
||||
if (mt9t001->power_count == !on) {
|
||||
ret = __mt9t001_set_power(mt9t001, !!on);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update the power count. */
|
||||
mt9t001->power_count += on ? 1 : -1;
|
||||
WARN_ON(mt9t001->power_count < 0);
|
||||
|
||||
out:
|
||||
mutex_unlock(&mt9t001->power_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 subdev internal operations
|
||||
*/
|
||||
|
||||
static int mt9t001_registered(struct v4l2_subdev *subdev)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
||||
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
|
||||
s32 data;
|
||||
int ret;
|
||||
|
||||
ret = mt9t001_power_on(mt9t001);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "MT9T001 power up failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read out the chip version register */
|
||||
data = mt9t001_read(client, MT9T001_CHIP_VERSION);
|
||||
mt9t001_power_off(mt9t001);
|
||||
|
||||
if (data != MT9T001_CHIP_ID) {
|
||||
dev_err(&client->dev,
|
||||
"MT9T001 not detected, wrong version 0x%04x\n", data);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
|
||||
client->addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
@@ -651,9 +798,18 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
format->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
|
||||
return 0;
|
||||
return mt9t001_set_power(subdev, 1);
|
||||
}
|
||||
|
||||
static int mt9t001_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
return mt9t001_set_power(subdev, 0);
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = {
|
||||
.s_power = mt9t001_set_power,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = {
|
||||
.s_stream = mt9t001_s_stream,
|
||||
};
|
||||
@@ -668,58 +824,17 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops mt9t001_subdev_ops = {
|
||||
.core = &mt9t001_subdev_core_ops,
|
||||
.video = &mt9t001_subdev_video_ops,
|
||||
.pad = &mt9t001_subdev_pad_ops,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
|
||||
.registered = mt9t001_registered,
|
||||
.open = mt9t001_open,
|
||||
.close = mt9t001_close,
|
||||
};
|
||||
|
||||
static int mt9t001_video_probe(struct i2c_client *client)
|
||||
{
|
||||
struct mt9t001_platform_data *pdata = client->dev.platform_data;
|
||||
s32 data;
|
||||
int ret;
|
||||
|
||||
dev_info(&client->dev, "Probing MT9T001 at address 0x%02x\n",
|
||||
client->addr);
|
||||
|
||||
/* Reset the chip and stop data read out */
|
||||
ret = mt9t001_write(client, MT9T001_RESET, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt9t001_write(client, MT9T001_RESET, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the pixel clock polarity */
|
||||
if (pdata->clk_pol) {
|
||||
ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
|
||||
MT9T001_PIXEL_CLOCK_INVERT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read and check the sensor version */
|
||||
data = mt9t001_read(client, MT9T001_CHIP_VERSION);
|
||||
if (data != MT9T001_CHIP_ID) {
|
||||
dev_err(&client->dev, "MT9T001 not detected, wrong version "
|
||||
"0x%04x\n", data);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
|
||||
client->addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9t001_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *did)
|
||||
{
|
||||
@@ -740,14 +855,28 @@ static int mt9t001_probe(struct i2c_client *client,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = mt9t001_video_probe(client);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL);
|
||||
if (!mt9t001)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&mt9t001->power_lock);
|
||||
mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
|
||||
|
||||
mt9t001->regulators[0].supply = "vdd";
|
||||
mt9t001->regulators[1].supply = "vaa";
|
||||
|
||||
ret = devm_regulator_bulk_get(&client->dev, 2, mt9t001->regulators);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Unable to get regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mt9t001->clk = devm_clk_get(&client->dev, NULL);
|
||||
if (IS_ERR(mt9t001->clk)) {
|
||||
dev_err(&client->dev, "Unable to get clock\n");
|
||||
return PTR_ERR(mt9t001->clk);
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
|
||||
ARRAY_SIZE(mt9t001_gains) + 4);
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
|
||||
*
|
||||
* Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
|
||||
* Copyright (c) 2009 Mauro Carvalho Chehab
|
||||
* This code is placed under the terms of the GNU General Public License v2
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <media/mt9v011.h>
|
||||
|
||||
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
|
@@ -317,8 +317,14 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
||||
int ret;
|
||||
|
||||
clk_set_rate(mt9v032->clk, mt9v032->sysclk);
|
||||
clk_prepare_enable(mt9v032->clk);
|
||||
ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(mt9v032->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
udelay(1);
|
||||
|
||||
/* Reset the chip and stop data read out */
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* and HeungJun Kim <riverful.kim@samsung.com>.
|
||||
*
|
||||
* Based on mt9v011 Micron Digital Image Sensor driver
|
||||
* Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
|
||||
* Copyright (c) 2009 Mauro Carvalho Chehab
|
||||
*
|
||||
* 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
|
||||
|
@@ -217,8 +217,8 @@ static void ths8200_core_init(struct v4l2_subdev *sd)
|
||||
/* Disable embedded syncs on the output by setting
|
||||
* the amplitude to zero for all channels.
|
||||
*/
|
||||
ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x2a);
|
||||
ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x2a);
|
||||
ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x00);
|
||||
ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x00);
|
||||
}
|
||||
|
||||
static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
|
||||
@@ -318,15 +318,15 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
|
||||
(htotal(bt) >> 8) & 0x1f);
|
||||
ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, htotal(bt));
|
||||
|
||||
/* v sync width transmitted */
|
||||
ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync) & 0xff);
|
||||
/* v sync width transmitted (must add 1 to get correct output) */
|
||||
ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync + 1) & 0xff);
|
||||
ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0x3f,
|
||||
((bt->vsync) >> 2) & 0xc0);
|
||||
((bt->vsync + 1) >> 2) & 0xc0);
|
||||
|
||||
/* The pixel value v sync is asserted on */
|
||||
/* The pixel value v sync is asserted on (must add 1 to get correct output) */
|
||||
ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0xf8,
|
||||
(vtotal(bt)>>8) & 0x7);
|
||||
ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt));
|
||||
((vtotal(bt) + 1) >> 8) & 0x7);
|
||||
ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt) + 1);
|
||||
|
||||
/* For progressive video vlength2 must be set to all 0 and vdly2 must
|
||||
* be set to all 1.
|
||||
@@ -336,11 +336,11 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
|
||||
ths8200_write(sd, THS8200_DTG2_VDLY2_LSB, 0xff);
|
||||
|
||||
/* Internal delay factors to synchronize the sync pulses and the data */
|
||||
/* Experimental values delays (hor 4, ver 1) */
|
||||
ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, (htotal(bt)>>8) & 0x1f);
|
||||
ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, (htotal(bt) - 4) & 0xff);
|
||||
/* Experimental values delays (hor 0, ver 0) */
|
||||
ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, 0);
|
||||
ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, 0);
|
||||
ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_MSB, 0);
|
||||
ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 1);
|
||||
ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 0);
|
||||
|
||||
/* Polarity of received and transmitted sync signals */
|
||||
if (bt->polarities & V4L2_DV_HSYNC_POS_POL) {
|
||||
@@ -356,7 +356,7 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
|
||||
/* Timing of video input bus is derived from HS, VS, and FID dedicated
|
||||
* inputs
|
||||
*/
|
||||
ths8200_write(sd, THS8200_DTG2_CNTL, 0x47 | polarity);
|
||||
ths8200_write(sd, THS8200_DTG2_CNTL, 0x44 | polarity);
|
||||
|
||||
/* leave reset */
|
||||
ths8200_s_stream(sd, true);
|
||||
|
@@ -16,9 +16,9 @@
|
||||
|
||||
#include "tvp5150_reg.h"
|
||||
|
||||
#define TVP5150_H_MAX 720
|
||||
#define TVP5150_V_MAX_525_60 480
|
||||
#define TVP5150_V_MAX_OTHERS 576
|
||||
#define TVP5150_H_MAX 720U
|
||||
#define TVP5150_V_MAX_525_60 480U
|
||||
#define TVP5150_V_MAX_OTHERS 576U
|
||||
#define TVP5150_MAX_CROP_LEFT 511
|
||||
#define TVP5150_MAX_CROP_TOP 127
|
||||
#define TVP5150_CROP_SHIFT 2
|
||||
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-2)");
|
||||
|
||||
struct tvp5150 {
|
||||
|
Reference in New Issue
Block a user