| .. | .. |
|---|
| 5 | 5 | * Copyright (C) 2020 Rockchip Electronics Co., Ltd. |
|---|
| 6 | 6 | * |
|---|
| 7 | 7 | * V0.0X01.0X00 first version. |
|---|
| 8 | + * V0.0X01.0X01 fix power on & off sequence |
|---|
| 8 | 9 | */ |
|---|
| 9 | 10 | |
|---|
| 10 | 11 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 27 | 28 | #include <linux/rk-preisp.h> |
|---|
| 28 | 29 | #include "../platform/rockchip/isp/rkisp_tb_helper.h" |
|---|
| 29 | 30 | |
|---|
| 30 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00) |
|---|
| 31 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) |
|---|
| 31 | 32 | |
|---|
| 32 | 33 | #ifndef V4L2_CID_DIGITAL_GAIN |
|---|
| 33 | 34 | #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN |
|---|
| .. | .. |
|---|
| 91 | 92 | #define SENSOR_ID(_msb, _lsb) ((_msb) << 8 | (_lsb)) |
|---|
| 92 | 93 | |
|---|
| 93 | 94 | static const char * const OV02B10_supply_names[] = { |
|---|
| 94 | | - "avdd", /* Analog power */ |
|---|
| 95 | 95 | "dovdd", /* Digital I/O power */ |
|---|
| 96 | | - "dvdd", /* Digital core power */ |
|---|
| 96 | + "avdd", /* Analog power */ |
|---|
| 97 | 97 | }; |
|---|
| 98 | 98 | |
|---|
| 99 | 99 | #define OV02B10_NUM_SUPPLIES ARRAY_SIZE(OV02B10_supply_names) |
|---|
| 100 | | - |
|---|
| 101 | | -enum ov02b10_max_pad { |
|---|
| 102 | | - PAD0, |
|---|
| 103 | | - PAD1, |
|---|
| 104 | | - PAD2, |
|---|
| 105 | | - PAD3, |
|---|
| 106 | | - PAD_MAX, |
|---|
| 107 | | -}; |
|---|
| 108 | 100 | |
|---|
| 109 | 101 | struct regval { |
|---|
| 110 | 102 | u8 addr; |
|---|
| .. | .. |
|---|
| 534 | 526 | struct ov02b10 *ov02b10 = to_ov02b10(sd); |
|---|
| 535 | 527 | const struct ov02b10_mode *mode = ov02b10->cur_mode; |
|---|
| 536 | 528 | |
|---|
| 537 | | - mutex_lock(&ov02b10->mutex); |
|---|
| 538 | 529 | fi->interval = mode->max_fps; |
|---|
| 539 | | - mutex_unlock(&ov02b10->mutex); |
|---|
| 540 | 530 | |
|---|
| 541 | 531 | return 0; |
|---|
| 542 | 532 | } |
|---|
| 543 | 533 | |
|---|
| 544 | | -static int ov02b10_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 534 | +static int ov02b10_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
|---|
| 545 | 535 | struct v4l2_mbus_config *config) |
|---|
| 546 | 536 | { |
|---|
| 547 | 537 | struct ov02b10 *ov02b10 = to_ov02b10(sd); |
|---|
| .. | .. |
|---|
| 558 | 548 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | |
|---|
| 559 | 549 | V4L2_MBUS_CSI2_CHANNEL_1; |
|---|
| 560 | 550 | |
|---|
| 561 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 551 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 562 | 552 | config->flags = val; |
|---|
| 563 | 553 | |
|---|
| 564 | 554 | return 0; |
|---|
| .. | .. |
|---|
| 639 | 629 | } |
|---|
| 640 | 630 | |
|---|
| 641 | 631 | ret = ov02b10_ioctl(sd, cmd, inf); |
|---|
| 642 | | - if (!ret) |
|---|
| 632 | + if (!ret) { |
|---|
| 643 | 633 | ret = copy_to_user(up, inf, sizeof(*inf)); |
|---|
| 634 | + if (ret) |
|---|
| 635 | + ret = -EFAULT; |
|---|
| 636 | + } |
|---|
| 644 | 637 | kfree(inf); |
|---|
| 645 | 638 | break; |
|---|
| 646 | 639 | case RKMODULE_AWB_CFG: |
|---|
| .. | .. |
|---|
| 653 | 646 | ret = copy_from_user(cfg, up, sizeof(*cfg)); |
|---|
| 654 | 647 | if (!ret) |
|---|
| 655 | 648 | ret = ov02b10_ioctl(sd, cmd, cfg); |
|---|
| 649 | + else |
|---|
| 650 | + ret = -EFAULT; |
|---|
| 656 | 651 | kfree(cfg); |
|---|
| 657 | 652 | break; |
|---|
| 658 | 653 | case RKMODULE_GET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 663 | 658 | } |
|---|
| 664 | 659 | |
|---|
| 665 | 660 | ret = ov02b10_ioctl(sd, cmd, hdr); |
|---|
| 666 | | - if (!ret) |
|---|
| 661 | + if (!ret) { |
|---|
| 667 | 662 | ret = copy_to_user(up, hdr, sizeof(*hdr)); |
|---|
| 663 | + if (ret) |
|---|
| 664 | + ret = -EFAULT; |
|---|
| 665 | + } |
|---|
| 668 | 666 | kfree(hdr); |
|---|
| 669 | 667 | break; |
|---|
| 670 | 668 | case RKMODULE_SET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 677 | 675 | ret = copy_from_user(hdr, up, sizeof(*hdr)); |
|---|
| 678 | 676 | if (!ret) |
|---|
| 679 | 677 | ret = ov02b10_ioctl(sd, cmd, hdr); |
|---|
| 678 | + else |
|---|
| 679 | + ret = -EFAULT; |
|---|
| 680 | 680 | kfree(hdr); |
|---|
| 681 | 681 | break; |
|---|
| 682 | 682 | case PREISP_CMD_SET_HDRAE_EXP: |
|---|
| .. | .. |
|---|
| 689 | 689 | ret = copy_from_user(hdrae, up, sizeof(*hdrae)); |
|---|
| 690 | 690 | if (!ret) |
|---|
| 691 | 691 | ret = ov02b10_ioctl(sd, cmd, hdrae); |
|---|
| 692 | + else |
|---|
| 693 | + ret = -EFAULT; |
|---|
| 692 | 694 | kfree(hdrae); |
|---|
| 693 | 695 | break; |
|---|
| 694 | 696 | case RKMODULE_SET_CONVERSION_GAIN: |
|---|
| 695 | 697 | ret = copy_from_user(&cg, up, sizeof(cg)); |
|---|
| 696 | 698 | if (!ret) |
|---|
| 697 | 699 | ret = ov02b10_ioctl(sd, cmd, &cg); |
|---|
| 700 | + else |
|---|
| 701 | + ret = -EFAULT; |
|---|
| 698 | 702 | break; |
|---|
| 699 | 703 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 700 | 704 | ret = copy_from_user(&stream, up, sizeof(u32)); |
|---|
| 701 | 705 | if (!ret) |
|---|
| 702 | 706 | ret = ov02b10_ioctl(sd, cmd, &stream); |
|---|
| 707 | + else |
|---|
| 708 | + ret = -EFAULT; |
|---|
| 703 | 709 | break; |
|---|
| 704 | 710 | default: |
|---|
| 705 | 711 | ret = -ENOIOCTLCMD; |
|---|
| .. | .. |
|---|
| 813 | 819 | return ret; |
|---|
| 814 | 820 | } |
|---|
| 815 | 821 | |
|---|
| 822 | +static int ov02b10_enable_regulators(struct ov02b10 *ov02b10, |
|---|
| 823 | + struct regulator_bulk_data *consumers) |
|---|
| 824 | +{ |
|---|
| 825 | + int i, j; |
|---|
| 826 | + int ret = 0; |
|---|
| 827 | + struct device *dev = &ov02b10->client->dev; |
|---|
| 828 | + int num_consumers = OV02B10_NUM_SUPPLIES; |
|---|
| 829 | + |
|---|
| 830 | + for (i = 0; i < num_consumers; i++) { |
|---|
| 831 | + |
|---|
| 832 | + ret = regulator_enable(consumers[i].consumer); |
|---|
| 833 | + if (ret < 0) { |
|---|
| 834 | + dev_err(dev, "Failed to enable regulator: %s\n", |
|---|
| 835 | + consumers[i].supply); |
|---|
| 836 | + goto err; |
|---|
| 837 | + } |
|---|
| 838 | + } |
|---|
| 839 | + return 0; |
|---|
| 840 | +err: |
|---|
| 841 | + for (j = 0; j < i; j++) |
|---|
| 842 | + regulator_disable(consumers[j].consumer); |
|---|
| 843 | + |
|---|
| 844 | + return ret; |
|---|
| 845 | +} |
|---|
| 846 | + |
|---|
| 816 | 847 | static int __ov02b10_power_on(struct ov02b10 *ov02b10) |
|---|
| 817 | 848 | { |
|---|
| 818 | 849 | int ret; |
|---|
| .. | .. |
|---|
| 829 | 860 | dev_warn(dev, "Failed to set xvclk rate (24MHz)\n"); |
|---|
| 830 | 861 | if (clk_get_rate(ov02b10->xvclk) != OV02B10_XVCLK_FREQ) |
|---|
| 831 | 862 | dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); |
|---|
| 832 | | - ret = clk_prepare_enable(ov02b10->xvclk); |
|---|
| 833 | | - if (ret < 0) { |
|---|
| 834 | | - dev_err(dev, "Failed to enable xvclk\n"); |
|---|
| 835 | | - return ret; |
|---|
| 836 | | - } |
|---|
| 837 | 863 | |
|---|
| 838 | 864 | if (!IS_ERR(ov02b10->pwdn_gpio)) |
|---|
| 839 | 865 | gpiod_direction_output(ov02b10->pwdn_gpio, 1); |
|---|
| .. | .. |
|---|
| 841 | 867 | if (!IS_ERR(ov02b10->reset_gpio)) |
|---|
| 842 | 868 | gpiod_direction_output(ov02b10->reset_gpio, 1); |
|---|
| 843 | 869 | |
|---|
| 844 | | - ret = regulator_bulk_enable(OV02B10_NUM_SUPPLIES, ov02b10->supplies); |
|---|
| 870 | + ret = ov02b10_enable_regulators(ov02b10, ov02b10->supplies); |
|---|
| 845 | 871 | if (ret < 0) { |
|---|
| 846 | 872 | dev_err(dev, "Failed to enable regulators\n"); |
|---|
| 847 | 873 | goto disable_clk; |
|---|
| 874 | + } |
|---|
| 875 | + usleep_range(100, 110); |
|---|
| 876 | + ret = clk_prepare_enable(ov02b10->xvclk); |
|---|
| 877 | + if (ret < 0) { |
|---|
| 878 | + dev_err(dev, "Failed to enable xvclk\n"); |
|---|
| 879 | + return ret; |
|---|
| 848 | 880 | } |
|---|
| 849 | 881 | |
|---|
| 850 | 882 | /* From spec: delay from power stable to pwdn off: 5ms */ |
|---|
| .. | .. |
|---|
| 872 | 904 | int ret; |
|---|
| 873 | 905 | struct device *dev = &ov02b10->client->dev; |
|---|
| 874 | 906 | |
|---|
| 875 | | - if (!IS_ERR(ov02b10->pwdn_gpio)) |
|---|
| 876 | | - gpiod_direction_output(ov02b10->pwdn_gpio, 1); |
|---|
| 907 | + if (!IS_ERR(ov02b10->reset_gpio)) |
|---|
| 908 | + gpiod_direction_output(ov02b10->reset_gpio, 1); |
|---|
| 877 | 909 | |
|---|
| 878 | 910 | clk_disable_unprepare(ov02b10->xvclk); |
|---|
| 879 | 911 | |
|---|
| 880 | | - if (!IS_ERR(ov02b10->reset_gpio)) |
|---|
| 881 | | - gpiod_direction_output(ov02b10->reset_gpio, 1); |
|---|
| 912 | + if (!IS_ERR(ov02b10->pwdn_gpio)) |
|---|
| 913 | + gpiod_direction_output(ov02b10->pwdn_gpio, 1); |
|---|
| 914 | + |
|---|
| 882 | 915 | if (!IS_ERR_OR_NULL(ov02b10->pins_sleep)) { |
|---|
| 883 | 916 | ret = pinctrl_select_state(ov02b10->pinctrl, |
|---|
| 884 | 917 | ov02b10->pins_sleep); |
|---|
| .. | .. |
|---|
| 888 | 921 | regulator_bulk_disable(OV02B10_NUM_SUPPLIES, ov02b10->supplies); |
|---|
| 889 | 922 | } |
|---|
| 890 | 923 | |
|---|
| 891 | | -static int ov02b10_runtime_resume(struct device *dev) |
|---|
| 924 | +static int __maybe_unused ov02b10_runtime_resume(struct device *dev) |
|---|
| 892 | 925 | { |
|---|
| 893 | 926 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 894 | 927 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 897 | 930 | return __ov02b10_power_on(ov02b10); |
|---|
| 898 | 931 | } |
|---|
| 899 | 932 | |
|---|
| 900 | | -static int ov02b10_runtime_suspend(struct device *dev) |
|---|
| 933 | +static int __maybe_unused ov02b10_runtime_suspend(struct device *dev) |
|---|
| 901 | 934 | { |
|---|
| 902 | 935 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 903 | 936 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 969 | 1002 | static const struct v4l2_subdev_video_ops ov02b10_video_ops = { |
|---|
| 970 | 1003 | .s_stream = ov02b10_s_stream, |
|---|
| 971 | 1004 | .g_frame_interval = ov02b10_g_frame_interval, |
|---|
| 972 | | - .g_mbus_config = ov02b10_g_mbus_config, |
|---|
| 973 | 1005 | }; |
|---|
| 974 | 1006 | |
|---|
| 975 | 1007 | static const struct v4l2_subdev_pad_ops ov02b10_pad_ops = { |
|---|
| .. | .. |
|---|
| 978 | 1010 | .enum_frame_interval = ov02b10_enum_frame_interval, |
|---|
| 979 | 1011 | .get_fmt = ov02b10_get_fmt, |
|---|
| 980 | 1012 | .set_fmt = ov02b10_set_fmt, |
|---|
| 1013 | + .get_mbus_config = ov02b10_g_mbus_config, |
|---|
| 981 | 1014 | }; |
|---|
| 982 | 1015 | |
|---|
| 983 | 1016 | static const struct v4l2_subdev_ops ov02b10_subdev_ops = { |
|---|