.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Omnivision OV2659 CMOS Image Sensor driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Benoit Parrot <bparrot@ti.com> |
---|
7 | 8 | * Lad, Prabhakar <prabhakar.csengg@gmail.com> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you may redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; version 2 of the License. |
---|
12 | | - * |
---|
13 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
14 | | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
---|
15 | | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
16 | | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
---|
17 | | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
---|
18 | | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
---|
19 | | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
---|
20 | | - * SOFTWARE. |
---|
21 | 9 | */ |
---|
22 | 10 | |
---|
23 | 11 | #include <linux/clk.h> |
---|
24 | 12 | #include <linux/delay.h> |
---|
25 | | -#include <linux/err.h> |
---|
26 | | -#include <linux/init.h> |
---|
27 | | -#include <linux/interrupt.h> |
---|
28 | | -#include <linux/io.h> |
---|
| 13 | +#include <linux/gpio/consumer.h> |
---|
29 | 14 | #include <linux/i2c.h> |
---|
30 | | -#include <linux/kernel.h> |
---|
31 | | -#include <linux/media.h> |
---|
32 | 15 | #include <linux/module.h> |
---|
33 | | -#include <linux/of.h> |
---|
34 | 16 | #include <linux/of_graph.h> |
---|
35 | | -#include <linux/slab.h> |
---|
36 | | -#include <linux/uaccess.h> |
---|
37 | | -#include <linux/videodev2.h> |
---|
| 17 | +#include <linux/pm_runtime.h> |
---|
38 | 18 | |
---|
39 | | -#include <media/media-entity.h> |
---|
40 | 19 | #include <media/i2c/ov2659.h> |
---|
41 | | -#include <media/v4l2-common.h> |
---|
42 | 20 | #include <media/v4l2-ctrls.h> |
---|
43 | | -#include <media/v4l2-device.h> |
---|
44 | 21 | #include <media/v4l2-event.h> |
---|
45 | 22 | #include <media/v4l2-fwnode.h> |
---|
46 | 23 | #include <media/v4l2-image-sizes.h> |
---|
47 | | -#include <media/v4l2-mediabus.h> |
---|
48 | 24 | #include <media/v4l2-subdev.h> |
---|
49 | 25 | |
---|
50 | 26 | #define DRIVER_NAME "ov2659" |
---|
.. | .. |
---|
228 | 204 | struct i2c_client *client; |
---|
229 | 205 | struct v4l2_ctrl_handler ctrls; |
---|
230 | 206 | struct v4l2_ctrl *link_frequency; |
---|
| 207 | + struct clk *clk; |
---|
231 | 208 | const struct ov2659_framesize *frame_size; |
---|
232 | 209 | struct sensor_register *format_ctrl_regs; |
---|
233 | 210 | struct ov2659_pll_ctrl pll; |
---|
234 | 211 | int streaming; |
---|
| 212 | + /* used to control the sensor PWDN pin */ |
---|
| 213 | + struct gpio_desc *pwdn_gpio; |
---|
| 214 | + /* used to control the sensor RESETB pin */ |
---|
| 215 | + struct gpio_desc *resetb_gpio; |
---|
235 | 216 | }; |
---|
236 | 217 | |
---|
237 | 218 | static const struct sensor_register ov2659_init_regs[] = { |
---|
.. | .. |
---|
665 | 646 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, |
---|
666 | 647 | { 0x370a, 0x52 }, |
---|
667 | 648 | { REG_VFIFO_READ_START_H, 0x00 }, |
---|
668 | | - { REG_VFIFO_READ_START_L, 0x80 }, |
---|
| 649 | + { REG_VFIFO_READ_START_L, 0xa0 }, |
---|
669 | 650 | { REG_ISP_CTRL02, 0x10 }, |
---|
670 | 651 | { REG_NULL, 0x00 }, |
---|
671 | 652 | }; |
---|
.. | .. |
---|
713 | 694 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, |
---|
714 | 695 | { 0x370a, 0x52 }, |
---|
715 | 696 | { REG_VFIFO_READ_START_H, 0x00 }, |
---|
716 | | - { REG_VFIFO_READ_START_L, 0x80 }, |
---|
| 697 | + { REG_VFIFO_READ_START_L, 0xa0 }, |
---|
717 | 698 | { REG_ISP_CTRL02, 0x10 }, |
---|
718 | 699 | { REG_NULL, 0x00 }, |
---|
719 | 700 | }; |
---|
.. | .. |
---|
1059 | 1040 | mutex_unlock(&ov2659->lock); |
---|
1060 | 1041 | return 0; |
---|
1061 | 1042 | #else |
---|
1062 | | - return -ENOTTY; |
---|
| 1043 | + return -EINVAL; |
---|
1063 | 1044 | #endif |
---|
1064 | 1045 | } |
---|
1065 | 1046 | |
---|
.. | .. |
---|
1135 | 1116 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
---|
1136 | 1117 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
---|
1137 | 1118 | *mf = fmt->format; |
---|
1138 | | -#else |
---|
1139 | | - ret = -ENOTTY; |
---|
1140 | 1119 | #endif |
---|
1141 | 1120 | } else { |
---|
1142 | 1121 | s64 val; |
---|
.. | .. |
---|
1204 | 1183 | /* Stop Streaming Sequence */ |
---|
1205 | 1184 | ov2659_set_streaming(ov2659, 0); |
---|
1206 | 1185 | ov2659->streaming = on; |
---|
| 1186 | + pm_runtime_put(&client->dev); |
---|
1207 | 1187 | goto unlock; |
---|
1208 | 1188 | } |
---|
1209 | 1189 | |
---|
1210 | | - ret = ov2659_set_pixel_clock(ov2659); |
---|
| 1190 | + ret = pm_runtime_get_sync(&client->dev); |
---|
| 1191 | + if (ret < 0) { |
---|
| 1192 | + pm_runtime_put_noidle(&client->dev); |
---|
| 1193 | + goto unlock; |
---|
| 1194 | + } |
---|
| 1195 | + |
---|
| 1196 | + ret = ov2659_init(sd, 0); |
---|
| 1197 | + if (!ret) |
---|
| 1198 | + ret = ov2659_set_pixel_clock(ov2659); |
---|
1211 | 1199 | if (!ret) |
---|
1212 | 1200 | ret = ov2659_set_frame_size(ov2659); |
---|
1213 | 1201 | if (!ret) |
---|
.. | .. |
---|
1249 | 1237 | { |
---|
1250 | 1238 | struct ov2659 *ov2659 = |
---|
1251 | 1239 | container_of(ctrl->handler, struct ov2659, ctrls); |
---|
| 1240 | + struct i2c_client *client = ov2659->client; |
---|
| 1241 | + |
---|
| 1242 | + /* V4L2 controls values will be applied only when power is already up */ |
---|
| 1243 | + if (!pm_runtime_get_if_in_use(&client->dev)) |
---|
| 1244 | + return 0; |
---|
1252 | 1245 | |
---|
1253 | 1246 | switch (ctrl->id) { |
---|
1254 | 1247 | case V4L2_CID_TEST_PATTERN: |
---|
1255 | 1248 | return ov2659_set_test_pattern(ov2659, ctrl->val); |
---|
1256 | 1249 | } |
---|
1257 | 1250 | |
---|
| 1251 | + pm_runtime_put(&client->dev); |
---|
1258 | 1252 | return 0; |
---|
1259 | 1253 | } |
---|
1260 | 1254 | |
---|
.. | .. |
---|
1266 | 1260 | "Disabled", |
---|
1267 | 1261 | "Vertical Color Bars", |
---|
1268 | 1262 | }; |
---|
| 1263 | + |
---|
| 1264 | +static int ov2659_power_off(struct device *dev) |
---|
| 1265 | +{ |
---|
| 1266 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 1267 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
| 1268 | + struct ov2659 *ov2659 = to_ov2659(sd); |
---|
| 1269 | + |
---|
| 1270 | + dev_dbg(&client->dev, "%s:\n", __func__); |
---|
| 1271 | + |
---|
| 1272 | + gpiod_set_value(ov2659->pwdn_gpio, 1); |
---|
| 1273 | + |
---|
| 1274 | + clk_disable_unprepare(ov2659->clk); |
---|
| 1275 | + |
---|
| 1276 | + return 0; |
---|
| 1277 | +} |
---|
| 1278 | + |
---|
| 1279 | +static int ov2659_power_on(struct device *dev) |
---|
| 1280 | +{ |
---|
| 1281 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 1282 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
| 1283 | + struct ov2659 *ov2659 = to_ov2659(sd); |
---|
| 1284 | + int ret; |
---|
| 1285 | + |
---|
| 1286 | + dev_dbg(&client->dev, "%s:\n", __func__); |
---|
| 1287 | + |
---|
| 1288 | + ret = clk_prepare_enable(ov2659->clk); |
---|
| 1289 | + if (ret) { |
---|
| 1290 | + dev_err(&client->dev, "%s: failed to enable clock\n", |
---|
| 1291 | + __func__); |
---|
| 1292 | + return ret; |
---|
| 1293 | + } |
---|
| 1294 | + |
---|
| 1295 | + gpiod_set_value(ov2659->pwdn_gpio, 0); |
---|
| 1296 | + |
---|
| 1297 | + if (ov2659->resetb_gpio) { |
---|
| 1298 | + gpiod_set_value(ov2659->resetb_gpio, 1); |
---|
| 1299 | + usleep_range(500, 1000); |
---|
| 1300 | + gpiod_set_value(ov2659->resetb_gpio, 0); |
---|
| 1301 | + usleep_range(3000, 5000); |
---|
| 1302 | + } |
---|
| 1303 | + |
---|
| 1304 | + return 0; |
---|
| 1305 | +} |
---|
1269 | 1306 | |
---|
1270 | 1307 | /* ----------------------------------------------------------------------------- |
---|
1271 | 1308 | * V4L2 subdev internal operations |
---|
.. | .. |
---|
1340 | 1377 | unsigned short id; |
---|
1341 | 1378 | |
---|
1342 | 1379 | id = OV265X_ID(pid, ver); |
---|
1343 | | - if (id != OV2659_ID) |
---|
| 1380 | + if (id != OV2659_ID) { |
---|
1344 | 1381 | dev_err(&client->dev, |
---|
1345 | 1382 | "Sensor detection failed (%04X, %d)\n", |
---|
1346 | 1383 | id, ret); |
---|
1347 | | - else { |
---|
| 1384 | + ret = -ENODEV; |
---|
| 1385 | + } else { |
---|
1348 | 1386 | dev_info(&client->dev, "Found OV%04X sensor\n", id); |
---|
1349 | | - ret = ov2659_init(sd, 0); |
---|
1350 | 1387 | } |
---|
1351 | 1388 | } |
---|
1352 | 1389 | |
---|
.. | .. |
---|
1357 | 1394 | ov2659_get_pdata(struct i2c_client *client) |
---|
1358 | 1395 | { |
---|
1359 | 1396 | struct ov2659_platform_data *pdata; |
---|
1360 | | - struct v4l2_fwnode_endpoint *bus_cfg; |
---|
| 1397 | + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; |
---|
1361 | 1398 | struct device_node *endpoint; |
---|
| 1399 | + int ret; |
---|
1362 | 1400 | |
---|
1363 | 1401 | if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) |
---|
1364 | 1402 | return client->dev.platform_data; |
---|
.. | .. |
---|
1367 | 1405 | if (!endpoint) |
---|
1368 | 1406 | return NULL; |
---|
1369 | 1407 | |
---|
1370 | | - bus_cfg = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint)); |
---|
1371 | | - if (IS_ERR(bus_cfg)) { |
---|
| 1408 | + ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint), |
---|
| 1409 | + &bus_cfg); |
---|
| 1410 | + if (ret) { |
---|
1372 | 1411 | pdata = NULL; |
---|
1373 | 1412 | goto done; |
---|
1374 | 1413 | } |
---|
.. | .. |
---|
1377 | 1416 | if (!pdata) |
---|
1378 | 1417 | goto done; |
---|
1379 | 1418 | |
---|
1380 | | - if (!bus_cfg->nr_of_link_frequencies) { |
---|
| 1419 | + if (!bus_cfg.nr_of_link_frequencies) { |
---|
1381 | 1420 | dev_err(&client->dev, |
---|
1382 | 1421 | "link-frequencies property not found or too many\n"); |
---|
1383 | 1422 | pdata = NULL; |
---|
1384 | 1423 | goto done; |
---|
1385 | 1424 | } |
---|
1386 | 1425 | |
---|
1387 | | - pdata->link_frequency = bus_cfg->link_frequencies[0]; |
---|
| 1426 | + pdata->link_frequency = bus_cfg.link_frequencies[0]; |
---|
1388 | 1427 | |
---|
1389 | 1428 | done: |
---|
1390 | | - v4l2_fwnode_endpoint_free(bus_cfg); |
---|
| 1429 | + v4l2_fwnode_endpoint_free(&bus_cfg); |
---|
1391 | 1430 | of_node_put(endpoint); |
---|
1392 | 1431 | return pdata; |
---|
1393 | 1432 | } |
---|
1394 | 1433 | |
---|
1395 | | -static int ov2659_probe(struct i2c_client *client, |
---|
1396 | | - const struct i2c_device_id *id) |
---|
| 1434 | +static int ov2659_probe(struct i2c_client *client) |
---|
1397 | 1435 | { |
---|
1398 | 1436 | const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); |
---|
1399 | 1437 | struct v4l2_subdev *sd; |
---|
1400 | 1438 | struct ov2659 *ov2659; |
---|
1401 | | - struct clk *clk; |
---|
1402 | 1439 | int ret; |
---|
1403 | 1440 | |
---|
1404 | 1441 | if (!pdata) { |
---|
.. | .. |
---|
1413 | 1450 | ov2659->pdata = pdata; |
---|
1414 | 1451 | ov2659->client = client; |
---|
1415 | 1452 | |
---|
1416 | | - clk = devm_clk_get(&client->dev, "xvclk"); |
---|
1417 | | - if (IS_ERR(clk)) |
---|
1418 | | - return PTR_ERR(clk); |
---|
| 1453 | + ov2659->clk = devm_clk_get(&client->dev, "xvclk"); |
---|
| 1454 | + if (IS_ERR(ov2659->clk)) |
---|
| 1455 | + return PTR_ERR(ov2659->clk); |
---|
1419 | 1456 | |
---|
1420 | | - ov2659->xvclk_frequency = clk_get_rate(clk); |
---|
| 1457 | + ov2659->xvclk_frequency = clk_get_rate(ov2659->clk); |
---|
1421 | 1458 | if (ov2659->xvclk_frequency < 6000000 || |
---|
1422 | 1459 | ov2659->xvclk_frequency > 27000000) |
---|
1423 | 1460 | return -EINVAL; |
---|
| 1461 | + |
---|
| 1462 | + /* Optional gpio don't fail if not present */ |
---|
| 1463 | + ov2659->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", |
---|
| 1464 | + GPIOD_OUT_LOW); |
---|
| 1465 | + if (IS_ERR(ov2659->pwdn_gpio)) |
---|
| 1466 | + return PTR_ERR(ov2659->pwdn_gpio); |
---|
| 1467 | + |
---|
| 1468 | + /* Optional gpio don't fail if not present */ |
---|
| 1469 | + ov2659->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", |
---|
| 1470 | + GPIOD_OUT_HIGH); |
---|
| 1471 | + if (IS_ERR(ov2659->resetb_gpio)) |
---|
| 1472 | + return PTR_ERR(ov2659->resetb_gpio); |
---|
1424 | 1473 | |
---|
1425 | 1474 | v4l2_ctrl_handler_init(&ov2659->ctrls, 2); |
---|
1426 | 1475 | ov2659->link_frequency = |
---|
.. | .. |
---|
1467 | 1516 | ov2659->frame_size = &ov2659_framesizes[2]; |
---|
1468 | 1517 | ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs; |
---|
1469 | 1518 | |
---|
| 1519 | + ret = ov2659_power_on(&client->dev); |
---|
| 1520 | + if (ret < 0) |
---|
| 1521 | + goto error; |
---|
| 1522 | + |
---|
1470 | 1523 | ret = ov2659_detect(sd); |
---|
1471 | 1524 | if (ret < 0) |
---|
1472 | 1525 | goto error; |
---|
.. | .. |
---|
1480 | 1533 | |
---|
1481 | 1534 | dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name); |
---|
1482 | 1535 | |
---|
| 1536 | + pm_runtime_set_active(&client->dev); |
---|
| 1537 | + pm_runtime_enable(&client->dev); |
---|
| 1538 | + pm_runtime_idle(&client->dev); |
---|
| 1539 | + |
---|
1483 | 1540 | return 0; |
---|
1484 | 1541 | |
---|
1485 | 1542 | error: |
---|
1486 | 1543 | v4l2_ctrl_handler_free(&ov2659->ctrls); |
---|
| 1544 | + ov2659_power_off(&client->dev); |
---|
1487 | 1545 | media_entity_cleanup(&sd->entity); |
---|
1488 | 1546 | mutex_destroy(&ov2659->lock); |
---|
1489 | 1547 | return ret; |
---|
.. | .. |
---|
1499 | 1557 | media_entity_cleanup(&sd->entity); |
---|
1500 | 1558 | mutex_destroy(&ov2659->lock); |
---|
1501 | 1559 | |
---|
| 1560 | + pm_runtime_disable(&client->dev); |
---|
| 1561 | + if (!pm_runtime_status_suspended(&client->dev)) |
---|
| 1562 | + ov2659_power_off(&client->dev); |
---|
| 1563 | + pm_runtime_set_suspended(&client->dev); |
---|
| 1564 | + |
---|
1502 | 1565 | return 0; |
---|
1503 | 1566 | } |
---|
| 1567 | + |
---|
| 1568 | +static const struct dev_pm_ops ov2659_pm_ops = { |
---|
| 1569 | + SET_RUNTIME_PM_OPS(ov2659_power_off, ov2659_power_on, NULL) |
---|
| 1570 | +}; |
---|
1504 | 1571 | |
---|
1505 | 1572 | static const struct i2c_device_id ov2659_id[] = { |
---|
1506 | 1573 | { "ov2659", 0 }, |
---|
.. | .. |
---|
1519 | 1586 | static struct i2c_driver ov2659_i2c_driver = { |
---|
1520 | 1587 | .driver = { |
---|
1521 | 1588 | .name = DRIVER_NAME, |
---|
| 1589 | + .pm = &ov2659_pm_ops, |
---|
1522 | 1590 | .of_match_table = of_match_ptr(ov2659_of_match), |
---|
1523 | 1591 | }, |
---|
1524 | | - .probe = ov2659_probe, |
---|
| 1592 | + .probe_new = ov2659_probe, |
---|
1525 | 1593 | .remove = ov2659_remove, |
---|
1526 | 1594 | .id_table = ov2659_id, |
---|
1527 | 1595 | }; |
---|