Merge remote-tracking branch 'iommu/next'
[deliverable/linux.git] / drivers / media / i2c / adv7180.c
index 95cbc857f36e981145a01e221281767afa6adaa9..515ea6ae41d7385c303a6790234f5ef4b620653c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/gpio/consumer.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
 
 #define ADV7182_REG_INPUT_VIDSEL                       0x0002
 
+#define ADV7180_REG_OUTPUT_CONTROL                     0x0003
 #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL            0x0004
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS                0xC5
 
-#define ADV7180_REG_AUTODETECT_ENABLE                  0x07
+#define ADV7180_REG_AUTODETECT_ENABLE                  0x0007
 #define ADV7180_AUTODETECT_DEFAULT                     0x7f
 /* Contrast */
 #define ADV7180_REG_CON                0x0008  /*Unsigned */
 #define ADV7180_REG_IDENT 0x0011
 #define ADV7180_ID_7180 0x18
 
+#define ADV7180_REG_STATUS3            0x0013
+#define ADV7180_REG_ANALOG_CLAMP_CTL   0x0014
+#define ADV7180_REG_SHAP_FILTER_CTL_1  0x0017
+#define ADV7180_REG_CTRL_2             0x001d
+#define ADV7180_REG_VSYNC_FIELD_CTL_1  0x0031
+#define ADV7180_REG_MANUAL_WIN_CTL_1   0x003d
+#define ADV7180_REG_MANUAL_WIN_CTL_2   0x003e
+#define ADV7180_REG_MANUAL_WIN_CTL_3   0x003f
+#define ADV7180_REG_LOCK_CNT           0x0051
+#define ADV7180_REG_CVBS_TRIM          0x0052
+#define ADV7180_REG_CLAMP_ADJ          0x005a
+#define ADV7180_REG_RES_CIR            0x005f
+#define ADV7180_REG_DIFF_MODE          0x0060
+
 #define ADV7180_REG_ICONF1             0x2040
 #define ADV7180_ICONF1_ACTIVE_LOW      0x01
 #define ADV7180_ICONF1_PSYNC_ONLY      0x10
 #define ADV7180_REG_VPP_SLAVE_ADDR     0xFD
 #define ADV7180_REG_CSI_SLAVE_ADDR     0xFE
 
-#define ADV7180_REG_FLCONTROL 0x40e0
+#define ADV7180_REG_ACE_CTRL1          0x4080
+#define ADV7180_REG_ACE_CTRL5          0x4084
+#define ADV7180_REG_FLCONTROL          0x40e0
 #define ADV7180_FLCONTROL_FL_ENABLE 0x1
 
+#define ADV7180_REG_RST_CLAMP  0x809c
+#define ADV7180_REG_AGC_ADJ1   0x80b6
+#define ADV7180_REG_AGC_ADJ2   0x80c0
+
 #define ADV7180_CSI_REG_PWRDN  0x00
 #define ADV7180_CSI_PWRDN      0x80
 
@@ -192,6 +214,7 @@ struct adv7180_state {
        struct media_pad        pad;
        struct mutex            mutex; /* mutual excl. when accessing chip */
        int                     irq;
+       struct gpio_desc        *pwdn_gpio;
        v4l2_std_id             curr_norm;
        bool                    powered;
        bool                    streaming;
@@ -442,6 +465,19 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
        return 0;
 }
 
+static void adv7180_set_power_pin(struct adv7180_state *state, bool on)
+{
+       if (!state->pwdn_gpio)
+               return;
+
+       if (on) {
+               gpiod_set_value_cansleep(state->pwdn_gpio, 0);
+               usleep_range(5000, 10000);
+       } else {
+               gpiod_set_value_cansleep(state->pwdn_gpio, 1);
+       }
+}
+
 static int adv7180_set_power(struct adv7180_state *state, bool on)
 {
        u8 val;
@@ -725,16 +761,16 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap)
+static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
 {
        struct adv7180_state *state = to_state(sd);
 
        if (state->curr_norm & V4L2_STD_525_60) {
-               cropcap->pixelaspect.numerator = 11;
-               cropcap->pixelaspect.denominator = 10;
+               aspect->numerator = 11;
+               aspect->denominator = 10;
        } else {
-               cropcap->pixelaspect.numerator = 54;
-               cropcap->pixelaspect.denominator = 59;
+               aspect->numerator = 54;
+               aspect->denominator = 59;
        }
 
        return 0;
@@ -787,7 +823,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
        .g_input_status = adv7180_g_input_status,
        .s_routing = adv7180_s_routing,
        .g_mbus_config = adv7180_g_mbus_config,
-       .cropcap = adv7180_cropcap,
+       .g_pixelaspect = adv7180_g_pixelaspect,
        .g_tvnorms = adv7180_g_tvnorms,
        .s_stream = adv7180_s_stream,
 };
