Skip to content

Commit f25ee50

Browse files
tombaAndrzej Hajda
authored andcommitted
drm/bridge: tc358767: add IRQ and HPD support
Add support for interrupt and hotplug handling. Both are optional. Signed-off-by: Tomi Valkeinen <[email protected]> Reviewed-by: Andrzej Hajda <[email protected]> Signed-off-by: Andrzej Hajda <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent af9526f commit f25ee50

File tree

1 file changed

+145
-18
lines changed

1 file changed

+145
-18
lines changed

drivers/gpu/drm/bridge/tc358767.c

Lines changed: 145 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
/* System */
7373
#define TC_IDREG 0x0500
74+
#define SYSSTAT 0x0508
7475
#define SYSCTRL 0x0510
7576
#define DP0_AUDSRC_NO_INPUT (0 << 3)
7677
#define DP0_AUDSRC_I2S_RX (1 << 3)
@@ -79,9 +80,16 @@
7980
#define DP0_VIDSRC_DPI_RX (2 << 0)
8081
#define DP0_VIDSRC_COLOR_BAR (3 << 0)
8182
#define GPIOM 0x0540
83+
#define GPIOC 0x0544
84+
#define GPIOO 0x0548
8285
#define GPIOI 0x054c
8386
#define INTCTL_G 0x0560
8487
#define INTSTS_G 0x0564
88+
89+
#define INT_SYSERR BIT(16)
90+
#define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10))
91+
#define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11))
92+
8593
#define INT_GP0_LCNT 0x0584
8694
#define INT_GP1_LCNT 0x0588
8795

@@ -219,6 +227,12 @@ struct tc_data {
219227
struct gpio_desc *sd_gpio;
220228
struct gpio_desc *reset_gpio;
221229
struct clk *refclk;
230+
231+
/* do we have IRQ */
232+
bool have_irq;
233+
234+
/* HPD pin number (0 or 1) or -ENODEV */
235+
int hpd_pin;
222236
};
223237

224238
static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a)
@@ -1109,6 +1123,12 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
11091123
struct tc_data *tc = bridge_to_tc(bridge);
11101124
int ret;
11111125

1126+
ret = tc_get_display_props(tc);
1127+
if (ret < 0) {
1128+
dev_err(tc->dev, "failed to read display props: %d\n", ret);
1129+
return;
1130+
}
1131+
11121132
ret = tc_main_link_enable(tc);
11131133
if (ret < 0) {
11141134
dev_err(tc->dev, "main link enable error: %d\n", ret);
@@ -1221,19 +1241,40 @@ static int tc_connector_get_modes(struct drm_connector *connector)
12211241
return count;
12221242
}
12231243

1224-
static void tc_connector_set_polling(struct tc_data *tc,
1225-
struct drm_connector *connector)
1226-
{
1227-
/* TODO: add support for HPD */
1228-
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
1229-
DRM_CONNECTOR_POLL_DISCONNECT;
1230-
}
1231-
12321244
static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
12331245
.get_modes = tc_connector_get_modes,
12341246
};
12351247

1248+
static enum drm_connector_status tc_connector_detect(struct drm_connector *connector,
1249+
bool force)
1250+
{
1251+
struct tc_data *tc = connector_to_tc(connector);
1252+
bool conn;
1253+
u32 val;
1254+
int ret;
1255+
1256+
if (tc->hpd_pin < 0) {
1257+
if (tc->panel)
1258+
return connector_status_connected;
1259+
else
1260+
return connector_status_unknown;
1261+
}
1262+
1263+
tc_read(GPIOI, &val);
1264+
1265+
conn = val & BIT(tc->hpd_pin);
1266+
1267+
if (conn)
1268+
return connector_status_connected;
1269+
else
1270+
return connector_status_disconnected;
1271+
1272+
err:
1273+
return connector_status_unknown;
1274+
}
1275+
12361276
static const struct drm_connector_funcs tc_connector_funcs = {
1277+
.detect = tc_connector_detect,
12371278
.fill_modes = drm_helper_probe_single_connector_modes,
12381279
.destroy = drm_connector_cleanup,
12391280
.reset = drm_atomic_helper_connector_reset,
@@ -1248,14 +1289,23 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
12481289
struct drm_device *drm = bridge->dev;
12491290
int ret;
12501291

1251-
/* Create eDP connector */
1292+
/* Create DP/eDP connector */
12521293
drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
12531294
ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
12541295
tc->panel ? DRM_MODE_CONNECTOR_eDP :
12551296
DRM_MODE_CONNECTOR_DisplayPort);
12561297
if (ret)
12571298
return ret;
12581299

