[media] ad9389b/adv7604/ths8200: use new v4l2_print_dv_timings helper
[deliverable/linux.git] / drivers / media / i2c / adv7604.c
index 31a63c9324fe245b1d981ae124836f20fd1d17c5..ba8602c06d6bae5613948534bbef7900fec9cdd6 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/v4l2-dv-timings.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-dv-timings.h>
 #include <media/adv7604.h>
 
 static int debug;
@@ -77,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;
@@ -261,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);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -643,12 +644,6 @@ static void adv7604_inv_register(struct v4l2_subdev *sd)
 static int adv7604_g_register(struct v4l2_subdev *sd,
                                        struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 1;
        switch (reg->reg >> 8) {
        case 0:
@@ -701,12 +696,6 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
 static int adv7604_s_register(struct v4l2_subdev *sd,
                                        const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        switch (reg->reg >> 8) {
        case 0:
                io_write(sd, reg->reg & 0xff, reg->val & 0xff);
@@ -984,14 +973,6 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int adv7604_g_chip_ident(struct v4l2_subdev *sd,
-                                       struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7604, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static inline bool no_power(struct v4l2_subdev *sd)
@@ -1011,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 */
@@ -1065,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;
@@ -1263,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 +
@@ -1350,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;
 }
@@ -1393,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;
 }
 
@@ -1555,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;
@@ -1565,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;
        }
@@ -1646,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;
        }
@@ -1707,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");
@@ -1744,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",
@@ -1756,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);
        }
@@ -1787,7 +1796,6 @@ static const struct v4l2_subdev_core_ops adv7604_core_ops = {
        .s_ctrl = v4l2_subdev_s_ctrl,
        .queryctrl = v4l2_subdev_queryctrl,
        .querymenu = v4l2_subdev_querymenu,
-       .g_chip_ident = adv7604_g_chip_ident,
        .interrupt_service_routine = adv7604_isr,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = adv7604_g_register,
@@ -1968,17 +1976,20 @@ static int adv7604_probe(struct i2c_client *client,
        v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n",
                        client->addr << 1);
 
-       state = kzalloc(sizeof(struct adv7604_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state) {
                v4l_err(client, "Could not allocate adv7604_state memory!\n");
                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");
-               err = -ENODEV;
-               goto err_state;
+               return -ENODEV;
        }
        memcpy(&state->pdata, pdata, sizeof(state->pdata));
 
@@ -1991,8 +2002,7 @@ static int adv7604_probe(struct i2c_client *client,
        if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
                v4l2_info(sd, "not an adv7604 on address 0x%x\n",
                                client->addr << 1);
-               err = -ENODEV;
-               goto err_state;
+               return -ENODEV;
        }
 
        /* control handlers */
@@ -2059,7 +2069,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);
@@ -2093,8 +2102,6 @@ err_i2c:
        adv7604_unregister_clients(state);
 err_hdl:
        v4l2_ctrl_handler_free(hdl);
-err_state:
-       kfree(state);
        return err;
 }
 
@@ -2111,7 +2118,6 @@ static int adv7604_remove(struct i2c_client *client)
        media_entity_cleanup(&sd->entity);
        adv7604_unregister_clients(to_state(sd));
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       kfree(to_state(sd));
        return 0;
 }
 
This page took 0.051298 seconds and 5 git commands to generate.