/*
* Analog Devices ADV7511 HDMI Transmitter Device Driver
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dv-timings.h>
#include <media/adv7511.h>
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver");
MODULE_AUTHOR("Hans Verkuil");
MODULE_LICENSE("GPL");
#define MASK_ADV7511_EDID_RDY_INT 0x04
#define MASK_ADV7511_MSEN_INT 0x40
#define MASK_ADV7511_HPD_INT 0x80
#define MASK_ADV7511_HPD_DETECT 0x40
#define MASK_ADV7511_MSEN_DETECT 0x20
#define MASK_ADV7511_EDID_RDY 0x10
#define EDID_MAX_RETRIES (8)
#define EDID_DELAY 250
#define EDID_MAX_SEGM 8
#define ADV7511_MAX_WIDTH 1920
#define ADV7511_MAX_HEIGHT 1200
#define ADV7511_MIN_PIXELCLOCK 20000000
#define ADV7511_MAX_PIXELCLOCK 225000000
/*
**********************************************************************
*
* Arrays with configuration parameters for the ADV7511
*
**********************************************************************
*/
struct i2c_reg_value {
unsigned char reg;
unsigned char value;
};
struct adv7511_state_edid {
/* total number of blocks */
u32 blocks;
/* Number of segments read */
u32 segments;
uint8_t data[EDID_MAX_SEGM * 256];
/* Number of EDID read retries left */
unsigned read_retries;
bool complete;
};
struct adv7511_state {
struct adv7511_platform_data pdata;
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler hdl;
int chip_revision;
uint8_t i2c_edid_addr;
uint8_t i2c_cec_addr;
/* Is the adv7511 powered on? */
bool power_on;
/* Did we receive hotplug and rx-sense signals? */
bool have_monitor;
/* timings from s_dv_timings */
struct v4l2_dv_timings dv_timings;
/* controls */
struct v4l2_ctrl *hdmi_mode_ctrl;
struct v4l2_ctrl *hotplug_ctrl;
struct v4l2_ctrl *rx_sense_ctrl;
struct v4l2_ctrl *have_edid0_ctrl;
struct v4l2_ctrl *rgb_quantization_range_ctrl;
struct i2c_client *i2c_edid;
struct adv7511_state_edid edid;
/* Running counter of the number of detected EDIDs (for debugging) */
unsigned edid_detect_counter;
struct workqueue_struct *work_queue;
struct delayed_work edid_handler; /* work entry */
};
static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd);
static bool adv7511_check_edid_status(struct v4l2_subdev *sd);
static void adv7511_setup(struct v4l2_subdev *sd);
static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq);
static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
.type = V4L2_DV_BT_656_1120,