Skip to content

Commit fa90dac

Browse files
committed
Merge branch 'at91-4.19-trunk/base_lcd' into linux-4.19-at91
2 parents 7c19085 + 5ec234b commit fa90dac

2 files changed

Lines changed: 179 additions & 69 deletions

File tree

drivers/gpu/drm/bridge/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ config DRM_SII902X
9595
depends on OF
9696
select DRM_KMS_HELPER
9797
select REGMAP_I2C
98+
select I2C_MUX
9899
---help---
99100
Silicon Image sii902x bridge chip driver.
100101

drivers/gpu/drm/bridge/sii902x.c

Lines changed: 178 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/*
2+
* Copyright (C) 2018 Renesas Electronics
3+
*
24
* Copyright (C) 2016 Atmel
35
* Bo Shen <voice.shen@atmel.com>
46
*
@@ -21,6 +23,7 @@
2123
*/
2224

2325
#include <linux/gpio/consumer.h>
26+
#include <linux/i2c-mux.h>
2427
#include <linux/i2c.h>
2528
#include <linux/module.h>
2629
#include <linux/regmap.h>
@@ -86,8 +89,49 @@ struct sii902x {
8689
struct drm_bridge bridge;
8790
struct drm_connector connector;
8891
struct gpio_desc *reset_gpio;
92+
struct i2c_mux_core *i2cmux;
8993
};
9094

95+
static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val)
96+
{
97+
union i2c_smbus_data data;
98+
int ret;
99+
100+
ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
101+
I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data);
102+
103+
if (ret < 0)
104+
return ret;
105+
106+
*val = data.byte;
107+
return 0;
108+
}
109+
110+
static int sii902x_write_unlocked(struct i2c_client *i2c, u8 reg, u8 val)
111+
{
112+
union i2c_smbus_data data;
113+
114+
data.byte = val;
115+
116+
return __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
117+
I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA,
118+
&data);
119+
}
120+
121+
static int sii902x_update_bits_unlocked(struct i2c_client *i2c, u8 reg, u8 mask,
122+
u8 val)
123+
{
124+
int ret;
125+
u8 status;
126+
127+
ret = sii902x_read_unlocked(i2c, reg, &status);
128+
if (ret)
129+
return ret;
130+
status &= ~mask;
131+
status |= val & mask;
132+
return sii902x_write_unlocked(i2c, reg, status);
133+
}
134+
91135
static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge)
92136
{
93137
return container_of(bridge, struct sii902x, bridge);
@@ -135,41 +179,11 @@ static const struct drm_connector_funcs sii902x_connector_funcs = {
135179
static int sii902x_get_modes(struct drm_connector *connector)
136180
{
137181
struct sii902x *sii902x = connector_to_sii902x(connector);
138-
struct regmap *regmap = sii902x->regmap;
139182
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
140-
struct device *dev = &sii902x->i2c->dev;
141-
unsigned long timeout;
142-
unsigned int retries;
143-
unsigned int status;
144183
struct edid *edid;
145-
int num = 0;
146-
int ret;
147-
148-
ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
149-
SII902X_SYS_CTRL_DDC_BUS_REQ,
150-
SII902X_SYS_CTRL_DDC_BUS_REQ);
151-
if (ret)
152-
return ret;
153-
154-
timeout = jiffies +
155-
msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
156-
do {
157-
ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
158-
if (ret)
159-
return ret;
160-
} while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
161-
time_before(jiffies, timeout));
184+
int num = 0, ret;
162185

163-
if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
164-
dev_err(dev, "failed to acquire the i2c bus\n");
165-
return -ETIMEDOUT;
166-
}
167-
168-
ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status);
169-
if (ret)
170-
return ret;
171-
172-
edid = drm_get_edid(connector, sii902x->i2c->adapter);
186+
edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]);
173187
drm_connector_update_edid_property(connector, edid);
174188
if (edid) {
175189
num = drm_add_edid_modes(connector, edid);
@@ -181,42 +195,6 @@ static int sii902x_get_modes(struct drm_connector *connector)
181195
if (ret)
182196
return ret;
183197

184-
/*
185-
* Sometimes the I2C bus can stall after failure to use the
186-
* EDID channel. Retry a few times to see if things clear
187-
* up, else continue anyway.
188-
*/
189-
retries = 5;
190-
do {
191-
ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA,
192-
&status);
193-
retries--;
194-
} while (ret && retries);
195-
if (ret)
196-
dev_err(dev, "failed to read status (%d)\n", ret);
197-
198-
ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
199-
SII902X_SYS_CTRL_DDC_BUS_REQ |
200-
SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
201-
if (ret)
202-
return ret;
203-
204-
timeout = jiffies +
205-
msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
206-
do {
207-
ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
208-
if (ret)
209-
return ret;
210-
} while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
211-
SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
212-
time_before(jiffies, timeout));
213-
214-
if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
215-
SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
216-
dev_err(dev, "failed to release the i2c bus\n");
217-
return -ETIMEDOUT;
218-
}
219-
220198
return num;
221199
}
222200

