linux/drivers/media/i2c/upd64031a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * upd64031A - NEC Electronics Ghost Reduction for NTSC in Japan
   4 *
   5 * 2003 by T.Adachi <tadachi@tadachi-net.com>
   6 * 2003 by Takeru KOMORIYA <komoriya@paken.org>
   7 * 2006 by Hans Verkuil <hverkuil@xs4all.nl>
   8 */
   9
  10
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/i2c.h>
  14#include <linux/videodev2.h>
  15#include <linux/slab.h>
  16#include <media/v4l2-device.h>
  17#include <media/i2c/upd64031a.h>
  18
  19/* --------------------- read registers functions define -------------------- */
  20
  21/* bit masks */
  22#define GR_MODE_MASK              0xc0
  23#define DIRECT_3DYCS_CONNECT_MASK 0xc0
  24#define SYNC_CIRCUIT_MASK         0xa0
  25
  26/* -------------------------------------------------------------------------- */
  27
  28MODULE_DESCRIPTION("uPD64031A driver");
  29MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
  30MODULE_LICENSE("GPL");
  31
  32static int debug;
  33module_param(debug, int, 0644);
  34
  35MODULE_PARM_DESC(debug, "Debug level (0-1)");
  36
  37
  38enum {
  39        R00 = 0, R01, R02, R03, R04,
  40        R05, R06, R07, R08, R09,
  41        R0A, R0B, R0C, R0D, R0E, R0F,
  42        /* unused registers
  43         R10, R11, R12, R13, R14,
  44         R15, R16, R17,
  45         */
  46        TOT_REGS
  47};
  48
  49struct upd64031a_state {
  50        struct v4l2_subdev sd;
  51        u8 regs[TOT_REGS];
  52        u8 gr_mode;
  53        u8 direct_3dycs_connect;
  54        u8 ext_comp_sync;
  55        u8 ext_vert_sync;
  56};
  57
  58static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd)
  59{
  60        return container_of(sd, struct upd64031a_state, sd);
  61}
  62
  63static u8 upd64031a_init[] = {
  64        0x00, 0xb8, 0x48, 0xd2, 0xe6,
  65        0x03, 0x10, 0x0b, 0xaf, 0x7f,
  66        0x00, 0x00, 0x1d, 0x5e, 0x00,
  67        0xd0
  68};
  69
  70/* ------------------------------------------------------------------------ */
  71
  72static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg)
  73{
  74        struct i2c_client *client = v4l2_get_subdevdata(sd);
  75        u8 buf[2];
  76
  77        if (reg >= sizeof(buf))
  78                return 0xff;
  79        i2c_master_recv(client, buf, 2);
  80        return buf[reg];
  81}
  82
  83/* ------------------------------------------------------------------------ */
  84
  85static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
  86{
  87        struct i2c_client *client = v4l2_get_subdevdata(sd);
  88        u8 buf[2];
  89
  90        buf[0] = reg;
  91        buf[1] = val;
  92        v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val);
  93        if (i2c_master_send(client, buf, 2) != 2)
  94                v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
  95}
  96
  97/* ------------------------------------------------------------------------ */
  98
  99/* The input changed due to new input or channel changed */
 100static int upd64031a_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
 101{
 102        struct upd64031a_state *state = to_state(sd);
 103        u8 reg = state->regs[R00];
 104
 105        v4l2_dbg(1, debug, sd, "changed input or channel\n");
 106        upd64031a_write(sd, R00, reg | 0x10);
 107        upd64031a_write(sd, R00, reg & ~0x10);
 108        return 0;
 109}
 110
 111/* ------------------------------------------------------------------------ */
 112
 113static int upd64031a_s_routing(struct v4l2_subdev *sd,
 114                               u32 input, u32 output, u32 config)
 115{
 116        struct upd64031a_state *state = to_state(sd);
 117        u8 r00, r05, r08;
 118
 119        state->gr_mode = (input & 3) << 6;
 120        state->direct_3dycs_connect = (input & 0xc) << 4;
 121        state->ext_comp_sync =
 122                (input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
 123        state->ext_vert_sync =
 124                (input & UPD64031A_VERTICAL_EXTERNAL) << 2;
 125        r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
 126        r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
 127                state->ext_comp_sync | state->ext_vert_sync;
 128        r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
 129                state->direct_3dycs_connect;
 130        upd64031a_write(sd, R00, r00);
 131        upd64031a_write(sd, R05, r05);
 132        upd64031a_write(sd, R08, r08);
 133        return upd64031a_s_frequency(sd, NULL);
 134}
 135
 136static int upd64031a_log_status(struct v4l2_subdev *sd)
 137{
 138        v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
 139                        upd64031a_read(sd, 0), upd64031a_read(sd, 1));
 140        return 0;
 141}
 142
 143#ifdef CONFIG_VIDEO_ADV_DEBUG
 144static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 145{
 146        reg->val = upd64031a_read(sd, reg->reg & 0xff);
 147        reg->size = 1;
 148        return 0;
 149}
 150
 151static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 152{
 153        upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
 154        return 0;
 155}
 156#endif
 157
 158/* ----------------------------------------------------------------------- */
 159
 160static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
 161        .log_status = upd64031a_log_status,
 162#ifdef CONFIG_VIDEO_ADV_DEBUG
 163        .g_register = upd64031a_g_register,
 164        .s_register = upd64031a_s_register,
 165#endif
 166};
 167
 168static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = {
 169        .s_frequency = upd64031a_s_frequency,
 170};
 171
 172static const struct v4l2_subdev_video_ops upd64031a_video_ops = {
 173        .s_routing = upd64031a_s_routing,
 174};
 175
 176static const struct v4l2_subdev_ops upd64031a_ops = {
 177        .core = &upd64031a_core_ops,
 178        .tuner = &upd64031a_tuner_ops,
 179        .video = &upd64031a_video_ops,
 180};
 181
 182/* ------------------------------------------------------------------------ */
 183
 184/* i2c implementation */
 185
 186static int upd64031a_probe(struct i2c_client *client,
 187                           const struct i2c_device_id *id)
 188{
 189        struct upd64031a_state *state;
 190        struct v4l2_subdev *sd;
 191        int i;
 192
 193        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 194                return -EIO;
 195
 196        v4l_info(client, "chip found @ 0x%x (%s)\n",
 197                        client->addr << 1, client->adapter->name);
 198
 199        state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
 200        if (state == NULL)
 201                return -ENOMEM;
 202        sd = &state->sd;
 203        v4l2_i2c_subdev_init(sd, client, &upd64031a_ops);
 204        memcpy(state->regs, upd64031a_init, sizeof(state->regs));
 205        state->gr_mode = UPD64031A_GR_ON << 6;
 206        state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
 207        state->ext_comp_sync = state->ext_vert_sync = 0;
 208        for (i = 0; i < TOT_REGS; i++)
 209                upd64031a_write(sd, i, state->regs[i]);
 210        return 0;
 211}
 212
 213static int upd64031a_remove(struct i2c_client *client)
 214{
 215        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 216
 217        v4l2_device_unregister_subdev(sd);
 218        return 0;
 219}
 220
 221/* ----------------------------------------------------------------------- */
 222
 223static const struct i2c_device_id upd64031a_id[] = {
 224        { "upd64031a", 0 },
 225        { }
 226};
 227MODULE_DEVICE_TABLE(i2c, upd64031a_id);
 228
 229static struct i2c_driver upd64031a_driver = {
 230        .driver = {
 231                .name   = "upd64031a",
 232        },
 233        .probe          = upd64031a_probe,
 234        .remove         = upd64031a_remove,
 235        .id_table       = upd64031a_id,
 236};
 237
 238module_i2c_driver(upd64031a_driver);
 239