| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * adv7180.c Analog Devices ADV7180 video decoder driver |
|---|
| 3 | 4 | * Copyright (c) 2009 Intel Corporation |
|---|
| 4 | 5 | * Copyright (C) 2013 Cogent Embedded, Inc. |
|---|
| 5 | 6 | * Copyright (C) 2013 Renesas Solutions Corp. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | 7 | */ |
|---|
| 16 | | - |
|---|
| 17 | 8 | #include <linux/module.h> |
|---|
| 18 | 9 | #include <linux/init.h> |
|---|
| 19 | 10 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 188 | 179 | #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 |
|---|
| 189 | 180 | |
|---|
| 190 | 181 | #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) |
|---|
| 182 | + |
|---|
| 183 | +/* Initial number of frames to skip to avoid possible garbage */ |
|---|
| 184 | +#define ADV7180_NUM_OF_SKIP_FRAMES 2 |
|---|
| 191 | 185 | |
|---|
| 192 | 186 | struct adv7180_state; |
|---|
| 193 | 187 | |
|---|
| .. | .. |
|---|
| 732 | 726 | case V4L2_FIELD_NONE: |
|---|
| 733 | 727 | if (state->chip_info->flags & ADV7180_FLAG_I2P) |
|---|
| 734 | 728 | break; |
|---|
| 735 | | - /* fall through */ |
|---|
| 729 | + fallthrough; |
|---|
| 736 | 730 | default: |
|---|
| 737 | 731 | format->format.field = V4L2_FIELD_ALTERNATE; |
|---|
| 738 | 732 | break; |
|---|
| .. | .. |
|---|
| 755 | 749 | return ret; |
|---|
| 756 | 750 | } |
|---|
| 757 | 751 | |
|---|
| 758 | | -static int adv7180_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 759 | | - struct v4l2_mbus_config *cfg) |
|---|
| 752 | +static int adv7180_init_cfg(struct v4l2_subdev *sd, |
|---|
| 753 | + struct v4l2_subdev_pad_config *cfg) |
|---|
| 754 | +{ |
|---|
| 755 | + struct v4l2_subdev_format fmt = { |
|---|
| 756 | + .which = cfg ? V4L2_SUBDEV_FORMAT_TRY |
|---|
| 757 | + : V4L2_SUBDEV_FORMAT_ACTIVE, |
|---|
| 758 | + }; |
|---|
| 759 | + |
|---|
| 760 | + return adv7180_set_pad_format(sd, cfg, &fmt); |
|---|
| 761 | +} |
|---|
| 762 | + |
|---|
| 763 | +static int adv7180_get_mbus_config(struct v4l2_subdev *sd, |
|---|
| 764 | + unsigned int pad, |
|---|
| 765 | + struct v4l2_mbus_config *cfg) |
|---|
| 760 | 766 | { |
|---|
| 761 | 767 | struct adv7180_state *state = to_state(sd); |
|---|
| 762 | 768 | |
|---|
| 763 | 769 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { |
|---|
| 764 | | - cfg->type = V4L2_MBUS_CSI2; |
|---|
| 770 | + cfg->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 765 | 771 | cfg->flags = V4L2_MBUS_CSI2_1_LANE | |
|---|
| 766 | 772 | V4L2_MBUS_CSI2_CHANNEL_0 | |
|---|
| 767 | 773 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; |
|---|
| .. | .. |
|---|
| 774 | 780 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
|---|
| 775 | 781 | cfg->type = V4L2_MBUS_BT656; |
|---|
| 776 | 782 | } |
|---|
| 783 | + |
|---|
| 784 | + return 0; |
|---|
| 785 | +} |
|---|
| 786 | + |
|---|
| 787 | +static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) |
|---|
| 788 | +{ |
|---|
| 789 | + *frames = ADV7180_NUM_OF_SKIP_FRAMES; |
|---|
| 777 | 790 | |
|---|
| 778 | 791 | return 0; |
|---|
| 779 | 792 | } |
|---|
| .. | .. |
|---|
| 840 | 853 | .querystd = adv7180_querystd, |
|---|
| 841 | 854 | .g_input_status = adv7180_g_input_status, |
|---|
| 842 | 855 | .s_routing = adv7180_s_routing, |
|---|
| 843 | | - .g_mbus_config = adv7180_g_mbus_config, |
|---|
| 844 | 856 | .g_pixelaspect = adv7180_g_pixelaspect, |
|---|
| 845 | 857 | .g_tvnorms = adv7180_g_tvnorms, |
|---|
| 846 | 858 | .s_stream = adv7180_s_stream, |
|---|
| .. | .. |
|---|
| 853 | 865 | }; |
|---|
| 854 | 866 | |
|---|
| 855 | 867 | static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { |
|---|
| 868 | + .init_cfg = adv7180_init_cfg, |
|---|
| 856 | 869 | .enum_mbus_code = adv7180_enum_mbus_code, |
|---|
| 857 | 870 | .set_fmt = adv7180_set_pad_format, |
|---|
| 858 | 871 | .get_fmt = adv7180_get_pad_format, |
|---|
| 872 | + .get_mbus_config = adv7180_get_mbus_config, |
|---|
| 873 | +}; |
|---|
| 874 | + |
|---|
| 875 | +static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = { |
|---|
| 876 | + .g_skip_frames = adv7180_get_skip_frames, |
|---|
| 859 | 877 | }; |
|---|
| 860 | 878 | |
|---|
| 861 | 879 | static const struct v4l2_subdev_ops adv7180_ops = { |
|---|
| 862 | 880 | .core = &adv7180_core_ops, |
|---|
| 863 | 881 | .video = &adv7180_video_ops, |
|---|
| 864 | 882 | .pad = &adv7180_pad_ops, |
|---|
| 883 | + .sensor = &adv7180_sensor_ops, |
|---|
| 865 | 884 | }; |
|---|
| 866 | 885 | |
|---|
| 867 | 886 | static irqreturn_t adv7180_irq(int irq, void *devid) |
|---|
| .. | .. |
|---|
| 1303 | 1322 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
|---|
| 1304 | 1323 | return -EIO; |
|---|
| 1305 | 1324 | |
|---|
| 1306 | | - v4l_info(client, "chip found @ 0x%02x (%s)\n", |
|---|
| 1307 | | - client->addr, client->adapter->name); |
|---|
| 1308 | | - |
|---|
| 1309 | 1325 | state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); |
|---|
| 1310 | 1326 | if (state == NULL) |
|---|
| 1311 | 1327 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 1323 | 1339 | } |
|---|
| 1324 | 1340 | |
|---|
| 1325 | 1341 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { |
|---|
| 1326 | | - state->csi_client = i2c_new_dummy(client->adapter, |
|---|
| 1342 | + state->csi_client = i2c_new_dummy_device(client->adapter, |
|---|
| 1327 | 1343 | ADV7180_DEFAULT_CSI_I2C_ADDR); |
|---|
| 1328 | | - if (!state->csi_client) |
|---|
| 1329 | | - return -ENOMEM; |
|---|
| 1344 | + if (IS_ERR(state->csi_client)) |
|---|
| 1345 | + return PTR_ERR(state->csi_client); |
|---|
| 1330 | 1346 | } |
|---|
| 1331 | 1347 | |
|---|
| 1332 | 1348 | if (state->chip_info->flags & ADV7180_FLAG_I2P) { |
|---|
| 1333 | | - state->vpp_client = i2c_new_dummy(client->adapter, |
|---|
| 1349 | + state->vpp_client = i2c_new_dummy_device(client->adapter, |
|---|
| 1334 | 1350 | ADV7180_DEFAULT_VPP_I2C_ADDR); |
|---|
| 1335 | | - if (!state->vpp_client) { |
|---|
| 1336 | | - ret = -ENOMEM; |
|---|
| 1351 | + if (IS_ERR(state->vpp_client)) { |
|---|
| 1352 | + ret = PTR_ERR(state->vpp_client); |
|---|
| 1337 | 1353 | goto err_unregister_csi_client; |
|---|
| 1338 | 1354 | } |
|---|
| 1339 | 1355 | } |
|---|
| .. | .. |
|---|
| 1376 | 1392 | if (ret) |
|---|
| 1377 | 1393 | goto err_free_irq; |
|---|
| 1378 | 1394 | |
|---|
| 1395 | + v4l_info(client, "chip found @ 0x%02x (%s)\n", |
|---|
| 1396 | + client->addr, client->adapter->name); |
|---|
| 1397 | + |
|---|
| 1379 | 1398 | return 0; |
|---|
| 1380 | 1399 | |
|---|
| 1381 | 1400 | err_free_irq: |
|---|