.. | .. |
---|
43 | 43 | #include <linux/printk.h> |
---|
44 | 44 | |
---|
45 | 45 | #include <linux/rk-camera-module.h> |
---|
| 46 | +#include "../platform/rockchip/isp/rkisp_tb_helper.h" |
---|
46 | 47 | #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) |
---|
47 | 48 | |
---|
48 | 49 | #ifndef V4L2_CID_DIGITAL_GAIN |
---|
.. | .. |
---|
195 | 196 | const char *module_name; |
---|
196 | 197 | const char *len_name; |
---|
197 | 198 | bool has_init_exp; |
---|
| 199 | + bool is_thunderboot; |
---|
| 200 | + bool is_first_streamoff; |
---|
198 | 201 | struct preisp_hdrae_exp_s init_hdrae_exp; |
---|
199 | 202 | }; |
---|
200 | 203 | |
---|
.. | .. |
---|
1351 | 1354 | { |
---|
1352 | 1355 | int ret; |
---|
1353 | 1356 | |
---|
1354 | | - ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); |
---|
1355 | | - if (ret) |
---|
1356 | | - return ret; |
---|
1357 | | - |
---|
1358 | | - /* In case these controls are set before streaming */ |
---|
1359 | | - ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); |
---|
1360 | | - if (ret) |
---|
1361 | | - return ret; |
---|
1362 | | - if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { |
---|
1363 | | - ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, |
---|
1364 | | - &sc530ai->init_hdrae_exp); |
---|
1365 | | - if (ret) { |
---|
1366 | | - dev_err(&sc530ai->client->dev, |
---|
1367 | | - "init exp fail in hdr mode\n"); |
---|
| 1357 | + if (!sc530ai->is_thunderboot) { |
---|
| 1358 | + ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); |
---|
| 1359 | + if (ret) |
---|
1368 | 1360 | return ret; |
---|
| 1361 | + |
---|
| 1362 | + /* In case these controls are set before streaming */ |
---|
| 1363 | + ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); |
---|
| 1364 | + if (ret) |
---|
| 1365 | + return ret; |
---|
| 1366 | + if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { |
---|
| 1367 | + ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, |
---|
| 1368 | + &sc530ai->init_hdrae_exp); |
---|
| 1369 | + if (ret) { |
---|
| 1370 | + dev_err(&sc530ai->client->dev, |
---|
| 1371 | + "init exp fail in hdr mode\n"); |
---|
| 1372 | + return ret; |
---|
| 1373 | + } |
---|
1369 | 1374 | } |
---|
1370 | 1375 | } |
---|
1371 | 1376 | return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, |
---|
.. | .. |
---|
1376 | 1381 | static int __sc530ai_stop_stream(struct sc530ai *sc530ai) |
---|
1377 | 1382 | { |
---|
1378 | 1383 | sc530ai->has_init_exp = false; |
---|
| 1384 | + if (sc530ai->is_thunderboot) { |
---|
| 1385 | + sc530ai->is_first_streamoff = true; |
---|
| 1386 | + pm_runtime_put(&sc530ai->client->dev); |
---|
| 1387 | + } |
---|
1379 | 1388 | return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, |
---|
1380 | 1389 | SC530AI_REG_VALUE_08BIT, |
---|
1381 | 1390 | SC530AI_MODE_SW_STANDBY); |
---|
1382 | 1391 | } |
---|
1383 | 1392 | |
---|
| 1393 | +static int __sc530ai_power_on(struct sc530ai *sc530ai); |
---|
1384 | 1394 | static int sc530ai_s_stream(struct v4l2_subdev *sd, int on) |
---|
1385 | 1395 | { |
---|
1386 | 1396 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
.. | .. |
---|
1392 | 1402 | if (on == sc530ai->streaming) |
---|
1393 | 1403 | goto unlock_and_return; |
---|
1394 | 1404 | if (on) { |
---|
| 1405 | + if (sc530ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { |
---|
| 1406 | + sc530ai->is_thunderboot = false; |
---|
| 1407 | + __sc530ai_power_on(sc530ai); |
---|
| 1408 | + } |
---|
1395 | 1409 | ret = pm_runtime_get_sync(&client->dev); |
---|
1396 | 1410 | if (ret < 0) { |
---|
1397 | 1411 | pm_runtime_put_noidle(&client->dev); |
---|
.. | .. |
---|
1434 | 1448 | pm_runtime_put_noidle(&client->dev); |
---|
1435 | 1449 | goto unlock_and_return; |
---|
1436 | 1450 | } |
---|
1437 | | - |
---|
1438 | | - ret |= sc530ai_write_reg(sc530ai->client, |
---|
1439 | | - SC530AI_SOFTWARE_RESET_REG, |
---|
1440 | | - SC530AI_REG_VALUE_08BIT, |
---|
1441 | | - 0x01); |
---|
1442 | | - usleep_range(100, 200); |
---|
1443 | | - |
---|
| 1451 | + if (!sc530ai->is_thunderboot) { |
---|
| 1452 | + ret |= sc530ai_write_reg(sc530ai->client, |
---|
| 1453 | + SC530AI_SOFTWARE_RESET_REG, |
---|
| 1454 | + SC530AI_REG_VALUE_08BIT, |
---|
| 1455 | + 0x01); |
---|
| 1456 | + if (ret) { |
---|
| 1457 | + v4l2_err(sd, "could not set init registers\n"); |
---|
| 1458 | + pm_runtime_put_noidle(&client->dev); |
---|
| 1459 | + goto unlock_and_return; |
---|
| 1460 | + } |
---|
| 1461 | + usleep_range(100, 200); |
---|
| 1462 | + } |
---|
1444 | 1463 | sc530ai->power_on = true; |
---|
1445 | 1464 | } else { |
---|
1446 | 1465 | pm_runtime_put(&client->dev); |
---|
.. | .. |
---|
1474 | 1493 | dev_err(dev, "Failed to enable xvclk\n"); |
---|
1475 | 1494 | return ret; |
---|
1476 | 1495 | } |
---|
| 1496 | + |
---|
| 1497 | + if (sc530ai->is_thunderboot) |
---|
| 1498 | + return 0; |
---|
| 1499 | + |
---|
1477 | 1500 | if (!IS_ERR(sc530ai->reset_gpio)) |
---|
1478 | 1501 | gpiod_set_value_cansleep(sc530ai->reset_gpio, 0); |
---|
1479 | 1502 | |
---|
.. | .. |
---|
1503 | 1526 | { |
---|
1504 | 1527 | int ret; |
---|
1505 | 1528 | struct device *dev = &sc530ai->client->dev; |
---|
| 1529 | + |
---|
| 1530 | + if (sc530ai->is_thunderboot) { |
---|
| 1531 | + if (sc530ai->is_first_streamoff) { |
---|
| 1532 | + sc530ai->is_thunderboot = false; |
---|
| 1533 | + sc530ai->is_first_streamoff = false; |
---|
| 1534 | + } else { |
---|
| 1535 | + return; |
---|
| 1536 | + } |
---|
| 1537 | + } |
---|
1506 | 1538 | |
---|
1507 | 1539 | if (!IS_ERR(sc530ai->pwdn_gpio)) |
---|
1508 | 1540 | gpiod_set_value_cansleep(sc530ai->pwdn_gpio, 0); |
---|
.. | .. |
---|
1903 | 1935 | u32 id = 0; |
---|
1904 | 1936 | int ret; |
---|
1905 | 1937 | |
---|
| 1938 | + if (sc530ai->is_thunderboot) { |
---|
| 1939 | + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); |
---|
| 1940 | + return 0; |
---|
| 1941 | + } |
---|
1906 | 1942 | ret = sc530ai_read_reg(client, SC530AI_REG_CHIP_ID, |
---|
1907 | 1943 | SC530AI_REG_VALUE_16BIT, &id); |
---|
1908 | 1944 | if (id != SC530AI_CHIP_ID) { |
---|
.. | .. |
---|
1961 | 1997 | return -EINVAL; |
---|
1962 | 1998 | } |
---|
1963 | 1999 | |
---|
| 2000 | + sc530ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); |
---|
1964 | 2001 | sc530ai->client = client; |
---|
1965 | 2002 | |
---|
1966 | 2003 | ret = sc530ai_parse_of(sc530ai); |
---|
.. | .. |
---|
1973 | 2010 | return -EINVAL; |
---|
1974 | 2011 | } |
---|
1975 | 2012 | |
---|
1976 | | - sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
---|
| 2013 | + sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", |
---|
| 2014 | + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
---|
1977 | 2015 | if (IS_ERR(sc530ai->reset_gpio)) |
---|
1978 | 2016 | dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
1979 | 2017 | |
---|
1980 | | - sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
---|
| 2018 | + sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", |
---|
| 2019 | + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
---|
1981 | 2020 | if (IS_ERR(sc530ai->pwdn_gpio)) |
---|
1982 | 2021 | dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
1983 | 2022 | |
---|
.. | .. |
---|
2051 | 2090 | |
---|
2052 | 2091 | pm_runtime_set_active(dev); |
---|
2053 | 2092 | pm_runtime_enable(dev); |
---|
2054 | | - pm_runtime_idle(dev); |
---|
| 2093 | + if (sc530ai->is_thunderboot) |
---|
| 2094 | + pm_runtime_get_sync(dev); |
---|
| 2095 | + else |
---|
| 2096 | + pm_runtime_idle(dev); |
---|
2055 | 2097 | |
---|
2056 | 2098 | return 0; |
---|
2057 | 2099 | |
---|