@@ -886,16 +922,20 @@ static int adv7182_init(struct adv7180_state *state)
 
        /* ADI required writes */
        if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
-               adv7180_write(state, 0x0003, 0x4e);
-               adv7180_write(state, 0x0004, 0x57);
-               adv7180_write(state, 0x001d, 0xc0);
+               adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e);
+               adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57);
+               adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0);
        } else {
                if (state->chip_info->flags & ADV7180_FLAG_V2)
-                       adv7180_write(state, 0x0004, 0x17);
+                       adv7180_write(state,
+                                     ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
+                                     0x17);
                else
-                       adv7180_write(state, 0x0004, 0x07);
-               adv7180_write(state, 0x0003, 0x0c);
-               adv7180_write(state, 0x001d, 0x40);
+                       adv7180_write(state,
+                                     ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
+                                     0x07);
+               adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c);
+               adv7180_write(state, ADV7180_REG_CTRL_2, 0x40);
        }
 
        adv7180_write(state, 0x0013, 0x00);
@@ -972,8 +1012,8 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
                return ret;
 
        /* Reset clamp circuitry - ADI recommended writes */
-       adv7180_write(state, 0x809c, 0x00);
-       adv7180_write(state, 0x809c, 0xff);
+       adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00);
+       adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff);
 
        input_type = adv7182_get_input_type(input);
 
@@ -981,10 +1021,10 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
        case ADV7182_INPUT_TYPE_CVBS:
        case ADV7182_INPUT_TYPE_DIFF_CVBS:
                /* ADI recommends to use the SH1 filter */
-               adv7180_write(state, 0x0017, 0x41);
+               adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41);
                break;
        default:
-               adv7180_write(state, 0x0017, 0x01);
+               adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01);
                break;
        }
 
@@ -994,21 +1034,21 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
                lbias = adv7182_lbias_settings[input_type];
 
        for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
-               adv7180_write(state, 0x0052 + i, lbias[i]);
+               adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]);
 
        if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
                /* ADI required writes to make differential CVBS work */
-               adv7180_write(state, 0x005f, 0xa8);
-               adv7180_write(state, 0x005a, 0x90);
-               adv7180_write(state, 0x0060, 0xb0);
-               adv7180_write(state, 0x80b6, 0x08);
-               adv7180_write(state, 0x80c0, 0xa0);
+               adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8);
+               adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90);
+               adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0);
+               adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08);
+               adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0);
        } else {
-               adv7180_write(state, 0x005f, 0xf0);
-               adv7180_write(state, 0x005a, 0xd0);
-               adv7180_write(state, 0x0060, 0x10);
-               adv7180_write(state, 0x80b6, 0x9c);
-               adv7180_write(state, 0x80c0, 0x00);
+               adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0);
+               adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0);
+               adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10);
+               adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c);
+               adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00);
        }
 
        return 0;
@@ -1185,6 +1225,8 @@ static int init_device(struct adv7180_state *state)
 
        mutex_lock(&state->mutex);
 
+       adv7180_set_power_pin(state, true);
+
        adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
        usleep_range(5000, 10000);
 
@@ -1254,6 +1296,14 @@ static int adv7180_probe(struct i2c_client *client,
        state->field = V4L2_FIELD_INTERLACED;
        state->chip_info = (struct adv7180_chip_info *)id->driver_data;
 
+       state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+                                                  GPIOD_OUT_HIGH);
+       if (IS_ERR(state->pwdn_gpio)) {
+               ret = PTR_ERR(state->pwdn_gpio);
+               v4l_err(client, "request for power pin failed: %d\n", ret);
+               return ret;
+       }
+
        if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
                state->csi_client = i2c_new_dummy(client->adapter,
                                ADV7180_DEFAULT_CSI_I2C_ADDR);
@@ -1345,6 +1395,8 @@ static int adv7180_remove(struct i2c_client *client)
        if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
                i2c_unregister_device(state->csi_client);
 
+       adv7180_set_power_pin(state, false);
+
        mutex_destroy(&state->mutex);
 
        return 0;
This page took 0.029025 seconds and 5 git commands to generate.