root/drivers/media/spi/gs1662.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gs_read_register
  2. gs_write_register
  3. gs_g_register
  4. gs_s_register
  5. gs_status_format
  6. get_register_timings
  7. to_gs
  8. gs_s_dv_timings
  9. gs_g_dv_timings
  10. gs_query_dv_timings
  11. gs_enum_dv_timings
  12. gs_s_stream
  13. gs_g_input_status
  14. gs_dv_timings_cap
  15. gs_probe
  16. gs_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * GS1662 device registration.
   4  *
   5  * Copyright (C) 2015-2016 Nexvision
   6  * Author: Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/init.h>
  11 #include <linux/spi/spi.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/ctype.h>
  14 #include <linux/err.h>
  15 #include <linux/device.h>
  16 #include <linux/module.h>
  17 
  18 #include <linux/videodev2.h>
  19 #include <media/v4l2-common.h>
  20 #include <media/v4l2-ctrls.h>
  21 #include <media/v4l2-device.h>
  22 #include <media/v4l2-subdev.h>
  23 #include <media/v4l2-dv-timings.h>
  24 #include <linux/v4l2-dv-timings.h>
  25 
  26 #define REG_STATUS                      0x04
  27 #define REG_FORCE_FMT                   0x06
  28 #define REG_LINES_PER_FRAME             0x12
  29 #define REG_WORDS_PER_LINE              0x13
  30 #define REG_WORDS_PER_ACT_LINE          0x14
  31 #define REG_ACT_LINES_PER_FRAME 0x15
  32 
  33 #define MASK_H_LOCK                     0x001
  34 #define MASK_V_LOCK                     0x002
  35 #define MASK_STD_LOCK                   0x004
  36 #define MASK_FORCE_STD                  0x020
  37 #define MASK_STD_STATUS         0x3E0
  38 
  39 #define GS_WIDTH_MIN                    720
  40 #define GS_WIDTH_MAX                    2048
  41 #define GS_HEIGHT_MIN                   487
  42 #define GS_HEIGHT_MAX                   1080
  43 #define GS_PIXELCLOCK_MIN               10519200
  44 #define GS_PIXELCLOCK_MAX               74250000
  45 
  46 struct gs {
  47         struct spi_device *pdev;
  48         struct v4l2_subdev sd;
  49         struct v4l2_dv_timings current_timings;
  50         int enabled;
  51 };
  52 
  53 struct gs_reg_fmt {
  54         u16 reg_value;
  55         struct v4l2_dv_timings format;
  56 };
  57 
  58 struct gs_reg_fmt_custom {
  59         u16 reg_value;
  60         __u32 width;
  61         __u32 height;
  62         __u64 pixelclock;
  63         __u32 interlaced;
  64 };
  65 
  66 static const struct spi_device_id gs_id[] = {
  67         { "gs1662", 0 },
  68         { }
  69 };
  70 MODULE_DEVICE_TABLE(spi, gs_id);
  71 
  72 static const struct v4l2_dv_timings fmt_cap[] = {
  73         V4L2_DV_BT_SDI_720X487I60,
  74         V4L2_DV_BT_CEA_720X576P50,
  75         V4L2_DV_BT_CEA_1280X720P24,
  76         V4L2_DV_BT_CEA_1280X720P25,
  77         V4L2_DV_BT_CEA_1280X720P30,
  78         V4L2_DV_BT_CEA_1280X720P50,
  79         V4L2_DV_BT_CEA_1280X720P60,
  80         V4L2_DV_BT_CEA_1920X1080P24,
  81         V4L2_DV_BT_CEA_1920X1080P25,
  82         V4L2_DV_BT_CEA_1920X1080P30,
  83         V4L2_DV_BT_CEA_1920X1080I50,
  84         V4L2_DV_BT_CEA_1920X1080I60,
  85 };
  86 
  87 static const struct gs_reg_fmt reg_fmt[] = {
  88         { 0x00, V4L2_DV_BT_CEA_1280X720P60 },
  89         { 0x01, V4L2_DV_BT_CEA_1280X720P60 },
  90         { 0x02, V4L2_DV_BT_CEA_1280X720P30 },
  91         { 0x03, V4L2_DV_BT_CEA_1280X720P30 },
  92         { 0x04, V4L2_DV_BT_CEA_1280X720P50 },
  93         { 0x05, V4L2_DV_BT_CEA_1280X720P50 },
  94         { 0x06, V4L2_DV_BT_CEA_1280X720P25 },
  95         { 0x07, V4L2_DV_BT_CEA_1280X720P25 },
  96         { 0x08, V4L2_DV_BT_CEA_1280X720P24 },
  97         { 0x09, V4L2_DV_BT_CEA_1280X720P24 },
  98         { 0x0A, V4L2_DV_BT_CEA_1920X1080I60 },
  99         { 0x0B, V4L2_DV_BT_CEA_1920X1080P30 },
 100 
 101         /* Default value: keep this field before 0xC */
 102         { 0x14, V4L2_DV_BT_CEA_1920X1080I50 },
 103         { 0x0C, V4L2_DV_BT_CEA_1920X1080I50 },
 104         { 0x0D, V4L2_DV_BT_CEA_1920X1080P25 },
 105         { 0x0E, V4L2_DV_BT_CEA_1920X1080P25 },
 106         { 0x10, V4L2_DV_BT_CEA_1920X1080P24 },
 107         { 0x12, V4L2_DV_BT_CEA_1920X1080P24 },
 108         { 0x16, V4L2_DV_BT_SDI_720X487I60 },
 109         { 0x19, V4L2_DV_BT_SDI_720X487I60 },
 110         { 0x18, V4L2_DV_BT_CEA_720X576P50 },
 111         { 0x1A, V4L2_DV_BT_CEA_720X576P50 },
 112 
 113         /* Implement following timings before enable it.
 114          * Because of we don't have access to these theoretical timings yet.
 115          * Workaround: use functions to get and set registers for these formats.
 116          */
 117 #if 0
 118         { 0x0F, V4L2_DV_BT_XXX_1920X1080I25 }, /* SMPTE 274M */
 119         { 0x11, V4L2_DV_BT_XXX_1920X1080I24 }, /* SMPTE 274M */
 120         { 0x13, V4L2_DV_BT_XXX_1920X1080I25 }, /* SMPTE 274M */
 121         { 0x15, V4L2_DV_BT_XXX_1920X1035I60 }, /* SMPTE 260M */
 122         { 0x17, V4L2_DV_BT_SDI_720X507I60 }, /* SMPTE 125M */
 123         { 0x1B, V4L2_DV_BT_SDI_720X507I60 }, /* SMPTE 125M */
 124         { 0x1C, V4L2_DV_BT_XXX_2048X1080P25 }, /* SMPTE 428.1M */
 125 #endif
 126 };
 127 
 128 static const struct v4l2_dv_timings_cap gs_timings_cap = {
 129         .type = V4L2_DV_BT_656_1120,
 130         /* keep this initialization for compatibility with GCC < 4.4.6 */
 131         .reserved = { 0 },
 132         V4L2_INIT_BT_TIMINGS(GS_WIDTH_MIN, GS_WIDTH_MAX, GS_HEIGHT_MIN,
 133                              GS_HEIGHT_MAX, GS_PIXELCLOCK_MIN,
 134                              GS_PIXELCLOCK_MAX,
 135                              V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_SDI,
 136                              V4L2_DV_BT_CAP_PROGRESSIVE
 137                              | V4L2_DV_BT_CAP_INTERLACED)
 138 };
 139 
 140 static int gs_read_register(struct spi_device *spi, u16 addr, u16 *value)
 141 {
 142         int ret;
 143         u16 buf_addr = (0x8000 | (0x0FFF & addr));
 144         u16 buf_value = 0;
 145         struct spi_message msg;
 146         struct spi_transfer tx[] = {
 147                 {
 148                         .tx_buf = &buf_addr,
 149                         .len = 2,
 150                         .delay_usecs = 1,
 151                 }, {
 152                         .rx_buf = &buf_value,
 153                         .len = 2,
 154                         .delay_usecs = 1,
 155                 },
 156         };
 157 
 158         spi_message_init(&msg);
 159         spi_message_add_tail(&tx[0], &msg);
 160         spi_message_add_tail(&tx[1], &msg);
 161         ret = spi_sync(spi, &msg);
 162 
 163         *value = buf_value;
 164 
 165         return ret;
 166 }
 167 
 168 static int gs_write_register(struct spi_device *spi, u16 addr, u16 value)
 169 {
 170         int ret;
 171         u16 buf_addr = addr;
 172         u16 buf_value = value;
 173         struct spi_message msg;
 174         struct spi_transfer tx[] = {
 175                 {
 176                         .tx_buf = &buf_addr,
 177                         .len = 2,
 178                         .delay_usecs = 1,
 179                 }, {
 180                         .tx_buf = &buf_value,
 181                         .len = 2,
 182                         .delay_usecs = 1,
 183                 },
 184         };
 185 
 186         spi_message_init(&msg);
 187         spi_message_add_tail(&tx[0], &msg);
 188         spi_message_add_tail(&tx[1], &msg);
 189         ret = spi_sync(spi, &msg);
 190 
 191         return ret;
 192 }
 193 
 194 #ifdef CONFIG_VIDEO_ADV_DEBUG
 195 static int gs_g_register(struct v4l2_subdev *sd,
 196                   struct v4l2_dbg_register *reg)
 197 {
 198         struct spi_device *spi = v4l2_get_subdevdata(sd);
 199         u16 val;
 200         int ret;
 201 
 202         ret = gs_read_register(spi, reg->reg & 0xFFFF, &val);
 203         reg->val = val;
 204         reg->size = 2;
 205         return ret;
 206 }
 207 
 208 static int gs_s_register(struct v4l2_subdev *sd,
 209                   const struct v4l2_dbg_register *reg)
 210 {
 211         struct spi_device *spi = v4l2_get_subdevdata(sd);
 212 
 213         return gs_write_register(spi, reg->reg & 0xFFFF, reg->val & 0xFFFF);
 214 }
 215 #endif
 216 
 217 static int gs_status_format(u16 status, struct v4l2_dv_timings *timings)
 218 {
 219         int std = (status & MASK_STD_STATUS) >> 5;
 220         int i;
 221 
 222         for (i = 0; i < ARRAY_SIZE(reg_fmt); i++) {
 223                 if (reg_fmt[i].reg_value == std) {
 224                         *timings = reg_fmt[i].format;
 225                         return 0;
 226                 }
 227         }
 228 
 229         return -ERANGE;
 230 }
 231 
 232 static u16 get_register_timings(struct v4l2_dv_timings *timings)
 233 {
 234         int i;
 235 
 236         for (i = 0; i < ARRAY_SIZE(reg_fmt); i++) {
 237                 if (v4l2_match_dv_timings(timings, &reg_fmt[i].format, 0,
 238                                           false))
 239                         return reg_fmt[i].reg_value | MASK_FORCE_STD;
 240         }
 241 
 242         return 0x0;
 243 }
 244 
 245 static inline struct gs *to_gs(struct v4l2_subdev *sd)
 246 {
 247         return container_of(sd, struct gs, sd);
 248 }
 249 
 250 static int gs_s_dv_timings(struct v4l2_subdev *sd,
 251                     struct v4l2_dv_timings *timings)
 252 {
 253         struct gs *gs = to_gs(sd);
 254         int reg_value;
 255 
 256         reg_value = get_register_timings(timings);
 257         if (reg_value == 0x0)
 258                 return -EINVAL;
 259 
 260         gs->current_timings = *timings;
 261         return 0;
 262 }
 263 
 264 static int gs_g_dv_timings(struct v4l2_subdev *sd,
 265                     struct v4l2_dv_timings *timings)
 266 {
 267         struct gs *gs = to_gs(sd);
 268 
 269         *timings = gs->current_timings;
 270         return 0;
 271 }
 272 
 273 static int gs_query_dv_timings(struct v4l2_subdev *sd,
 274                         struct v4l2_dv_timings *timings)
 275 {
 276         struct gs *gs = to_gs(sd);
 277         struct v4l2_dv_timings fmt;
 278         u16 reg_value, i;
 279         int ret;
 280 
 281         if (gs->enabled)
 282                 return -EBUSY;
 283 
 284         /*
 285          * Check if the component detect a line, a frame or something else
 286          * which looks like a video signal activity.
 287          */
 288         for (i = 0; i < 4; i++) {
 289                 gs_read_register(gs->pdev, REG_LINES_PER_FRAME + i, &reg_value);
 290                 if (reg_value)
 291                         break;
 292         }
 293 
 294         /* If no register reports a video signal */
 295         if (i >= 4)
 296                 return -ENOLINK;
 297 
 298         gs_read_register(gs->pdev, REG_STATUS, &reg_value);
 299         if (!(reg_value & MASK_H_LOCK) || !(reg_value & MASK_V_LOCK))
 300                 return -ENOLCK;
 301         if (!(reg_value & MASK_STD_LOCK))
 302                 return -ERANGE;
 303 
 304         ret = gs_status_format(reg_value, &fmt);
 305 
 306         if (ret < 0)
 307                 return ret;
 308 
 309         *timings = fmt;
 310         return 0;
 311 }
 312 
 313 static int gs_enum_dv_timings(struct v4l2_subdev *sd,
 314                        struct v4l2_enum_dv_timings *timings)
 315 {
 316         if (timings->index >= ARRAY_SIZE(fmt_cap))
 317                 return -EINVAL;
 318 
 319         if (timings->pad != 0)
 320                 return -EINVAL;
 321 
 322         timings->timings = fmt_cap[timings->index];
 323         return 0;
 324 }
 325 
 326 static int gs_s_stream(struct v4l2_subdev *sd, int enable)
 327 {
 328         struct gs *gs = to_gs(sd);
 329         int reg_value;
 330 
 331         if (gs->enabled == enable)
 332                 return 0;
 333 
 334         gs->enabled = enable;
 335 
 336         if (enable) {
 337                 /* To force the specific format */
 338                 reg_value = get_register_timings(&gs->current_timings);
 339                 return gs_write_register(gs->pdev, REG_FORCE_FMT, reg_value);
 340         }
 341 
 342         /* To renable auto-detection mode */
 343         return gs_write_register(gs->pdev, REG_FORCE_FMT, 0x0);
 344 }
 345 
 346 static int gs_g_input_status(struct v4l2_subdev *sd, u32 *status)
 347 {
 348         struct gs *gs = to_gs(sd);
 349         u16 reg_value, i;
 350         int ret;
 351 
 352         /*
 353          * Check if the component detect a line, a frame or something else
 354          * which looks like a video signal activity.
 355          */
 356         for (i = 0; i < 4; i++) {
 357                 ret = gs_read_register(gs->pdev,
 358                                        REG_LINES_PER_FRAME + i, &reg_value);
 359                 if (reg_value)
 360                         break;
 361                 if (ret) {
 362                         *status = V4L2_IN_ST_NO_POWER;
 363                         return ret;
 364                 }
 365         }
 366 
 367         /* If no register reports a video signal */
 368         if (i >= 4)
 369                 *status |= V4L2_IN_ST_NO_SIGNAL;
 370 
 371         ret = gs_read_register(gs->pdev, REG_STATUS, &reg_value);
 372         if (!(reg_value & MASK_H_LOCK))
 373                 *status |=  V4L2_IN_ST_NO_H_LOCK;
 374         if (!(reg_value & MASK_V_LOCK))
 375                 *status |=  V4L2_IN_ST_NO_V_LOCK;
 376         if (!(reg_value & MASK_STD_LOCK))
 377                 *status |=  V4L2_IN_ST_NO_STD_LOCK;
 378 
 379         return ret;
 380 }
 381 
 382 static int gs_dv_timings_cap(struct v4l2_subdev *sd,
 383                              struct v4l2_dv_timings_cap *cap)
 384 {
 385         if (cap->pad != 0)
 386                 return -EINVAL;
 387 
 388         *cap = gs_timings_cap;
 389         return 0;
 390 }
 391 
 392 /* V4L2 core operation handlers */
 393 static const struct v4l2_subdev_core_ops gs_core_ops = {
 394 #ifdef CONFIG_VIDEO_ADV_DEBUG
 395         .g_register = gs_g_register,
 396         .s_register = gs_s_register,
 397 #endif
 398 };
 399 
 400 static const struct v4l2_subdev_video_ops gs_video_ops = {
 401         .s_dv_timings = gs_s_dv_timings,
 402         .g_dv_timings = gs_g_dv_timings,
 403         .s_stream = gs_s_stream,
 404         .g_input_status = gs_g_input_status,
 405         .query_dv_timings = gs_query_dv_timings,
 406 };
 407 
 408 static const struct v4l2_subdev_pad_ops gs_pad_ops = {
 409         .enum_dv_timings = gs_enum_dv_timings,
 410         .dv_timings_cap = gs_dv_timings_cap,
 411 };
 412 
 413 /* V4L2 top level operation handlers */
 414 static const struct v4l2_subdev_ops gs_ops = {
 415         .core = &gs_core_ops,
 416         .video = &gs_video_ops,
 417         .pad = &gs_pad_ops,
 418 };
 419 
 420 static int gs_probe(struct spi_device *spi)
 421 {
 422         int ret;
 423         struct gs *gs;
 424         struct v4l2_subdev *sd;
 425 
 426         gs = devm_kzalloc(&spi->dev, sizeof(struct gs), GFP_KERNEL);
 427         if (!gs)
 428                 return -ENOMEM;
 429 
 430         gs->pdev = spi;
 431         sd = &gs->sd;
 432 
 433         spi->mode = SPI_MODE_0;
 434         spi->irq = -1;
 435         spi->max_speed_hz = 10000000;
 436         spi->bits_per_word = 16;
 437         ret = spi_setup(spi);
 438         v4l2_spi_subdev_init(sd, spi, &gs_ops);
 439 
 440         gs->current_timings = reg_fmt[0].format;
 441         gs->enabled = 0;
 442 
 443         /* Set H_CONFIG to SMPTE timings */
 444         gs_write_register(spi, 0x0, 0x300);
 445 
 446         return ret;
 447 }
 448 
 449 static int gs_remove(struct spi_device *spi)
 450 {
 451         struct v4l2_subdev *sd = spi_get_drvdata(spi);
 452 
 453         v4l2_device_unregister_subdev(sd);
 454 
 455         return 0;
 456 }
 457 
 458 static struct spi_driver gs_driver = {
 459         .driver = {
 460                 .name           = "gs1662",
 461         },
 462 
 463         .probe          = gs_probe,
 464         .remove         = gs_remove,
 465         .id_table       = gs_id,
 466 };
 467 
 468 module_spi_driver(gs_driver);
 469 
 470 MODULE_LICENSE("GPL");
 471 MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>");
 472 MODULE_DESCRIPTION("Gennum GS1662 HD/SD-SDI Serializer driver");

/* [<][>][^][v][top][bottom][index][help] */