diff options
Diffstat (limited to 'drivers/gpu/drm/i2c/tda998x_drv.c')
-rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index d4762799351d..a9041d1a8ff0 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -32,6 +32,8 @@ | |||
32 | struct tda998x_priv { | 32 | struct tda998x_priv { |
33 | struct i2c_client *cec; | 33 | struct i2c_client *cec; |
34 | struct i2c_client *hdmi; | 34 | struct i2c_client *hdmi; |
35 | struct mutex mutex; | ||
36 | struct delayed_work dwork; | ||
35 | uint16_t rev; | 37 | uint16_t rev; |
36 | uint8_t current_page; | 38 | uint8_t current_page; |
37 | int dpms; | 39 | int dpms; |
@@ -402,9 +404,10 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) | |||
402 | uint8_t addr = REG2ADDR(reg); | 404 | uint8_t addr = REG2ADDR(reg); |
403 | int ret; | 405 | int ret; |
404 | 406 | ||
407 | mutex_lock(&priv->mutex); | ||
405 | ret = set_page(priv, reg); | 408 | ret = set_page(priv, reg); |
406 | if (ret < 0) | 409 | if (ret < 0) |
407 | return ret; | 410 | goto out; |
408 | 411 | ||
409 | ret = i2c_master_send(client, &addr, sizeof(addr)); | 412 | ret = i2c_master_send(client, &addr, sizeof(addr)); |
410 | if (ret < 0) | 413 | if (ret < 0) |
@@ -414,10 +417,12 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) | |||
414 | if (ret < 0) | 417 | if (ret < 0) |
415 | goto fail; | 418 | goto fail; |
416 | 419 | ||
417 | return ret; | 420 | goto out; |
418 | 421 | ||
419 | fail: | 422 | fail: |
420 | dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg); | 423 | dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg); |
424 | out: | ||
425 | mutex_unlock(&priv->mutex); | ||
421 | return ret; | 426 | return ret; |
422 | } | 427 | } |
423 | 428 | ||
@@ -431,13 +436,16 @@ reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt) | |||
431 | buf[0] = REG2ADDR(reg); | 436 | buf[0] = REG2ADDR(reg); |
432 | memcpy(&buf[1], p, cnt); | 437 | memcpy(&buf[1], p, cnt); |
433 | 438 | ||
439 | mutex_lock(&priv->mutex); | ||
434 | ret = set_page(priv, reg); | 440 | ret = set_page(priv, reg); |
435 | if (ret < 0) | 441 | if (ret < 0) |
436 | return; | 442 | goto out; |
437 | 443 | ||
438 | ret = i2c_master_send(client, buf, cnt + 1); | 444 | ret = i2c_master_send(client, buf, cnt + 1); |
439 | if (ret < 0) | 445 | if (ret < 0) |
440 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); | 446 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); |
447 | out: | ||
448 | mutex_unlock(&priv->mutex); | ||
441 | } | 449 | } |
442 | 450 | ||
443 | static int | 451 | static int |
@@ -459,13 +467,16 @@ reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val) | |||
459 | uint8_t buf[] = {REG2ADDR(reg), val}; | 467 | uint8_t buf[] = {REG2ADDR(reg), val}; |
460 | int ret; | 468 | int ret; |
461 | 469 | ||
470 | mutex_lock(&priv->mutex); | ||
462 | ret = set_page(priv, reg); | 471 | ret = set_page(priv, reg); |
463 | if (ret < 0) | 472 | if (ret < 0) |
464 | return; | 473 | goto out; |
465 | 474 | ||
466 | ret = i2c_master_send(client, buf, sizeof(buf)); | 475 | ret = i2c_master_send(client, buf, sizeof(buf)); |
467 | if (ret < 0) | 476 | if (ret < 0) |
468 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); | 477 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); |
478 | out: | ||
479 | mutex_unlock(&priv->mutex); | ||
469 | } | 480 | } |
470 | 481 | ||
471 | static void | 482 | static void |
@@ -475,13 +486,16 @@ reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val) | |||
475 | uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; | 486 | uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; |
476 | int ret; | 487 | int ret; |
477 | 488 | ||
489 | mutex_lock(&priv->mutex); | ||
478 | ret = set_page(priv, reg); | 490 | ret = set_page(priv, reg); |
479 | if (ret < 0) | 491 | if (ret < 0) |
480 | return; | 492 | goto out; |
481 | 493 | ||
482 | ret = i2c_master_send(client, buf, sizeof(buf)); | 494 | ret = i2c_master_send(client, buf, sizeof(buf)); |
483 | if (ret < 0) | 495 | if (ret < 0) |
484 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); | 496 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); |
497 | out: | ||
498 | mutex_unlock(&priv->mutex); | ||
485 | } | 499 | } |
486 | 500 | ||
487 | static void | 501 | static void |
@@ -536,6 +550,17 @@ tda998x_reset(struct tda998x_priv *priv) | |||
536 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); | 550 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); |
537 | } | 551 | } |
538 | 552 | ||
553 | /* handle HDMI connect/disconnect */ | ||
554 | static void tda998x_hpd(struct work_struct *work) | ||
555 | { | ||
556 | struct delayed_work *dwork = to_delayed_work(work); | ||
557 | struct tda998x_priv *priv = | ||
558 | container_of(dwork, struct tda998x_priv, dwork); | ||
559 | |||
560 | if (priv->encoder && priv->encoder->dev) | ||
561 | drm_kms_helper_hotplug_event(priv->encoder->dev); | ||
562 | } | ||
563 | |||
539 | /* | 564 | /* |
540 | * only 2 interrupts may occur: screen plug/unplug and EDID read | 565 | * only 2 interrupts may occur: screen plug/unplug and EDID read |
541 | */ | 566 | */ |
@@ -559,8 +584,7 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) | |||
559 | priv->wq_edid_wait = 0; | 584 | priv->wq_edid_wait = 0; |
560 | wake_up(&priv->wq_edid); | 585 | wake_up(&priv->wq_edid); |
561 | } else if (cec != 0) { /* HPD change */ | 586 | } else if (cec != 0) { /* HPD change */ |
562 | if (priv->encoder && priv->encoder->dev) | 587 | schedule_delayed_work(&priv->dwork, HZ/10); |
563 | drm_helper_hpd_irq_event(priv->encoder->dev); | ||
564 | } | 588 | } |
565 | return IRQ_HANDLED; | 589 | return IRQ_HANDLED; |
566 | } | 590 | } |
@@ -1170,8 +1194,10 @@ static void tda998x_destroy(struct tda998x_priv *priv) | |||
1170 | /* disable all IRQs and free the IRQ handler */ | 1194 | /* disable all IRQs and free the IRQ handler */ |
1171 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); | 1195 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); |
1172 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); | 1196 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); |
1173 | if (priv->hdmi->irq) | 1197 | if (priv->hdmi->irq) { |
1174 | free_irq(priv->hdmi->irq, priv); | 1198 | free_irq(priv->hdmi->irq, priv); |
1199 | cancel_delayed_work_sync(&priv->dwork); | ||
1200 | } | ||
1175 | 1201 | ||
1176 | i2c_unregister_device(priv->cec); | 1202 | i2c_unregister_device(priv->cec); |
1177 | } | 1203 | } |
@@ -1255,6 +1281,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
1255 | struct device_node *np = client->dev.of_node; | 1281 | struct device_node *np = client->dev.of_node; |
1256 | u32 video; | 1282 | u32 video; |
1257 | int rev_lo, rev_hi, ret; | 1283 | int rev_lo, rev_hi, ret; |
1284 | unsigned short cec_addr; | ||
1258 | 1285 | ||
1259 | priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); | 1286 | priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); |
1260 | priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); | 1287 | priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); |
@@ -1262,12 +1289,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
1262 | 1289 | ||
1263 | priv->current_page = 0xff; | 1290 | priv->current_page = 0xff; |
1264 | priv->hdmi = client; | 1291 | priv->hdmi = client; |
1265 | priv->cec = i2c_new_dummy(client->adapter, 0x34); | 1292 | /* CEC I2C address bound to TDA998x I2C addr by configuration pins */ |
1293 | cec_addr = 0x34 + (client->addr & 0x03); | ||
1294 | priv->cec = i2c_new_dummy(client->adapter, cec_addr); | ||
1266 | if (!priv->cec) | 1295 | if (!priv->cec) |
1267 | return -ENODEV; | 1296 | return -ENODEV; |
1268 | 1297 | ||
1269 | priv->dpms = DRM_MODE_DPMS_OFF; | 1298 | priv->dpms = DRM_MODE_DPMS_OFF; |
1270 | 1299 | ||
1300 | mutex_init(&priv->mutex); /* protect the page access */ | ||
1301 | |||
1271 | /* wake up the device: */ | 1302 | /* wake up the device: */ |
1272 | cec_write(priv, REG_CEC_ENAMODS, | 1303 | cec_write(priv, REG_CEC_ENAMODS, |
1273 | CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI); | 1304 | CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI); |
@@ -1323,8 +1354,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
1323 | if (client->irq) { | 1354 | if (client->irq) { |
1324 | int irqf_trigger; | 1355 | int irqf_trigger; |
1325 | 1356 | ||
1326 | /* init read EDID waitqueue */ | 1357 | /* init read EDID waitqueue and HDP work */ |
1327 | init_waitqueue_head(&priv->wq_edid); | 1358 | init_waitqueue_head(&priv->wq_edid); |
1359 | INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd); | ||
1328 | 1360 | ||
1329 | /* clear pending interrupts */ | 1361 | /* clear pending interrupts */ |
1330 | reg_read(priv, REG_INT_FLAGS_0); | 1362 | reg_read(priv, REG_INT_FLAGS_0); |