@@ -366,6 +344,121 @@ static irqreturn_t sii902x_interrupt(int irq, void *data)
366344
return IRQ_HANDLED;
367345
}
368346

347+
/*
348+
* The purpose of sii902x_i2c_bypass_select is to enable the pass through
349+
* mode of the HDMI transmitter. Do not use regmap from within this function,
350+
* only use sii902x_*_unlocked functions to read/modify/write registers.
351+
* We are holding the parent adapter lock here, keep this in mind before
352+
* adding more i2c transactions.
353+
*
354+
* Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere
355+
* in this driver, we need to make sure that we only touch 0x1A[2:1] from
356+
* within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that
357+
* we leave the remaining bits as we have found them.
358+
*/
359+
static int sii902x_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
360+
{
361+
struct sii902x *sii902x = i2c_mux_priv(mux);
362+
struct device *dev = &sii902x->i2c->dev;
363+
unsigned long timeout;
364+
u8 status;
365+
int ret;
366+
367+
ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
368+
SII902X_SYS_CTRL_DDC_BUS_REQ,
369+
SII902X_SYS_CTRL_DDC_BUS_REQ);
370+
if (ret)
371+
return ret;
372+
373+
timeout = jiffies +
374+
msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
375+
do {
376+
ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
377+
&status);
378+
if (ret)
379+
return ret;
380+
} while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
381+
time_before(jiffies, timeout));
382+
383+
if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
384+
dev_err(dev, "Failed to acquire the i2c bus\n");
385+
return -ETIMEDOUT;
386+
}
387+
388+
return sii902x_write_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
389+
status);
390+
}
391+
392+
/*
393+
* The purpose of sii902x_i2c_bypass_deselect is to disable the pass through
394+
* mode of the HDMI transmitter. Do not use regmap from within this function,
395+
* only use sii902x_*_unlocked functions to read/modify/write registers.
396+
* We are holding the parent adapter lock here, keep this in mind before
397+
* adding more i2c transactions.
398+
*
399+
* Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere
400+
* in this driver, we need to make sure that we only touch 0x1A[2:1] from
401+
* within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that
402+
* we leave the remaining bits as we have found them.
403+
*/
404+
static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
405+
{
406+
struct sii902x *sii902x = i2c_mux_priv(mux);
407+
struct device *dev = &sii902x->i2c->dev;
408+
unsigned long timeout;
409+
unsigned int retries;
410+
u8 status;
411+
int ret;
412+
413+
/*
414+
* When the HDMI transmitter is in pass through mode, we need an
415+
* (undocumented) additional delay between STOP and START conditions
416+
* to guarantee the bus won't get stuck.
417+
*/
418+
udelay(30);
419+
420+
/*
421+
* Sometimes the I2C bus can stall after failure to use the
422+
* EDID channel. Retry a few times to see if things clear
423+
* up, else continue anyway.
424+
*/
425+
retries = 5;
426+
do {
427+
ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
428+
&status);
429+
retries--;
430+
} while (ret && retries);
431+
if (ret) {
432+
dev_err(dev, "failed to read status (%d)\n", ret);
433+
return ret;
434+
}
435+
436+
ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
437+
SII902X_SYS_CTRL_DDC_BUS_REQ |
438+
SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
439+
if (ret)
440+
return ret;
441+
442+
timeout = jiffies +
443+
msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
444+
do {
445+
ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
446+
&status);
447+
if (ret)
448+
return ret;
449+
} while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
450+
SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
451+
time_before(jiffies, timeout));
452+
453+
if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
454+
SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
455+
dev_err(dev, "failed to release the i2c bus\n");
456+
return -ETIMEDOUT;
457+
}
458+
459+
return 0;
460+
}
461+
369462
static int sii902x_probe(struct i2c_client *client,
370463
const struct i2c_device_id *id)
371464
{
@@ -375,6 +468,13 @@ static int sii902x_probe(struct i2c_client *client,
375468
u8 chipid[4];
376469
int ret;
377470

471+
ret = i2c_check_functionality(client->adapter,
472+
I2C_FUNC_SMBUS_BYTE_DATA);
473+
if (!ret) {
474+
dev_err(dev, "I2C adapter not suitable\n");
475+
return -EIO;
476+
}
477+
378478
sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL);
379479
if (!sii902x)
380480
return -ENOMEM;
@@ -433,14 +533,23 @@ static int sii902x_probe(struct i2c_client *client,
433533

434534
i2c_set_clientdata(client, sii902x);
435535

436-
return 0;
536+
sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev,
537+
1, 0, I2C_MUX_GATE,
538+
sii902x_i2c_bypass_select,
539+
sii902x_i2c_bypass_deselect);
540+
if (!sii902x->i2cmux)
541+
return -ENOMEM;
542+
543+
sii902x->i2cmux->priv = sii902x;
544+
return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
437545
}
438546

439547
static int sii902x_remove(struct i2c_client *client)
440548

441549
{
442550
struct sii902x *sii902x = i2c_get_clientdata(client);
443551

552+
i2c_mux_del_adapters(sii902x->i2cmux);
444553
drm_bridge_remove(&sii902x->bridge);
445554

446555
return 0;

0 commit comments

Comments
 (0)