diff options
| -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); |
