|
@@ -23,7 +23,6 @@
|
|
|
|
|
|
#include <drm/drmP.h>
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_crtc_helper.h>
|
|
#include <drm/drm_crtc_helper.h>
|
|
-#include <drm/drm_encoder_slave.h>
|
|
|
|
#include <drm/drm_edid.h>
|
|
#include <drm/drm_edid.h>
|
|
#include <drm/drm_of.h>
|
|
#include <drm/drm_of.h>
|
|
#include <drm/i2c/tda998x.h>
|
|
#include <drm/i2c/tda998x.h>
|
|
@@ -34,9 +33,8 @@ struct tda998x_priv {
|
|
struct i2c_client *cec;
|
|
struct i2c_client *cec;
|
|
struct i2c_client *hdmi;
|
|
struct i2c_client *hdmi;
|
|
struct mutex mutex;
|
|
struct mutex mutex;
|
|
- struct delayed_work dwork;
|
|
|
|
- uint16_t rev;
|
|
|
|
- uint8_t current_page;
|
|
|
|
|
|
+ u16 rev;
|
|
|
|
+ u8 current_page;
|
|
int dpms;
|
|
int dpms;
|
|
bool is_hdmi_sink;
|
|
bool is_hdmi_sink;
|
|
u8 vip_cntrl_0;
|
|
u8 vip_cntrl_0;
|
|
@@ -46,10 +44,21 @@ struct tda998x_priv {
|
|
|
|
|
|
wait_queue_head_t wq_edid;
|
|
wait_queue_head_t wq_edid;
|
|
volatile int wq_edid_wait;
|
|
volatile int wq_edid_wait;
|
|
- struct drm_encoder *encoder;
|
|
|
|
|
|
+
|
|
|
|
+ struct work_struct detect_work;
|
|
|
|
+ struct timer_list edid_delay_timer;
|
|
|
|
+ wait_queue_head_t edid_delay_waitq;
|
|
|
|
+ bool edid_delay_active;
|
|
|
|
+
|
|
|
|
+ struct drm_encoder encoder;
|
|
|
|
+ struct drm_connector connector;
|
|
};
|
|
};
|
|
|
|
|
|
-#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
|
|
|
|
|
|
+#define conn_to_tda998x_priv(x) \
|
|
|
|
+ container_of(x, struct tda998x_priv, connector)
|
|
|
|
+
|
|
|
|
+#define enc_to_tda998x_priv(x) \
|
|
|
|
+ container_of(x, struct tda998x_priv, encoder)
|
|
|
|
|
|
/* The TDA9988 series of devices use a paged register scheme.. to simplify
|
|
/* The TDA9988 series of devices use a paged register scheme.. to simplify
|
|
* things we encode the page # in upper bits of the register #. To read/
|
|
* things we encode the page # in upper bits of the register #. To read/
|
|
@@ -326,6 +335,8 @@ struct tda998x_priv {
|
|
# define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0)
|
|
# define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0)
|
|
#define REG_CEC_RXSHPDINTENA 0xfc /* read/write */
|
|
#define REG_CEC_RXSHPDINTENA 0xfc /* read/write */
|
|
#define REG_CEC_RXSHPDINT 0xfd /* read */
|
|
#define REG_CEC_RXSHPDINT 0xfd /* read */
|
|
|
|
+# define CEC_RXSHPDINT_RXSENS BIT(0)
|
|
|
|
+# define CEC_RXSHPDINT_HPD BIT(1)
|
|
#define REG_CEC_RXSHPDLEV 0xfe /* read */
|
|
#define REG_CEC_RXSHPDLEV 0xfe /* read */
|
|
# define CEC_RXSHPDLEV_RXSENS (1 << 0)
|
|
# define CEC_RXSHPDLEV_RXSENS (1 << 0)
|
|
# define CEC_RXSHPDLEV_HPD (1 << 1)
|
|
# define CEC_RXSHPDLEV_HPD (1 << 1)
|
|
@@ -345,10 +356,10 @@ struct tda998x_priv {
|
|
#define TDA19988 0x0301
|
|
#define TDA19988 0x0301
|
|
|
|
|
|
static void
|
|
static void
|
|
-cec_write(struct tda998x_priv *priv, uint16_t addr, uint8_t val)
|
|
|
|
|
|
+cec_write(struct tda998x_priv *priv, u16 addr, u8 val)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->cec;
|
|
struct i2c_client *client = priv->cec;
|
|
- uint8_t buf[] = {addr, val};
|
|
|
|
|
|
+ u8 buf[] = {addr, val};
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = i2c_master_send(client, buf, sizeof(buf));
|
|
ret = i2c_master_send(client, buf, sizeof(buf));
|
|
@@ -356,11 +367,11 @@ cec_write(struct tda998x_priv *priv, uint16_t addr, uint8_t val)
|
|
dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr);
|
|
dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr);
|
|
}
|
|
}
|
|
|
|
|
|
-static uint8_t
|
|
|
|
-cec_read(struct tda998x_priv *priv, uint8_t addr)
|
|
|
|
|
|
+static u8
|
|
|
|
+cec_read(struct tda998x_priv *priv, u8 addr)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->cec;
|
|
struct i2c_client *client = priv->cec;
|
|
- uint8_t val;
|
|
|
|
|
|
+ u8 val;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = i2c_master_send(client, &addr, sizeof(addr));
|
|
ret = i2c_master_send(client, &addr, sizeof(addr));
|
|
@@ -379,11 +390,11 @@ fail:
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-set_page(struct tda998x_priv *priv, uint16_t reg)
|
|
|
|
|
|
+set_page(struct tda998x_priv *priv, u16 reg)
|
|
{
|
|
{
|
|
if (REG2PAGE(reg) != priv->current_page) {
|
|
if (REG2PAGE(reg) != priv->current_page) {
|
|
struct i2c_client *client = priv->hdmi;
|
|
struct i2c_client *client = priv->hdmi;
|
|
- uint8_t buf[] = {
|
|
|
|
|
|
+ u8 buf[] = {
|
|
REG_CURPAGE, REG2PAGE(reg)
|
|
REG_CURPAGE, REG2PAGE(reg)
|
|
};
|
|
};
|
|
int ret = i2c_master_send(client, buf, sizeof(buf));
|
|
int ret = i2c_master_send(client, buf, sizeof(buf));
|
|
@@ -399,10 +410,10 @@ set_page(struct tda998x_priv *priv, uint16_t reg)
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt)
|
|
|
|
|
|
+reg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->hdmi;
|
|
struct i2c_client *client = priv->hdmi;
|
|
- uint8_t addr = REG2ADDR(reg);
|
|
|
|
|
|
+ u8 addr = REG2ADDR(reg);
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&priv->mutex);
|
|
mutex_lock(&priv->mutex);
|
|
@@ -428,10 +439,10 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt)
|
|
|
|
|
|
+reg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->hdmi;
|
|
struct i2c_client *client = priv->hdmi;
|
|
- uint8_t buf[cnt+1];
|
|
|
|
|
|
+ u8 buf[cnt+1];
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
buf[0] = REG2ADDR(reg);
|
|
buf[0] = REG2ADDR(reg);
|
|
@@ -450,9 +461,9 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-reg_read(struct tda998x_priv *priv, uint16_t reg)
|
|
|
|
|
|
+reg_read(struct tda998x_priv *priv, u16 reg)
|
|
{
|
|
{
|
|
- uint8_t val = 0;
|
|
|
|
|
|
+ u8 val = 0;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = reg_read_range(priv, reg, &val, sizeof(val));
|
|
ret = reg_read_range(priv, reg, &val, sizeof(val));
|
|
@@ -462,10 +473,10 @@ reg_read(struct tda998x_priv *priv, uint16_t reg)
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
|
|
|
|
|
|
+reg_write(struct tda998x_priv *priv, u16 reg, u8 val)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->hdmi;
|
|
struct i2c_client *client = priv->hdmi;
|
|
- uint8_t buf[] = {REG2ADDR(reg), val};
|
|
|
|
|
|
+ u8 buf[] = {REG2ADDR(reg), val};
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&priv->mutex);
|
|
mutex_lock(&priv->mutex);
|
|
@@ -481,10 +492,10 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val)
|
|
|
|
|
|
+reg_write16(struct tda998x_priv *priv, u16 reg, u16 val)
|
|
{
|
|
{
|
|
struct i2c_client *client = priv->hdmi;
|
|
struct i2c_client *client = priv->hdmi;
|
|
- uint8_t buf[] = {REG2ADDR(reg), val >> 8, val};
|
|
|
|
|
|
+ u8 buf[] = {REG2ADDR(reg), val >> 8, val};
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&priv->mutex);
|
|
mutex_lock(&priv->mutex);
|
|
@@ -500,7 +511,7 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
|
|
|
|
|
|
+reg_set(struct tda998x_priv *priv, u16 reg, u8 val)
|
|
{
|
|
{
|
|
int old_val;
|
|
int old_val;
|
|
|
|
|
|
@@ -510,7 +521,7 @@ reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-reg_clear(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
|
|
|
|
|
|
+reg_clear(struct tda998x_priv *priv, u16 reg, u8 val)
|
|
{
|
|
{
|
|
int old_val;
|
|
int old_val;
|
|
|
|
|
|
@@ -551,15 +562,50 @@ tda998x_reset(struct tda998x_priv *priv)
|
|
reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
|
|
reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
|
|
}
|
|
}
|
|
|
|
|
|
-/* handle HDMI connect/disconnect */
|
|
|
|
-static void tda998x_hpd(struct work_struct *work)
|
|
|
|
|
|
+/*
|
|
|
|
+ * The TDA998x has a problem when trying to read the EDID close to a
|
|
|
|
+ * HPD assertion: it needs a delay of 100ms to avoid timing out while
|
|
|
|
+ * trying to read EDID data.
|
|
|
|
+ *
|
|
|
|
+ * However, tda998x_encoder_get_modes() may be called at any moment
|
|
|
|
+ * after tda998x_connector_detect() indicates that we are connected, so
|
|
|
|
+ * we need to delay probing modes in tda998x_encoder_get_modes() after
|
|
|
|
+ * we have seen a HPD inactive->active transition. This code implements
|
|
|
|
+ * that delay.
|
|
|
|
+ */
|
|
|
|
+static void tda998x_edid_delay_done(unsigned long data)
|
|
|
|
+{
|
|
|
|
+ struct tda998x_priv *priv = (struct tda998x_priv *)data;
|
|
|
|
+
|
|
|
|
+ priv->edid_delay_active = false;
|
|
|
|
+ wake_up(&priv->edid_delay_waitq);
|
|
|
|
+ schedule_work(&priv->detect_work);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void tda998x_edid_delay_start(struct tda998x_priv *priv)
|
|
|
|
+{
|
|
|
|
+ priv->edid_delay_active = true;
|
|
|
|
+ mod_timer(&priv->edid_delay_timer, jiffies + HZ/10);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int tda998x_edid_delay_wait(struct tda998x_priv *priv)
|
|
|
|
+{
|
|
|
|
+ return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * We need to run the KMS hotplug event helper outside of our threaded
|
|
|
|
+ * interrupt routine as this can call back into our get_modes method,
|
|
|
|
+ * which will want to make use of interrupts.
|
|
|
|
+ */
|
|
|
|
+static void tda998x_detect_work(struct work_struct *work)
|
|
{
|
|
{
|
|
- struct delayed_work *dwork = to_delayed_work(work);
|
|
|
|
struct tda998x_priv *priv =
|
|
struct tda998x_priv *priv =
|
|
- container_of(dwork, struct tda998x_priv, dwork);
|
|
|
|
|
|
+ container_of(work, struct tda998x_priv, detect_work);
|
|
|
|
+ struct drm_device *dev = priv->encoder.dev;
|
|
|
|
|
|
- if (priv->encoder && priv->encoder->dev)
|
|
|
|
- drm_kms_helper_hotplug_event(priv->encoder->dev);
|
|
|
|
|
|
+ if (dev)
|
|
|
|
+ drm_kms_helper_hotplug_event(dev);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -569,9 +615,8 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
|
|
{
|
|
{
|
|
struct tda998x_priv *priv = data;
|
|
struct tda998x_priv *priv = data;
|
|
u8 sta, cec, lvl, flag0, flag1, flag2;
|
|
u8 sta, cec, lvl, flag0, flag1, flag2;
|
|
|
|
+ bool handled = false;
|
|
|
|
|
|
- if (!priv)
|
|
|
|
- return IRQ_HANDLED;
|
|
|
|
sta = cec_read(priv, REG_CEC_INTSTATUS);
|
|
sta = cec_read(priv, REG_CEC_INTSTATUS);
|
|
cec = cec_read(priv, REG_CEC_RXSHPDINT);
|
|
cec = cec_read(priv, REG_CEC_RXSHPDINT);
|
|
lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
|
|
lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
|
|
@@ -581,75 +626,76 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
|
|
DRM_DEBUG_DRIVER(
|
|
DRM_DEBUG_DRIVER(
|
|
"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
|
|
"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
|
|
sta, cec, lvl, flag0, flag1, flag2);
|
|
sta, cec, lvl, flag0, flag1, flag2);
|
|
|
|
+
|
|
|
|
+ if (cec & CEC_RXSHPDINT_HPD) {
|
|
|
|
+ if (lvl & CEC_RXSHPDLEV_HPD)
|
|
|
|
+ tda998x_edid_delay_start(priv);
|
|
|
|
+ else
|
|
|
|
+ schedule_work(&priv->detect_work);
|
|
|
|
+
|
|
|
|
+ handled = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
|
|
if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
|
|
priv->wq_edid_wait = 0;
|
|
priv->wq_edid_wait = 0;
|
|
wake_up(&priv->wq_edid);
|
|
wake_up(&priv->wq_edid);
|
|
- } else if (cec != 0) { /* HPD change */
|
|
|
|
- schedule_delayed_work(&priv->dwork, HZ/10);
|
|
|
|
|
|
+ handled = true;
|
|
}
|
|
}
|
|
- return IRQ_HANDLED;
|
|
|
|
-}
|
|
|
|
|
|
|
|
-static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes)
|
|
|
|
-{
|
|
|
|
- int sum = 0;
|
|
|
|
-
|
|
|
|
- while (bytes--)
|
|
|
|
- sum -= *buf++;
|
|
|
|
- return sum;
|
|
|
|
|
|
+ return IRQ_RETVAL(handled);
|
|
}
|
|
}
|
|
|
|
|
|
-#define HB(x) (x)
|
|
|
|
-#define PB(x) (HB(2) + 1 + (x))
|
|
|
|
-
|
|
|
|
static void
|
|
static void
|
|
-tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
|
|
|
|
- uint8_t *buf, size_t size)
|
|
|
|
|
|
+tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr,
|
|
|
|
+ union hdmi_infoframe *frame)
|
|
{
|
|
{
|
|
|
|
+ u8 buf[32];
|
|
|
|
+ ssize_t len;
|
|
|
|
+
|
|
|
|
+ len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
|
|
|
|
+ if (len < 0) {
|
|
|
|
+ dev_err(&priv->hdmi->dev,
|
|
|
|
+ "hdmi_infoframe_pack() type=0x%02x failed: %zd\n",
|
|
|
|
+ frame->any.type, len);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
reg_clear(priv, REG_DIP_IF_FLAGS, bit);
|
|
reg_clear(priv, REG_DIP_IF_FLAGS, bit);
|
|
- reg_write_range(priv, addr, buf, size);
|
|
|
|
|
|
+ reg_write_range(priv, addr, buf, len);
|
|
reg_set(priv, REG_DIP_IF_FLAGS, bit);
|
|
reg_set(priv, REG_DIP_IF_FLAGS, bit);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
|
|
tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
|
|
{
|
|
{
|
|
- u8 buf[PB(HDMI_AUDIO_INFOFRAME_SIZE) + 1];
|
|
|
|
|
|
+ union hdmi_infoframe frame;
|
|
|
|
+
|
|
|
|
+ hdmi_audio_infoframe_init(&frame.audio);
|
|
|
|
|
|
- memset(buf, 0, sizeof(buf));
|
|
|
|
- buf[HB(0)] = HDMI_INFOFRAME_TYPE_AUDIO;
|
|
|
|
- buf[HB(1)] = 0x01;
|
|
|
|
- buf[HB(2)] = HDMI_AUDIO_INFOFRAME_SIZE;
|
|
|
|
- buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */
|
|
|
|
- buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */
|
|
|
|
- buf[PB(4)] = p->audio_frame[4];
|
|
|
|
- buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
|
|
|
|
|
|
+ frame.audio.channels = p->audio_frame[1] & 0x07;
|
|
|
|
+ frame.audio.channel_allocation = p->audio_frame[4];
|
|
|
|
+ frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3;
|
|
|
|
+ frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7;
|
|
|
|
|
|
- buf[PB(0)] = tda998x_cksum(buf, sizeof(buf));
|
|
|
|
|
|
+ /*
|
|
|
|
+ * L-PCM and IEC61937 compressed audio shall always set sample
|
|
|
|
+ * frequency to "refer to stream". For others, see the HDMI
|
|
|
|
+ * specification.
|
|
|
|
+ */
|
|
|
|
+ frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2;
|
|
|
|
|
|
- tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
|
|
|
|
- sizeof(buf));
|
|
|
|
|
|
+ tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode)
|
|
tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode)
|
|
{
|
|
{
|
|
- struct hdmi_avi_infoframe frame;
|
|
|
|
- u8 buf[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
|
|
|
- ssize_t len;
|
|
|
|
|
|
+ union hdmi_infoframe frame;
|
|
|
|
|
|
- drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
|
|
|
|
|
|
+ drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
|
|
|
|
+ frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
|
|
|
|
|
|
- frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
|
|
|
|
-
|
|
|
|
- len = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf));
|
|
|
|
- if (len < 0) {
|
|
|
|
- dev_err(&priv->hdmi->dev,
|
|
|
|
- "hdmi_avi_infoframe_pack() failed: %zd\n", len);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf, len);
|
|
|
|
|
|
+ tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
|
|
}
|
|
}
|
|
|
|
|
|
static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
|
|
static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
|
|
@@ -667,8 +713,8 @@ static void
|
|
tda998x_configure_audio(struct tda998x_priv *priv,
|
|
tda998x_configure_audio(struct tda998x_priv *priv,
|
|
struct drm_display_mode *mode, struct tda998x_encoder_params *p)
|
|
struct drm_display_mode *mode, struct tda998x_encoder_params *p)
|
|
{
|
|
{
|
|
- uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv;
|
|
|
|
- uint32_t n;
|
|
|
|
|
|
+ u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv;
|
|
|
|
+ u32 n;
|
|
|
|
|
|
/* Enable audio ports */
|
|
/* Enable audio ports */
|
|
reg_write(priv, REG_ENA_AP, p->audio_cfg);
|
|
reg_write(priv, REG_ENA_AP, p->audio_cfg);
|
|
@@ -776,8 +822,10 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv,
|
|
priv->params = *p;
|
|
priv->params = *p;
|
|
}
|
|
}
|
|
|
|
|
|
-static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode)
|
|
|
|
|
|
+static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|
{
|
|
{
|
|
|
|
+ struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
|
|
|
|
+
|
|
/* we only care about on or off: */
|
|
/* we only care about on or off: */
|
|
if (mode != DRM_MODE_DPMS_ON)
|
|
if (mode != DRM_MODE_DPMS_ON)
|
|
mode = DRM_MODE_DPMS_OFF;
|
|
mode = DRM_MODE_DPMS_OFF;
|
|
@@ -827,8 +875,8 @@ tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-static int tda998x_encoder_mode_valid(struct tda998x_priv *priv,
|
|
|
|
- struct drm_display_mode *mode)
|
|
|
|
|
|
+static int tda998x_connector_mode_valid(struct drm_connector *connector,
|
|
|
|
+ struct drm_display_mode *mode)
|
|
{
|
|
{
|
|
if (mode->clock > 150000)
|
|
if (mode->clock > 150000)
|
|
return MODE_CLOCK_HIGH;
|
|
return MODE_CLOCK_HIGH;
|
|
@@ -840,18 +888,19 @@ static int tda998x_encoder_mode_valid(struct tda998x_priv *priv,
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-tda998x_encoder_mode_set(struct tda998x_priv *priv,
|
|
|
|
|
|
+tda998x_encoder_mode_set(struct drm_encoder *encoder,
|
|
struct drm_display_mode *mode,
|
|
struct drm_display_mode *mode,
|
|
struct drm_display_mode *adjusted_mode)
|
|
struct drm_display_mode *adjusted_mode)
|
|
{
|
|
{
|
|
- uint16_t ref_pix, ref_line, n_pix, n_line;
|
|
|
|
- uint16_t hs_pix_s, hs_pix_e;
|
|
|
|
- uint16_t vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
|
|
|
|
- uint16_t vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e;
|
|
|
|
- uint16_t vwin1_line_s, vwin1_line_e;
|
|
|
|
- uint16_t vwin2_line_s, vwin2_line_e;
|
|
|
|
- uint16_t de_pix_s, de_pix_e;
|
|
|
|
- uint8_t reg, div, rep;
|
|
|
|
|
|
+ struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
|
|
|
|
+ u16 ref_pix, ref_line, n_pix, n_line;
|
|
|
|
+ u16 hs_pix_s, hs_pix_e;
|
|
|
|
+ u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
|
|
|
|
+ u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e;
|
|
|
|
+ u16 vwin1_line_s, vwin1_line_e;
|
|
|
|
+ u16 vwin2_line_s, vwin2_line_e;
|
|
|
|
+ u16 de_pix_s, de_pix_e;
|
|
|
|
+ u8 reg, div, rep;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Internally TDA998x is using ITU-R BT.656 style sync but
|
|
* Internally TDA998x is using ITU-R BT.656 style sync but
|
|
@@ -1031,9 +1080,10 @@ tda998x_encoder_mode_set(struct tda998x_priv *priv,
|
|
}
|
|
}
|
|
|
|
|
|
static enum drm_connector_status
|
|
static enum drm_connector_status
|
|
-tda998x_encoder_detect(struct tda998x_priv *priv)
|
|
|
|
|
|
+tda998x_connector_detect(struct drm_connector *connector, bool force)
|
|
{
|
|
{
|
|
- uint8_t val = cec_read(priv, REG_CEC_RXSHPDLEV);
|
|
|
|
|
|
+ struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
|
|
|
|
+ u8 val = cec_read(priv, REG_CEC_RXSHPDLEV);
|
|
|
|
|
|
return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
|
|
return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
|
|
connector_status_disconnected;
|
|
connector_status_disconnected;
|
|
@@ -1042,7 +1092,7 @@ tda998x_encoder_detect(struct tda998x_priv *priv)
|
|
static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
|
|
static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
|
|
{
|
|
{
|
|
struct tda998x_priv *priv = data;
|
|
struct tda998x_priv *priv = data;
|
|
- uint8_t offset, segptr;
|
|
|
|
|
|
+ u8 offset, segptr;
|
|
int ret, i;
|
|
int ret, i;
|
|
|
|
|
|
offset = (blk & 1) ? 128 : 0;
|
|
offset = (blk & 1) ? 128 : 0;
|
|
@@ -1095,13 +1145,20 @@ static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
-tda998x_encoder_get_modes(struct tda998x_priv *priv,
|
|
|
|
- struct drm_connector *connector)
|
|
|
|
|
|
+static int tda998x_connector_get_modes(struct drm_connector *connector)
|
|
{
|
|
{
|
|
|
|
+ struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
|
|
struct edid *edid;
|
|
struct edid *edid;
|
|
int n;
|
|
int n;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If we get killed while waiting for the HPD timeout, return
|
|
|
|
+ * no modes found: we are not in a restartable path, so we
|
|
|
|
+ * can't handle signals gracefully.
|
|
|
|
+ */
|
|
|
|
+ if (tda998x_edid_delay_wait(priv))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
if (priv->rev == TDA19988)
|
|
if (priv->rev == TDA19988)
|
|
reg_clear(priv, REG_TX4, TX4_PD_RAM);
|
|
reg_clear(priv, REG_TX4, TX4_PD_RAM);
|
|
|
|
|
|
@@ -1133,101 +1190,21 @@ static void tda998x_encoder_set_polling(struct tda998x_priv *priv,
|
|
DRM_CONNECTOR_POLL_DISCONNECT;
|
|
DRM_CONNECTOR_POLL_DISCONNECT;
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
-tda998x_encoder_set_property(struct drm_encoder *encoder,
|
|
|
|
- struct drm_connector *connector,
|
|
|
|
- struct drm_property *property,
|
|
|
|
- uint64_t val)
|
|
|
|
-{
|
|
|
|
- DBG("");
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void tda998x_destroy(struct tda998x_priv *priv)
|
|
static void tda998x_destroy(struct tda998x_priv *priv)
|
|
{
|
|
{
|
|
/* disable all IRQs and free the IRQ handler */
|
|
/* disable all IRQs and free the IRQ handler */
|
|
cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
|
|
cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
|
|
reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
|
|
reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
|
|
- if (priv->hdmi->irq) {
|
|
|
|
- free_irq(priv->hdmi->irq, priv);
|
|
|
|
- cancel_delayed_work_sync(&priv->dwork);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- i2c_unregister_device(priv->cec);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Slave encoder support */
|
|
|
|
-
|
|
|
|
-static void
|
|
|
|
-tda998x_encoder_slave_set_config(struct drm_encoder *encoder, void *params)
|
|
|
|
-{
|
|
|
|
- tda998x_encoder_set_config(to_tda998x_priv(encoder), params);
|
|
|
|
-}
|
|
|
|
|
|
|
|
-static void tda998x_encoder_slave_destroy(struct drm_encoder *encoder)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv *priv = to_tda998x_priv(encoder);
|
|
|
|
-
|
|
|
|
- tda998x_destroy(priv);
|
|
|
|
- drm_i2c_encoder_destroy(encoder);
|
|
|
|
- kfree(priv);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void tda998x_encoder_slave_dpms(struct drm_encoder *encoder, int mode)
|
|
|
|
-{
|
|
|
|
- tda998x_encoder_dpms(to_tda998x_priv(encoder), mode);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int tda998x_encoder_slave_mode_valid(struct drm_encoder *encoder,
|
|
|
|
- struct drm_display_mode *mode)
|
|
|
|
-{
|
|
|
|
- return tda998x_encoder_mode_valid(to_tda998x_priv(encoder), mode);
|
|
|
|
-}
|
|
|
|
|
|
+ if (priv->hdmi->irq)
|
|
|
|
+ free_irq(priv->hdmi->irq, priv);
|
|
|
|
|
|
-static void
|
|
|
|
-tda998x_encoder_slave_mode_set(struct drm_encoder *encoder,
|
|
|
|
- struct drm_display_mode *mode,
|
|
|
|
- struct drm_display_mode *adjusted_mode)
|
|
|
|
-{
|
|
|
|
- tda998x_encoder_mode_set(to_tda998x_priv(encoder), mode, adjusted_mode);
|
|
|
|
-}
|
|
|
|
|
|
+ del_timer_sync(&priv->edid_delay_timer);
|
|
|
|
+ cancel_work_sync(&priv->detect_work);
|
|
|
|
|
|
-static enum drm_connector_status
|
|
|
|
-tda998x_encoder_slave_detect(struct drm_encoder *encoder,
|
|
|
|
- struct drm_connector *connector)
|
|
|
|
-{
|
|
|
|
- return tda998x_encoder_detect(to_tda998x_priv(encoder));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int tda998x_encoder_slave_get_modes(struct drm_encoder *encoder,
|
|
|
|
- struct drm_connector *connector)
|
|
|
|
-{
|
|
|
|
- return tda998x_encoder_get_modes(to_tda998x_priv(encoder), connector);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int
|
|
|
|
-tda998x_encoder_slave_create_resources(struct drm_encoder *encoder,
|
|
|
|
- struct drm_connector *connector)
|
|
|
|
-{
|
|
|
|
- tda998x_encoder_set_polling(to_tda998x_priv(encoder), connector);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ i2c_unregister_device(priv->cec);
|
|
}
|
|
}
|
|
|
|
|
|
-static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = {
|
|
|
|
- .set_config = tda998x_encoder_slave_set_config,
|
|
|
|
- .destroy = tda998x_encoder_slave_destroy,
|
|
|
|
- .dpms = tda998x_encoder_slave_dpms,
|
|
|
|
- .save = tda998x_encoder_save,
|
|
|
|
- .restore = tda998x_encoder_restore,
|
|
|
|
- .mode_fixup = tda998x_encoder_mode_fixup,
|
|
|
|
- .mode_valid = tda998x_encoder_slave_mode_valid,
|
|
|
|
- .mode_set = tda998x_encoder_slave_mode_set,
|
|
|
|
- .detect = tda998x_encoder_slave_detect,
|
|
|
|
- .get_modes = tda998x_encoder_slave_get_modes,
|
|
|
|
- .create_resources = tda998x_encoder_slave_create_resources,
|
|
|
|
- .set_property = tda998x_encoder_set_property,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
/* I2C driver functions */
|
|
/* I2C driver functions */
|
|
|
|
|
|
static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
|
|
static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
|
|
@@ -1252,6 +1229,10 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
|
|
priv->dpms = DRM_MODE_DPMS_OFF;
|
|
priv->dpms = DRM_MODE_DPMS_OFF;
|
|
|
|
|
|
mutex_init(&priv->mutex); /* protect the page access */
|
|
mutex_init(&priv->mutex); /* protect the page access */
|
|
|
|
+ init_waitqueue_head(&priv->edid_delay_waitq);
|
|
|
|
+ setup_timer(&priv->edid_delay_timer, tda998x_edid_delay_done,
|
|
|
|
+ (unsigned long)priv);
|
|
|
|
+ INIT_WORK(&priv->detect_work, tda998x_detect_work);
|
|
|
|
|
|
/* wake up the device: */
|
|
/* wake up the device: */
|
|
cec_write(priv, REG_CEC_ENAMODS,
|
|
cec_write(priv, REG_CEC_ENAMODS,
|
|
@@ -1310,7 +1291,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
|
|
|
|
|
|
/* init read EDID waitqueue and HDP work */
|
|
/* init read EDID waitqueue and HDP work */
|
|
init_waitqueue_head(&priv->wq_edid);
|
|
init_waitqueue_head(&priv->wq_edid);
|
|
- INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd);
|
|
|
|
|
|
|
|
/* clear pending interrupts */
|
|
/* clear pending interrupts */
|
|
reg_read(priv, REG_INT_FLAGS_0);
|
|
reg_read(priv, REG_INT_FLAGS_0);
|
|
@@ -1359,84 +1339,31 @@ fail:
|
|
return -ENXIO;
|
|
return -ENXIO;
|
|
}
|
|
}
|
|
|
|
|
|
-static int tda998x_encoder_init(struct i2c_client *client,
|
|
|
|
- struct drm_device *dev,
|
|
|
|
- struct drm_encoder_slave *encoder_slave)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv *priv;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
|
|
- if (!priv)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- priv->encoder = &encoder_slave->base;
|
|
|
|
-
|
|
|
|
- ret = tda998x_create(client, priv);
|
|
|
|
- if (ret) {
|
|
|
|
- kfree(priv);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- encoder_slave->slave_priv = priv;
|
|
|
|
- encoder_slave->slave_funcs = &tda998x_encoder_slave_funcs;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct tda998x_priv2 {
|
|
|
|
- struct tda998x_priv base;
|
|
|
|
- struct drm_encoder encoder;
|
|
|
|
- struct drm_connector connector;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-#define conn_to_tda998x_priv2(x) \
|
|
|
|
- container_of(x, struct tda998x_priv2, connector);
|
|
|
|
-
|
|
|
|
-#define enc_to_tda998x_priv2(x) \
|
|
|
|
- container_of(x, struct tda998x_priv2, encoder);
|
|
|
|
-
|
|
|
|
-static void tda998x_encoder2_dpms(struct drm_encoder *encoder, int mode)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder);
|
|
|
|
-
|
|
|
|
- tda998x_encoder_dpms(&priv->base, mode);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void tda998x_encoder_prepare(struct drm_encoder *encoder)
|
|
static void tda998x_encoder_prepare(struct drm_encoder *encoder)
|
|
{
|
|
{
|
|
- tda998x_encoder2_dpms(encoder, DRM_MODE_DPMS_OFF);
|
|
|
|
|
|
+ tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
|
}
|
|
}
|
|
|
|
|
|
static void tda998x_encoder_commit(struct drm_encoder *encoder)
|
|
static void tda998x_encoder_commit(struct drm_encoder *encoder)
|
|
{
|
|
{
|
|
- tda998x_encoder2_dpms(encoder, DRM_MODE_DPMS_ON);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void tda998x_encoder2_mode_set(struct drm_encoder *encoder,
|
|
|
|
- struct drm_display_mode *mode,
|
|
|
|
- struct drm_display_mode *adjusted_mode)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder);
|
|
|
|
-
|
|
|
|
- tda998x_encoder_mode_set(&priv->base, mode, adjusted_mode);
|
|
|
|
|
|
+ tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
|
|
}
|
|
}
|
|
|
|
|
|
static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
|
|
static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
|
|
- .dpms = tda998x_encoder2_dpms,
|
|
|
|
|
|
+ .dpms = tda998x_encoder_dpms,
|
|
.save = tda998x_encoder_save,
|
|
.save = tda998x_encoder_save,
|
|
.restore = tda998x_encoder_restore,
|
|
.restore = tda998x_encoder_restore,
|
|
.mode_fixup = tda998x_encoder_mode_fixup,
|
|
.mode_fixup = tda998x_encoder_mode_fixup,
|
|
.prepare = tda998x_encoder_prepare,
|
|
.prepare = tda998x_encoder_prepare,
|
|
.commit = tda998x_encoder_commit,
|
|
.commit = tda998x_encoder_commit,
|
|
- .mode_set = tda998x_encoder2_mode_set,
|
|
|
|
|
|
+ .mode_set = tda998x_encoder_mode_set,
|
|
};
|
|
};
|
|
|
|
|
|
static void tda998x_encoder_destroy(struct drm_encoder *encoder)
|
|
static void tda998x_encoder_destroy(struct drm_encoder *encoder)
|
|
{
|
|
{
|
|
- struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder);
|
|
|
|
|
|
+ struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
|
|
|
|
|
|
- tda998x_destroy(&priv->base);
|
|
|
|
|
|
+ tda998x_destroy(priv);
|
|
drm_encoder_cleanup(encoder);
|
|
drm_encoder_cleanup(encoder);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1444,25 +1371,10 @@ static const struct drm_encoder_funcs tda998x_encoder_funcs = {
|
|
.destroy = tda998x_encoder_destroy,
|
|
.destroy = tda998x_encoder_destroy,
|
|
};
|
|
};
|
|
|
|
|
|
-static int tda998x_connector_get_modes(struct drm_connector *connector)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector);
|
|
|
|
-
|
|
|
|
- return tda998x_encoder_get_modes(&priv->base, connector);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int tda998x_connector_mode_valid(struct drm_connector *connector,
|
|
|
|
- struct drm_display_mode *mode)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector);
|
|
|
|
-
|
|
|
|
- return tda998x_encoder_mode_valid(&priv->base, mode);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static struct drm_encoder *
|
|
static struct drm_encoder *
|
|
tda998x_connector_best_encoder(struct drm_connector *connector)
|
|
tda998x_connector_best_encoder(struct drm_connector *connector)
|
|
{
|
|
{
|
|
- struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector);
|
|
|
|
|
|
+ struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
|
|
|
|
|
|
return &priv->encoder;
|
|
return &priv->encoder;
|
|
}
|
|
}
|
|
@@ -1474,14 +1386,6 @@ const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = {
|
|
.best_encoder = tda998x_connector_best_encoder,
|
|
.best_encoder = tda998x_connector_best_encoder,
|
|
};
|
|
};
|
|
|
|
|
|
-static enum drm_connector_status
|
|
|
|
-tda998x_connector_detect(struct drm_connector *connector, bool force)
|
|
|
|
-{
|
|
|
|
- struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector);
|
|
|
|
-
|
|
|
|
- return tda998x_encoder_detect(&priv->base);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void tda998x_connector_destroy(struct drm_connector *connector)
|
|
static void tda998x_connector_destroy(struct drm_connector *connector)
|
|
{
|
|
{
|
|
drm_connector_unregister(connector);
|
|
drm_connector_unregister(connector);
|
|
@@ -1500,8 +1404,8 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
|
|
struct tda998x_encoder_params *params = dev->platform_data;
|
|
struct tda998x_encoder_params *params = dev->platform_data;
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
struct drm_device *drm = data;
|
|
struct drm_device *drm = data;
|
|
- struct tda998x_priv2 *priv;
|
|
|
|
- uint32_t crtcs = 0;
|
|
|
|
|
|
+ struct tda998x_priv *priv;
|
|
|
|
+ u32 crtcs = 0;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
@@ -1519,18 +1423,17 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
|
|
crtcs = 1 << 0;
|
|
crtcs = 1 << 0;
|
|
}
|
|
}
|
|
|
|
|
|
- priv->base.encoder = &priv->encoder;
|
|
|
|
priv->connector.interlace_allowed = 1;
|
|
priv->connector.interlace_allowed = 1;
|
|
priv->encoder.possible_crtcs = crtcs;
|
|
priv->encoder.possible_crtcs = crtcs;
|
|
|
|
|
|
- ret = tda998x_create(client, &priv->base);
|
|
|
|
|
|
+ ret = tda998x_create(client, priv);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
if (!dev->of_node && params)
|
|
if (!dev->of_node && params)
|
|
- tda998x_encoder_set_config(&priv->base, params);
|
|
|
|
|
|
+ tda998x_encoder_set_config(priv, params);
|
|
|
|
|
|
- tda998x_encoder_set_polling(&priv->base, &priv->connector);
|
|
|
|
|
|
+ tda998x_encoder_set_polling(priv, &priv->connector);
|
|
|
|
|
|
drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
|
|
drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
|
|
ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
|
|
ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
|
|
@@ -1560,18 +1463,18 @@ err_sysfs:
|
|
err_connector:
|
|
err_connector:
|
|
drm_encoder_cleanup(&priv->encoder);
|
|
drm_encoder_cleanup(&priv->encoder);
|
|
err_encoder:
|
|
err_encoder:
|
|
- tda998x_destroy(&priv->base);
|
|
|
|
|
|
+ tda998x_destroy(priv);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static void tda998x_unbind(struct device *dev, struct device *master,
|
|
static void tda998x_unbind(struct device *dev, struct device *master,
|
|
void *data)
|
|
void *data)
|
|
{
|
|
{
|
|
- struct tda998x_priv2 *priv = dev_get_drvdata(dev);
|
|
|
|
|
|
+ struct tda998x_priv *priv = dev_get_drvdata(dev);
|
|
|
|
|
|
drm_connector_cleanup(&priv->connector);
|
|
drm_connector_cleanup(&priv->connector);
|
|
drm_encoder_cleanup(&priv->encoder);
|
|
drm_encoder_cleanup(&priv->encoder);
|
|
- tda998x_destroy(&priv->base);
|
|
|
|
|
|
+ tda998x_destroy(priv);
|
|
}
|
|
}
|
|
|
|
|
|
static const struct component_ops tda998x_ops = {
|
|
static const struct component_ops tda998x_ops = {
|
|
@@ -1605,38 +1508,18 @@ static struct i2c_device_id tda998x_ids[] = {
|
|
};
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, tda998x_ids);
|
|
MODULE_DEVICE_TABLE(i2c, tda998x_ids);
|
|
|
|
|
|
-static struct drm_i2c_encoder_driver tda998x_driver = {
|
|
|
|
- .i2c_driver = {
|
|
|
|
- .probe = tda998x_probe,
|
|
|
|
- .remove = tda998x_remove,
|
|
|
|
- .driver = {
|
|
|
|
- .name = "tda998x",
|
|
|
|
- .of_match_table = of_match_ptr(tda998x_dt_ids),
|
|
|
|
- },
|
|
|
|
- .id_table = tda998x_ids,
|
|
|
|
|
|
+static struct i2c_driver tda998x_driver = {
|
|
|
|
+ .probe = tda998x_probe,
|
|
|
|
+ .remove = tda998x_remove,
|
|
|
|
+ .driver = {
|
|
|
|
+ .name = "tda998x",
|
|
|
|
+ .of_match_table = of_match_ptr(tda998x_dt_ids),
|
|
},
|
|
},
|
|
- .encoder_init = tda998x_encoder_init,
|
|
|
|
|
|
+ .id_table = tda998x_ids,
|
|
};
|
|
};
|
|
|
|
|
|
-/* Module initialization */
|
|
|
|
-
|
|
|
|
-static int __init
|
|
|
|
-tda998x_init(void)
|
|
|
|
-{
|
|
|
|
- DBG("");
|
|
|
|
- return drm_i2c_encoder_register(THIS_MODULE, &tda998x_driver);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void __exit
|
|
|
|
-tda998x_exit(void)
|
|
|
|
-{
|
|
|
|
- DBG("");
|
|
|
|
- drm_i2c_encoder_unregister(&tda998x_driver);
|
|
|
|
-}
|
|
|
|
|
|
+module_i2c_driver(tda998x_driver);
|
|
|
|
|
|
MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
|
|
MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
|
|
MODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder");
|
|
MODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_LICENSE("GPL");
|
|
-
|
|
|
|
-module_init(tda998x_init);
|
|
|
|
-module_exit(tda998x_exit);
|
|
|