1300+
/* Don't poll if don't have HPD connected */
1301+
if (tc->hpd_pin >= 0) {
1302+
if (tc->have_irq)
1303+
tc->connector.polled = DRM_CONNECTOR_POLL_HPD;
1304+
else
1305+
tc->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
1306+
DRM_CONNECTOR_POLL_DISCONNECT;
1307+
}
1308+
12591309
if (tc->panel)
12601310
drm_panel_attach(tc->panel, &tc->connector);
12611311

@@ -1322,6 +1372,49 @@ static const struct regmap_config tc_regmap_config = {
13221372
.val_format_endian = REGMAP_ENDIAN_LITTLE,
13231373
};
13241374

1375+
static irqreturn_t tc_irq_handler(int irq, void *arg)
1376+
{
1377+
struct tc_data *tc = arg;
1378+
u32 val;
1379+
int r;
1380+
1381+
r = regmap_read(tc->regmap, INTSTS_G, &val);
1382+
if (r)
1383+
return IRQ_NONE;
1384+
1385+
if (!val)
1386+
return IRQ_NONE;
1387+
1388+
if (val & INT_SYSERR) {
1389+
u32 stat = 0;
1390+
1391+
regmap_read(tc->regmap, SYSSTAT, &stat);
1392+
1393+
dev_err(tc->dev, "syserr %x\n", stat);
1394+
}
1395+
1396+
if (tc->hpd_pin >= 0 && tc->bridge.dev) {
1397+
/*
1398+
* H is triggered when the GPIO goes high.
1399+
*
1400+
* LC is triggered when the GPIO goes low and stays low for
1401+
* the duration of LCNT
1402+
*/
1403+
bool h = val & INT_GPIO_H(tc->hpd_pin);
1404+
bool lc = val & INT_GPIO_LC(tc->hpd_pin);
1405+
1406+
dev_dbg(tc->dev, "GPIO%d: %s %s\n", tc->hpd_pin,
1407+
h ? "H" : "", lc ? "LC" : "");
1408+
1409+
if (h || lc)
1410+
drm_kms_helper_hotplug_event(tc->bridge.dev);
1411+
}
1412+
1413+
regmap_write(tc->regmap, INTSTS_G, val);
1414+
1415+
return IRQ_HANDLED;
1416+
}
1417+
13251418
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
13261419
{
13271420
struct device *dev = &client->dev;
@@ -1373,6 +1466,33 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
13731466
return ret;
13741467
}
13751468

1469+
ret = of_property_read_u32(dev->of_node, "toshiba,hpd-pin",
1470+
&tc->hpd_pin);
1471+
if (ret) {
1472+
tc->hpd_pin = -ENODEV;
1473+
} else {
1474+
if (tc->hpd_pin < 0 || tc->hpd_pin > 1) {
1475+
dev_err(dev, "failed to parse HPD number\n");
1476+
return ret;
1477+
}
1478+
}
1479+
1480+
if (client->irq > 0) {
1481+
/* enable SysErr */
1482+
regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
1483+
1484+
ret = devm_request_threaded_irq(dev, client->irq,
1485+
NULL, tc_irq_handler,
1486+
IRQF_ONESHOT,
1487+
"tc358767-irq", tc);
1488+
if (ret) {
1489+
dev_err(dev, "failed to register dp interrupt\n");
1490+
return ret;
1491+
}
1492+
1493+
tc->have_irq = true;
1494+
}
1495+
13761496
ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
13771497
if (ret) {
13781498
dev_err(tc->dev, "can not read device ID: %d\n", ret);
@@ -1386,6 +1506,22 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
13861506

13871507
tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
13881508

1509+
if (tc->hpd_pin >= 0) {
1510+
u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
1511+
u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
1512+
1513+
/* Set LCNT to 2ms */
1514+
regmap_write(tc->regmap, lcnt_reg,
1515+
clk_get_rate(tc->refclk) * 2 / 1000);
1516+
/* We need the "alternate" mode for HPD */
1517+
regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
1518+
1519+
if (tc->have_irq) {
1520+
/* enable H & LC */
1521+
regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
1522+
}
1523+
}
1524+
13891525
ret = tc_aux_link_setup(tc);
13901526
if (ret)
13911527
return ret;
@@ -1398,22 +1534,13 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
13981534
if (ret)
13991535
return ret;
14001536

1401-
ret = tc_get_display_props(tc);
1402-
if (ret)
1403-
goto err_unregister_aux;
1404-
1405-
tc_connector_set_polling(tc, &tc->connector);
1406-
14071537
tc->bridge.funcs = &tc_bridge_funcs;
14081538
tc->bridge.of_node = dev->of_node;
14091539
drm_bridge_add(&tc->bridge);
14101540

14111541
i2c_set_clientdata(client, tc);
14121542

14131543
return 0;
1414-
err_unregister_aux:
1415-
drm_dp_aux_unregister(&tc->aux);
1416-
return ret;
14171544
}
14181545

14191546
static int tc_remove(struct i2c_client *client)

0 commit comments

Comments
 (0)