... | ... | ||
---|---|---|---|
12 | 12 | ||
13 | Regards, | 13 | Regards, |
14 | Benjamin | 14 | Benjamin |
15 | 15 | ||
16 | --- | 16 | --- |
17 | Changes in v4: | ||
18 | - Fix data-lanes syntax in binding | ||
19 | - Link to v3: https://lore.kernel.org/r/20250402-b4-vd55g1-v3-0-393985404759@foss.st.com | ||
20 | |||
21 | Changes in v3: | ||
22 | - Add maxItems to data-lanes in binding | ||
23 | - Drop redondant 'binding' in binding commit message | ||
24 | - Link to v2: https://lore.kernel.org/r/20250401-b4-vd55g1-v2-0-0c8ab8a48c55@foss.st.com | ||
25 | |||
17 | Changes in v2: | 26 | Changes in v2: |
18 | - Fix device tree binding mistakes | 27 | - Fix device tree binding mistakes |
19 | - Drop linux media git from MAINTAINERS file | 28 | - Drop linux media git from MAINTAINERS file |
20 | - Fix coding style mistakes | 29 | - Fix coding style mistakes |
21 | - Drop vd55g1_err_probe wrapper | 30 | - Drop vd55g1_err_probe wrapper |
22 | - Fix 32bits build | 31 | - Fix 32bits build |
23 | - Fix config symbol help paragraph being too short for checkpatch | 32 | - Fix config symbol help paragraph being too short for checkpatch |
24 | - Link to v1: https://lore.kernel.org/r/20250328-b4-vd55g1-v1-0-8d16b4a79f29@foss.st.com | 33 | - Link to v1: https://lore.kernel.org/r/20250328-b4-vd55g1-v1-0-8d16b4a79f29@foss.st.com |
25 | 34 | ||
26 | --- | 35 | --- |
27 | Benjamin Mugnier (2): | 36 | Benjamin Mugnier (2): |
28 | media: dt-bindings: Add ST VD55G1 camera sensor binding | 37 | media: dt-bindings: Add ST VD55G1 camera sensor |
29 | media: i2c: Add driver for ST VD55G1 camera sensor | 38 | media: i2c: Add driver for ST VD55G1 camera sensor |
30 | 39 | ||
31 | .../devicetree/bindings/media/i2c/st,vd55g1.yaml | 132 ++ | 40 | .../devicetree/bindings/media/i2c/st,vd55g1.yaml | 132 ++ |
32 | MAINTAINERS | 9 + | 41 | MAINTAINERS | 9 + |
33 | drivers/media/i2c/Kconfig | 11 + | 42 | drivers/media/i2c/Kconfig | 11 + |
... | ... | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
81 | + unevaluatedProperties: false | 81 | + unevaluatedProperties: false |
82 | + | 82 | + |
83 | + properties: | 83 | + properties: |
84 | + data-lanes: | 84 | + data-lanes: |
85 | + items: | 85 | + items: |
86 | + const: 1 | 86 | + - const: 1 |
87 | + | 87 | + |
88 | + link-frequencies: | 88 | + link-frequencies: |
89 | + maxItems: 1 | 89 | + maxItems: 1 |
90 | + items: | 90 | + items: |
91 | + minimum: 125000000 | 91 | + minimum: 125000000 |
... | ... | diff view generated by jsdifflib |
1 | The VD55G1 is a monochrome global shutter camera with a 804x704 maximum | 1 | The VD55G1 is a monochrome global shutter camera with a 804x704 maximum |
---|---|---|---|
2 | resolution with RAW8 and RAW10 bytes per pixel. | 2 | resolution with RAW8 and RAW10 bytes per pixel. |
3 | The driver supports : | 3 | The driver supports : |
4 | - Auto exposure from the sensor, or manual exposure mode | 4 | - Auto exposure from the sensor, or manual exposure mode |
5 | - HDR subtraction mode, allowing edge detection and background removal | 5 | - HDR subtraction mode, allowing edge detection and background removal |
6 | - Auto exposure cold start, using configuration values from last stream | 6 | - Auto exposure cold start, using configuration values from last stream |
7 | to start the next one | 7 | to start the next one |
8 | - LED GPIOs for illumination | 8 | - LED GPIOs for illumination |
9 | - Most standard camera sensor features (hblank, vblank, test patterns, | 9 | - Most standard camera sensor features (hblank, vblank, test patterns, |
10 | again, dgain, hflip, vflip, auto exposure bias, etc.) | 10 | again, dgain, hflip, vflip, auto exposure bias, etc.) |
11 | Add driver source code to MAINTAINERS file. | 11 | Add driver source code to MAINTAINERS file. |
12 | 12 | ||
13 | Signed-off-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com> | 13 | Signed-off-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com> |
14 | --- | 14 | --- |
15 | MAINTAINERS | 2 + | 15 | MAINTAINERS | 2 + |
16 | drivers/media/i2c/Kconfig | 11 + | 16 | drivers/media/i2c/Kconfig | 11 + |
17 | drivers/media/i2c/Makefile | 1 + | 17 | drivers/media/i2c/Makefile | 1 + |
18 | drivers/media/i2c/vd55g1.c | 1993 ++++++++++++++++++++++++++++++++++++++++++++ | 18 | drivers/media/i2c/vd55g1.c | 1993 ++++++++++++++++++++++++++++++++++++++++++++ |
19 | 4 files changed, 2007 insertions(+) | 19 | 4 files changed, 2007 insertions(+) |
20 | 20 | ||
21 | diff --git a/MAINTAINERS b/MAINTAINERS | 21 | diff --git a/MAINTAINERS b/MAINTAINERS |
22 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/MAINTAINERS | 23 | --- a/MAINTAINERS |
24 | +++ b/MAINTAINERS | 24 | +++ b/MAINTAINERS |
25 | @@ -XXX,XX +XXX,XX @@ M: Sylvain Petinot <sylvain.petinot@foss.st.com> | 25 | @@ -XXX,XX +XXX,XX @@ M: Sylvain Petinot <sylvain.petinot@foss.st.com> |
26 | L: linux-media@vger.kernel.org | 26 | L: linux-media@vger.kernel.org |
27 | S: Maintained | 27 | S: Maintained |
28 | F: Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml | 28 | F: Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml |
29 | +F: drivers/media/i2c/vd55g1.c | 29 | +F: drivers/media/i2c/vd55g1.c |
30 | 30 | ||
31 | ST VGXY61 DRIVER | 31 | ST VGXY61 DRIVER |
32 | M: Benjamin Mugnier <benjamin.mugnier@foss.st.com> | 32 | M: Benjamin Mugnier <benjamin.mugnier@foss.st.com> |
33 | @@ -XXX,XX +XXX,XX @@ F: drivers/media/i2c/mt* | 33 | @@ -XXX,XX +XXX,XX @@ F: drivers/media/i2c/mt* |
34 | F: drivers/media/i2c/og* | 34 | F: drivers/media/i2c/og* |
35 | F: drivers/media/i2c/ov* | 35 | F: drivers/media/i2c/ov* |
36 | F: drivers/media/i2c/s5* | 36 | F: drivers/media/i2c/s5* |
37 | +F: drivers/media/i2c/vd55g1.c | 37 | +F: drivers/media/i2c/vd55g1.c |
38 | F: drivers/media/i2c/vgxy61.c | 38 | F: drivers/media/i2c/vgxy61.c |
39 | 39 | ||
40 | VF610 NAND DRIVER | 40 | VF610 NAND DRIVER |
41 | diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig | 41 | diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig |
42 | index XXXXXXX..XXXXXXX 100644 | 42 | index XXXXXXX..XXXXXXX 100644 |
43 | --- a/drivers/media/i2c/Kconfig | 43 | --- a/drivers/media/i2c/Kconfig |
44 | +++ b/drivers/media/i2c/Kconfig | 44 | +++ b/drivers/media/i2c/Kconfig |
45 | @@ -XXX,XX +XXX,XX @@ config VIDEO_S5K6A3 | 45 | @@ -XXX,XX +XXX,XX @@ config VIDEO_S5K6A3 |
46 | This is a V4L2 sensor driver for Samsung S5K6A3 raw | 46 | This is a V4L2 sensor driver for Samsung S5K6A3 raw |
47 | camera sensor. | 47 | camera sensor. |
48 | 48 | ||
49 | +config VIDEO_VD55G1 | 49 | +config VIDEO_VD55G1 |
50 | + tristate "ST VD55G1 sensor support" | 50 | + tristate "ST VD55G1 sensor support" |
51 | + select V4L2_CCI_I2C | 51 | + select V4L2_CCI_I2C |
52 | + depends on OF && GPIOLIB | 52 | + depends on OF && GPIOLIB |
53 | + help | 53 | + help |
54 | + This is a Video4Linux2 sensor driver for the ST VD55G1 | 54 | + This is a Video4Linux2 sensor driver for the ST VD55G1 |
55 | + camera sensor. | 55 | + camera sensor. |
56 | + | 56 | + |
57 | + To compile this driver as a module, choose M here: the | 57 | + To compile this driver as a module, choose M here: the |
58 | + module will be called vd55g1. | 58 | + module will be called vd55g1. |
59 | + | 59 | + |
60 | config VIDEO_VGXY61 | 60 | config VIDEO_VGXY61 |
61 | tristate "ST VGXY61 sensor support" | 61 | tristate "ST VGXY61 sensor support" |
62 | select V4L2_CCI_I2C | 62 | select V4L2_CCI_I2C |
63 | diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile | 63 | diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile |
64 | index XXXXXXX..XXXXXXX 100644 | 64 | index XXXXXXX..XXXXXXX 100644 |
65 | --- a/drivers/media/i2c/Makefile | 65 | --- a/drivers/media/i2c/Makefile |
66 | +++ b/drivers/media/i2c/Makefile | 66 | +++ b/drivers/media/i2c/Makefile |
67 | @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o | 67 | @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o |
68 | obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o | 68 | obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o |
69 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o | 69 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o |
70 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | 70 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
71 | +obj-$(CONFIG_VIDEO_VD55G1) += vd55g1.o | 71 | +obj-$(CONFIG_VIDEO_VD55G1) += vd55g1.o |
72 | obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o | 72 | obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o |
73 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o | 73 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o |
74 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o | 74 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
75 | diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c | 75 | diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c |
76 | new file mode 100644 | 76 | new file mode 100644 |
77 | index XXXXXXX..XXXXXXX | 77 | index XXXXXXX..XXXXXXX |
78 | --- /dev/null | 78 | --- /dev/null |
79 | +++ b/drivers/media/i2c/vd55g1.c | 79 | +++ b/drivers/media/i2c/vd55g1.c |
80 | @@ -XXX,XX +XXX,XX @@ | 80 | @@ -XXX,XX +XXX,XX @@ |
81 | +// SPDX-License-Identifier: GPL-2.0 | 81 | +// SPDX-License-Identifier: GPL-2.0 |
82 | +/* | 82 | +/* |
83 | + * Driver for VD55G1 global shutter sensor family driver | 83 | + * Driver for VD55G1 global shutter sensor family driver |
84 | + * | 84 | + * |
85 | + * Copyright (C) 2025 STMicroelectronics SA | 85 | + * Copyright (C) 2025 STMicroelectronics SA |
86 | + */ | 86 | + */ |
87 | + | 87 | + |
88 | +#include <linux/clk.h> | 88 | +#include <linux/clk.h> |
89 | +#include <linux/delay.h> | 89 | +#include <linux/delay.h> |
90 | +#include <linux/gpio/consumer.h> | 90 | +#include <linux/gpio/consumer.h> |
91 | +#include <linux/i2c.h> | 91 | +#include <linux/i2c.h> |
92 | +#include <linux/iopoll.h> | 92 | +#include <linux/iopoll.h> |
93 | +#include <linux/module.h> | 93 | +#include <linux/module.h> |
94 | +#include <linux/pm_runtime.h> | 94 | +#include <linux/pm_runtime.h> |
95 | +#include <linux/regmap.h> | 95 | +#include <linux/regmap.h> |
96 | +#include <linux/regulator/consumer.h> | 96 | +#include <linux/regulator/consumer.h> |
97 | +#include <linux/unaligned.h> | 97 | +#include <linux/unaligned.h> |
98 | +#include <linux/units.h> | 98 | +#include <linux/units.h> |
99 | + | 99 | + |
100 | +#include <media/mipi-csi2.h> | 100 | +#include <media/mipi-csi2.h> |
101 | +#include <media/v4l2-async.h> | 101 | +#include <media/v4l2-async.h> |
102 | +#include <media/v4l2-cci.h> | 102 | +#include <media/v4l2-cci.h> |
103 | +#include <media/v4l2-ctrls.h> | 103 | +#include <media/v4l2-ctrls.h> |
104 | +#include <media/v4l2-device.h> | 104 | +#include <media/v4l2-device.h> |
105 | +#include <media/v4l2-event.h> | 105 | +#include <media/v4l2-event.h> |
106 | +#include <media/v4l2-fwnode.h> | 106 | +#include <media/v4l2-fwnode.h> |
107 | +#include <media/v4l2-subdev.h> | 107 | +#include <media/v4l2-subdev.h> |
108 | + | 108 | + |
109 | +/* Register Map */ | 109 | +/* Register Map */ |
110 | +#define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000) | 110 | +#define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000) |
111 | +#define VD55G1_MODEL_ID 0x53354731 | 111 | +#define VD55G1_MODEL_ID 0x53354731 |
112 | +#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004) | 112 | +#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004) |
113 | +#define VD55G1_REVISION_CCB 0x2020 | 113 | +#define VD55G1_REVISION_CCB 0x2020 |
114 | +#define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012) | 114 | +#define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012) |
115 | +#define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) | 115 | +#define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) |
116 | +#define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c) | 116 | +#define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c) |
117 | +#define VD55G1_SYSTEM_FSM_READY_TO_BOOT 0x01 | 117 | +#define VD55G1_SYSTEM_FSM_READY_TO_BOOT 0x01 |
118 | +#define VD55G1_SYSTEM_FSM_SW_STBY 0x02 | 118 | +#define VD55G1_SYSTEM_FSM_SW_STBY 0x02 |
119 | +#define VD55G1_SYSTEM_FSM_STREAMING 0x03 | 119 | +#define VD55G1_SYSTEM_FSM_STREAMING 0x03 |
120 | +#define VD55G1_REG_BOOT CCI_REG8(0x0200) | 120 | +#define VD55G1_REG_BOOT CCI_REG8(0x0200) |
121 | +#define VD55G1_BOOT_PATCH_SETUP 2 | 121 | +#define VD55G1_BOOT_PATCH_SETUP 2 |
122 | +#define VD55G1_REG_STBY CCI_REG8(0x0201) | 122 | +#define VD55G1_REG_STBY CCI_REG8(0x0201) |
123 | +#define VD55G1_STBY_START_STREAM 1 | 123 | +#define VD55G1_STBY_START_STREAM 1 |
124 | +#define VD55G1_REG_STREAMING CCI_REG8(0x0202) | 124 | +#define VD55G1_REG_STREAMING CCI_REG8(0x0202) |
125 | +#define VD55G1_STREAMING_STOP_STREAM 1 | 125 | +#define VD55G1_STREAMING_STOP_STREAM 1 |
126 | +#define VD55G1_REG_EXT_CLOCK CCI_REG32_LE(0x0220) | 126 | +#define VD55G1_REG_EXT_CLOCK CCI_REG32_LE(0x0220) |
127 | +#define VD55G1_REG_LINE_LENGTH CCI_REG16_LE(0x0300) | 127 | +#define VD55G1_REG_LINE_LENGTH CCI_REG16_LE(0x0300) |
128 | +#define VD55G1_REG_ORIENTATION CCI_REG8(0x0302) | 128 | +#define VD55G1_REG_ORIENTATION CCI_REG8(0x0302) |
129 | +#define VD55G1_REG_FORMAT_CTRL CCI_REG8(0x030a) | 129 | +#define VD55G1_REG_FORMAT_CTRL CCI_REG8(0x030a) |
130 | +#define VD55G1_REG_OIF_CTRL CCI_REG16_LE(0x030c) | 130 | +#define VD55G1_REG_OIF_CTRL CCI_REG16_LE(0x030c) |
131 | +#define VD55G1_REG_ISL_ENABLE CCI_REG16_LE(0x326) | 131 | +#define VD55G1_REG_ISL_ENABLE CCI_REG16_LE(0x326) |
132 | +#define VD55G1_REG_OIF_IMG_CTRL CCI_REG8(0x030f) | 132 | +#define VD55G1_REG_OIF_IMG_CTRL CCI_REG8(0x030f) |
133 | +#define VD55G1_REG_MIPI_DATA_RATE CCI_REG32_LE(0x0224) | 133 | +#define VD55G1_REG_MIPI_DATA_RATE CCI_REG32_LE(0x0224) |
134 | +#define VD55G1_REG_PATGEN_CTRL CCI_REG16_LE(0x0304) | 134 | +#define VD55G1_REG_PATGEN_CTRL CCI_REG16_LE(0x0304) |
135 | +#define VD55G1_PATGEN_TYPE_SHIFT 4 | 135 | +#define VD55G1_PATGEN_TYPE_SHIFT 4 |
136 | +#define VD55G1_PATGEN_ENABLE BIT(0) | 136 | +#define VD55G1_PATGEN_ENABLE BIT(0) |
137 | +#define VD55G1_REG_MANUAL_ANALOG_GAIN CCI_REG8(0x0501) | 137 | +#define VD55G1_REG_MANUAL_ANALOG_GAIN CCI_REG8(0x0501) |
138 | +#define VD55G1_REG_MANUAL_COARSE_EXPOSURE CCI_REG16_LE(0x0502) | 138 | +#define VD55G1_REG_MANUAL_COARSE_EXPOSURE CCI_REG16_LE(0x0502) |
139 | +#define VD55G1_REG_MANUAL_DIGITAL_GAIN CCI_REG16_LE(0x0504) | 139 | +#define VD55G1_REG_MANUAL_DIGITAL_GAIN CCI_REG16_LE(0x0504) |
140 | +#define VD55G1_REG_APPLIED_COARSE_EXPOSURE CCI_REG16_LE(0x00e8) | 140 | +#define VD55G1_REG_APPLIED_COARSE_EXPOSURE CCI_REG16_LE(0x00e8) |
141 | +#define VD55G1_REG_APPLIED_ANALOG_GAIN CCI_REG16_LE(0x00ea) | 141 | +#define VD55G1_REG_APPLIED_ANALOG_GAIN CCI_REG16_LE(0x00ea) |
142 | +#define VD55G1_REG_APPLIED_DIGITAL_GAIN CCI_REG16_LE(0x00ec) | 142 | +#define VD55G1_REG_APPLIED_DIGITAL_GAIN CCI_REG16_LE(0x00ec) |
143 | +#define VD55G1_REG_AE_FORCE_COLDSTART CCI_REG16_LE(0x0308) | 143 | +#define VD55G1_REG_AE_FORCE_COLDSTART CCI_REG16_LE(0x0308) |
144 | +#define VD55G1_REG_AE_COLDSTART_EXP_TIME CCI_REG32_LE(0x0374) | 144 | +#define VD55G1_REG_AE_COLDSTART_EXP_TIME CCI_REG32_LE(0x0374) |
145 | +#define VD55G1_REG_READOUT_CTRL CCI_REG8(0x052e) | 145 | +#define VD55G1_REG_READOUT_CTRL CCI_REG8(0x052e) |
146 | +#define VD55G1_REG_DARKCAL_CTRL CCI_REG8(0x032a) | 146 | +#define VD55G1_REG_DARKCAL_CTRL CCI_REG8(0x032a) |
147 | +#define VD55G1_DARKCAL_BYPASS 0 | 147 | +#define VD55G1_DARKCAL_BYPASS 0 |
148 | +#define VD55G1_DARKCAL_AUTO 1 | 148 | +#define VD55G1_DARKCAL_AUTO 1 |
149 | +#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ea) | 149 | +#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ea) |
150 | +#define VD55G1_DUSTER_ENABLE BIT(0) | 150 | +#define VD55G1_DUSTER_ENABLE BIT(0) |
151 | +#define VD55G1_DUSTER_DISABLE 0 | 151 | +#define VD55G1_DUSTER_DISABLE 0 |
152 | +#define VD55G1_DUSTER_DYN_ENABLE BIT(1) | 152 | +#define VD55G1_DUSTER_DYN_ENABLE BIT(1) |
153 | +#define VD55G1_DUSTER_RING_ENABLE BIT(4) | 153 | +#define VD55G1_DUSTER_RING_ENABLE BIT(4) |
154 | +#define VD55G1_REG_AE_TARGET_PERCENTAGE CCI_REG8(0x0486) | 154 | +#define VD55G1_REG_AE_TARGET_PERCENTAGE CCI_REG8(0x0486) |
155 | +#define VD55G1_REG_NEXT_CTX CCI_REG16_LE(0x03e4) | 155 | +#define VD55G1_REG_NEXT_CTX CCI_REG16_LE(0x03e4) |
156 | +#define VD55G1_REG_EXPOSURE_USE_CASES CCI_REG8(0x0312) | 156 | +#define VD55G1_REG_EXPOSURE_USE_CASES CCI_REG8(0x0312) |
157 | +#define VD55G1_EXPOSURE_USE_CASES_MULTI_CONTEXT BIT(2) | 157 | +#define VD55G1_EXPOSURE_USE_CASES_MULTI_CONTEXT BIT(2) |
158 | +#define VD55G1_REG_EXPOSURE_MAX_COARSE CCI_REG16_LE(0x0372) | 158 | +#define VD55G1_REG_EXPOSURE_MAX_COARSE CCI_REG16_LE(0x0372) |
159 | +#define VD55G1_EXPOSURE_MAX_COARSE_DEF 0x7fff | 159 | +#define VD55G1_EXPOSURE_MAX_COARSE_DEF 0x7fff |
160 | +#define VD55G1_EXPOSURE_MAX_COARSE_SUB 446 | 160 | +#define VD55G1_EXPOSURE_MAX_COARSE_SUB 446 |
161 | +#define VD55G1_REG_CTX_REPEAT_COUNT_CTX0 CCI_REG16_LE(0x03dc) | 161 | +#define VD55G1_REG_CTX_REPEAT_COUNT_CTX0 CCI_REG16_LE(0x03dc) |
162 | +#define VD55G1_REG_CTX_REPEAT_COUNT_CTX1 CCI_REG16_LE(0x03de) | 162 | +#define VD55G1_REG_CTX_REPEAT_COUNT_CTX1 CCI_REG16_LE(0x03de) |
163 | + | 163 | + |
164 | +#define VD55G1_REG_EXP_MODE(ctx) \ | 164 | +#define VD55G1_REG_EXP_MODE(ctx) \ |
165 | + CCI_REG8(0x0500 + VD55G1_CTX_OFFSET * (ctx)) | 165 | + CCI_REG8(0x0500 + VD55G1_CTX_OFFSET * (ctx)) |
166 | +#define VD55G1_REG_FRAME_LENGTH(ctx) \ | 166 | +#define VD55G1_REG_FRAME_LENGTH(ctx) \ |
167 | + CCI_REG32_LE(0x050c + VD55G1_CTX_OFFSET * (ctx)) | 167 | + CCI_REG32_LE(0x050c + VD55G1_CTX_OFFSET * (ctx)) |
168 | +#define VD55G1_REG_X_START(ctx) \ | 168 | +#define VD55G1_REG_X_START(ctx) \ |
169 | + CCI_REG16_LE(0x0514 + VD55G1_CTX_OFFSET * (ctx)) | 169 | + CCI_REG16_LE(0x0514 + VD55G1_CTX_OFFSET * (ctx)) |
170 | +#define VD55G1_REG_X_WIDTH(ctx) \ | 170 | +#define VD55G1_REG_X_WIDTH(ctx) \ |
171 | + CCI_REG16_LE(0x0516 + VD55G1_CTX_OFFSET * (ctx)) | 171 | + CCI_REG16_LE(0x0516 + VD55G1_CTX_OFFSET * (ctx)) |
172 | +#define VD55G1_REG_Y_START(ctx) \ | 172 | +#define VD55G1_REG_Y_START(ctx) \ |
173 | + CCI_REG16_LE(0x0510 + VD55G1_CTX_OFFSET * (ctx)) | 173 | + CCI_REG16_LE(0x0510 + VD55G1_CTX_OFFSET * (ctx)) |
174 | +#define VD55G1_REG_Y_HEIGHT(ctx) \ | 174 | +#define VD55G1_REG_Y_HEIGHT(ctx) \ |
175 | + CCI_REG16_LE(0x0512 + VD55G1_CTX_OFFSET * (ctx)) | 175 | + CCI_REG16_LE(0x0512 + VD55G1_CTX_OFFSET * (ctx)) |
176 | +#define VD55G1_REG_GPIO_0_CTRL(ctx) \ | 176 | +#define VD55G1_REG_GPIO_0_CTRL(ctx) \ |
177 | + CCI_REG8(0x051d + VD55G1_CTX_OFFSET * (ctx)) | 177 | + CCI_REG8(0x051d + VD55G1_CTX_OFFSET * (ctx)) |
178 | +#define VD55G1_REG_VT_MODE(ctx) \ | 178 | +#define VD55G1_REG_VT_MODE(ctx) \ |
179 | + CCI_REG8(0x0536 + VD55G1_CTX_OFFSET * (ctx)) | 179 | + CCI_REG8(0x0536 + VD55G1_CTX_OFFSET * (ctx)) |
180 | +#define VD55G1_VT_MODE_NORMAL 0 | 180 | +#define VD55G1_VT_MODE_NORMAL 0 |
181 | +#define VD55G1_VT_MODE_SUBTRACTION 1 | 181 | +#define VD55G1_VT_MODE_SUBTRACTION 1 |
182 | +#define VD55G1_REG_MASK_FRAME_CTRL(ctx) \ | 182 | +#define VD55G1_REG_MASK_FRAME_CTRL(ctx) \ |
183 | + CCI_REG8(0x0537 + VD55G1_CTX_OFFSET * (ctx)) | 183 | + CCI_REG8(0x0537 + VD55G1_CTX_OFFSET * (ctx)) |
184 | +#define VD55G1_MASK_FRAME_CTRL_OUTPUT 0 | 184 | +#define VD55G1_MASK_FRAME_CTRL_OUTPUT 0 |
185 | +#define VD55G1_MASK_FRAME_CTRL_MASK 1 | 185 | +#define VD55G1_MASK_FRAME_CTRL_MASK 1 |
186 | +#define VD55G1_REG_EXPOSURE_INSTANCE(ctx) \ | 186 | +#define VD55G1_REG_EXPOSURE_INSTANCE(ctx) \ |
187 | + CCI_REG32_LE(0x52D + VD55G1_CTX_OFFSET * (ctx)) | 187 | + CCI_REG32_LE(0x52D + VD55G1_CTX_OFFSET * (ctx)) |
188 | + | 188 | + |
189 | +#define VD55G1_WIDTH 804 | 189 | +#define VD55G1_WIDTH 804 |
190 | +#define VD55G1_HEIGHT 704 | 190 | +#define VD55G1_HEIGHT 704 |
191 | +#define VD55G1_DEFAULT_MODE 0 | 191 | +#define VD55G1_DEFAULT_MODE 0 |
192 | +#define VD55G1_NB_GPIOS 4 | 192 | +#define VD55G1_NB_GPIOS 4 |
193 | +#define VD55G1_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8 | 193 | +#define VD55G1_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8 |
194 | +#define VD55G1_DGAIN_DEF 256 | 194 | +#define VD55G1_DGAIN_DEF 256 |
195 | +#define VD55G1_AGAIN_DEF 19 | 195 | +#define VD55G1_AGAIN_DEF 19 |
196 | +#define VD55G1_EXPO_MAX_TERM 64 | 196 | +#define VD55G1_EXPO_MAX_TERM 64 |
197 | +#define VD55G1_EXPO_DEF 500 | 197 | +#define VD55G1_EXPO_DEF 500 |
198 | +#define VD55G1_LINE_LENGTH_MIN 1128 | 198 | +#define VD55G1_LINE_LENGTH_MIN 1128 |
199 | +#define VD55G1_LINE_LENGTH_SUB_MIN 1344 | 199 | +#define VD55G1_LINE_LENGTH_SUB_MIN 1344 |
200 | +#define VD55G1_VBLANK_MIN 86 | 200 | +#define VD55G1_VBLANK_MIN 86 |
201 | +#define VD55G1_VBLANK_MAX 0xffff | 201 | +#define VD55G1_VBLANK_MAX 0xffff |
202 | +#define VD55G1_FRAME_LENGTH_DEF 1860 /* 60 fps */ | 202 | +#define VD55G1_FRAME_LENGTH_DEF 1860 /* 60 fps */ |
203 | +#define VD55G1_MIPI_MARGIN 900 | 203 | +#define VD55G1_MIPI_MARGIN 900 |
204 | +#define VD55G1_CTX_OFFSET 0x50 | 204 | +#define VD55G1_CTX_OFFSET 0x50 |
205 | +#define VD55G1_FWPATCH_REVISION_MAJOR 2 | 205 | +#define VD55G1_FWPATCH_REVISION_MAJOR 2 |
206 | +#define VD55G1_FWPATCH_REVISION_MINOR 9 | 206 | +#define VD55G1_FWPATCH_REVISION_MINOR 9 |
207 | + | 207 | + |
208 | +static const u8 patch_array[] = { | 208 | +static const u8 patch_array[] = { |
209 | +0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, 0xf0, | 209 | +0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, 0xf0, |
210 | +0x01, 0x42, 0x00, 0xe6, 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 210 | +0x01, 0x42, 0x00, 0xe6, 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
211 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 211 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
212 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 212 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
213 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 213 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
214 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 214 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
215 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, | 215 | +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, |
216 | +0xfa, 0x68, 0x40, 0x00, 0xe8, 0x09, 0xbe, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, | 216 | +0xfa, 0x68, 0x40, 0x00, 0xe8, 0x09, 0xbe, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, |
217 | +0x1c, 0x00, 0xc0, 0xe2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x6b, | 217 | +0x1c, 0x00, 0xc0, 0xe2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x6b, |
218 | +0x80, 0x98, 0x7f, 0xfc, 0xef, 0x11, 0xc1, 0x0f, 0x82, 0x69, 0xbe, 0x0f, 0xac, | 218 | +0x80, 0x98, 0x7f, 0xfc, 0xef, 0x11, 0xc1, 0x0f, 0x82, 0x69, 0xbe, 0x0f, 0xac, |
219 | +0x58, 0x40, 0x00, 0xe8, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x1c, 0x00, 0x40, | 219 | +0x58, 0x40, 0x00, 0xe8, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x1c, 0x00, 0x40, |
220 | +0xe3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x84, 0xfa, 0x46, 0x0e, 0xe8, 0xe0, | 220 | +0xe3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x84, 0xfa, 0x46, 0x0e, 0xe8, 0xe0, |
221 | +0x08, 0xde, 0x4a, 0x40, 0x84, 0xe0, 0xa5, 0x86, 0xa8, 0x7d, 0xfc, 0xef, 0x6b, | 221 | +0x08, 0xde, 0x4a, 0x40, 0x84, 0xe0, 0xa5, 0x86, 0xa8, 0x7d, 0xfc, 0xef, 0x6b, |
222 | +0x80, 0x01, 0xbf, 0x28, 0x77, 0x0c, 0xef, 0x0b, 0x0e, 0x21, 0x78, 0x06, 0xc0, | 222 | +0x80, 0x01, 0xbf, 0x28, 0x77, 0x0c, 0xef, 0x0b, 0x0e, 0x21, 0x78, 0x06, 0xc0, |
223 | +0x0b, 0xa5, 0xb5, 0x84, 0x06, 0x42, 0x98, 0xe1, 0x01, 0x81, 0x01, 0x42, 0x38, | 223 | +0x0b, 0xa5, 0xb5, 0x84, 0x06, 0x42, 0x98, 0xe1, 0x01, 0x81, 0x01, 0x42, 0x38, |
224 | +0xe0, 0x0c, 0xc4, 0x0e, 0x84, 0x46, 0x02, 0x84, 0xe0, 0x0c, 0x84, 0x11, 0x81, | 224 | +0xe0, 0x0c, 0xc4, 0x0e, 0x84, 0x46, 0x02, 0x84, 0xe0, 0x0c, 0x84, 0x11, 0x81, |
225 | +0x21, 0x81, 0x31, 0x81, 0x41, 0x81, 0x51, 0x81, 0xc1, 0x81, 0x05, 0x83, 0x0c, | 225 | +0x21, 0x81, 0x31, 0x81, 0x41, 0x81, 0x51, 0x81, 0xc1, 0x81, 0x05, 0x83, 0x0c, |
226 | +0x0c, 0x84, 0xf2, 0x93, 0xdd, 0x06, 0x40, 0x98, 0xe1, 0xc8, 0x80, 0x58, 0x82, | 226 | +0x0c, 0x84, 0xf2, 0x93, 0xdd, 0x06, 0x40, 0x98, 0xe1, 0xc8, 0x80, 0x58, 0x82, |
227 | +0x48, 0xc0, 0x38, 0xc2, 0x29, 0x00, 0x10, 0xe0, 0x19, 0x00, 0x14, 0xe0, 0x09, | 227 | +0x48, 0xc0, 0x38, 0xc2, 0x29, 0x00, 0x10, 0xe0, 0x19, 0x00, 0x14, 0xe0, 0x09, |
228 | +0x00, 0x38, 0xe0, 0x5f, 0xb8, 0x5f, 0xa8, 0x5f, 0xa6, 0x5f, 0xa4, 0x5f, 0xa2, | 228 | +0x00, 0x38, 0xe0, 0x5f, 0xb8, 0x5f, 0xa8, 0x5f, 0xa6, 0x5f, 0xa4, 0x5f, 0xa2, |
229 | +0x5f, 0xa0, 0x56, 0x41, 0x98, 0xe1, 0x18, 0x82, 0x28, 0x80, 0x38, 0xc0, 0x5f, | 229 | +0x5f, 0xa0, 0x56, 0x41, 0x98, 0xe1, 0x18, 0x82, 0x28, 0x80, 0x38, 0xc0, 0x5f, |
230 | +0xa2, 0x19, 0x00, 0x20, 0xf8, 0x5f, 0xa4, 0x28, 0xc2, 0x5f, 0xa6, 0x39, 0x00, | 230 | +0xa2, 0x19, 0x00, 0x20, 0xf8, 0x5f, 0xa4, 0x28, 0xc2, 0x5f, 0xa6, 0x39, 0x00, |
231 | +0x10, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x14, 0xe0, 0x5f, 0xa4, 0x29, 0x00, 0x18, | 231 | +0x10, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x14, 0xe0, 0x5f, 0xa4, 0x29, 0x00, 0x18, |
232 | +0xe0, 0x5f, 0xa6, 0x39, 0x00, 0x40, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x44, 0xe0, | 232 | +0xe0, 0x5f, 0xa6, 0x39, 0x00, 0x40, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x44, 0xe0, |
233 | +0x5f, 0xa4, 0x29, 0x00, 0x1c, 0xe0, 0x5f, 0xa6, 0x39, 0x00, 0x38, 0xe0, 0x5f, | 233 | +0x5f, 0xa4, 0x29, 0x00, 0x1c, 0xe0, 0x5f, 0xa6, 0x39, 0x00, 0x38, 0xe0, 0x5f, |
234 | +0xa2, 0x19, 0x00, 0x20, 0xe0, 0x5f, 0xa4, 0x29, 0x00, 0x24, 0xe0, 0x5f, 0xa6, | 234 | +0xa2, 0x19, 0x00, 0x20, 0xe0, 0x5f, 0xa4, 0x29, 0x00, 0x24, 0xe0, 0x5f, 0xa6, |
235 | +0x39, 0x00, 0x28, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x2c, 0xe0, 0x5f, 0xa4, 0x29, | 235 | +0x39, 0x00, 0x28, 0xe0, 0x5f, 0xa2, 0x19, 0x00, 0x2c, 0xe0, 0x5f, 0xa4, 0x29, |
236 | +0x00, 0x30, 0xe0, 0x5f, 0xa6, 0x09, 0x00, 0x34, 0xe0, 0x5f, 0xa2, 0x5f, 0xa4, | 236 | +0x00, 0x30, 0xe0, 0x5f, 0xa6, 0x09, 0x00, 0x34, 0xe0, 0x5f, 0xa2, 0x5f, 0xa4, |
237 | +0x5f, 0xa0, 0x4a, 0x0a, 0xfc, 0xfb, 0xe5, 0x82, 0x08, 0xde, 0x4a, 0x40, 0x88, | 237 | +0x5f, 0xa0, 0x4a, 0x0a, 0xfc, 0xfb, 0xe5, 0x82, 0x08, 0xde, 0x4a, 0x40, 0x88, |
238 | +0xe0, 0xf6, 0x40, 0x00, 0xe0, 0x01, 0x4e, 0x99, 0x78, 0x0a, 0xc0, 0x85, 0x80, | 238 | +0xe0, 0xf6, 0x40, 0x00, 0xe0, 0x01, 0x4e, 0x99, 0x78, 0x0a, 0xc0, 0x85, 0x80, |
239 | +0x98, 0x40, 0x00, 0xe8, 0x35, 0x81, 0xa8, 0x40, 0x00, 0xe8, 0x0b, 0x8c, 0x0c, | 239 | +0x98, 0x40, 0x00, 0xe8, 0x35, 0x81, 0xa8, 0x40, 0x00, 0xe8, 0x0b, 0x8c, 0x0c, |
240 | +0x0c, 0x84, 0xf2, 0xd5, 0xed, 0x83, 0xc1, 0x13, 0xc5, 0x93, 0xdd, 0xc3, 0xc1, | 240 | +0x0c, 0x84, 0xf2, 0xd5, 0xed, 0x83, 0xc1, 0x13, 0xc5, 0x93, 0xdd, 0xc3, 0xc1, |
241 | +0x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0xc6, | 241 | +0x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0xc6, |
242 | +0x0f, 0x94, 0xe0, 0x19, 0x0e, 0xc9, 0x65, 0x01, 0xc0, 0x28, 0xde, 0x0a, 0x42, | 242 | +0x0f, 0x94, 0xe0, 0x19, 0x0e, 0xc9, 0x65, 0x01, 0xc0, 0x28, 0xde, 0x0a, 0x42, |
243 | +0x80, 0xe0, 0x24, 0x02, 0x00, 0xfc, 0x16, 0xde, 0xa5, 0x8a, 0x19, 0x00, 0xb8, | 243 | +0x80, 0xe0, 0x24, 0x02, 0x00, 0xfc, 0x16, 0xde, 0xa5, 0x8a, 0x19, 0x00, 0xb8, |
244 | +0xe0, 0x10, 0x02, 0x0c, 0xec, 0x1d, 0xe6, 0x14, 0x02, 0x88, 0x80, 0x4e, 0x04, | 244 | +0xe0, 0x10, 0x02, 0x0c, 0xec, 0x1d, 0xe6, 0x14, 0x02, 0x88, 0x80, 0x4e, 0x04, |
245 | +0x01, 0x00, 0x10, 0x80, 0x25, 0x02, 0x08, 0x9c, 0x86, 0x02, 0x00, 0x80, 0x08, | 245 | +0x01, 0x00, 0x10, 0x80, 0x25, 0x02, 0x08, 0x9c, 0x86, 0x02, 0x00, 0x80, 0x08, |
246 | +0x44, 0x00, 0x98, 0x55, 0x81, 0x11, 0x85, 0x45, 0x81, 0x11, 0x89, 0x25, 0x81, | 246 | +0x44, 0x00, 0x98, 0x55, 0x81, 0x11, 0x85, 0x45, 0x81, 0x11, 0x89, 0x25, 0x81, |
247 | +0x11, 0x83, 0x2b, 0x00, 0x24, 0xe0, 0x64, 0xc2, 0x0b, 0x84, 0x08, 0x51, 0x00, | 247 | +0x11, 0x83, 0x2b, 0x00, 0x24, 0xe0, 0x64, 0xc2, 0x0b, 0x84, 0x08, 0x51, 0x00, |
248 | +0xef, 0x2b, 0x80, 0x01, 0x83, 0x1b, 0x8c, 0x38, 0x7d, 0x5c, 0xef, 0x18, 0xde, | 248 | +0xef, 0x2b, 0x80, 0x01, 0x83, 0x1b, 0x8c, 0x38, 0x7d, 0x5c, 0xef, 0x18, 0xde, |
249 | +0x0b, 0xa1, 0x25, 0x82, 0x0b, 0x0e, 0x88, 0xf9, 0x0a, 0x00, 0x00, 0xe8, 0x10, | 249 | +0x0b, 0xa1, 0x25, 0x82, 0x0b, 0x0e, 0x88, 0xf9, 0x0a, 0x00, 0x00, 0xe8, 0x10, |
250 | +0x42, 0x04, 0x9c, 0x11, 0x4e, 0x0c, 0x80, 0x10, 0x40, 0x04, 0xf0, 0x4e, 0x05, | 250 | +0x42, 0x04, 0x9c, 0x11, 0x4e, 0x0c, 0x80, 0x10, 0x40, 0x04, 0xf0, 0x4e, 0x05, |
251 | +0x01, 0x60, 0x10, 0xc0, 0x06, 0x88, 0x10, 0x40, 0xf8, 0xf3, 0x06, 0xde, 0x4c, | 251 | +0x01, 0x60, 0x10, 0xc0, 0x06, 0x88, 0x10, 0x40, 0xf8, 0xf3, 0x06, 0xde, 0x4c, |
252 | +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x1c, 0xfe, 0xf6, 0x0f, 0x94, 0xe0, | 252 | +0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x1c, 0xfe, 0xf6, 0x0f, 0x94, 0xe0, |
253 | +0x38, 0x9c, 0x46, 0x51, 0xfc, 0xe0, 0x46, 0x49, 0x38, 0xe2, 0x30, 0x46, 0xf8, | 253 | +0x38, 0x9c, 0x46, 0x51, 0xfc, 0xe0, 0x46, 0x49, 0x38, 0xe2, 0x30, 0x46, 0xf8, |
254 | +0xf3, 0x36, 0x9c, 0xc6, 0x46, 0x0c, 0xe1, 0x34, 0x8c, 0x94, 0xa0, 0x4e, 0xa0, | 254 | +0xf3, 0x36, 0x9c, 0xc6, 0x46, 0x0c, 0xe1, 0x34, 0x8c, 0x94, 0xa0, 0x4e, 0xa0, |
255 | +0x39, 0x06, 0x80, 0xe0, 0x4a, 0x46, 0x94, 0xe0, 0x05, 0x8c, 0x6a, 0x40, 0x80, | 255 | +0x39, 0x06, 0x80, 0xe0, 0x4a, 0x46, 0x94, 0xe0, 0x05, 0x8c, 0x6a, 0x40, 0x80, |
256 | +0xe0, 0x2c, 0x0c, 0x00, 0xe2, 0x0b, 0x8c, 0xb8, 0x7c, 0x5c, 0xef, 0x0b, 0x8c, | 256 | +0xe0, 0x2c, 0x0c, 0x00, 0xe2, 0x0b, 0x8c, 0xb8, 0x7c, 0x5c, 0xef, 0x0b, 0x8c, |
257 | +0x9e, 0xa0, 0xf8, 0x40, 0x60, 0xef, 0x0b, 0xa1, 0x5a, 0x40, 0x80, 0xe0, 0x65, | 257 | +0x9e, 0xa0, 0xf8, 0x40, 0x60, 0xef, 0x0b, 0xa1, 0x5a, 0x40, 0x80, 0xe0, 0x65, |
258 | +0x88, 0x28, 0x02, 0x01, 0x40, 0x00, 0x80, 0x2a, 0x42, 0x9c, 0xe1, 0x28, 0x49, | 258 | +0x88, 0x28, 0x02, 0x01, 0x40, 0x00, 0x80, 0x2a, 0x42, 0x9c, 0xe1, 0x28, 0x49, |
259 | +0x60, 0xef, 0x96, 0x4d, 0x9c, 0xe1, 0x01, 0x81, 0x06, 0x98, 0xd5, 0x81, 0x09, | 259 | +0x60, 0xef, 0x96, 0x4d, 0x9c, 0xe1, 0x01, 0x81, 0x06, 0x98, 0xd5, 0x81, 0x09, |
260 | +0x0e, 0xa1, 0x64, 0x01, 0xc0, 0x4a, 0x40, 0x88, 0xe0, 0x85, 0x80, 0xb8, 0x77, | 260 | +0x0e, 0xa1, 0x64, 0x01, 0xc0, 0x4a, 0x40, 0x88, 0xe0, 0x85, 0x80, 0xb8, 0x77, |
261 | +0xfc, 0xef, 0x35, 0x81, 0xc8, 0x77, 0xfc, 0xef, 0x08, 0x98, 0x4a, 0x00, 0xfc, | 261 | +0xfc, 0xef, 0x35, 0x81, 0xc8, 0x77, 0xfc, 0xef, 0x08, 0x98, 0x4a, 0x00, 0xfc, |
262 | +0xfb, 0x55, 0xfc, 0xe8, 0x4a, 0x60, 0xef, 0x1a, 0x44, 0x9c, 0xe1, 0x35, 0x81, | 262 | +0xfb, 0x55, 0xfc, 0xe8, 0x4a, 0x60, 0xef, 0x1a, 0x44, 0x9c, 0xe1, 0x35, 0x81, |
263 | +0x1a, 0x4e, 0x9c, 0xe9, 0x1c, 0x00, 0x00, 0xe2, 0x0c, 0x0c, 0x1c, 0xf6, 0x93, | 263 | +0x1a, 0x4e, 0x9c, 0xe9, 0x1c, 0x00, 0x00, 0xe2, 0x0c, 0x0c, 0x1c, 0xf6, 0x93, |
264 | +0xdd, 0x0d, 0xc3, 0x1a, 0x41, 0x08, 0xe4, 0x0a, 0x40, 0x84, 0xe1, 0x0c, 0x00, | 264 | +0xdd, 0x0d, 0xc3, 0x1a, 0x41, 0x08, 0xe4, 0x0a, 0x40, 0x84, 0xe1, 0x0c, 0x00, |
265 | +0x00, 0xe2, 0x93, 0xdd, 0x4c, 0x04, 0x1c, 0xfa, 0x86, 0x52, 0xec, 0xe1, 0x08, | 265 | +0x00, 0xe2, 0x93, 0xdd, 0x4c, 0x04, 0x1c, 0xfa, 0x86, 0x52, 0xec, 0xe1, 0x08, |
266 | +0xa6, 0x65, 0x12, 0x24, 0xf8, 0x0e, 0x02, 0x99, 0x7a, 0x00, 0xc0, 0x00, 0x40, | 266 | +0xa6, 0x65, 0x12, 0x24, 0xf8, 0x0e, 0x02, 0x99, 0x7a, 0x00, 0xc0, 0x00, 0x40, |
267 | +0xa0, 0xf3, 0x06, 0xa6, 0x0b, 0x8c, 0x08, 0x49, 0x00, 0xef, 0x85, 0x12, 0x28, | 267 | +0xa0, 0xf3, 0x06, 0xa6, 0x0b, 0x8c, 0x08, 0x49, 0x00, 0xef, 0x85, 0x12, 0x28, |
268 | +0xf8, 0x02, 0x02, 0xfc, 0xed, 0xf6, 0x47, 0xfd, 0x6f, 0xe0, 0xff, 0x04, 0xe2, | 268 | +0xf8, 0x02, 0x02, 0xfc, 0xed, 0xf6, 0x47, 0xfd, 0x6f, 0xe0, 0xff, 0x04, 0xe2, |
269 | +0x14, 0x04, 0xc0, 0xe0, 0x0f, 0x86, 0x2f, 0xa0, 0x0b, 0x8c, 0x2e, 0xe2, 0x08, | 269 | +0x14, 0x04, 0xc0, 0xe0, 0x0f, 0x86, 0x2f, 0xa0, 0x0b, 0x8c, 0x2e, 0xe2, 0x08, |
270 | +0x48, 0x00, 0xef, 0x86, 0x02, 0x84, 0xfe, 0x0e, 0x05, 0x09, 0x7d, 0x00, 0xc0, | 270 | +0x48, 0x00, 0xef, 0x86, 0x02, 0x84, 0xfe, 0x0e, 0x05, 0x09, 0x7d, 0x00, 0xc0, |
271 | +0x05, 0x52, 0x08, 0xf8, 0x18, 0x7d, 0xfc, 0xef, 0x4a, 0x40, 0x80, 0xe0, 0x09, | 271 | +0x05, 0x52, 0x08, 0xf8, 0x18, 0x7d, 0xfc, 0xef, 0x4a, 0x40, 0x80, 0xe0, 0x09, |
272 | +0x12, 0x04, 0xc0, 0x65, 0x12, 0x20, 0xf8, 0x00, 0x40, 0x40, 0xdc, 0x01, 0x52, | 272 | +0x12, 0x04, 0xc0, 0x65, 0x12, 0x20, 0xf8, 0x00, 0x40, 0x40, 0xdc, 0x01, 0x52, |
273 | +0x04, 0xc0, 0x0e, 0x00, 0x41, 0x78, 0xf5, 0xc5, 0x6d, 0xc0, 0xb5, 0x82, 0x05, | 273 | +0x04, 0xc0, 0x0e, 0x00, 0x41, 0x78, 0xf5, 0xc5, 0x6d, 0xc0, 0xb5, 0x82, 0x05, |
274 | +0x10, 0x10, 0xe0, 0x11, 0xf1, 0x0f, 0x82, 0x05, 0x50, 0x10, 0xe0, 0x05, 0x10, | 274 | +0x10, 0x10, 0xe0, 0x11, 0xf1, 0x0f, 0x82, 0x05, 0x50, 0x10, 0xe0, 0x05, 0x10, |
275 | +0x10, 0xe0, 0xfe, 0x02, 0xf0, 0xff, 0x0f, 0x82, 0x85, 0x83, 0x15, 0x10, 0x10, | 275 | +0x10, 0xe0, 0xfe, 0x02, 0xf0, 0xff, 0x0f, 0x82, 0x85, 0x83, 0x15, 0x10, 0x10, |
276 | +0xe0, 0x16, 0x00, 0x91, 0x6e, 0x69, 0xcd, 0x21, 0xf1, 0x6d, 0xc1, 0x01, 0x83, | 276 | +0xe0, 0x16, 0x00, 0x91, 0x6e, 0x69, 0xcd, 0x21, 0xf1, 0x6d, 0xc1, 0x01, 0x83, |
277 | +0x2f, 0x82, 0x26, 0x00, 0x00, 0x80, 0x2f, 0xa0, 0x25, 0x50, 0x10, 0xe0, 0x05, | 277 | +0x2f, 0x82, 0x26, 0x00, 0x00, 0x80, 0x2f, 0xa0, 0x25, 0x50, 0x10, 0xe0, 0x05, |
278 | +0x10, 0x10, 0xe0, 0x11, 0xa1, 0xfe, 0x04, 0xf0, 0xff, 0x06, 0x42, 0x00, 0x80, | 278 | +0x10, 0x10, 0xe0, 0x11, 0xa1, 0xfe, 0x04, 0xf0, 0xff, 0x06, 0x42, 0x00, 0x80, |
279 | +0x0f, 0x84, 0x0f, 0xa2, 0x05, 0x50, 0x10, 0xe0, 0x16, 0x00, 0x91, 0x6e, 0x69, | 279 | +0x0f, 0x84, 0x0f, 0xa2, 0x05, 0x50, 0x10, 0xe0, 0x16, 0x00, 0x91, 0x6e, 0x69, |
280 | +0xcd, 0x6d, 0xc1, 0x71, 0x8d, 0x16, 0x00, 0x79, 0x61, 0x2d, 0xcb, 0x86, 0x0e, | 280 | +0xcd, 0x6d, 0xc1, 0x71, 0x8d, 0x16, 0x00, 0x79, 0x61, 0x2d, 0xcb, 0x86, 0x0e, |
281 | +0x00, 0x80, 0x6d, 0xc1, 0x56, 0x0e, 0x00, 0xc0, 0x0b, 0x8c, 0x1b, 0x8e, 0x71, | 281 | +0x00, 0x80, 0x6d, 0xc1, 0x56, 0x0e, 0x00, 0xc0, 0x0b, 0x8c, 0x1b, 0x8e, 0x71, |
282 | +0x52, 0x0c, 0xf8, 0x08, 0x43, 0x00, 0xef, 0x05, 0x52, 0x14, 0xf8, 0x15, 0x10, | 282 | +0x52, 0x0c, 0xf8, 0x08, 0x43, 0x00, 0xef, 0x05, 0x52, 0x14, 0xf8, 0x15, 0x10, |
283 | +0x28, 0xe0, 0x70, 0x04, 0x04, 0xec, 0x31, 0xe1, 0x29, 0x9e, 0x1f, 0x86, 0x1f, | 283 | +0x28, 0xe0, 0x70, 0x04, 0x04, 0xec, 0x31, 0xe1, 0x29, 0x9e, 0x1f, 0x86, 0x1f, |
284 | +0xa4, 0x15, 0x50, 0x28, 0xe0, 0x86, 0x42, 0x3c, 0xe0, 0x0e, 0x04, 0x9d, 0x64, | 284 | +0xa4, 0x15, 0x50, 0x28, 0xe0, 0x86, 0x42, 0x3c, 0xe0, 0x0e, 0x04, 0x9d, 0x64, |
285 | +0x9b, 0xc2, 0x05, 0x52, 0x1c, 0xf8, 0x78, 0xa6, 0x48, 0x77, 0xfc, 0xef, 0x4a, | 285 | +0x9b, 0xc2, 0x05, 0x52, 0x1c, 0xf8, 0x78, 0xa6, 0x48, 0x77, 0xfc, 0xef, 0x4a, |
286 | +0x40, 0x80, 0xe0, 0x70, 0x4e, 0x10, 0xdc, 0x1e, 0x00, 0x81, 0x70, 0xeb, 0xcb, | 286 | +0x40, 0x80, 0xe0, 0x70, 0x4e, 0x10, 0xdc, 0x1e, 0x00, 0x81, 0x70, 0xeb, 0xcb, |
287 | +0x70, 0x4e, 0xec, 0x93, 0x6d, 0xc1, 0x11, 0x85, 0x36, 0x02, 0x00, 0x80, 0x76, | 287 | +0x70, 0x4e, 0xec, 0x93, 0x6d, 0xc1, 0x11, 0x85, 0x36, 0x02, 0x00, 0x80, 0x76, |
288 | +0xa6, 0x11, 0x52, 0x10, 0xf8, 0x05, 0x10, 0x40, 0xe0, 0xfe, 0x47, 0x0c, 0xff, | 288 | +0xa6, 0x11, 0x52, 0x10, 0xf8, 0x05, 0x10, 0x40, 0xe0, 0xfe, 0x47, 0x0c, 0xff, |
289 | +0x14, 0x04, 0xa0, 0xe0, 0x0f, 0x86, 0x0f, 0xa4, 0x05, 0x50, 0x40, 0xe0, 0x05, | 289 | +0x14, 0x04, 0xa0, 0xe0, 0x0f, 0x86, 0x0f, 0xa4, 0x05, 0x50, 0x40, 0xe0, 0x05, |
290 | +0x10, 0x28, 0xe0, 0xfe, 0x47, 0xfd, 0x7f, 0xe3, 0xff, 0x14, 0x04, 0xd0, 0xe0, | 290 | +0x10, 0x28, 0xe0, 0xfe, 0x47, 0xfd, 0x7f, 0xe3, 0xff, 0x14, 0x04, 0xd0, 0xe0, |
291 | +0x0f, 0x86, 0x2f, 0xa0, 0x20, 0x00, 0x01, 0x6c, 0x00, 0xd0, 0x05, 0x50, 0x28, | 291 | +0x0f, 0x86, 0x2f, 0xa0, 0x20, 0x00, 0x01, 0x6c, 0x00, 0xd0, 0x05, 0x50, 0x28, |
292 | +0xe0, 0x0b, 0x8c, 0xf8, 0x7e, 0xfc, 0xee, 0x0e, 0x03, 0x59, 0x78, 0xf5, 0xc5, | 292 | +0xe0, 0x0b, 0x8c, 0xf8, 0x7e, 0xfc, 0xee, 0x0e, 0x03, 0x59, 0x78, 0xf5, 0xc5, |
293 | +0x0d, 0xc2, 0x05, 0x52, 0x0c, 0xf8, 0x08, 0xa6, 0x46, 0x42, 0xb4, 0xe0, 0x18, | 293 | +0x0d, 0xc2, 0x05, 0x52, 0x0c, 0xf8, 0x08, 0xa6, 0x46, 0x42, 0xb4, 0xe0, 0x18, |
294 | +0x84, 0x00, 0x40, 0xf4, 0x93, 0x00, 0x40, 0x08, 0xdc, 0x1b, 0xa1, 0x06, 0xa6, | 294 | +0x84, 0x00, 0x40, 0xf4, 0x93, 0x00, 0x40, 0x08, 0xdc, 0x1b, 0xa1, 0x06, 0xa6, |
295 | +0x05, 0x10, 0x40, 0x80, 0x04, 0x00, 0x50, 0x9c, 0x65, 0x8a, 0x05, 0x10, 0x44, | 295 | +0x05, 0x10, 0x40, 0x80, 0x04, 0x00, 0x50, 0x9c, 0x65, 0x8a, 0x05, 0x10, 0x44, |
296 | +0xe0, 0xf6, 0x43, 0xfd, 0x6f, 0x00, 0xf8, 0x0f, 0x82, 0x06, 0x02, 0x01, 0x60, | 296 | +0xe0, 0xf6, 0x43, 0xfd, 0x6f, 0x00, 0xf8, 0x0f, 0x82, 0x06, 0x02, 0x01, 0x60, |
297 | +0x1e, 0xc0, 0x0f, 0xa2, 0x05, 0x50, 0x44, 0xe0, 0x05, 0x10, 0x44, 0xe0, 0x0e, | 297 | +0x1e, 0xc0, 0x0f, 0xa2, 0x05, 0x50, 0x44, 0xe0, 0x05, 0x10, 0x44, 0xe0, 0x0e, |
298 | +0x02, 0x00, 0xf8, 0x0f, 0x82, 0x09, 0xf6, 0x05, 0x50, 0x44, 0xe0, 0x05, 0x10, | 298 | +0x02, 0x00, 0xf8, 0x0f, 0x82, 0x09, 0xf6, 0x05, 0x50, 0x44, 0xe0, 0x05, 0x10, |
299 | +0x40, 0xe0, 0x04, 0x00, 0x54, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, | 299 | +0x40, 0xe0, 0x04, 0x00, 0x54, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, |
300 | +0xe0, 0x04, 0x00, 0xcc, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, 0xe0, | 300 | +0xe0, 0x04, 0x00, 0xcc, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, 0xe0, |
301 | +0x04, 0x00, 0x4c, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, 0xe0, 0x04, | 301 | +0x04, 0x00, 0x4c, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x05, 0x10, 0x40, 0xe0, 0x04, |
302 | +0x00, 0xd0, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x4c, 0x0c, 0x1c, 0xf2, 0x93, 0xdd, | 302 | +0x00, 0xd0, 0xfc, 0x05, 0x50, 0x40, 0xe0, 0x4c, 0x0c, 0x1c, 0xf2, 0x93, 0xdd, |
303 | +0xc3, 0xc1, 0xc6, 0x40, 0xfc, 0xe0, 0x04, 0x80, 0xc6, 0x44, 0x0c, 0xe1, 0x15, | 303 | +0xc3, 0xc1, 0xc6, 0x40, 0xfc, 0xe0, 0x04, 0x80, 0xc6, 0x44, 0x0c, 0xe1, 0x15, |
304 | +0x04, 0x0c, 0xf8, 0x0a, 0x80, 0x06, 0x07, 0x04, 0xe0, 0x03, 0x42, 0x48, 0xe1, | 304 | +0x04, 0x0c, 0xf8, 0x0a, 0x80, 0x06, 0x07, 0x04, 0xe0, 0x03, 0x42, 0x48, 0xe1, |
305 | +0x46, 0x02, 0x40, 0xe2, 0x08, 0xc6, 0x44, 0x88, 0x06, 0x46, 0x0e, 0xe0, 0x86, | 305 | +0x46, 0x02, 0x40, 0xe2, 0x08, 0xc6, 0x44, 0x88, 0x06, 0x46, 0x0e, 0xe0, 0x86, |
306 | +0x01, 0x84, 0xe0, 0x33, 0x80, 0x39, 0x06, 0xd8, 0xef, 0x0a, 0x46, 0x80, 0xe0, | 306 | +0x01, 0x84, 0xe0, 0x33, 0x80, 0x39, 0x06, 0xd8, 0xef, 0x0a, 0x46, 0x80, 0xe0, |
307 | +0x31, 0xbf, 0x06, 0x06, 0x00, 0xc0, 0x31, 0x48, 0x60, 0xe0, 0x34, 0x88, 0x49, | 307 | +0x31, 0xbf, 0x06, 0x06, 0x00, 0xc0, 0x31, 0x48, 0x60, 0xe0, 0x34, 0x88, 0x49, |
308 | +0x06, 0x40, 0xe1, 0x40, 0x48, 0x7c, 0xf3, 0x41, 0x46, 0x40, 0xe1, 0x24, 0x8a, | 308 | +0x06, 0x40, 0xe1, 0x40, 0x48, 0x7c, 0xf3, 0x41, 0x46, 0x40, 0xe1, 0x24, 0x8a, |
309 | +0x39, 0x04, 0x10, 0xe0, 0x39, 0xc2, 0x31, 0x44, 0x10, 0xe0, 0x14, 0xc4, 0x1b, | 309 | +0x39, 0x04, 0x10, 0xe0, 0x39, 0xc2, 0x31, 0x44, 0x10, 0xe0, 0x14, 0xc4, 0x1b, |
310 | +0xa5, 0x11, 0x83, 0x11, 0x40, 0x25, 0x6a, 0x01, 0xc0, 0x08, 0x5c, 0x00, 0xda, | 310 | +0xa5, 0x11, 0x83, 0x11, 0x40, 0x25, 0x6a, 0x01, 0xc0, 0x08, 0x5c, 0x00, 0xda, |
311 | +0x15, 0x00, 0xcc, 0xe0, 0x25, 0x00, 0xf8, 0xe0, 0x1b, 0x85, 0x08, 0x5c, 0x00, | 311 | +0x15, 0x00, 0xcc, 0xe0, 0x25, 0x00, 0xf8, 0xe0, 0x1b, 0x85, 0x08, 0x5c, 0x00, |
312 | +0x9a, 0x4e, 0x03, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x00, 0x1c, 0xe4, 0x18, 0x84, | 312 | +0x9a, 0x4e, 0x03, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x00, 0x1c, 0xe4, 0x18, 0x84, |
313 | +0x20, 0x44, 0xf8, 0xf3, 0x2f, 0xa2, 0x21, 0x40, 0x1c, 0xe4, 0x93, 0xdd, 0x0c, | 313 | +0x20, 0x44, 0xf8, 0xf3, 0x2f, 0xa2, 0x21, 0x40, 0x1c, 0xe4, 0x93, 0xdd, 0x0c, |
314 | +0x00, 0x80, 0xfa, 0x15, 0x00, 0x3c, 0xe0, 0x21, 0x81, 0x31, 0x85, 0x21, 0x42, | 314 | +0x00, 0x80, 0xfa, 0x15, 0x00, 0x3c, 0xe0, 0x21, 0x81, 0x31, 0x85, 0x21, 0x42, |
315 | +0x60, 0xe0, 0x15, 0x00, 0x44, 0xe0, 0x31, 0x42, 0x40, 0xe1, 0x15, 0x00, 0x34, | 315 | +0x60, 0xe0, 0x15, 0x00, 0x44, 0xe0, 0x31, 0x42, 0x40, 0xe1, 0x15, 0x00, 0x34, |
316 | +0xe0, 0x21, 0x42, 0x20, 0xe0, 0x15, 0x00, 0x34, 0xe0, 0xd6, 0x04, 0x10, 0xe0, | 316 | +0xe0, 0x21, 0x42, 0x20, 0xe0, 0x15, 0x00, 0x34, 0xe0, 0xd6, 0x04, 0x10, 0xe0, |
317 | +0x23, 0x42, 0x30, 0xe0, 0x15, 0x00, 0x34, 0xe0, 0x86, 0x44, 0x04, 0xe0, 0x23, | 317 | +0x23, 0x42, 0x30, 0xe0, 0x15, 0x00, 0x34, 0xe0, 0x86, 0x44, 0x04, 0xe0, 0x23, |
318 | +0x42, 0x38, 0xe0, 0x05, 0x00, 0x30, 0xe0, 0xc6, 0x02, 0x08, 0xe0, 0x13, 0x40, | 318 | +0x42, 0x38, 0xe0, 0x05, 0x00, 0x30, 0xe0, 0xc6, 0x02, 0x08, 0xe0, 0x13, 0x40, |
319 | +0x10, 0xe3, 0xe8, 0x56, 0x40, 0xef, 0x06, 0x40, 0x0c, 0xe1, 0x04, 0x80, 0x06, | 319 | +0x10, 0xe3, 0xe8, 0x56, 0x40, 0xef, 0x06, 0x40, 0x0c, 0xe1, 0x04, 0x80, 0x06, |
320 | +0x02, 0x94, 0xe0, 0x2b, 0x02, 0xc4, 0xea, 0x3b, 0x00, 0x78, 0xe2, 0x20, 0x44, | 320 | +0x02, 0x94, 0xe0, 0x2b, 0x02, 0xc4, 0xea, 0x3b, 0x00, 0x78, 0xe2, 0x20, 0x44, |
321 | +0xfd, 0x73, 0x07, 0xc0, 0x30, 0x46, 0x01, 0x70, 0xf8, 0xc0, 0x3f, 0xa4, 0x33, | 321 | +0xfd, 0x73, 0x07, 0xc0, 0x30, 0x46, 0x01, 0x70, 0xf8, 0xc0, 0x3f, 0xa4, 0x33, |
322 | +0x40, 0x78, 0xe2, 0x0a, 0x84, 0x0c, 0x08, 0x80, 0xf2, 0xf8, 0x3b, 0x3c, 0xff, | 322 | +0x40, 0x78, 0xe2, 0x0a, 0x84, 0x0c, 0x08, 0x80, 0xf2, 0xf8, 0x3b, 0x3c, 0xff, |
323 | +0xc3, 0xc1, 0x06, 0x40, 0x0c, 0xe1, 0x04, 0x80, 0x1b, 0x00, 0x40, 0xe4, 0x19, | 323 | +0xc3, 0xc1, 0x06, 0x40, 0x0c, 0xe1, 0x04, 0x80, 0x1b, 0x00, 0x40, 0xe4, 0x19, |
324 | +0xc2, 0x13, 0x40, 0x40, 0xe4, 0x1b, 0x00, 0x40, 0xe4, 0x19, 0xc4, 0x13, 0x40, | 324 | +0xc2, 0x13, 0x40, 0x40, 0xe4, 0x1b, 0x00, 0x40, 0xe4, 0x19, 0xc4, 0x13, 0x40, |
325 | +0x40, 0xe4, 0x93, 0xdd, 0xc6, 0x43, 0xec, 0xe0, 0x46, 0x41, 0xfc, 0xe0, 0x24, | 325 | +0x40, 0xe4, 0x93, 0xdd, 0xc6, 0x43, 0xec, 0xe0, 0x46, 0x41, 0xfc, 0xe0, 0x24, |
326 | +0x84, 0x04, 0x80, 0x31, 0x81, 0x4a, 0x44, 0x80, 0xe0, 0x86, 0x44, 0x0c, 0xe1, | 326 | +0x84, 0x04, 0x80, 0x31, 0x81, 0x4a, 0x44, 0x80, 0xe0, 0x86, 0x44, 0x0c, 0xe1, |
327 | +0x09, 0x00, 0x6c, 0xe0, 0xc4, 0x8a, 0x8e, 0x47, 0xfc, 0x9f, 0x01, 0x42, 0x51, | 327 | +0x09, 0x00, 0x6c, 0xe0, 0xc4, 0x8a, 0x8e, 0x47, 0xfc, 0x9f, 0x01, 0x42, 0x51, |
328 | +0x78, 0x0c, 0xc0, 0x31, 0x58, 0x90, 0xe0, 0x34, 0x8a, 0x41, 0xbf, 0x06, 0x08, | 328 | +0x78, 0x0c, 0xc0, 0x31, 0x58, 0x90, 0xe0, 0x34, 0x8a, 0x41, 0xbf, 0x06, 0x08, |
329 | +0x00, 0xc0, 0x41, 0x46, 0xa0, 0xe0, 0x34, 0x8a, 0x51, 0x81, 0xf6, 0x0b, 0x00, | 329 | +0x00, 0xc0, 0x41, 0x46, 0xa0, 0xe0, 0x34, 0x8a, 0x51, 0x81, 0xf6, 0x0b, 0x00, |
330 | +0xc0, 0x51, 0x46, 0xd0, 0xe0, 0x34, 0x8a, 0x01, 0xbf, 0x51, 0x46, 0xe0, 0xe0, | 330 | +0xc0, 0x51, 0x46, 0xd0, 0xe0, 0x34, 0x8a, 0x01, 0xbf, 0x51, 0x46, 0xe0, 0xe0, |
331 | +0x44, 0x84, 0x0a, 0x48, 0x84, 0xe0, 0x75, 0x86, 0x54, 0xca, 0x49, 0x88, 0x44, | 331 | +0x44, 0x84, 0x0a, 0x48, 0x84, 0xe0, 0x75, 0x86, 0x54, 0xca, 0x49, 0x88, 0x44, |
332 | +0x06, 0x88, 0xe1, 0x36, 0x94, 0x4a, 0x46, 0x80, 0xe0, 0x34, 0xca, 0x47, 0xc6, | 332 | +0x06, 0x88, 0xe1, 0x36, 0x94, 0x4a, 0x46, 0x80, 0xe0, 0x34, 0xca, 0x47, 0xc6, |
333 | +0x11, 0x8d, 0x41, 0x46, 0xd0, 0xe0, 0x34, 0x88, 0x76, 0x02, 0x00, 0xc0, 0x06, | 333 | +0x11, 0x8d, 0x41, 0x46, 0xd0, 0xe0, 0x34, 0x88, 0x76, 0x02, 0x00, 0xc0, 0x06, |
334 | +0x00, 0x00, 0xc0, 0x16, 0x8c, 0x14, 0x88, 0x01, 0x42, 0xc0, 0xe1, 0x01, 0x42, | 334 | +0x00, 0x00, 0xc0, 0x16, 0x8c, 0x14, 0x88, 0x01, 0x42, 0xc0, 0xe1, 0x01, 0x42, |
335 | +0xe0, 0xe1, 0x01, 0x42, 0xf0, 0xe1, 0x93, 0xdd, 0x34, 0xca, 0x41, 0x85, 0x46, | 335 | +0xe0, 0xe1, 0x01, 0x42, 0xf0, 0xe1, 0x93, 0xdd, 0x34, 0xca, 0x41, 0x85, 0x46, |
336 | +0x8c, 0x34, 0xca, 0x06, 0x48, 0x00, 0xe0, 0x41, 0x46, 0xd0, 0xe0, 0x34, 0x88, | 336 | +0x8c, 0x34, 0xca, 0x06, 0x48, 0x00, 0xe0, 0x41, 0x46, 0xd0, 0xe0, 0x34, 0x88, |
337 | +0x41, 0x83, 0x46, 0x8c, 0x34, 0x88, 0x01, 0x46, 0xc0, 0xe1, 0x01, 0x46, 0xe0, | 337 | +0x41, 0x83, 0x46, 0x8c, 0x34, 0x88, 0x01, 0x46, 0xc0, 0xe1, 0x01, 0x46, 0xe0, |
338 | +0xe1, 0x01, 0x46, 0xf0, 0xe1, 0x09, 0x02, 0x20, 0xe0, 0x14, 0xca, 0x03, 0x42, | 338 | +0xe1, 0x01, 0x46, 0xf0, 0xe1, 0x09, 0x02, 0x20, 0xe0, 0x14, 0xca, 0x03, 0x42, |
339 | +0x58, 0xe0, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x46, 0x4e, 0x08, | 339 | +0x58, 0xe0, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x46, 0x4e, 0x08, |
340 | +0xe1, 0x06, 0x4c, 0x0c, 0xe1, 0x0a, 0x9e, 0x14, 0x98, 0x05, 0x42, 0x44, 0xe0, | 340 | +0xe1, 0x06, 0x4c, 0x0c, 0xe1, 0x0a, 0x9e, 0x14, 0x98, 0x05, 0x42, 0x44, 0xe0, |
341 | +0x10, 0x00, 0xe1, 0x65, 0x03, 0xc0, 0x78, 0x41, 0x00, 0xe8, 0x08, 0x9c, 0x0b, | 341 | +0x10, 0x00, 0xe1, 0x65, 0x03, 0xc0, 0x78, 0x41, 0x00, 0xe8, 0x08, 0x9c, 0x0b, |
342 | +0xa1, 0x04, 0x98, 0x06, 0x02, 0x10, 0x80, 0x13, 0x40, 0xf8, 0x86, 0x65, 0x82, | 342 | +0xa1, 0x04, 0x98, 0x06, 0x02, 0x10, 0x80, 0x13, 0x40, 0xf8, 0x86, 0x65, 0x82, |
343 | +0x00, 0x00, 0xe1, 0x65, 0x03, 0xc0, 0xa8, 0x40, 0x00, 0xe8, 0x14, 0x98, 0x04, | 343 | +0x00, 0x00, 0xe1, 0x65, 0x03, 0xc0, 0xa8, 0x40, 0x00, 0xe8, 0x14, 0x98, 0x04, |
344 | +0x00, 0xa0, 0xfc, 0x03, 0x42, 0x00, 0xe7, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, | 344 | +0x00, 0xa0, 0xfc, 0x03, 0x42, 0x00, 0xe7, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, |
345 | +0x0a, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x06, 0x02, 0xec, 0xe1, 0x64, | 345 | +0x0a, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x06, 0x02, 0xec, 0xe1, 0x64, |
346 | +0x84, 0x15, 0x0c, 0x2c, 0xe0, 0x14, 0x02, 0xa0, 0xfc, 0x15, 0x4c, 0x2c, 0xe0, | 346 | +0x84, 0x15, 0x0c, 0x2c, 0xe0, 0x14, 0x02, 0xa0, 0xfc, 0x15, 0x4c, 0x2c, 0xe0, |
347 | +0xd8, 0x40, 0x00, 0xe8, 0x14, 0xd8, 0x09, 0x82, 0x14, 0x02, 0x00, 0xfc, 0x1f, | 347 | +0xd8, 0x40, 0x00, 0xe8, 0x14, 0xd8, 0x09, 0x82, 0x14, 0x02, 0x00, 0xfc, 0x1f, |
348 | +0xa0, 0x1e, 0xd8, 0x01, 0x85, 0x0c, 0x0c, 0x00, 0xf2, 0xe8, 0x32, 0x2c, 0xff, | 348 | +0xa0, 0x1e, 0xd8, 0x01, 0x85, 0x0c, 0x0c, 0x00, 0xf2, 0xe8, 0x32, 0x2c, 0xff, |
349 | +0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x80, 0xf6, 0x01, 0x94, | 349 | +0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x80, 0xf6, 0x01, 0x94, |
350 | +0xe0, 0x08, 0x80, 0x4a, 0x40, 0x80, 0xe0, 0x45, 0x86, 0x06, 0x40, 0x0c, 0xe1, | 350 | +0xe0, 0x08, 0x80, 0x4a, 0x40, 0x80, 0xe0, 0x45, 0x86, 0x06, 0x40, 0x0c, 0xe1, |
351 | +0x04, 0x80, 0xc6, 0x02, 0x40, 0xe2, 0x09, 0x00, 0xd0, 0xe0, 0x14, 0x84, 0x1b, | 351 | +0x04, 0x80, 0xc6, 0x02, 0x40, 0xe2, 0x09, 0x00, 0xd0, 0xe0, 0x14, 0x84, 0x1b, |
352 | +0xa5, 0x15, 0x84, 0x07, 0xc5, 0x09, 0x82, 0x18, 0x41, 0x00, 0xe8, 0x46, 0x43, | 352 | +0xa5, 0x15, 0x84, 0x07, 0xc5, 0x09, 0x82, 0x18, 0x41, 0x00, 0xe8, 0x46, 0x43, |
353 | +0xfc, 0xe0, 0x14, 0x84, 0x19, 0x02, 0xd8, 0xe0, 0x19, 0x82, 0x0b, 0x83, 0x16, | 353 | +0xfc, 0xe0, 0x14, 0x84, 0x19, 0x02, 0xd8, 0xe0, 0x19, 0x82, 0x0b, 0x83, 0x16, |
354 | +0x00, 0x00, 0xc0, 0x01, 0x4c, 0x00, 0xc0, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, | 354 | +0x00, 0x00, 0xc0, 0x01, 0x4c, 0x00, 0xc0, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, |
355 | +0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0xe2, 0x93, 0xdd, 0xc3, | 355 | +0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0xe2, 0x93, 0xdd, 0xc3, |
356 | +0xc1, 0x46, 0x40, 0x84, 0xe0, 0x11, 0xaf, 0x13, 0x40, 0x6c, 0xec, 0x11, 0xb3, | 356 | +0xc1, 0x46, 0x40, 0x84, 0xe0, 0x11, 0xaf, 0x13, 0x40, 0x6c, 0xec, 0x11, 0xb3, |
357 | +0x13, 0x40, 0x70, 0xec, 0xc6, 0x43, 0xf0, 0xe0, 0x13, 0x40, 0xdc, 0xec, 0xc6, | 357 | +0x13, 0x40, 0x70, 0xec, 0xc6, 0x43, 0xf0, 0xe0, 0x13, 0x40, 0xdc, 0xec, 0xc6, |
358 | +0x02, 0x24, 0xe0, 0x1c, 0x80, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, 0xc8, 0x60, | 358 | +0x02, 0x24, 0xe0, 0x1c, 0x80, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, 0xc8, 0x60, |
359 | +0x7c, 0xef, 0xe8, 0x61, 0x7c, 0xef, 0x28, 0x7e, 0x80, 0xef, 0xc6, 0x40, 0x98, | 359 | +0x7c, 0xef, 0xe8, 0x61, 0x7c, 0xef, 0x28, 0x7e, 0x80, 0xef, 0xc6, 0x40, 0x98, |
360 | +0xe1, 0x11, 0x83, 0x16, 0x80, 0x46, 0x01, 0x10, 0xe1, 0x11, 0x81, 0x16, 0x80, | 360 | +0xe1, 0x11, 0x83, 0x16, 0x80, 0x46, 0x01, 0x10, 0xe1, 0x11, 0x81, 0x16, 0x80, |
361 | +0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, | 361 | +0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, |
362 | +0x80, 0x04, 0x98, 0x7b, 0x82, 0x56, 0x42, 0xb4, 0xe0, 0x88, 0x84, 0x05, 0x00, | 362 | +0x80, 0x04, 0x98, 0x7b, 0x82, 0x56, 0x42, 0xb4, 0xe0, 0x88, 0x84, 0x05, 0x00, |
363 | +0x10, 0xe0, 0x09, 0x86, 0x0b, 0xa5, 0x46, 0x02, 0x00, 0x80, 0x06, 0x05, 0x00, | 363 | +0x10, 0xe0, 0x09, 0x86, 0x0b, 0xa5, 0x46, 0x02, 0x00, 0x80, 0x06, 0x05, 0x00, |
364 | +0x80, 0x25, 0x82, 0x0b, 0xa3, 0xa5, 0x80, 0x0b, 0xa1, 0x06, 0x00, 0xf4, 0xef, | 364 | +0x80, 0x25, 0x82, 0x0b, 0xa3, 0xa5, 0x80, 0x0b, 0xa1, 0x06, 0x00, 0xf4, 0xef, |
365 | +0xd5, 0x84, 0x11, 0x85, 0x21, 0x91, 0x0b, 0x8e, 0x88, 0x74, 0x10, 0xef, 0x0b, | 365 | +0xd5, 0x84, 0x11, 0x85, 0x21, 0x91, 0x0b, 0x8e, 0x88, 0x74, 0x10, 0xef, 0x0b, |
366 | +0xa1, 0xf5, 0x82, 0x0a, 0x9e, 0x1a, 0x9c, 0x24, 0x98, 0x07, 0xe0, 0x0f, 0xa2, | 366 | +0xa1, 0xf5, 0x82, 0x0a, 0x9e, 0x1a, 0x9c, 0x24, 0x98, 0x07, 0xe0, 0x0f, 0xa2, |
367 | +0x0e, 0xca, 0x0a, 0xde, 0x1a, 0xdc, 0x24, 0x98, 0x03, 0xb0, 0x07, 0xe0, 0x0f, | 367 | +0x0e, 0xca, 0x0a, 0xde, 0x1a, 0xdc, 0x24, 0x98, 0x03, 0xb0, 0x07, 0xe0, 0x0f, |
368 | +0xa2, 0x0e, 0xc8, 0x01, 0x81, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, | 368 | +0xa2, 0x0e, 0xc8, 0x01, 0x81, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, |
369 | +0x0c, 0x04, 0x7c, 0xfa, 0x46, 0x42, 0x9c, 0xe0, 0x0b, 0x02, 0x04, 0xe3, 0xf0, | 369 | +0x0c, 0x04, 0x7c, 0xfa, 0x46, 0x42, 0x9c, 0xe0, 0x0b, 0x02, 0x04, 0xe3, 0xf0, |
370 | +0x1e, 0x30, 0xec, 0x0b, 0xa3, 0x35, 0x96, 0x8e, 0x01, 0x01, 0x60, 0x10, 0xc0, | 370 | +0x1e, 0x30, 0xec, 0x0b, 0xa3, 0x35, 0x96, 0x8e, 0x01, 0x01, 0x60, 0x10, 0xc0, |
371 | +0x0e, 0xfc, 0xc6, 0x05, 0xd0, 0xe1, 0x0b, 0x82, 0x31, 0x81, 0x10, 0x16, 0x00, | 371 | +0x0e, 0xfc, 0xc6, 0x05, 0xd0, 0xe1, 0x0b, 0x82, 0x31, 0x81, 0x10, 0x16, 0x00, |
372 | +0xe5, 0x20, 0x10, 0x20, 0xe7, 0x0e, 0xbe, 0xb5, 0x85, 0x94, 0xfc, 0xa4, 0xbe, | 372 | +0xe5, 0x20, 0x10, 0x20, 0xe7, 0x0e, 0xbe, 0xb5, 0x85, 0x94, 0xfc, 0xa4, 0xbe, |
373 | +0x82, 0x4c, 0x9c, 0xf0, 0x05, 0x0c, 0x40, 0xe0, 0x11, 0x89, 0x93, 0x8e, 0xa3, | 373 | +0x82, 0x4c, 0x9c, 0xf0, 0x05, 0x0c, 0x40, 0xe0, 0x11, 0x89, 0x93, 0x8e, 0xa3, |
374 | +0x8e, 0x58, 0x44, 0x00, 0xe8, 0x15, 0x0c, 0xc0, 0xf8, 0x04, 0x0c, 0x80, 0xfb, | 374 | +0x8e, 0x58, 0x44, 0x00, 0xe8, 0x15, 0x0c, 0xc0, 0xf8, 0x04, 0x0c, 0x80, 0xfb, |
375 | +0x0c, 0xed, 0x0b, 0x82, 0x1b, 0x8c, 0x48, 0x44, 0x00, 0xe8, 0x15, 0x10, 0x1c, | 375 | +0x0c, 0xed, 0x0b, 0x82, 0x1b, 0x8c, 0x48, 0x44, 0x00, 0xe8, 0x15, 0x10, 0x1c, |
376 | +0xfc, 0x0e, 0xa8, 0x0b, 0x82, 0x1b, 0x8c, 0xd8, 0x43, 0x00, 0xe8, 0x71, 0x88, | 376 | +0xfc, 0x0e, 0xa8, 0x0b, 0x82, 0x1b, 0x8c, 0xd8, 0x43, 0x00, 0xe8, 0x71, 0x88, |
377 | +0x0e, 0xa4, 0x0a, 0x0e, 0x40, 0xe0, 0x35, 0xf8, 0x04, 0xbe, 0x14, 0xbc, 0x81, | 377 | +0x0e, 0xa4, 0x0a, 0x0e, 0x40, 0xe0, 0x35, 0xf8, 0x04, 0xbe, 0x14, 0xbc, 0x81, |
378 | +0xa0, 0x03, 0x8e, 0x0e, 0xbe, 0x04, 0xfc, 0x11, 0x82, 0x3b, 0x82, 0x03, 0x8e, | 378 | +0xa0, 0x03, 0x8e, 0x0e, 0xbe, 0x04, 0xfc, 0x11, 0x82, 0x3b, 0x82, 0x03, 0x8e, |
379 | +0x0e, 0xfc, 0x3b, 0xa9, 0x06, 0x0e, 0x00, 0xc0, 0x35, 0x5e, 0x00, 0xc0, 0xd5, | 379 | +0x0e, 0xfc, 0x3b, 0xa9, 0x06, 0x0e, 0x00, 0xc0, 0x35, 0x5e, 0x00, 0xc0, 0xd5, |
380 | +0xfa, 0xc6, 0x01, 0xd0, 0xe1, 0x7b, 0x80, 0x04, 0x9e, 0x11, 0x91, 0x98, 0x41, | 380 | +0xfa, 0xc6, 0x01, 0xd0, 0xe1, 0x7b, 0x80, 0x04, 0x9e, 0x11, 0x91, 0x98, 0x41, |
381 | +0x00, 0xe8, 0x24, 0x9c, 0x46, 0x42, 0x9c, 0xe0, 0x6b, 0x82, 0x03, 0x4c, 0xc4, | 381 | +0x00, 0xe8, 0x24, 0x9c, 0x46, 0x42, 0x9c, 0xe0, 0x6b, 0x82, 0x03, 0x4c, 0xc4, |
382 | +0xe0, 0x11, 0x91, 0x0b, 0x84, 0xf8, 0x40, 0x00, 0xe8, 0x19, 0x0e, 0x20, 0xe5, | 382 | +0xe0, 0x11, 0x91, 0x0b, 0x84, 0xf8, 0x40, 0x00, 0xe8, 0x19, 0x0e, 0x20, 0xe5, |
383 | +0x03, 0x4c, 0xc0, 0xe0, 0x0b, 0x82, 0x08, 0x72, 0xfc, 0xef, 0x01, 0x4c, 0x24, | 383 | +0x03, 0x4c, 0xc0, 0xe0, 0x0b, 0x82, 0x08, 0x72, 0xfc, 0xef, 0x01, 0x4c, 0x24, |
384 | +0xf9, 0xf1, 0x98, 0x0c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, | 384 | +0xf9, 0xf1, 0x98, 0x0c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x4c, 0x00, 0x00, 0xfa, |
385 | +0x48, 0x65, 0x2c, 0xef, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, | 385 | +0x48, 0x65, 0x2c, 0xef, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, |
386 | +0x04, 0x00, 0xfa, 0x6b, 0x82, 0x78, 0x6e, 0xfc, 0xee, 0x46, 0x42, 0xec, 0xe0, | 386 | +0x04, 0x00, 0xfa, 0x6b, 0x82, 0x78, 0x6e, 0xfc, 0xee, 0x46, 0x42, 0xec, 0xe0, |
387 | +0x24, 0x84, 0x24, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x83, 0xf5, 0x82, 0x24, | 387 | +0x24, 0x84, 0x24, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x83, 0xf5, 0x82, 0x24, |
388 | +0x02, 0xa0, 0xe1, 0x14, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x85, 0x15, 0x82, | 388 | +0x02, 0xa0, 0xe1, 0x14, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x85, 0x15, 0x82, |
389 | +0x27, 0xe1, 0x24, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x89, 0x86, 0x02, 0x00, | 389 | +0x27, 0xe1, 0x24, 0x02, 0x80, 0xfa, 0x1d, 0xcc, 0x11, 0x89, 0x86, 0x02, 0x00, |
390 | +0x80, 0x0c, 0x0c, 0x00, 0xf2, 0x18, 0x17, 0xfc, 0xfe, 0xc3, 0xc1, 0x0c, 0x04, | 390 | +0x80, 0x0c, 0x0c, 0x00, 0xf2, 0x18, 0x17, 0xfc, 0xfe, 0xc3, 0xc1, 0x0c, 0x04, |
391 | +0x00, 0xfa, 0x06, 0x41, 0x8c, 0xe0, 0x1b, 0x00, 0xec, 0xe4, 0x1b, 0xa3, 0x75, | 391 | +0x00, 0xfa, 0x06, 0x41, 0x8c, 0xe0, 0x1b, 0x00, 0xec, 0xe4, 0x1b, 0xa3, 0x75, |
392 | +0x84, 0x11, 0x81, 0x8e, 0x05, 0x01, 0x60, 0x10, 0xc0, 0x00, 0x06, 0xc0, 0xe5, | 392 | +0x84, 0x11, 0x81, 0x8e, 0x05, 0x01, 0x60, 0x10, 0xc0, 0x00, 0x06, 0xc0, 0xe5, |
393 | +0x95, 0x81, 0x44, 0x88, 0x1d, 0xee, 0x75, 0x80, 0x4e, 0xc1, 0x25, 0x81, 0x4e, | 393 | +0x95, 0x81, 0x44, 0x88, 0x1d, 0xee, 0x75, 0x80, 0x4e, 0xc1, 0x25, 0x81, 0x4e, |
394 | +0xcd, 0x21, 0x88, 0x11, 0x82, 0x0a, 0x02, 0x40, 0xe0, 0xd5, 0xfc, 0x56, 0x00, | 394 | +0xcd, 0x21, 0x88, 0x11, 0x82, 0x0a, 0x02, 0x40, 0xe0, 0xd5, 0xfc, 0x56, 0x00, |
395 | +0x00, 0xe1, 0x18, 0x80, 0x1b, 0xa1, 0xc5, 0x84, 0x08, 0x82, 0x4a, 0x00, 0xfc, | 395 | +0x00, 0xe1, 0x18, 0x80, 0x1b, 0xa1, 0xc5, 0x84, 0x08, 0x82, 0x4a, 0x00, 0xfc, |
396 | +0xfb, 0x45, 0x84, 0x86, 0x4d, 0x84, 0xe1, 0x04, 0x98, 0x05, 0x00, 0x10, 0xe0, | 396 | +0xfb, 0x45, 0x84, 0x86, 0x4d, 0x84, 0xe1, 0x04, 0x98, 0x05, 0x00, 0x10, 0xe0, |
397 | +0x4a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0x11, 0x81, 0x0b, 0x8c, 0x58, 0x76, 0x28, | 397 | +0x4a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0x11, 0x81, 0x0b, 0x8c, 0x58, 0x76, 0x28, |
398 | +0xef, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x88, 0x35, 0x28, 0xff, 0x0c, 0x0c, | 398 | +0xef, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x88, 0x35, 0x28, 0xff, 0x0c, 0x0c, |
399 | +0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x46, 0x41, 0xfc, 0xe0, 0x04, 0x80, 0x09, | 399 | +0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x46, 0x41, 0xfc, 0xe0, 0x04, 0x80, 0x09, |
400 | +0x00, 0x80, 0xe0, 0x09, 0x9e, 0x0b, 0xa3, 0x75, 0x82, 0x46, 0x41, 0x80, 0xe1, | 400 | +0x00, 0x80, 0xe0, 0x09, 0x9e, 0x0b, 0xa3, 0x75, 0x82, 0x46, 0x41, 0x80, 0xe1, |
401 | +0x04, 0x80, 0xc6, 0x42, 0x8c, 0xe0, 0x04, 0xc2, 0x00, 0x40, 0x00, 0xf2, 0x07, | 401 | +0x04, 0x80, 0xc6, 0x42, 0x8c, 0xe0, 0x04, 0xc2, 0x00, 0x40, 0x00, 0xf2, 0x07, |
402 | +0xcf, 0x06, 0x84, 0x06, 0x40, 0x84, 0xe0, 0x15, 0x00, 0x28, 0xe5, 0x1c, 0xc2, | 402 | +0xcf, 0x06, 0x84, 0x06, 0x40, 0x84, 0xe0, 0x15, 0x00, 0x28, 0xe5, 0x1c, 0xc2, |
403 | +0x93, 0xdd, 0x0b, 0xa1, 0xc6, 0x00, 0xa0, 0xe1, 0x15, 0x00, 0x04, 0xf8, 0x05, | 403 | +0x93, 0xdd, 0x0b, 0xa1, 0xc6, 0x00, 0xa0, 0xe1, 0x15, 0x00, 0x04, 0xf8, 0x05, |
404 | +0x84, 0x21, 0x8b, 0x2c, 0x84, 0x14, 0x80, 0x2c, 0x84, 0x14, 0x82, 0x2c, 0x84, | 404 | +0x84, 0x21, 0x8b, 0x2c, 0x84, 0x14, 0x80, 0x2c, 0x84, 0x14, 0x82, 0x2c, 0x84, |
405 | +0x15, 0x00, 0x10, 0xe0, 0x21, 0xa1, 0x21, 0x42, 0x10, 0xe0, 0x05, 0x00, 0x14, | 405 | +0x15, 0x00, 0x10, 0xe0, 0x21, 0xa1, 0x21, 0x42, 0x10, 0xe0, 0x05, 0x00, 0x14, |
406 | +0xe0, 0x01, 0x88, 0x75, 0x83, 0x21, 0x85, 0x2c, 0x84, 0x14, 0x80, 0x06, 0x46, | 406 | +0xe0, 0x01, 0x88, 0x75, 0x83, 0x21, 0x85, 0x2c, 0x84, 0x14, 0x80, 0x06, 0x46, |
407 | +0x00, 0xe0, 0x2c, 0x84, 0x14, 0x82, 0x2c, 0x84, 0x14, 0xc0, 0x21, 0xa1, 0x21, | 407 | +0x00, 0xe0, 0x2c, 0x84, 0x14, 0x82, 0x2c, 0x84, 0x14, 0xc0, 0x21, 0xa1, 0x21, |
408 | +0x42, 0x20, 0xe0, 0x14, 0xc2, 0x31, 0x42, 0x20, 0xe0, 0x15, 0x00, 0x10, 0xe0, | 408 | +0x42, 0x20, 0xe0, 0x14, 0xc2, 0x31, 0x42, 0x20, 0xe0, 0x15, 0x00, 0x10, 0xe0, |
409 | +0x21, 0x42, 0x20, 0xe0, 0x05, 0x00, 0x14, 0xe0, 0x01, 0x90, 0x06, 0x42, 0x00, | 409 | +0x21, 0x42, 0x20, 0xe0, 0x05, 0x00, 0x14, 0xe0, 0x01, 0x90, 0x06, 0x42, 0x00, |
410 | +0xe0, 0x16, 0x80, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x7c, 0xfa, 0x4a, 0x40, | 410 | +0xe0, 0x16, 0x80, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x7c, 0xfa, 0x4a, 0x40, |
411 | +0x80, 0xe0, 0xf0, 0x1e, 0x30, 0xec, 0xe5, 0x82, 0xa6, 0x40, 0x00, 0xe1, 0x1a, | 411 | +0x80, 0xe0, 0xf0, 0x1e, 0x30, 0xec, 0xe5, 0x82, 0xa6, 0x40, 0x00, 0xe1, 0x1a, |
412 | +0x80, 0x2a, 0xc0, 0x3a, 0xc2, 0x13, 0x40, 0x10, 0xe0, 0x1a, 0x82, 0x23, 0x40, | 412 | +0x80, 0x2a, 0xc0, 0x3a, 0xc2, 0x13, 0x40, 0x10, 0xe0, 0x1a, 0x82, 0x23, 0x40, |
413 | +0x18, 0xe0, 0x33, 0x40, 0x1c, 0xe0, 0x13, 0x40, 0x14, 0xe0, 0xf8, 0x61, 0x68, | 413 | +0x18, 0xe0, 0x33, 0x40, 0x1c, 0xe0, 0x13, 0x40, 0x14, 0xe0, 0xf8, 0x61, 0x68, |
414 | +0xef, 0xc6, 0x13, 0x00, 0xe1, 0x15, 0x12, 0x28, 0xf8, 0x0b, 0x02, 0x2c, 0xe0, | 414 | +0xef, 0xc6, 0x13, 0x00, 0xe1, 0x15, 0x12, 0x28, 0xf8, 0x0b, 0x02, 0x2c, 0xe0, |
415 | +0x1b, 0x02, 0x24, 0xe0, 0x8a, 0x00, 0xa5, 0x64, 0x03, 0xc0, 0x35, 0x82, 0x0a, | 415 | +0x1b, 0x02, 0x24, 0xe0, 0x8a, 0x00, 0xa5, 0x64, 0x03, 0xc0, 0x35, 0x82, 0x0a, |
416 | +0x4e, 0x9c, 0xe1, 0x1a, 0x03, 0x11, 0x6f, 0x02, 0xc0, 0xe8, 0x13, 0x01, 0x20, | 416 | +0x4e, 0x9c, 0xe1, 0x1a, 0x03, 0x11, 0x6f, 0x02, 0xc0, 0xe8, 0x13, 0x01, 0x20, |
417 | +0x00, 0xc0, 0x1f, 0xa0, 0x5a, 0x42, 0x80, 0xe0, 0x0a, 0x4e, 0x9c, 0xe1, 0x68, | 417 | +0x00, 0xc0, 0x1f, 0xa0, 0x5a, 0x42, 0x80, 0xe0, 0x0a, 0x4e, 0x9c, 0xe1, 0x68, |
418 | +0x13, 0x00, 0xa0, 0x09, 0x12, 0x78, 0xf8, 0xa1, 0x81, 0xf0, 0x02, 0x10, 0xe4, | 418 | +0x13, 0x00, 0xa0, 0x09, 0x12, 0x78, 0xf8, 0xa1, 0x81, 0xf0, 0x02, 0x10, 0xe4, |
419 | +0x07, 0xc4, 0x0c, 0xfc, 0xf0, 0x00, 0x20, 0xe4, 0xa6, 0x91, 0xa8, 0x53, 0x74, | 419 | +0x07, 0xc4, 0x0c, 0xfc, 0xf0, 0x00, 0x20, 0xe4, 0xa6, 0x91, 0xa8, 0x53, 0x74, |
420 | +0xef, 0x05, 0x12, 0x30, 0xf8, 0x25, 0x12, 0x28, 0xf8, 0x61, 0x87, 0x09, 0x00, | 420 | +0xef, 0x05, 0x12, 0x30, 0xf8, 0x25, 0x12, 0x28, 0xf8, 0x61, 0x87, 0x09, 0x00, |
421 | +0x48, 0xe0, 0x81, 0x85, 0x09, 0x86, 0x0b, 0xa7, 0x26, 0x0c, 0x00, 0xc0, 0x0b, | 421 | +0x48, 0xe0, 0x81, 0x85, 0x09, 0x86, 0x0b, 0xa7, 0x26, 0x0c, 0x00, 0xc0, 0x0b, |
422 | +0xa1, 0x0b, 0x04, 0x28, 0xe0, 0x16, 0x0c, 0x00, 0x80, 0x03, 0x52, 0x04, 0xf8, | 422 | +0xa1, 0x0b, 0x04, 0x28, 0xe0, 0x16, 0x0c, 0x00, 0x80, 0x03, 0x52, 0x04, 0xf8, |
423 | +0x0b, 0x04, 0x20, 0xe0, 0x0c, 0xa6, 0x1b, 0x04, 0x2c, 0xe0, 0x3b, 0x04, 0x28, | 423 | +0x0b, 0x04, 0x20, 0xe0, 0x0c, 0xa6, 0x1b, 0x04, 0x2c, 0xe0, 0x3b, 0x04, 0x28, |
424 | +0xe0, 0x4b, 0x04, 0x20, 0xe0, 0x13, 0x86, 0x3b, 0x04, 0x24, 0xe0, 0x10, 0x0a, | 424 | +0xe0, 0x4b, 0x04, 0x20, 0xe0, 0x13, 0x86, 0x3b, 0x04, 0x24, 0xe0, 0x10, 0x0a, |
425 | +0x04, 0xec, 0x1a, 0xfc, 0x33, 0x88, 0x30, 0x06, 0x04, 0xec, 0x12, 0x4e, 0x94, | 425 | +0x04, 0xec, 0x1a, 0xfc, 0x33, 0x88, 0x30, 0x06, 0x04, 0xec, 0x12, 0x4e, 0x94, |
426 | +0xf0, 0x32, 0x48, 0x84, 0xf0, 0x4c, 0xe4, 0x7c, 0xa4, 0xcb, 0x04, 0x28, 0xe0, | 426 | +0xf0, 0x32, 0x48, 0x84, 0xf0, 0x4c, 0xe4, 0x7c, 0xa4, 0xcb, 0x04, 0x28, 0xe0, |
427 | +0x14, 0x08, 0x84, 0xe1, 0xcd, 0xc9, 0xc2, 0x58, 0x90, 0x91, 0x42, 0x4e, 0x94, | 427 | +0x14, 0x08, 0x84, 0xe1, 0xcd, 0xc9, 0xc2, 0x58, 0x90, 0x91, 0x42, 0x4e, 0x94, |
428 | +0x90, 0xc3, 0x52, 0x04, 0x98, 0x73, 0x52, 0x00, 0x80, 0x5b, 0x04, 0x20, 0xe0, | 428 | +0x90, 0xc3, 0x52, 0x04, 0x98, 0x73, 0x52, 0x00, 0x80, 0x5b, 0x04, 0x20, 0xe0, |
429 | +0x5d, 0xc9, 0x52, 0x40, 0x90, 0x91, 0x42, 0x48, 0x8c, 0x90, 0x03, 0x52, 0x04, | 429 | +0x5d, 0xc9, 0x52, 0x40, 0x90, 0x91, 0x42, 0x48, 0x8c, 0x90, 0x03, 0x52, 0x04, |
430 | +0x80, 0x43, 0x52, 0x08, 0x80, 0x3b, 0x04, 0x2c, 0xe0, 0x49, 0x04, 0xb8, 0xe0, | 430 | +0x80, 0x43, 0x52, 0x08, 0x80, 0x3b, 0x04, 0x2c, 0xe0, 0x49, 0x04, 0xb8, 0xe0, |
431 | +0x33, 0x52, 0x1c, 0xf8, 0x2b, 0x04, 0x24, 0xe0, 0x4b, 0xab, 0x23, 0x52, 0x18, | 431 | +0x33, 0x52, 0x1c, 0xf8, 0x2b, 0x04, 0x24, 0xe0, 0x4b, 0xab, 0x23, 0x52, 0x18, |
432 | +0xf8, 0x65, 0x8a, 0x4b, 0xa9, 0xe5, 0x90, 0x4b, 0xa7, 0x22, 0x44, 0x84, 0xd0, | 432 | +0xf8, 0x65, 0x8a, 0x4b, 0xa9, 0xe5, 0x90, 0x4b, 0xa7, 0x22, 0x44, 0x84, 0xd0, |
433 | +0x32, 0x46, 0x84, 0xd0, 0x33, 0x52, 0x1c, 0xd8, 0x23, 0x52, 0x18, 0xd8, 0x95, | 433 | +0x32, 0x46, 0x84, 0xd0, 0x33, 0x52, 0x1c, 0xd8, 0x23, 0x52, 0x18, 0xd8, 0x95, |
434 | +0x96, 0x20, 0x44, 0xf9, 0x73, 0xff, 0xc0, 0x27, 0xc3, 0x23, 0x82, 0x23, 0x52, | 434 | +0x96, 0x20, 0x44, 0xf9, 0x73, 0xff, 0xc0, 0x27, 0xc3, 0x23, 0x82, 0x23, 0x52, |
435 | +0x18, 0xf8, 0x24, 0x02, 0x80, 0xfb, 0x04, 0x00, 0x80, 0xfb, 0x2b, 0x8c, 0x58, | 435 | +0x18, 0xf8, 0x24, 0x02, 0x80, 0xfb, 0x04, 0x00, 0x80, 0xfb, 0x2b, 0x8c, 0x58, |
436 | +0x52, 0x74, 0xef, 0x1b, 0x12, 0x1c, 0xf8, 0x2a, 0xfc, 0x0c, 0xe4, 0x17, 0xc3, | 436 | +0x52, 0x74, 0xef, 0x1b, 0x12, 0x1c, 0xf8, 0x2a, 0xfc, 0x0c, 0xe4, 0x17, 0xc3, |
437 | +0x13, 0x84, 0x13, 0x52, 0x1c, 0xf8, 0x0b, 0x12, 0x04, 0xf8, 0x14, 0x02, 0x80, | 437 | +0x13, 0x84, 0x13, 0x52, 0x1c, 0xf8, 0x0b, 0x12, 0x04, 0xf8, 0x14, 0x02, 0x80, |
438 | +0xfb, 0x2b, 0x8c, 0x68, 0x51, 0x74, 0xef, 0xc5, 0x87, 0x20, 0x44, 0xe1, 0x73, | 438 | +0xfb, 0x2b, 0x8c, 0x68, 0x51, 0x74, 0xef, 0xc5, 0x87, 0x20, 0x44, 0xe1, 0x73, |
439 | +0xff, 0xc0, 0x27, 0xc7, 0x23, 0x82, 0x23, 0x52, 0x18, 0xf8, 0x24, 0x02, 0x80, | 439 | +0xff, 0xc0, 0x27, 0xc7, 0x23, 0x82, 0x23, 0x52, 0x18, 0xf8, 0x24, 0x02, 0x80, |
440 | +0xfb, 0x04, 0x00, 0x80, 0xfb, 0x2b, 0x8c, 0x78, 0x57, 0x74, 0xef, 0x1b, 0x12, | 440 | +0xfb, 0x04, 0x00, 0x80, 0xfb, 0x2b, 0x8c, 0x78, 0x57, 0x74, 0xef, 0x1b, 0x12, |
441 | +0x1c, 0xf8, 0x2a, 0xfc, 0x0c, 0xe4, 0x17, 0xc7, 0x13, 0x84, 0x13, 0x52, 0x1c, | 441 | +0x1c, 0xf8, 0x2a, 0xfc, 0x0c, 0xe4, 0x17, 0xc7, 0x13, 0x84, 0x13, 0x52, 0x1c, |
442 | +0xf8, 0x0b, 0x12, 0x04, 0xf8, 0x14, 0x02, 0x80, 0xfb, 0x2b, 0x8c, 0x88, 0x56, | 442 | +0xf8, 0x0b, 0x12, 0x04, 0xf8, 0x14, 0x02, 0x80, 0xfb, 0x2b, 0x8c, 0x88, 0x56, |
443 | +0x74, 0xef, 0xe5, 0x83, 0x20, 0x44, 0xf1, 0x73, 0xff, 0xc0, 0x27, 0xc5, 0x23, | 443 | +0x74, 0xef, 0xe5, 0x83, 0x20, 0x44, 0xf1, 0x73, 0xff, 0xc0, 0x27, 0xc5, 0x23, |
444 | +0x82, 0x23, 0x52, 0x18, 0xf8, 0x24, 0x02, 0x80, 0xfb, 0x04, 0x00, 0x80, 0xfb, | 444 | +0x82, 0x23, 0x52, 0x18, 0xf8, 0x24, 0x02, 0x80, 0xfb, 0x04, 0x00, 0x80, 0xfb, |
445 | +0x2b, 0x8c, 0x18, 0x52, 0x74, 0xef, 0x1b, 0x12, 0x1c, 0xf8, 0x2a, 0xfc, 0x0c, | 445 | +0x2b, 0x8c, 0x18, 0x52, 0x74, 0xef, 0x1b, 0x12, 0x1c, 0xf8, 0x2a, 0xfc, 0x0c, |
446 | +0xe4, 0x17, 0xc5, 0x13, 0x84, 0x13, 0x52, 0x1c, 0xf8, 0x0b, 0x12, 0x04, 0xf8, | 446 | +0xe4, 0x17, 0xc5, 0x13, 0x84, 0x13, 0x52, 0x1c, 0xf8, 0x0b, 0x12, 0x04, 0xf8, |
447 | +0x14, 0x02, 0x80, 0xfb, 0x2b, 0x8c, 0x28, 0x51, 0x74, 0xef, 0x7b, 0x80, 0x7c, | 447 | +0x14, 0x02, 0x80, 0xfb, 0x2b, 0x8c, 0x28, 0x51, 0x74, 0xef, 0x7b, 0x80, 0x7c, |
448 | +0xa4, 0x08, 0x91, 0xa3, 0x52, 0x1c, 0xe0, 0xa3, 0x52, 0x24, 0xe0, 0x0b, 0xa1, | 448 | +0xa4, 0x08, 0x91, 0xa3, 0x52, 0x1c, 0xe0, 0xa3, 0x52, 0x24, 0xe0, 0x0b, 0xa1, |
449 | +0x83, 0x52, 0x1c, 0x80, 0x83, 0x52, 0x24, 0x80, 0x89, 0x12, 0x78, 0xf8, 0xf6, | 449 | +0x83, 0x52, 0x1c, 0x80, 0x83, 0x52, 0x24, 0x80, 0x89, 0x12, 0x78, 0xf8, 0xf6, |
450 | +0x57, 0xfc, 0xef, 0x6b, 0x12, 0x1c, 0xf8, 0xab, 0x12, 0x18, 0xf8, 0xd6, 0x57, | 450 | +0x57, 0xfc, 0xef, 0x6b, 0x12, 0x1c, 0xf8, 0xab, 0x12, 0x18, 0xf8, 0xd6, 0x57, |
451 | +0xfc, 0x8f, 0x8b, 0xa3, 0xa0, 0x40, 0x00, 0x9c, 0xa5, 0x86, 0x64, 0x00, 0x80, | 451 | +0xfc, 0x8f, 0x8b, 0xa3, 0xa0, 0x40, 0x00, 0x9c, 0xa5, 0x86, 0x64, 0x00, 0x80, |
452 | +0xfb, 0x1b, 0x90, 0xf8, 0x7d, 0xf8, 0xee, 0x6b, 0x80, 0xa4, 0x00, 0x80, 0xfb, | 452 | +0xfb, 0x1b, 0x90, 0xf8, 0x7d, 0xf8, 0xee, 0x6b, 0x80, 0xa4, 0x00, 0x80, 0xfb, |
453 | +0x1b, 0x90, 0x98, 0x7d, 0xf8, 0xee, 0x15, 0x12, 0x28, 0xf8, 0x19, 0x02, 0xb8, | 453 | +0x1b, 0x90, 0x98, 0x7d, 0xf8, 0xee, 0x15, 0x12, 0x28, 0xf8, 0x19, 0x02, 0xb8, |
454 | +0xe0, 0x1b, 0xad, 0x95, 0x82, 0x1a, 0xa6, 0xa0, 0x44, 0xf9, 0x73, 0xff, 0xc0, | 454 | +0xe0, 0x1b, 0xad, 0x95, 0x82, 0x1a, 0xa6, 0xa0, 0x44, 0xf9, 0x73, 0xff, 0xc0, |
455 | +0x27, 0xc3, 0x13, 0x94, 0x10, 0x02, 0x08, 0xec, 0x1c, 0xe4, 0x23, 0x52, 0x18, | 455 | +0x27, 0xc3, 0x13, 0x94, 0x10, 0x02, 0x08, 0xec, 0x1c, 0xe4, 0x23, 0x52, 0x18, |
456 | +0xf8, 0x1b, 0x12, 0x04, 0xf8, 0x03, 0x96, 0x03, 0x52, 0x28, 0xe0, 0x1c, 0xe6, | 456 | +0xf8, 0x1b, 0x12, 0x04, 0xf8, 0x03, 0x96, 0x03, 0x52, 0x28, 0xe0, 0x1c, 0xe6, |
457 | +0x0a, 0xa6, 0x1a, 0xe4, 0x63, 0x96, 0x63, 0x52, 0x20, 0xe0, 0x73, 0x52, 0x10, | 457 | +0x0a, 0xa6, 0x1a, 0xe4, 0x63, 0x96, 0x63, 0x52, 0x20, 0xe0, 0x73, 0x52, 0x10, |
458 | +0xe0, 0x03, 0x52, 0x14, 0xe0, 0x13, 0x52, 0x18, 0xe0, 0x98, 0x52, 0x74, 0xef, | 458 | +0xe0, 0x03, 0x52, 0x14, 0xe0, 0x13, 0x52, 0x18, 0xe0, 0x98, 0x52, 0x74, 0xef, |
459 | +0x09, 0x12, 0x8c, 0xe0, 0x0b, 0xa1, 0x01, 0x81, 0x01, 0x52, 0x90, 0xe0, 0x65, | 459 | +0x09, 0x12, 0x8c, 0xe0, 0x0b, 0xa1, 0x01, 0x81, 0x01, 0x52, 0x90, 0xe0, 0x65, |
460 | +0x82, 0x05, 0x12, 0x30, 0xf8, 0x09, 0x00, 0xa8, 0xe0, 0x0a, 0x00, 0x0c, 0xf8, | 460 | +0x82, 0x05, 0x12, 0x30, 0xf8, 0x09, 0x00, 0xa8, 0xe0, 0x0a, 0x00, 0x0c, 0xf8, |
461 | +0x16, 0x00, 0x00, 0xc0, 0x01, 0x52, 0x90, 0xc0, 0x46, 0x41, 0x84, 0xe0, 0x0a, | 461 | +0x16, 0x00, 0x00, 0xc0, 0x01, 0x52, 0x90, 0xc0, 0x46, 0x41, 0x84, 0xe0, 0x0a, |
462 | +0x80, 0x0a, 0x4e, 0x9c, 0xe9, 0x1a, 0x00, 0x08, 0xe0, 0x38, 0x01, 0x01, 0x20, | 462 | +0x80, 0x0a, 0x4e, 0x9c, 0xe9, 0x1a, 0x00, 0x08, 0xe0, 0x38, 0x01, 0x01, 0x20, |
463 | +0x00, 0xc0, 0x0b, 0x12, 0x1c, 0xe0, 0x1b, 0x12, 0x24, 0xe0, 0x2b, 0x12, 0x28, | 463 | +0x00, 0xc0, 0x0b, 0x12, 0x1c, 0xe0, 0x1b, 0x12, 0x24, 0xe0, 0x2b, 0x12, 0x28, |
464 | +0xe0, 0x03, 0x52, 0x2c, 0xe0, 0x0b, 0x12, 0x20, 0xe0, 0x13, 0x52, 0x34, 0xe0, | 464 | +0xe0, 0x03, 0x52, 0x2c, 0xe0, 0x0b, 0x12, 0x20, 0xe0, 0x13, 0x52, 0x34, 0xe0, |
465 | +0x23, 0x52, 0x38, 0xe0, 0x03, 0x52, 0x30, 0xe0, 0x0c, 0x00, 0x00, 0xe2, 0xf1, | 465 | +0x23, 0x52, 0x38, 0xe0, 0x03, 0x52, 0x30, 0xe0, 0x0c, 0x00, 0x00, 0xe2, 0xf1, |
466 | +0x98, 0x0c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x13, 0xa9, 0x00, 0x00, 0xa8, 0xc1, | 466 | +0x98, 0x0c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x13, 0xa9, 0x00, 0x00, 0xa8, 0xc1, |
467 | +0x40, 0x00, 0x68, 0x04, 0xa0, 0xe0, 0x40, 0x6c, 0x40, 0x00, 0xe8, 0x34, 0xc8, | 467 | +0x40, 0x00, 0x68, 0x04, 0xa0, 0xe0, 0x40, 0x6c, 0x40, 0x00, 0xe8, 0x34, 0xc8, |
468 | +0xe0, 0xfc, 0x91, 0x40, 0x00, 0x68, 0x1f, 0xb8, 0xe0, 0x30, 0x16, 0x41, 0x00, | 468 | +0xe0, 0xfc, 0x91, 0x40, 0x00, 0x68, 0x1f, 0xb8, 0xe0, 0x30, 0x16, 0x41, 0x00, |
469 | +0x28, 0x39, 0x74, 0xe0, 0xb0, 0x7e, 0x40, 0x00, 0xe8, 0x38, 0xc0, 0xe0, 0x30, | 469 | +0x28, 0x39, 0x74, 0xe0, 0xb0, 0x7e, 0x40, 0x00, 0xe8, 0x38, 0xc0, 0xe0, 0x30, |
470 | +0x04, 0x41, 0x00, 0x48, 0x1b, 0x80, 0xe0, 0x30, 0x2e, 0x40, 0x00, 0x88, 0x0c, | 470 | +0x04, 0x41, 0x00, 0x48, 0x1b, 0x80, 0xe0, 0x30, 0x2e, 0x40, 0x00, 0x88, 0x0c, |
471 | +0xec, 0xe0, 0x10, 0x9f, 0x40, 0x00, 0x88, 0x08, 0xb4, 0xe0, 0x10, 0x01, 0x41, | 471 | +0xec, 0xe0, 0x10, 0x9f, 0x40, 0x00, 0x88, 0x08, 0xb4, 0xe0, 0x10, 0x01, 0x41, |
472 | +0x00, 0x68, 0x01, 0x84, 0xe0, 0x54, 0xd6, 0x40, 0x00, 0xc8, 0x1a, 0x98, 0xe0, | 472 | +0x00, 0x68, 0x01, 0x84, 0xe0, 0x54, 0xd6, 0x40, 0x00, 0xc8, 0x1a, 0x98, 0xe0, |
473 | +0xd0, 0xc8, 0x40, 0x00, 0x68, 0x08, 0xa0, 0xe0, 0x80, 0xdb, 0x40, 0x00, 0xe8, | 473 | +0xd0, 0xc8, 0x40, 0x00, 0x68, 0x08, 0xa0, 0xe0, 0x80, 0xdb, 0x40, 0x00, 0xe8, |
474 | +0x35, 0x94, 0xe0, 0x74, 0xff, 0x40, 0x00, 0xa8, 0x11, 0x80, 0xe0, 0xf8, 0x89, | 474 | +0x35, 0x94, 0xe0, 0x74, 0xff, 0x40, 0x00, 0xa8, 0x11, 0x80, 0xe0, 0xf8, 0x89, |
475 | +0x40, 0x00, 0x88, 0x16, 0xbc, 0xe0, 0x00, 0x90, 0x40, 0x00, 0x08, 0x35, 0xb8, | 475 | +0x40, 0x00, 0x88, 0x16, 0xbc, 0xe0, 0x00, 0x90, 0x40, 0x00, 0x08, 0x35, 0xb8, |
476 | +0xe0, 0x7c, 0x73, 0x40, 0x00, 0x88, 0x1b, 0xc8, 0xe0, 0xf4, 0xff, 0x40, 0x00, | 476 | +0xe0, 0x7c, 0x73, 0x40, 0x00, 0x88, 0x1b, 0xc8, 0xe0, 0xf4, 0xff, 0x40, 0x00, |
477 | +0x68, 0x39, 0x80, 0xe0, 0xa4, 0xa4, 0x40, 0x00, 0xa8, 0x16, 0xb0, 0xe0, 0x50, | 477 | +0x68, 0x39, 0x80, 0xe0, 0xa4, 0xa4, 0x40, 0x00, 0xa8, 0x16, 0xb0, 0xe0, 0x50, |
478 | +0xc9, 0x40, 0x00, 0x28, 0x3a, 0x98, 0xe0, 0x00, 0xb9, 0x00, 0x00, 0xb6, 0x85, | 478 | +0xc9, 0x40, 0x00, 0x28, 0x3a, 0x98, 0xe0, 0x00, 0xb9, 0x00, 0x00, 0xb6, 0x85, |
479 | +0x00, 0x00, | 479 | +0x00, 0x00, |
480 | +}; | 480 | +}; |
481 | + | 481 | + |
482 | +static const char * const vd55g1_tp_menu[] = { | 482 | +static const char * const vd55g1_tp_menu[] = { |
483 | + "Disabled", | 483 | + "Disabled", |
484 | + "Dgrey", | 484 | + "Dgrey", |
485 | + "PN28", | 485 | + "PN28", |
486 | +}; | 486 | +}; |
487 | + | 487 | + |
488 | +static const s64 vd55g1_ev_bias_menu[] = { | 488 | +static const s64 vd55g1_ev_bias_menu[] = { |
489 | + -3000, -2500, -2000, -1500, -1000, -500, | 489 | + -3000, -2500, -2000, -1500, -1000, -500, |
490 | + 0, | 490 | + 0, |
491 | + 500, 1000, 1500, 2000, 2500, 3000, | 491 | + 500, 1000, 1500, 2000, 2500, 3000, |
492 | +}; | 492 | +}; |
493 | + | 493 | + |
494 | +static const char * const vd55g1_hdr_menu[] = { | 494 | +static const char * const vd55g1_hdr_menu[] = { |
495 | + "No HDR", | 495 | + "No HDR", |
496 | + /* | 496 | + /* |
497 | + * This mode acquires 2 frames on the sensor, the first one is ditched | 497 | + * This mode acquires 2 frames on the sensor, the first one is ditched |
498 | + * out and only used for auto exposure data, the second one is output to | 498 | + * out and only used for auto exposure data, the second one is output to |
499 | + * the host | 499 | + * the host |
500 | + */ | 500 | + */ |
501 | + "Internal subtraction", | 501 | + "Internal subtraction", |
502 | +}; | 502 | +}; |
503 | + | 503 | + |
504 | +static const char * const vd55g1_supply_name[] = { | 504 | +static const char * const vd55g1_supply_name[] = { |
505 | + "vcore", | 505 | + "vcore", |
506 | + "vddio", | 506 | + "vddio", |
507 | + "vana", | 507 | + "vana", |
508 | +}; | 508 | +}; |
509 | + | 509 | + |
510 | +/* Will be filled on device tree parse */ | 510 | +/* Will be filled on device tree parse */ |
511 | +static u64 link_freq[1]; | 511 | +static u64 link_freq[1]; |
512 | + | 512 | + |
513 | +enum vd55g1_hdr_mode { | 513 | +enum vd55g1_hdr_mode { |
514 | + VD55G1_NO_HDR, | 514 | + VD55G1_NO_HDR, |
515 | + VD55G1_HDR_SUB, | 515 | + VD55G1_HDR_SUB, |
516 | +}; | 516 | +}; |
517 | + | 517 | + |
518 | +enum vd55g1_bin_mode { | 518 | +enum vd55g1_bin_mode { |
519 | + VD55G1_BIN_MODE_NORMAL, | 519 | + VD55G1_BIN_MODE_NORMAL, |
520 | + VD55G1_BIN_MODE_DIGITAL_X2, | 520 | + VD55G1_BIN_MODE_DIGITAL_X2, |
521 | + VD55G1_BIN_MODE_DIGITAL_X4, | 521 | + VD55G1_BIN_MODE_DIGITAL_X4, |
522 | +}; | 522 | +}; |
523 | + | 523 | + |
524 | +enum vd55g1_gpio_mode { | 524 | +enum vd55g1_gpio_mode { |
525 | + VD55G1_GPIO_MODE_IN = 0x01, | 525 | + VD55G1_GPIO_MODE_IN = 0x01, |
526 | + VD55G1_GPIO_MODE_STROBE = 0x02, | 526 | + VD55G1_GPIO_MODE_STROBE = 0x02, |
527 | +}; | 527 | +}; |
528 | + | 528 | + |
529 | +struct vd55g1_mode { | 529 | +struct vd55g1_mode { |
530 | + u32 width; | 530 | + u32 width; |
531 | + u32 height; | 531 | + u32 height; |
532 | +}; | 532 | +}; |
533 | + | 533 | + |
534 | +struct vd55g1_fmt_desc { | 534 | +struct vd55g1_fmt_desc { |
535 | + u32 code; | 535 | + u32 code; |
536 | + u8 bpp; | 536 | + u8 bpp; |
537 | + u8 data_type; | 537 | + u8 data_type; |
538 | +}; | 538 | +}; |
539 | + | 539 | + |
540 | +static const struct vd55g1_fmt_desc vd55g1_mbus_codes[] = { | 540 | +static const struct vd55g1_fmt_desc vd55g1_mbus_codes[] = { |
541 | + { | 541 | + { |
542 | + .code = MEDIA_BUS_FMT_Y8_1X8, | 542 | + .code = MEDIA_BUS_FMT_Y8_1X8, |
543 | + .bpp = 8, | 543 | + .bpp = 8, |
544 | + .data_type = MIPI_CSI2_DT_RAW8, | 544 | + .data_type = MIPI_CSI2_DT_RAW8, |
545 | + }, | 545 | + }, |
546 | + { | 546 | + { |
547 | + .code = MEDIA_BUS_FMT_Y10_1X10, | 547 | + .code = MEDIA_BUS_FMT_Y10_1X10, |
548 | + .bpp = 10, | 548 | + .bpp = 10, |
549 | + .data_type = MIPI_CSI2_DT_RAW10, | 549 | + .data_type = MIPI_CSI2_DT_RAW10, |
550 | + }, | 550 | + }, |
551 | +}; | 551 | +}; |
552 | + | 552 | + |
553 | +static const struct vd55g1_mode vd55g1_supported_modes[] = { | 553 | +static const struct vd55g1_mode vd55g1_supported_modes[] = { |
554 | + { | 554 | + { |
555 | + .width = VD55G1_WIDTH, | 555 | + .width = VD55G1_WIDTH, |
556 | + .height = VD55G1_HEIGHT, | 556 | + .height = VD55G1_HEIGHT, |
557 | + }, | 557 | + }, |
558 | + { | 558 | + { |
559 | + .width = 800, | 559 | + .width = 800, |
560 | + .height = VD55G1_HEIGHT, | 560 | + .height = VD55G1_HEIGHT, |
561 | + }, | 561 | + }, |
562 | + { | 562 | + { |
563 | + .width = 800, | 563 | + .width = 800, |
564 | + .height = 600, | 564 | + .height = 600, |
565 | + }, | 565 | + }, |
566 | + { | 566 | + { |
567 | + .width = 640, | 567 | + .width = 640, |
568 | + .height = 480, | 568 | + .height = 480, |
569 | + }, | 569 | + }, |
570 | + { | 570 | + { |
571 | + .width = 320, | 571 | + .width = 320, |
572 | + .height = 240, | 572 | + .height = 240, |
573 | + }, | 573 | + }, |
574 | +}; | 574 | +}; |
575 | + | 575 | + |
576 | +enum vd55g1_expo_state { | 576 | +enum vd55g1_expo_state { |
577 | + VD55G1_EXP_AUTO, | 577 | + VD55G1_EXP_AUTO, |
578 | + VD55G1_EXP_FREEZE, | 578 | + VD55G1_EXP_FREEZE, |
579 | + VD55G1_EXP_MANUAL, | 579 | + VD55G1_EXP_MANUAL, |
580 | + VD55G1_EXP_SINGLE_STEP, | 580 | + VD55G1_EXP_SINGLE_STEP, |
581 | + VD55G1_EXP_BYPASS, | 581 | + VD55G1_EXP_BYPASS, |
582 | +}; | 582 | +}; |
583 | + | 583 | + |
584 | +struct vblank_limits { | 584 | +struct vblank_limits { |
585 | + u16 min; | 585 | + u16 min; |
586 | + u16 def; | 586 | + u16 def; |
587 | + u16 max; | 587 | + u16 max; |
588 | +}; | 588 | +}; |
589 | + | 589 | + |
590 | +struct vd55g1 { | 590 | +struct vd55g1 { |
591 | + struct i2c_client *i2c_client; | 591 | + struct i2c_client *i2c_client; |
592 | + struct v4l2_subdev sd; | 592 | + struct v4l2_subdev sd; |
593 | + struct media_pad pad; | 593 | + struct media_pad pad; |
594 | + struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)]; | 594 | + struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)]; |
595 | + struct gpio_desc *reset_gpio; | 595 | + struct gpio_desc *reset_gpio; |
596 | + struct clk *xclk; | 596 | + struct clk *xclk; |
597 | + struct regmap *regmap; | 597 | + struct regmap *regmap; |
598 | + u32 xclk_freq; | 598 | + u32 xclk_freq; |
599 | + u16 oif_ctrl; | 599 | + u16 oif_ctrl; |
600 | + enum vd55g1_gpio_mode gpios[VD55G1_NB_GPIOS]; | 600 | + enum vd55g1_gpio_mode gpios[VD55G1_NB_GPIOS]; |
601 | + unsigned long ext_leds_mask; | 601 | + unsigned long ext_leds_mask; |
602 | + int data_rate_in_mbps; | 602 | + int data_rate_in_mbps; |
603 | + u32 pixel_clock; | 603 | + u32 pixel_clock; |
604 | + struct v4l2_ctrl_handler ctrl_handler; | 604 | + struct v4l2_ctrl_handler ctrl_handler; |
605 | + struct v4l2_ctrl *pixel_rate_ctrl; | 605 | + struct v4l2_ctrl *pixel_rate_ctrl; |
606 | + struct v4l2_ctrl *vblank_ctrl; | 606 | + struct v4l2_ctrl *vblank_ctrl; |
607 | + struct v4l2_ctrl *hblank_ctrl; | 607 | + struct v4l2_ctrl *hblank_ctrl; |
608 | + struct { | 608 | + struct { |
609 | + struct v4l2_ctrl *hflip_ctrl; | 609 | + struct v4l2_ctrl *hflip_ctrl; |
610 | + struct v4l2_ctrl *vflip_ctrl; | 610 | + struct v4l2_ctrl *vflip_ctrl; |
611 | + }; | 611 | + }; |
612 | + struct v4l2_ctrl *patgen_ctrl; | 612 | + struct v4l2_ctrl *patgen_ctrl; |
613 | + struct { | 613 | + struct { |
614 | + struct v4l2_ctrl *ae_ctrl; | 614 | + struct v4l2_ctrl *ae_ctrl; |
615 | + struct v4l2_ctrl *expo_ctrl; | 615 | + struct v4l2_ctrl *expo_ctrl; |
616 | + struct v4l2_ctrl *again_ctrl; | 616 | + struct v4l2_ctrl *again_ctrl; |
617 | + struct v4l2_ctrl *dgain_ctrl; | 617 | + struct v4l2_ctrl *dgain_ctrl; |
618 | + }; | 618 | + }; |
619 | + struct v4l2_ctrl *ae_lock_ctrl; | 619 | + struct v4l2_ctrl *ae_lock_ctrl; |
620 | + struct v4l2_ctrl *ae_bias_ctrl; | 620 | + struct v4l2_ctrl *ae_bias_ctrl; |
621 | + struct v4l2_ctrl *led_ctrl; | 621 | + struct v4l2_ctrl *led_ctrl; |
622 | + struct v4l2_ctrl *hdr_ctrl; | 622 | + struct v4l2_ctrl *hdr_ctrl; |
623 | +}; | 623 | +}; |
624 | + | 624 | + |
625 | +static inline struct vd55g1 *to_vd55g1(struct v4l2_subdev *sd) | 625 | +static inline struct vd55g1 *to_vd55g1(struct v4l2_subdev *sd) |
626 | +{ | 626 | +{ |
627 | + return container_of_const(sd, struct vd55g1, sd); | 627 | + return container_of_const(sd, struct vd55g1, sd); |
628 | +} | 628 | +} |
629 | + | 629 | + |
630 | +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | 630 | +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) |
631 | +{ | 631 | +{ |
632 | + return &container_of_const(ctrl->handler, struct vd55g1, | 632 | + return &container_of_const(ctrl->handler, struct vd55g1, |
633 | + ctrl_handler)->sd; | 633 | + ctrl_handler)->sd; |
634 | +} | 634 | +} |
635 | + | 635 | + |
636 | +static u8 get_bpp_by_code(struct vd55g1 *sensor, u32 code) | 636 | +static u8 get_bpp_by_code(struct vd55g1 *sensor, u32 code) |
637 | +{ | 637 | +{ |
638 | + struct i2c_client *client = sensor->i2c_client; | 638 | + struct i2c_client *client = sensor->i2c_client; |
639 | + unsigned int i; | 639 | + unsigned int i; |
640 | + | 640 | + |
641 | + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) { | 641 | + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) { |
642 | + if (vd55g1_mbus_codes[i].code == code) | 642 | + if (vd55g1_mbus_codes[i].code == code) |
643 | + return vd55g1_mbus_codes[i].bpp; | 643 | + return vd55g1_mbus_codes[i].bpp; |
644 | + } | 644 | + } |
645 | + /* Should never happen */ | 645 | + /* Should never happen */ |
646 | + dev_warn(&client->dev, "Unsupported code %d. default to 8 bpp", code); | 646 | + dev_warn(&client->dev, "Unsupported code %d. default to 8 bpp", code); |
647 | + return 8; | 647 | + return 8; |
648 | +} | 648 | +} |
649 | + | 649 | + |
650 | +static u8 get_data_type_by_code(struct vd55g1 *sensor, u32 code) | 650 | +static u8 get_data_type_by_code(struct vd55g1 *sensor, u32 code) |
651 | +{ | 651 | +{ |
652 | + struct i2c_client *client = sensor->i2c_client; | 652 | + struct i2c_client *client = sensor->i2c_client; |
653 | + unsigned int i; | 653 | + unsigned int i; |
654 | + | 654 | + |
655 | + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) { | 655 | + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) { |
656 | + if (vd55g1_mbus_codes[i].code == code) | 656 | + if (vd55g1_mbus_codes[i].code == code) |
657 | + return vd55g1_mbus_codes[i].data_type; | 657 | + return vd55g1_mbus_codes[i].data_type; |
658 | + } | 658 | + } |
659 | + /* Should never happen */ | 659 | + /* Should never happen */ |
660 | + dev_warn(&client->dev, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type", | 660 | + dev_warn(&client->dev, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type", |
661 | + code); | 661 | + code); |
662 | + return MIPI_CSI2_DT_RAW8; | 662 | + return MIPI_CSI2_DT_RAW8; |
663 | +} | 663 | +} |
664 | + | 664 | + |
665 | +static s32 get_pixel_rate(struct vd55g1 *sensor) | 665 | +static s32 get_pixel_rate(struct vd55g1 *sensor) |
666 | +{ | 666 | +{ |
667 | + struct v4l2_subdev_state *state = | 667 | + struct v4l2_subdev_state *state = |
668 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 668 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
669 | + const struct v4l2_mbus_framefmt *format = | 669 | + const struct v4l2_mbus_framefmt *format = |
670 | + v4l2_subdev_state_get_format(state, 0); | 670 | + v4l2_subdev_state_get_format(state, 0); |
671 | + | 671 | + |
672 | + return div64_u64((u64)sensor->data_rate_in_mbps, | 672 | + return div64_u64((u64)sensor->data_rate_in_mbps, |
673 | + get_bpp_by_code(sensor, format->code)); | 673 | + get_bpp_by_code(sensor, format->code)); |
674 | +} | 674 | +} |
675 | + | 675 | + |
676 | +static s32 get_min_line_length(struct vd55g1 *sensor) | 676 | +static s32 get_min_line_length(struct vd55g1 *sensor) |
677 | +{ | 677 | +{ |
678 | + u32 mipi_req_line_time; | 678 | + u32 mipi_req_line_time; |
679 | + u32 mipi_req_line_length; | 679 | + u32 mipi_req_line_length; |
680 | + u32 min_line_length; | 680 | + u32 min_line_length; |
681 | + struct v4l2_subdev_state *state = | 681 | + struct v4l2_subdev_state *state = |
682 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 682 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
683 | + const struct v4l2_rect *crop = | 683 | + const struct v4l2_rect *crop = |
684 | + v4l2_subdev_state_get_crop(state, 0); | 684 | + v4l2_subdev_state_get_crop(state, 0); |
685 | + const struct v4l2_mbus_framefmt *format = | 685 | + const struct v4l2_mbus_framefmt *format = |
686 | + v4l2_subdev_state_get_format(state, 0); | 686 | + v4l2_subdev_state_get_format(state, 0); |
687 | + | 687 | + |
688 | + /* MIPI required time */ | 688 | + /* MIPI required time */ |
689 | + mipi_req_line_time = (crop->width * | 689 | + mipi_req_line_time = (crop->width * |
690 | + get_bpp_by_code(sensor, format->code) + | 690 | + get_bpp_by_code(sensor, format->code) + |
691 | + VD55G1_MIPI_MARGIN) / | 691 | + VD55G1_MIPI_MARGIN) / |
692 | + (sensor->data_rate_in_mbps / MEGA); | 692 | + (sensor->data_rate_in_mbps / MEGA); |
693 | + mipi_req_line_length = mipi_req_line_time * sensor->pixel_clock / | 693 | + mipi_req_line_length = mipi_req_line_time * sensor->pixel_clock / |
694 | + HZ_PER_MHZ; | 694 | + HZ_PER_MHZ; |
695 | + | 695 | + |
696 | + /* Absolute time required for ADCs to convert pixels */ | 696 | + /* Absolute time required for ADCs to convert pixels */ |
697 | + min_line_length = VD55G1_LINE_LENGTH_MIN; | 697 | + min_line_length = VD55G1_LINE_LENGTH_MIN; |
698 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) | 698 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) |
699 | + min_line_length = VD55G1_LINE_LENGTH_SUB_MIN; | 699 | + min_line_length = VD55G1_LINE_LENGTH_SUB_MIN; |
700 | + | 700 | + |
701 | + /* Respect both constraint */ | 701 | + /* Respect both constraint */ |
702 | + return max(min_line_length, mipi_req_line_length); | 702 | + return max(min_line_length, mipi_req_line_length); |
703 | +} | 703 | +} |
704 | + | 704 | + |
705 | +static unsigned int get_hblank_min(struct vd55g1 *sensor) | 705 | +static unsigned int get_hblank_min(struct vd55g1 *sensor) |
706 | +{ | 706 | +{ |
707 | + struct v4l2_subdev_state *state = | 707 | + struct v4l2_subdev_state *state = |
708 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 708 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
709 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 709 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
710 | + | 710 | + |
711 | + return get_min_line_length(sensor) - crop->width; | 711 | + return get_min_line_length(sensor) - crop->width; |
712 | +} | 712 | +} |
713 | + | 713 | + |
714 | +static struct vblank_limits get_vblank_limits(struct vd55g1 *sensor) | 714 | +static struct vblank_limits get_vblank_limits(struct vd55g1 *sensor) |
715 | +{ | 715 | +{ |
716 | + struct vblank_limits limits; | 716 | + struct vblank_limits limits; |
717 | + struct v4l2_subdev_state *state = | 717 | + struct v4l2_subdev_state *state = |
718 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 718 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
719 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 719 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
720 | + | 720 | + |
721 | + limits.min = VD55G1_VBLANK_MIN; | 721 | + limits.min = VD55G1_VBLANK_MIN; |
722 | + limits.def = VD55G1_FRAME_LENGTH_DEF - crop->height; | 722 | + limits.def = VD55G1_FRAME_LENGTH_DEF - crop->height; |
723 | + limits.max = VD55G1_VBLANK_MAX - crop->height; | 723 | + limits.max = VD55G1_VBLANK_MAX - crop->height; |
724 | + | 724 | + |
725 | + return limits; | 725 | + return limits; |
726 | +} | 726 | +} |
727 | + | 727 | + |
728 | +#define vd55g1_read(sensor, reg, val, err) \ | 728 | +#define vd55g1_read(sensor, reg, val, err) \ |
729 | + cci_read((sensor)->regmap, reg, val, err) | 729 | + cci_read((sensor)->regmap, reg, val, err) |
730 | + | 730 | + |
731 | +#define vd55g1_write(sensor, reg, val, err) \ | 731 | +#define vd55g1_write(sensor, reg, val, err) \ |
732 | + cci_write((sensor)->regmap, reg, (u64)val, err) | 732 | + cci_write((sensor)->regmap, reg, (u64)val, err) |
733 | + | 733 | + |
734 | +static int vd55g1_write_array(struct vd55g1 *sensor, u32 reg, unsigned int len, | 734 | +static int vd55g1_write_array(struct vd55g1 *sensor, u32 reg, unsigned int len, |
735 | + const u8 *array, int *err) | 735 | + const u8 *array, int *err) |
736 | +{ | 736 | +{ |
737 | + unsigned int chunk_sz = 1024; | 737 | + unsigned int chunk_sz = 1024; |
738 | + unsigned int sz; | 738 | + unsigned int sz; |
739 | + int ret = 0; | 739 | + int ret = 0; |
740 | + | 740 | + |
741 | + if (err && *err) | 741 | + if (err && *err) |
742 | + return *err; | 742 | + return *err; |
743 | + | 743 | + |
744 | + /* | 744 | + /* |
745 | + * This loop isn't necessary but in certains conditions (platforms, cpu | 745 | + * This loop isn't necessary but in certains conditions (platforms, cpu |
746 | + * load, etc.) it has been observed that the bulk write could timeout. | 746 | + * load, etc.) it has been observed that the bulk write could timeout. |
747 | + */ | 747 | + */ |
748 | + while (len) { | 748 | + while (len) { |
749 | + sz = min(len, chunk_sz); | 749 | + sz = min(len, chunk_sz); |
750 | + ret = regmap_bulk_write(sensor->regmap, reg, array, sz); | 750 | + ret = regmap_bulk_write(sensor->regmap, reg, array, sz); |
751 | + if (ret < 0) | 751 | + if (ret < 0) |
752 | + goto out; | 752 | + goto out; |
753 | + len -= sz; | 753 | + len -= sz; |
754 | + reg += sz; | 754 | + reg += sz; |
755 | + array += sz; | 755 | + array += sz; |
756 | + } | 756 | + } |
757 | + | 757 | + |
758 | +out: | 758 | +out: |
759 | + if (ret && err) | 759 | + if (ret && err) |
760 | + *err = ret; | 760 | + *err = ret; |
761 | + | 761 | + |
762 | + return ret; | 762 | + return ret; |
763 | +} | 763 | +} |
764 | + | 764 | + |
765 | +static int vd55g1_poll_reg(struct vd55g1 *sensor, u32 reg, u8 poll_val, | 765 | +static int vd55g1_poll_reg(struct vd55g1 *sensor, u32 reg, u8 poll_val, |
766 | + int *err) | 766 | + int *err) |
767 | +{ | 767 | +{ |
768 | + unsigned int val = 0; | 768 | + unsigned int val = 0; |
769 | + int ret; | 769 | + int ret; |
770 | + | 770 | + |
771 | + if (err && *err) | 771 | + if (err && *err) |
772 | + return *err; | 772 | + return *err; |
773 | + | 773 | + |
774 | + ret = regmap_read_poll_timeout(sensor->regmap, CCI_REG_ADDR(reg), val, | 774 | + ret = regmap_read_poll_timeout(sensor->regmap, CCI_REG_ADDR(reg), val, |
775 | + (val == poll_val), 2000, | 775 | + (val == poll_val), 2000, |
776 | + 500 * USEC_PER_MSEC); | 776 | + 500 * USEC_PER_MSEC); |
777 | + | 777 | + |
778 | + if (ret && err) | 778 | + if (ret && err) |
779 | + *err = ret; | 779 | + *err = ret; |
780 | + | 780 | + |
781 | + return ret; | 781 | + return ret; |
782 | +} | 782 | +} |
783 | + | 783 | + |
784 | +static int vd55g1_wait_state(struct vd55g1 *sensor, int state, int *err) | 784 | +static int vd55g1_wait_state(struct vd55g1 *sensor, int state, int *err) |
785 | +{ | 785 | +{ |
786 | + return vd55g1_poll_reg(sensor, VD55G1_REG_SYSTEM_FSM, state, err); | 786 | + return vd55g1_poll_reg(sensor, VD55G1_REG_SYSTEM_FSM, state, err); |
787 | +} | 787 | +} |
788 | + | 788 | + |
789 | +static int vd55g1_get_regulators(struct vd55g1 *sensor) | 789 | +static int vd55g1_get_regulators(struct vd55g1 *sensor) |
790 | +{ | 790 | +{ |
791 | + int i; | 791 | + int i; |
792 | + | 792 | + |
793 | + for (i = 0; i < ARRAY_SIZE(vd55g1_supply_name); i++) | 793 | + for (i = 0; i < ARRAY_SIZE(vd55g1_supply_name); i++) |
794 | + sensor->supplies[i].supply = vd55g1_supply_name[i]; | 794 | + sensor->supplies[i].supply = vd55g1_supply_name[i]; |
795 | + | 795 | + |
796 | + return devm_regulator_bulk_get(&sensor->i2c_client->dev, | 796 | + return devm_regulator_bulk_get(&sensor->i2c_client->dev, |
797 | + ARRAY_SIZE(vd55g1_supply_name), | 797 | + ARRAY_SIZE(vd55g1_supply_name), |
798 | + sensor->supplies); | 798 | + sensor->supplies); |
799 | +} | 799 | +} |
800 | + | 800 | + |
801 | +static int vd55g1_prepare_clock_tree(struct vd55g1 *sensor) | 801 | +static int vd55g1_prepare_clock_tree(struct vd55g1 *sensor) |
802 | +{ | 802 | +{ |
803 | + struct i2c_client *client = sensor->i2c_client; | 803 | + struct i2c_client *client = sensor->i2c_client; |
804 | + /* Double data rate */ | 804 | + /* Double data rate */ |
805 | + u32 mipi_freq = link_freq[0] * 2; | 805 | + u32 mipi_freq = link_freq[0] * 2; |
806 | + u32 sys_clk, mipi_div, pixel_div; | 806 | + u32 sys_clk, mipi_div, pixel_div; |
807 | + int ret = 0; | 807 | + int ret = 0; |
808 | + | 808 | + |
809 | + if (sensor->xclk_freq < 6 * HZ_PER_MHZ || | 809 | + if (sensor->xclk_freq < 6 * HZ_PER_MHZ || |
810 | + sensor->xclk_freq > 27 * HZ_PER_MHZ) { | 810 | + sensor->xclk_freq > 27 * HZ_PER_MHZ) { |
811 | + dev_err(&client->dev, | 811 | + dev_err(&client->dev, |
812 | + "Only 6Mhz-27Mhz clock range supported. Provided %lu MHz\n", | 812 | + "Only 6Mhz-27Mhz clock range supported. Provided %lu MHz\n", |
813 | + sensor->xclk_freq / HZ_PER_MHZ); | 813 | + sensor->xclk_freq / HZ_PER_MHZ); |
814 | + return -EINVAL; | 814 | + return -EINVAL; |
815 | + } | 815 | + } |
816 | + | 816 | + |
817 | + if (mipi_freq < 250 * HZ_PER_MHZ || | 817 | + if (mipi_freq < 250 * HZ_PER_MHZ || |
818 | + mipi_freq > 1200 * HZ_PER_MHZ) { | 818 | + mipi_freq > 1200 * HZ_PER_MHZ) { |
819 | + dev_err(&client->dev, | 819 | + dev_err(&client->dev, |
820 | + "Only 250Mhz-1200Mhz link frequency range supported. Provided %lu MHz\n", | 820 | + "Only 250Mhz-1200Mhz link frequency range supported. Provided %lu MHz\n", |
821 | + mipi_freq / HZ_PER_MHZ); | 821 | + mipi_freq / HZ_PER_MHZ); |
822 | + return -EINVAL; | 822 | + return -EINVAL; |
823 | + } | 823 | + } |
824 | + | 824 | + |
825 | + if (mipi_freq <= 300 * HZ_PER_MHZ) | 825 | + if (mipi_freq <= 300 * HZ_PER_MHZ) |
826 | + mipi_div = 4; | 826 | + mipi_div = 4; |
827 | + else if (mipi_freq <= 600 * HZ_PER_MHZ) | 827 | + else if (mipi_freq <= 600 * HZ_PER_MHZ) |
828 | + mipi_div = 2; | 828 | + mipi_div = 2; |
829 | + else | 829 | + else |
830 | + mipi_div = 1; | 830 | + mipi_div = 1; |
831 | + | 831 | + |
832 | + sys_clk = mipi_freq * mipi_div; | 832 | + sys_clk = mipi_freq * mipi_div; |
833 | + | 833 | + |
834 | + if (sys_clk <= 780 * HZ_PER_MHZ) | 834 | + if (sys_clk <= 780 * HZ_PER_MHZ) |
835 | + pixel_div = 5; | 835 | + pixel_div = 5; |
836 | + else if (sys_clk <= 900 * HZ_PER_MHZ) | 836 | + else if (sys_clk <= 900 * HZ_PER_MHZ) |
837 | + pixel_div = 6; | 837 | + pixel_div = 6; |
838 | + else | 838 | + else |
839 | + pixel_div = 8; | 839 | + pixel_div = 8; |
840 | + | 840 | + |
841 | + sensor->pixel_clock = sys_clk / pixel_div; | 841 | + sensor->pixel_clock = sys_clk / pixel_div; |
842 | + /* Frequency to data rate is 1:1 ratio for MIPI */ | 842 | + /* Frequency to data rate is 1:1 ratio for MIPI */ |
843 | + sensor->data_rate_in_mbps = mipi_freq; | 843 | + sensor->data_rate_in_mbps = mipi_freq; |
844 | + | 844 | + |
845 | + return ret; | 845 | + return ret; |
846 | +} | 846 | +} |
847 | + | 847 | + |
848 | +static int vd55g1_update_patgen(struct vd55g1 *sensor, u32 patgen_index) | 848 | +static int vd55g1_update_patgen(struct vd55g1 *sensor, u32 patgen_index) |
849 | +{ | 849 | +{ |
850 | + static const u8 index2val[] = { | 850 | + static const u8 index2val[] = { |
851 | + 0x0, 0x22, 0x28 | 851 | + 0x0, 0x22, 0x28 |
852 | + }; | 852 | + }; |
853 | + u32 pattern = index2val[patgen_index]; | 853 | + u32 pattern = index2val[patgen_index]; |
854 | + u32 reg = pattern << VD55G1_PATGEN_TYPE_SHIFT; | 854 | + u32 reg = pattern << VD55G1_PATGEN_TYPE_SHIFT; |
855 | + u8 darkcal = VD55G1_DARKCAL_AUTO; | 855 | + u8 darkcal = VD55G1_DARKCAL_AUTO; |
856 | + u8 duster = VD55G1_DUSTER_RING_ENABLE | VD55G1_DUSTER_DYN_ENABLE | | 856 | + u8 duster = VD55G1_DUSTER_RING_ENABLE | VD55G1_DUSTER_DYN_ENABLE | |
857 | + VD55G1_DUSTER_ENABLE; | 857 | + VD55G1_DUSTER_ENABLE; |
858 | + int ret = 0; | 858 | + int ret = 0; |
859 | + | 859 | + |
860 | + if (pattern != 0) { | 860 | + if (pattern != 0) { |
861 | + reg |= VD55G1_PATGEN_ENABLE; | 861 | + reg |= VD55G1_PATGEN_ENABLE; |
862 | + /* | 862 | + /* |
863 | + * Take care of dark calibaration and duster to not mess up the | 863 | + * Take care of dark calibaration and duster to not mess up the |
864 | + * test pattern output. | 864 | + * test pattern output. |
865 | + */ | 865 | + */ |
866 | + darkcal = VD55G1_DARKCAL_BYPASS; | 866 | + darkcal = VD55G1_DARKCAL_BYPASS; |
867 | + duster = VD55G1_DUSTER_DISABLE; | 867 | + duster = VD55G1_DUSTER_DISABLE; |
868 | + } | 868 | + } |
869 | + | 869 | + |
870 | + vd55g1_write(sensor, VD55G1_REG_DARKCAL_CTRL, darkcal, &ret); | 870 | + vd55g1_write(sensor, VD55G1_REG_DARKCAL_CTRL, darkcal, &ret); |
871 | + vd55g1_write(sensor, VD55G1_REG_DUSTER_CTRL, duster, &ret); | 871 | + vd55g1_write(sensor, VD55G1_REG_DUSTER_CTRL, duster, &ret); |
872 | + vd55g1_write(sensor, VD55G1_REG_PATGEN_CTRL, reg, &ret); | 872 | + vd55g1_write(sensor, VD55G1_REG_PATGEN_CTRL, reg, &ret); |
873 | + | 873 | + |
874 | + return ret; | 874 | + return ret; |
875 | +} | 875 | +} |
876 | + | 876 | + |
877 | +static int vd55g1_update_expo_cluster(struct vd55g1 *sensor, bool is_auto) | 877 | +static int vd55g1_update_expo_cluster(struct vd55g1 *sensor, bool is_auto) |
878 | +{ | 878 | +{ |
879 | + enum vd55g1_expo_state expo_state = is_auto ? VD55G1_EXP_AUTO : | 879 | + enum vd55g1_expo_state expo_state = is_auto ? VD55G1_EXP_AUTO : |
880 | + VD55G1_EXP_MANUAL; | 880 | + VD55G1_EXP_MANUAL; |
881 | + int ret = 0; | 881 | + int ret = 0; |
882 | + | 882 | + |
883 | + if (sensor->ae_ctrl->is_new) | 883 | + if (sensor->ae_ctrl->is_new) |
884 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(0), expo_state, &ret); | 884 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(0), expo_state, &ret); |
885 | + | 885 | + |
886 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB && | 886 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB && |
887 | + sensor->hdr_ctrl->is_new) { | 887 | + sensor->hdr_ctrl->is_new) { |
888 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(1), VD55G1_EXP_BYPASS, | 888 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(1), VD55G1_EXP_BYPASS, |
889 | + &ret); | 889 | + &ret); |
890 | + if (ret) | 890 | + if (ret) |
891 | + return ret; | 891 | + return ret; |
892 | + } | 892 | + } |
893 | + | 893 | + |
894 | + if (!is_auto && sensor->expo_ctrl->is_new) | 894 | + if (!is_auto && sensor->expo_ctrl->is_new) |
895 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_COARSE_EXPOSURE, | 895 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_COARSE_EXPOSURE, |
896 | + sensor->expo_ctrl->val, &ret); | 896 | + sensor->expo_ctrl->val, &ret); |
897 | + | 897 | + |
898 | + if (!is_auto && sensor->again_ctrl->is_new) | 898 | + if (!is_auto && sensor->again_ctrl->is_new) |
899 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_ANALOG_GAIN, | 899 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_ANALOG_GAIN, |
900 | + sensor->again_ctrl->val, &ret); | 900 | + sensor->again_ctrl->val, &ret); |
901 | + | 901 | + |
902 | + if (!is_auto && sensor->dgain_ctrl->is_new) { | 902 | + if (!is_auto && sensor->dgain_ctrl->is_new) { |
903 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN, | 903 | + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN, |
904 | + sensor->dgain_ctrl->val, &ret); | 904 | + sensor->dgain_ctrl->val, &ret); |
905 | + } | 905 | + } |
906 | + | 906 | + |
907 | + return ret; | 907 | + return ret; |
908 | +} | 908 | +} |
909 | + | 909 | + |
910 | +static int vd55g1_lock_exposure(struct vd55g1 *sensor, u32 lock_val) | 910 | +static int vd55g1_lock_exposure(struct vd55g1 *sensor, u32 lock_val) |
911 | +{ | 911 | +{ |
912 | + bool ae_lock = lock_val & V4L2_LOCK_EXPOSURE; | 912 | + bool ae_lock = lock_val & V4L2_LOCK_EXPOSURE; |
913 | + enum vd55g1_expo_state expo_state = ae_lock ? VD55G1_EXP_FREEZE : | 913 | + enum vd55g1_expo_state expo_state = ae_lock ? VD55G1_EXP_FREEZE : |
914 | + VD55G1_EXP_AUTO; | 914 | + VD55G1_EXP_AUTO; |
915 | + int ret = 0; | 915 | + int ret = 0; |
916 | + | 916 | + |
917 | + if (sensor->ae_ctrl->val == V4L2_EXPOSURE_AUTO) | 917 | + if (sensor->ae_ctrl->val == V4L2_EXPOSURE_AUTO) |
918 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(0), expo_state, &ret); | 918 | + vd55g1_write(sensor, VD55G1_REG_EXP_MODE(0), expo_state, &ret); |
919 | + | 919 | + |
920 | + return ret; | 920 | + return ret; |
921 | +} | 921 | +} |
922 | + | 922 | + |
923 | +static int vd55g1_read_expo_cluster(struct vd55g1 *sensor) | 923 | +static int vd55g1_read_expo_cluster(struct vd55g1 *sensor) |
924 | +{ | 924 | +{ |
925 | + u64 exposure = 0; | 925 | + u64 exposure = 0; |
926 | + u64 again = 0; | 926 | + u64 again = 0; |
927 | + u64 dgain = 0; | 927 | + u64 dgain = 0; |
928 | + int ret = 0; | 928 | + int ret = 0; |
929 | + | 929 | + |
930 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_COARSE_EXPOSURE, &exposure, | 930 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_COARSE_EXPOSURE, &exposure, |
931 | + &ret); | 931 | + &ret); |
932 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_ANALOG_GAIN, &again, &ret); | 932 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_ANALOG_GAIN, &again, &ret); |
933 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_DIGITAL_GAIN, &dgain, &ret); | 933 | + vd55g1_read(sensor, VD55G1_REG_APPLIED_DIGITAL_GAIN, &dgain, &ret); |
934 | + if (ret) | 934 | + if (ret) |
935 | + return ret; | 935 | + return ret; |
936 | + | 936 | + |
937 | + sensor->expo_ctrl->cur.val = exposure; | 937 | + sensor->expo_ctrl->cur.val = exposure; |
938 | + sensor->again_ctrl->cur.val = again; | 938 | + sensor->again_ctrl->cur.val = again; |
939 | + sensor->dgain_ctrl->cur.val = dgain; | 939 | + sensor->dgain_ctrl->cur.val = dgain; |
940 | + | 940 | + |
941 | + return 0; | 941 | + return 0; |
942 | +} | 942 | +} |
943 | + | 943 | + |
944 | +static int vd55g1_update_frame_length(struct vd55g1 *sensor, | 944 | +static int vd55g1_update_frame_length(struct vd55g1 *sensor, |
945 | + unsigned int frame_length) | 945 | + unsigned int frame_length) |
946 | +{ | 946 | +{ |
947 | + int ret = 0; | 947 | + int ret = 0; |
948 | + | 948 | + |
949 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) { | 949 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) { |
950 | + vd55g1_write(sensor, VD55G1_REG_FRAME_LENGTH(1), frame_length, | 950 | + vd55g1_write(sensor, VD55G1_REG_FRAME_LENGTH(1), frame_length, |
951 | + &ret); | 951 | + &ret); |
952 | + } | 952 | + } |
953 | + vd55g1_write(sensor, VD55G1_REG_FRAME_LENGTH(0), frame_length, &ret); | 953 | + vd55g1_write(sensor, VD55G1_REG_FRAME_LENGTH(0), frame_length, &ret); |
954 | + | 954 | + |
955 | + return ret; | 955 | + return ret; |
956 | +} | 956 | +} |
957 | + | 957 | + |
958 | +static int vd55g1_update_exposure_target(struct vd55g1 *sensor, int index) | 958 | +static int vd55g1_update_exposure_target(struct vd55g1 *sensor, int index) |
959 | +{ | 959 | +{ |
960 | + /* | 960 | + /* |
961 | + * Find auto exposure target with: default target exposure * 2^EV | 961 | + * Find auto exposure target with: default target exposure * 2^EV |
962 | + * Defaut target exposure being 27 for the sensor. | 962 | + * Defaut target exposure being 27 for the sensor. |
963 | + */ | 963 | + */ |
964 | + static const unsigned int index2exposure_target[] = { | 964 | + static const unsigned int index2exposure_target[] = { |
965 | + 3, 5, 7, 10, 14, 19, 27, 38, 54, 76, 108, 153, 216, | 965 | + 3, 5, 7, 10, 14, 19, 27, 38, 54, 76, 108, 153, 216, |
966 | + }; | 966 | + }; |
967 | + int exposure_target = index2exposure_target[index]; | 967 | + int exposure_target = index2exposure_target[index]; |
968 | + | 968 | + |
969 | + return vd55g1_write(sensor, VD55G1_REG_AE_TARGET_PERCENTAGE, | 969 | + return vd55g1_write(sensor, VD55G1_REG_AE_TARGET_PERCENTAGE, |
970 | + exposure_target, NULL); | 970 | + exposure_target, NULL); |
971 | +} | 971 | +} |
972 | + | 972 | + |
973 | +static int vd55g1_apply_cold_start(struct vd55g1 *sensor) | 973 | +static int vd55g1_apply_cold_start(struct vd55g1 *sensor) |
974 | +{ | 974 | +{ |
975 | + struct v4l2_subdev_state *state = | 975 | + struct v4l2_subdev_state *state = |
976 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 976 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
977 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 977 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
978 | + | 978 | + |
979 | + /* | 979 | + /* |
980 | + * Cold start register is a single register expressed as exposure time | 980 | + * Cold start register is a single register expressed as exposure time |
981 | + * in us. This differ from status registers being a combination of | 981 | + * in us. This differ from status registers being a combination of |
982 | + * exposure, digital gain, and analog gain, requiring the following | 982 | + * exposure, digital gain, and analog gain, requiring the following |
983 | + * format conversion. | 983 | + * format conversion. |
984 | + */ | 984 | + */ |
985 | + unsigned int line_length = crop->width + sensor->hblank_ctrl->val; | 985 | + unsigned int line_length = crop->width + sensor->hblank_ctrl->val; |
986 | + unsigned int line_time_us = DIV_ROUND_UP(line_length * MEGA, | 986 | + unsigned int line_time_us = DIV_ROUND_UP(line_length * MEGA, |
987 | + sensor->pixel_clock); | 987 | + sensor->pixel_clock); |
988 | + u8 d_gain = DIV_ROUND_CLOSEST(sensor->dgain_ctrl->val, 1 << 8); | 988 | + u8 d_gain = DIV_ROUND_CLOSEST(sensor->dgain_ctrl->val, 1 << 8); |
989 | + u8 a_gain = DIV_ROUND_CLOSEST(32, (32 - sensor->again_ctrl->val)); | 989 | + u8 a_gain = DIV_ROUND_CLOSEST(32, (32 - sensor->again_ctrl->val)); |
990 | + unsigned int expo_us = sensor->expo_ctrl->val * d_gain * a_gain * | 990 | + unsigned int expo_us = sensor->expo_ctrl->val * d_gain * a_gain * |
991 | + line_time_us; | 991 | + line_time_us; |
992 | + int ret = 0; | 992 | + int ret = 0; |
993 | + | 993 | + |
994 | + vd55g1_write(sensor, VD55G1_REG_AE_FORCE_COLDSTART, 1, &ret); | 994 | + vd55g1_write(sensor, VD55G1_REG_AE_FORCE_COLDSTART, 1, &ret); |
995 | + vd55g1_write(sensor, VD55G1_REG_AE_COLDSTART_EXP_TIME, expo_us, &ret); | 995 | + vd55g1_write(sensor, VD55G1_REG_AE_COLDSTART_EXP_TIME, expo_us, &ret); |
996 | + | 996 | + |
997 | + return ret; | 997 | + return ret; |
998 | +} | 998 | +} |
999 | + | 999 | + |
1000 | +static void vd55g1_update_img_pad_format(struct vd55g1 *sensor, | 1000 | +static void vd55g1_update_img_pad_format(struct vd55g1 *sensor, |
1001 | + const struct vd55g1_mode *mode, | 1001 | + const struct vd55g1_mode *mode, |
1002 | + u32 code, | 1002 | + u32 code, |
1003 | + struct v4l2_mbus_framefmt *fmt) | 1003 | + struct v4l2_mbus_framefmt *fmt) |
1004 | +{ | 1004 | +{ |
1005 | + fmt->code = code; | 1005 | + fmt->code = code; |
1006 | + fmt->width = mode->width; | 1006 | + fmt->width = mode->width; |
1007 | + fmt->height = mode->height; | 1007 | + fmt->height = mode->height; |
1008 | + fmt->colorspace = V4L2_COLORSPACE_RAW; | 1008 | + fmt->colorspace = V4L2_COLORSPACE_RAW; |
1009 | + fmt->field = V4L2_FIELD_NONE; | 1009 | + fmt->field = V4L2_FIELD_NONE; |
1010 | + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | 1010 | + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
1011 | + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; | 1011 | + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; |
1012 | + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; | 1012 | + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
1013 | +} | 1013 | +} |
1014 | + | 1014 | + |
1015 | +static int vd55g1_update_hdr_mode(struct vd55g1 *sensor) | 1015 | +static int vd55g1_update_hdr_mode(struct vd55g1 *sensor) |
1016 | +{ | 1016 | +{ |
1017 | + int ret = 0; | 1017 | + int ret = 0; |
1018 | + | 1018 | + |
1019 | + switch (sensor->hdr_ctrl->val) { | 1019 | + switch (sensor->hdr_ctrl->val) { |
1020 | + case VD55G1_NO_HDR: | 1020 | + case VD55G1_NO_HDR: |
1021 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_MAX_COARSE, | 1021 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_MAX_COARSE, |
1022 | + VD55G1_EXPOSURE_MAX_COARSE_DEF, &ret); | 1022 | + VD55G1_EXPOSURE_MAX_COARSE_DEF, &ret); |
1023 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_USE_CASES, 0, &ret); | 1023 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_USE_CASES, 0, &ret); |
1024 | + vd55g1_write(sensor, VD55G1_REG_NEXT_CTX, 0x0, &ret); | 1024 | + vd55g1_write(sensor, VD55G1_REG_NEXT_CTX, 0x0, &ret); |
1025 | + | 1025 | + |
1026 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX0, 0, &ret); | 1026 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX0, 0, &ret); |
1027 | + | 1027 | + |
1028 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(0), | 1028 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(0), |
1029 | + VD55G1_VT_MODE_NORMAL, &ret); | 1029 | + VD55G1_VT_MODE_NORMAL, &ret); |
1030 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(0), | 1030 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(0), |
1031 | + VD55G1_MASK_FRAME_CTRL_OUTPUT, &ret); | 1031 | + VD55G1_MASK_FRAME_CTRL_OUTPUT, &ret); |
1032 | + break; | 1032 | + break; |
1033 | + case VD55G1_HDR_SUB: | 1033 | + case VD55G1_HDR_SUB: |
1034 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_MAX_COARSE, | 1034 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_MAX_COARSE, |
1035 | + VD55G1_EXPOSURE_MAX_COARSE_SUB, &ret); | 1035 | + VD55G1_EXPOSURE_MAX_COARSE_SUB, &ret); |
1036 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_USE_CASES, | 1036 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_USE_CASES, |
1037 | + VD55G1_EXPOSURE_USE_CASES_MULTI_CONTEXT, &ret); | 1037 | + VD55G1_EXPOSURE_USE_CASES_MULTI_CONTEXT, &ret); |
1038 | + vd55g1_write(sensor, VD55G1_REG_NEXT_CTX, 0x0001, &ret); | 1038 | + vd55g1_write(sensor, VD55G1_REG_NEXT_CTX, 0x0001, &ret); |
1039 | + | 1039 | + |
1040 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX0, 1, &ret); | 1040 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX0, 1, &ret); |
1041 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX1, 1, &ret); | 1041 | + vd55g1_write(sensor, VD55G1_REG_CTX_REPEAT_COUNT_CTX1, 1, &ret); |
1042 | + | 1042 | + |
1043 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(0), | 1043 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(0), |
1044 | + VD55G1_VT_MODE_NORMAL, &ret); | 1044 | + VD55G1_VT_MODE_NORMAL, &ret); |
1045 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(0), | 1045 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(0), |
1046 | + VD55G1_MASK_FRAME_CTRL_MASK, &ret); | 1046 | + VD55G1_MASK_FRAME_CTRL_MASK, &ret); |
1047 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_INSTANCE(0), 0, &ret); | 1047 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_INSTANCE(0), 0, &ret); |
1048 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(1), | 1048 | + vd55g1_write(sensor, VD55G1_REG_VT_MODE(1), |
1049 | + VD55G1_VT_MODE_SUBTRACTION, &ret); | 1049 | + VD55G1_VT_MODE_SUBTRACTION, &ret); |
1050 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(1), | 1050 | + vd55g1_write(sensor, VD55G1_REG_MASK_FRAME_CTRL(1), |
1051 | + VD55G1_MASK_FRAME_CTRL_OUTPUT, &ret); | 1051 | + VD55G1_MASK_FRAME_CTRL_OUTPUT, &ret); |
1052 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_INSTANCE(1), 1, &ret); | 1052 | + vd55g1_write(sensor, VD55G1_REG_EXPOSURE_INSTANCE(1), 1, &ret); |
1053 | + break; | 1053 | + break; |
1054 | + default: | 1054 | + default: |
1055 | + ret = -EINVAL; | 1055 | + ret = -EINVAL; |
1056 | + } | 1056 | + } |
1057 | + | 1057 | + |
1058 | + return ret; | 1058 | + return ret; |
1059 | +} | 1059 | +} |
1060 | + | 1060 | + |
1061 | +static int vd55g1_set_framefmt(struct vd55g1 *sensor) | 1061 | +static int vd55g1_set_framefmt(struct vd55g1 *sensor) |
1062 | +{ | 1062 | +{ |
1063 | + struct v4l2_subdev_state *state = | 1063 | + struct v4l2_subdev_state *state = |
1064 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 1064 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
1065 | + const struct v4l2_rect *crop = | 1065 | + const struct v4l2_rect *crop = |
1066 | + v4l2_subdev_state_get_crop(state, 0); | 1066 | + v4l2_subdev_state_get_crop(state, 0); |
1067 | + const struct v4l2_mbus_framefmt *format = | 1067 | + const struct v4l2_mbus_framefmt *format = |
1068 | + v4l2_subdev_state_get_format(state, 0); | 1068 | + v4l2_subdev_state_get_format(state, 0); |
1069 | + enum vd55g1_bin_mode binning; | 1069 | + enum vd55g1_bin_mode binning; |
1070 | + int ret = 0; | 1070 | + int ret = 0; |
1071 | + | 1071 | + |
1072 | + vd55g1_write(sensor, VD55G1_REG_FORMAT_CTRL, | 1072 | + vd55g1_write(sensor, VD55G1_REG_FORMAT_CTRL, |
1073 | + get_bpp_by_code(sensor, format->code), &ret); | 1073 | + get_bpp_by_code(sensor, format->code), &ret); |
1074 | + vd55g1_write(sensor, VD55G1_REG_OIF_IMG_CTRL, | 1074 | + vd55g1_write(sensor, VD55G1_REG_OIF_IMG_CTRL, |
1075 | + get_data_type_by_code(sensor, format->code), &ret); | 1075 | + get_data_type_by_code(sensor, format->code), &ret); |
1076 | + | 1076 | + |
1077 | + switch (crop->width / format->width) { | 1077 | + switch (crop->width / format->width) { |
1078 | + case 1: | 1078 | + case 1: |
1079 | + default: | 1079 | + default: |
1080 | + binning = VD55G1_BIN_MODE_NORMAL; | 1080 | + binning = VD55G1_BIN_MODE_NORMAL; |
1081 | + break; | 1081 | + break; |
1082 | + case 2: | 1082 | + case 2: |
1083 | + binning = VD55G1_BIN_MODE_DIGITAL_X2; | 1083 | + binning = VD55G1_BIN_MODE_DIGITAL_X2; |
1084 | + break; | 1084 | + break; |
1085 | + } | 1085 | + } |
1086 | + vd55g1_write(sensor, VD55G1_REG_READOUT_CTRL, binning, &ret); | 1086 | + vd55g1_write(sensor, VD55G1_REG_READOUT_CTRL, binning, &ret); |
1087 | + | 1087 | + |
1088 | + vd55g1_write(sensor, VD55G1_REG_X_START(0), crop->left, &ret); | 1088 | + vd55g1_write(sensor, VD55G1_REG_X_START(0), crop->left, &ret); |
1089 | + vd55g1_write(sensor, VD55G1_REG_X_WIDTH(0), crop->width, &ret); | 1089 | + vd55g1_write(sensor, VD55G1_REG_X_WIDTH(0), crop->width, &ret); |
1090 | + vd55g1_write(sensor, VD55G1_REG_Y_START(0), crop->top, &ret); | 1090 | + vd55g1_write(sensor, VD55G1_REG_Y_START(0), crop->top, &ret); |
1091 | + vd55g1_write(sensor, VD55G1_REG_Y_HEIGHT(0), crop->height, &ret); | 1091 | + vd55g1_write(sensor, VD55G1_REG_Y_HEIGHT(0), crop->height, &ret); |
1092 | + | 1092 | + |
1093 | + vd55g1_write(sensor, VD55G1_REG_X_START(1), crop->left, &ret); | 1093 | + vd55g1_write(sensor, VD55G1_REG_X_START(1), crop->left, &ret); |
1094 | + vd55g1_write(sensor, VD55G1_REG_X_WIDTH(1), crop->width, &ret); | 1094 | + vd55g1_write(sensor, VD55G1_REG_X_WIDTH(1), crop->width, &ret); |
1095 | + vd55g1_write(sensor, VD55G1_REG_Y_START(1), crop->top, &ret); | 1095 | + vd55g1_write(sensor, VD55G1_REG_Y_START(1), crop->top, &ret); |
1096 | + vd55g1_write(sensor, VD55G1_REG_Y_HEIGHT(1), crop->height, &ret); | 1096 | + vd55g1_write(sensor, VD55G1_REG_Y_HEIGHT(1), crop->height, &ret); |
1097 | + | 1097 | + |
1098 | + return ret; | 1098 | + return ret; |
1099 | +} | 1099 | +} |
1100 | + | 1100 | + |
1101 | +static int vd55g1_update_gpios(struct vd55g1 *sensor, unsigned long gpio_mask) | 1101 | +static int vd55g1_update_gpios(struct vd55g1 *sensor, unsigned long gpio_mask) |
1102 | +{ | 1102 | +{ |
1103 | + unsigned long io; | 1103 | + unsigned long io; |
1104 | + u32 gpio_val; | 1104 | + u32 gpio_val; |
1105 | + int ret = 0; | 1105 | + int ret = 0; |
1106 | + | 1106 | + |
1107 | + for_each_set_bit(io, &gpio_mask, VD55G1_NB_GPIOS) { | 1107 | + for_each_set_bit(io, &gpio_mask, VD55G1_NB_GPIOS) { |
1108 | + gpio_val = sensor->gpios[io]; | 1108 | + gpio_val = sensor->gpios[io]; |
1109 | + | 1109 | + |
1110 | + if (gpio_val == VD55G1_GPIO_MODE_STROBE && | 1110 | + if (gpio_val == VD55G1_GPIO_MODE_STROBE && |
1111 | + sensor->led_ctrl->val == V4L2_FLASH_LED_MODE_NONE) { | 1111 | + sensor->led_ctrl->val == V4L2_FLASH_LED_MODE_NONE) { |
1112 | + gpio_val = VD55G1_GPIO_MODE_IN; | 1112 | + gpio_val = VD55G1_GPIO_MODE_IN; |
1113 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) { | 1113 | + if (sensor->hdr_ctrl->val == VD55G1_HDR_SUB) { |
1114 | + /* Make its context 1 counterpart strobe too */ | 1114 | + /* Make its context 1 counterpart strobe too */ |
1115 | + vd55g1_write(sensor, | 1115 | + vd55g1_write(sensor, |
1116 | + VD55G1_REG_GPIO_0_CTRL(1) + io, | 1116 | + VD55G1_REG_GPIO_0_CTRL(1) + io, |
1117 | + gpio_val, &ret); | 1117 | + gpio_val, &ret); |
1118 | + } | 1118 | + } |
1119 | + } | 1119 | + } |
1120 | + | 1120 | + |
1121 | + ret = vd55g1_write(sensor, VD55G1_REG_GPIO_0_CTRL(0) + io, | 1121 | + ret = vd55g1_write(sensor, VD55G1_REG_GPIO_0_CTRL(0) + io, |
1122 | + gpio_val, &ret); | 1122 | + gpio_val, &ret); |
1123 | + } | 1123 | + } |
1124 | + | 1124 | + |
1125 | + return ret; | 1125 | + return ret; |
1126 | +} | 1126 | +} |
1127 | + | 1127 | + |
1128 | +static int vd55g1_ro_ctrls_setup(struct vd55g1 *sensor) | 1128 | +static int vd55g1_ro_ctrls_setup(struct vd55g1 *sensor) |
1129 | +{ | 1129 | +{ |
1130 | + struct v4l2_subdev_state *state = | 1130 | + struct v4l2_subdev_state *state = |
1131 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 1131 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
1132 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 1132 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
1133 | + | 1133 | + |
1134 | + return vd55g1_write(sensor, VD55G1_REG_LINE_LENGTH, | 1134 | + return vd55g1_write(sensor, VD55G1_REG_LINE_LENGTH, |
1135 | + crop->width + sensor->hblank_ctrl->val, NULL); | 1135 | + crop->width + sensor->hblank_ctrl->val, NULL); |
1136 | +} | 1136 | +} |
1137 | + | 1137 | + |
1138 | +static void vd55g1_lock_ctrls(struct vd55g1 *sensor, bool enable) | 1138 | +static void vd55g1_lock_ctrls(struct vd55g1 *sensor, bool enable) |
1139 | +{ | 1139 | +{ |
1140 | + /* These settings cannot change during stream */ | 1140 | + /* These settings cannot change during stream */ |
1141 | + v4l2_ctrl_grab(sensor->hflip_ctrl, enable); | 1141 | + v4l2_ctrl_grab(sensor->hflip_ctrl, enable); |
1142 | + v4l2_ctrl_grab(sensor->vflip_ctrl, enable); | 1142 | + v4l2_ctrl_grab(sensor->vflip_ctrl, enable); |
1143 | + v4l2_ctrl_grab(sensor->patgen_ctrl, enable); | 1143 | + v4l2_ctrl_grab(sensor->patgen_ctrl, enable); |
1144 | + v4l2_ctrl_grab(sensor->hdr_ctrl, enable); | 1144 | + v4l2_ctrl_grab(sensor->hdr_ctrl, enable); |
1145 | + v4l2_ctrl_grab(sensor->hblank_ctrl, enable); | 1145 | + v4l2_ctrl_grab(sensor->hblank_ctrl, enable); |
1146 | +} | 1146 | +} |
1147 | + | 1147 | + |
1148 | +static int vd55g1_enable_streams(struct v4l2_subdev *sd, | 1148 | +static int vd55g1_enable_streams(struct v4l2_subdev *sd, |
1149 | + struct v4l2_subdev_state *state, u32 pad, | 1149 | + struct v4l2_subdev_state *state, u32 pad, |
1150 | + u64 streams_mask) | 1150 | + u64 streams_mask) |
1151 | +{ | 1151 | +{ |
1152 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1152 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1153 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); | 1153 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); |
1154 | + int ret = 0; | 1154 | + int ret = 0; |
1155 | + | 1155 | + |
1156 | + ret = pm_runtime_resume_and_get(&client->dev); | 1156 | + ret = pm_runtime_resume_and_get(&client->dev); |
1157 | + if (ret < 0) | 1157 | + if (ret < 0) |
1158 | + return ret; | 1158 | + return ret; |
1159 | + | 1159 | + |
1160 | + vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret); | 1160 | + vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret); |
1161 | + | 1161 | + |
1162 | + /* configure output */ | 1162 | + /* configure output */ |
1163 | + vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE, | 1163 | + vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE, |
1164 | + sensor->data_rate_in_mbps, &ret); | 1164 | + sensor->data_rate_in_mbps, &ret); |
1165 | + vd55g1_write(sensor, VD55G1_REG_OIF_CTRL, sensor->oif_ctrl, &ret); | 1165 | + vd55g1_write(sensor, VD55G1_REG_OIF_CTRL, sensor->oif_ctrl, &ret); |
1166 | + vd55g1_write(sensor, VD55G1_REG_ISL_ENABLE, 0, &ret); | 1166 | + vd55g1_write(sensor, VD55G1_REG_ISL_ENABLE, 0, &ret); |
1167 | + if (ret) | 1167 | + if (ret) |
1168 | + goto err_rpm_put; | 1168 | + goto err_rpm_put; |
1169 | + | 1169 | + |
1170 | + ret = vd55g1_set_framefmt(sensor); | 1170 | + ret = vd55g1_set_framefmt(sensor); |
1171 | + if (ret) | 1171 | + if (ret) |
1172 | + goto err_rpm_put; | 1172 | + goto err_rpm_put; |
1173 | + | 1173 | + |
1174 | + /* Setup default GPIO values; could be overridden by V4L2 ctrl setup */ | 1174 | + /* Setup default GPIO values; could be overridden by V4L2 ctrl setup */ |
1175 | + ret = vd55g1_update_gpios(sensor, GENMASK(VD55G1_NB_GPIOS - 1, 0)); | 1175 | + ret = vd55g1_update_gpios(sensor, GENMASK(VD55G1_NB_GPIOS - 1, 0)); |
1176 | + if (ret) | 1176 | + if (ret) |
1177 | + goto err_rpm_put; | 1177 | + goto err_rpm_put; |
1178 | + | 1178 | + |
1179 | + ret = vd55g1_apply_cold_start(sensor); | 1179 | + ret = vd55g1_apply_cold_start(sensor); |
1180 | + if (ret) | 1180 | + if (ret) |
1181 | + goto err_rpm_put; | 1181 | + goto err_rpm_put; |
1182 | + | 1182 | + |
1183 | + /* Apply settings from V4L2 ctrls */ | 1183 | + /* Apply settings from V4L2 ctrls */ |
1184 | + ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); | 1184 | + ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); |
1185 | + if (ret) | 1185 | + if (ret) |
1186 | + goto err_rpm_put; | 1186 | + goto err_rpm_put; |
1187 | + | 1187 | + |
1188 | + /* Also apply settings from read-only V4L2 ctrls */ | 1188 | + /* Also apply settings from read-only V4L2 ctrls */ |
1189 | + ret = vd55g1_ro_ctrls_setup(sensor); | 1189 | + ret = vd55g1_ro_ctrls_setup(sensor); |
1190 | + if (ret) | 1190 | + if (ret) |
1191 | + goto err_rpm_put; | 1191 | + goto err_rpm_put; |
1192 | + | 1192 | + |
1193 | + /* Start streaming */ | 1193 | + /* Start streaming */ |
1194 | + vd55g1_write(sensor, VD55G1_REG_STBY, VD55G1_STBY_START_STREAM, &ret); | 1194 | + vd55g1_write(sensor, VD55G1_REG_STBY, VD55G1_STBY_START_STREAM, &ret); |
1195 | + vd55g1_poll_reg(sensor, VD55G1_REG_STBY, 0, &ret); | 1195 | + vd55g1_poll_reg(sensor, VD55G1_REG_STBY, 0, &ret); |
1196 | + vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_STREAMING, &ret); | 1196 | + vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_STREAMING, &ret); |
1197 | + if (ret) | 1197 | + if (ret) |
1198 | + goto err_rpm_put; | 1198 | + goto err_rpm_put; |
1199 | + | 1199 | + |
1200 | + vd55g1_lock_ctrls(sensor, true); | 1200 | + vd55g1_lock_ctrls(sensor, true); |
1201 | + | 1201 | + |
1202 | + return ret; | 1202 | + return ret; |
1203 | + | 1203 | + |
1204 | +err_rpm_put: | 1204 | +err_rpm_put: |
1205 | + pm_runtime_put(&client->dev); | 1205 | + pm_runtime_put(&client->dev); |
1206 | + return ret; | 1206 | + return ret; |
1207 | +} | 1207 | +} |
1208 | + | 1208 | + |
1209 | +static int vd55g1_disable_streams(struct v4l2_subdev *sd, | 1209 | +static int vd55g1_disable_streams(struct v4l2_subdev *sd, |
1210 | + struct v4l2_subdev_state *state, u32 pad, | 1210 | + struct v4l2_subdev_state *state, u32 pad, |
1211 | + u64 streams_mask) | 1211 | + u64 streams_mask) |
1212 | +{ | 1212 | +{ |
1213 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1213 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1214 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); | 1214 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); |
1215 | + int ret = 0; | 1215 | + int ret = 0; |
1216 | + | 1216 | + |
1217 | + /* Retrieve Expo cluster to enable coldstart of AE */ | 1217 | + /* Retrieve Expo cluster to enable coldstart of AE */ |
1218 | + ret = vd55g1_read_expo_cluster(sensor); | 1218 | + ret = vd55g1_read_expo_cluster(sensor); |
1219 | + | 1219 | + |
1220 | + vd55g1_write(sensor, VD55G1_REG_STREAMING, VD55G1_STREAMING_STOP_STREAM, | 1220 | + vd55g1_write(sensor, VD55G1_REG_STREAMING, VD55G1_STREAMING_STOP_STREAM, |
1221 | + &ret); | 1221 | + &ret); |
1222 | + vd55g1_poll_reg(sensor, VD55G1_REG_STREAMING, 0, &ret); | 1222 | + vd55g1_poll_reg(sensor, VD55G1_REG_STREAMING, 0, &ret); |
1223 | + vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, &ret); | 1223 | + vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, &ret); |
1224 | + | 1224 | + |
1225 | + if (ret) | 1225 | + if (ret) |
1226 | + dev_warn(&client->dev, "Can't disable stream"); | 1226 | + dev_warn(&client->dev, "Can't disable stream"); |
1227 | + | 1227 | + |
1228 | + vd55g1_lock_ctrls(sensor, false); | 1228 | + vd55g1_lock_ctrls(sensor, false); |
1229 | + | 1229 | + |
1230 | + pm_runtime_mark_last_busy(&client->dev); | 1230 | + pm_runtime_mark_last_busy(&client->dev); |
1231 | + __pm_runtime_put_autosuspend(&client->dev); | 1231 | + __pm_runtime_put_autosuspend(&client->dev); |
1232 | + | 1232 | + |
1233 | + return ret; | 1233 | + return ret; |
1234 | +} | 1234 | +} |
1235 | + | 1235 | + |
1236 | +static int vd55g1_patch(struct vd55g1 *sensor) | 1236 | +static int vd55g1_patch(struct vd55g1 *sensor) |
1237 | +{ | 1237 | +{ |
1238 | + struct i2c_client *client = sensor->i2c_client; | 1238 | + struct i2c_client *client = sensor->i2c_client; |
1239 | + u64 patch; | 1239 | + u64 patch; |
1240 | + int ret = 0; | 1240 | + int ret = 0; |
1241 | + | 1241 | + |
1242 | + vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, | 1242 | + vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, |
1243 | + sizeof(patch_array), patch_array, &ret); | 1243 | + sizeof(patch_array), patch_array, &ret); |
1244 | + vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_PATCH_SETUP, &ret); | 1244 | + vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_PATCH_SETUP, &ret); |
1245 | + vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret); | 1245 | + vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret); |
1246 | + if (ret) { | 1246 | + if (ret) { |
1247 | + dev_err(&client->dev, "Failed to apply patch"); | 1247 | + dev_err(&client->dev, "Failed to apply patch"); |
1248 | + return ret; | 1248 | + return ret; |
1249 | + } | 1249 | + } |
1250 | + | 1250 | + |
1251 | + vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret); | 1251 | + vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret); |
1252 | + if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) + | 1252 | + if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) + |
1253 | + VD55G1_FWPATCH_REVISION_MINOR) { | 1253 | + VD55G1_FWPATCH_REVISION_MINOR) { |
1254 | + dev_err(&client->dev, "Bad patch version expected %d.%d got %d.%d", | 1254 | + dev_err(&client->dev, "Bad patch version expected %d.%d got %d.%d", |
1255 | + VD55G1_FWPATCH_REVISION_MAJOR, | 1255 | + VD55G1_FWPATCH_REVISION_MAJOR, |
1256 | + VD55G1_FWPATCH_REVISION_MINOR, | 1256 | + VD55G1_FWPATCH_REVISION_MINOR, |
1257 | + (u8)(patch >> 8), (u8)(patch & 0xff)); | 1257 | + (u8)(patch >> 8), (u8)(patch & 0xff)); |
1258 | + return -ENODEV; | 1258 | + return -ENODEV; |
1259 | + } | 1259 | + } |
1260 | + dev_dbg(&client->dev, "patch %d.%d applied", | 1260 | + dev_dbg(&client->dev, "patch %d.%d applied", |
1261 | + (u8)(patch >> 8), (u8)(patch & 0xff)); | 1261 | + (u8)(patch >> 8), (u8)(patch & 0xff)); |
1262 | + | 1262 | + |
1263 | + return 0; | 1263 | + return 0; |
1264 | +} | 1264 | +} |
1265 | + | 1265 | + |
1266 | +static int vd55g1_get_selection(struct v4l2_subdev *sd, | 1266 | +static int vd55g1_get_selection(struct v4l2_subdev *sd, |
1267 | + struct v4l2_subdev_state *sd_state, | 1267 | + struct v4l2_subdev_state *sd_state, |
1268 | + struct v4l2_subdev_selection *sel) | 1268 | + struct v4l2_subdev_selection *sel) |
1269 | +{ | 1269 | +{ |
1270 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(sd_state, 0); | 1270 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(sd_state, 0); |
1271 | + | 1271 | + |
1272 | + switch (sel->target) { | 1272 | + switch (sel->target) { |
1273 | + case V4L2_SEL_TGT_CROP: | 1273 | + case V4L2_SEL_TGT_CROP: |
1274 | + sel->r = *crop; | 1274 | + sel->r = *crop; |
1275 | + return 0; | 1275 | + return 0; |
1276 | + case V4L2_SEL_TGT_NATIVE_SIZE: | 1276 | + case V4L2_SEL_TGT_NATIVE_SIZE: |
1277 | + case V4L2_SEL_TGT_CROP_DEFAULT: | 1277 | + case V4L2_SEL_TGT_CROP_DEFAULT: |
1278 | + case V4L2_SEL_TGT_CROP_BOUNDS: | 1278 | + case V4L2_SEL_TGT_CROP_BOUNDS: |
1279 | + sel->r.top = 0; | 1279 | + sel->r.top = 0; |
1280 | + sel->r.left = 0; | 1280 | + sel->r.left = 0; |
1281 | + sel->r.width = VD55G1_WIDTH; | 1281 | + sel->r.width = VD55G1_WIDTH; |
1282 | + sel->r.height = VD55G1_HEIGHT; | 1282 | + sel->r.height = VD55G1_HEIGHT; |
1283 | + return 0; | 1283 | + return 0; |
1284 | + } | 1284 | + } |
1285 | + | 1285 | + |
1286 | + return -EINVAL; | 1286 | + return -EINVAL; |
1287 | +} | 1287 | +} |
1288 | + | 1288 | + |
1289 | +static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd, | 1289 | +static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd, |
1290 | + struct v4l2_subdev_state *sd_state, | 1290 | + struct v4l2_subdev_state *sd_state, |
1291 | + struct v4l2_subdev_mbus_code_enum *code) | 1291 | + struct v4l2_subdev_mbus_code_enum *code) |
1292 | +{ | 1292 | +{ |
1293 | + if (code->index >= ARRAY_SIZE(vd55g1_mbus_codes)) | 1293 | + if (code->index >= ARRAY_SIZE(vd55g1_mbus_codes)) |
1294 | + return -EINVAL; | 1294 | + return -EINVAL; |
1295 | + | 1295 | + |
1296 | + code->code = vd55g1_mbus_codes[code->index].code; | 1296 | + code->code = vd55g1_mbus_codes[code->index].code; |
1297 | + | 1297 | + |
1298 | + return 0; | 1298 | + return 0; |
1299 | +} | 1299 | +} |
1300 | + | 1300 | + |
1301 | +static int vd55g1_new_format_change_controls(struct vd55g1 *sensor) | 1301 | +static int vd55g1_new_format_change_controls(struct vd55g1 *sensor) |
1302 | +{ | 1302 | +{ |
1303 | + struct v4l2_subdev_state *state = | 1303 | + struct v4l2_subdev_state *state = |
1304 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 1304 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
1305 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 1305 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
1306 | + struct vblank_limits vblank; | 1306 | + struct vblank_limits vblank; |
1307 | + unsigned int hblank; | 1307 | + unsigned int hblank; |
1308 | + unsigned int frame_length = 0; | 1308 | + unsigned int frame_length = 0; |
1309 | + unsigned int expo_max; | 1309 | + unsigned int expo_max; |
1310 | + int ret; | 1310 | + int ret; |
1311 | + | 1311 | + |
1312 | + /* Reset vblank and frame length to default */ | 1312 | + /* Reset vblank and frame length to default */ |
1313 | + vblank = get_vblank_limits(sensor); | 1313 | + vblank = get_vblank_limits(sensor); |
1314 | + ret = __v4l2_ctrl_modify_range(sensor->vblank_ctrl, vblank.min, | 1314 | + ret = __v4l2_ctrl_modify_range(sensor->vblank_ctrl, vblank.min, |
1315 | + vblank.max, 1, vblank.def); | 1315 | + vblank.max, 1, vblank.def); |
1316 | + if (ret) | 1316 | + if (ret) |
1317 | + return ret; | 1317 | + return ret; |
1318 | + | 1318 | + |
1319 | + /* Max exposure changes with vblank */ | 1319 | + /* Max exposure changes with vblank */ |
1320 | + frame_length = crop->height + sensor->vblank_ctrl->val; | 1320 | + frame_length = crop->height + sensor->vblank_ctrl->val; |
1321 | + expo_max = frame_length - VD55G1_EXPO_MAX_TERM; | 1321 | + expo_max = frame_length - VD55G1_EXPO_MAX_TERM; |
1322 | + ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1, | 1322 | + ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1, |
1323 | + VD55G1_EXPO_DEF); | 1323 | + VD55G1_EXPO_DEF); |
1324 | + if (ret) | 1324 | + if (ret) |
1325 | + return ret; | 1325 | + return ret; |
1326 | + | 1326 | + |
1327 | + /* Update pixel rate to reflect new bpp */ | 1327 | + /* Update pixel rate to reflect new bpp */ |
1328 | + ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl, | 1328 | + ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl, |
1329 | + get_pixel_rate(sensor)); | 1329 | + get_pixel_rate(sensor)); |
1330 | + if (ret) | 1330 | + if (ret) |
1331 | + return ret; | 1331 | + return ret; |
1332 | + | 1332 | + |
1333 | + /* Update hblank according to new width */ | 1333 | + /* Update hblank according to new width */ |
1334 | + hblank = get_hblank_min(sensor); | 1334 | + hblank = get_hblank_min(sensor); |
1335 | + ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, | 1335 | + ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, |
1336 | + hblank); | 1336 | + hblank); |
1337 | + | 1337 | + |
1338 | + return ret; | 1338 | + return ret; |
1339 | +} | 1339 | +} |
1340 | + | 1340 | + |
1341 | +static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd, | 1341 | +static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd, |
1342 | + struct v4l2_subdev_state *sd_state, | 1342 | + struct v4l2_subdev_state *sd_state, |
1343 | + struct v4l2_subdev_format *sd_fmt) | 1343 | + struct v4l2_subdev_format *sd_fmt) |
1344 | +{ | 1344 | +{ |
1345 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1345 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1346 | + const struct vd55g1_mode *new_mode; | 1346 | + const struct vd55g1_mode *new_mode; |
1347 | + struct v4l2_mbus_framefmt *format; | 1347 | + struct v4l2_mbus_framefmt *format; |
1348 | + struct v4l2_rect pad_crop; | 1348 | + struct v4l2_rect pad_crop; |
1349 | + unsigned int binning; | 1349 | + unsigned int binning; |
1350 | + | 1350 | + |
1351 | + new_mode = v4l2_find_nearest_size(vd55g1_supported_modes, | 1351 | + new_mode = v4l2_find_nearest_size(vd55g1_supported_modes, |
1352 | + ARRAY_SIZE(vd55g1_supported_modes), | 1352 | + ARRAY_SIZE(vd55g1_supported_modes), |
1353 | + width, height, sd_fmt->format.width, | 1353 | + width, height, sd_fmt->format.width, |
1354 | + sd_fmt->format.height); | 1354 | + sd_fmt->format.height); |
1355 | + | 1355 | + |
1356 | + vd55g1_update_img_pad_format(sensor, new_mode, sd_fmt->format.code, | 1356 | + vd55g1_update_img_pad_format(sensor, new_mode, sd_fmt->format.code, |
1357 | + &sd_fmt->format); | 1357 | + &sd_fmt->format); |
1358 | + | 1358 | + |
1359 | + /* | 1359 | + /* |
1360 | + * Use binning to maximize the crop rectangle size, and centre it in the | 1360 | + * Use binning to maximize the crop rectangle size, and centre it in the |
1361 | + * sensor. | 1361 | + * sensor. |
1362 | + */ | 1362 | + */ |
1363 | + binning = min(VD55G1_WIDTH / sd_fmt->format.width, | 1363 | + binning = min(VD55G1_WIDTH / sd_fmt->format.width, |
1364 | + VD55G1_HEIGHT / sd_fmt->format.height); | 1364 | + VD55G1_HEIGHT / sd_fmt->format.height); |
1365 | + binning = min(binning, 2U); | 1365 | + binning = min(binning, 2U); |
1366 | + pad_crop.width = sd_fmt->format.width * binning; | 1366 | + pad_crop.width = sd_fmt->format.width * binning; |
1367 | + pad_crop.height = sd_fmt->format.height * binning; | 1367 | + pad_crop.height = sd_fmt->format.height * binning; |
1368 | + pad_crop.left = (VD55G1_WIDTH - pad_crop.width) / 2; | 1368 | + pad_crop.left = (VD55G1_WIDTH - pad_crop.width) / 2; |
1369 | + pad_crop.top = (VD55G1_HEIGHT - pad_crop.height) / 2; | 1369 | + pad_crop.top = (VD55G1_HEIGHT - pad_crop.height) / 2; |
1370 | + | 1370 | + |
1371 | + format = v4l2_subdev_state_get_format(sd_state, sd_fmt->pad); | 1371 | + format = v4l2_subdev_state_get_format(sd_state, sd_fmt->pad); |
1372 | + | 1372 | + |
1373 | + *format = sd_fmt->format; | 1373 | + *format = sd_fmt->format; |
1374 | + | 1374 | + |
1375 | + *v4l2_subdev_state_get_crop(sd_state, sd_fmt->pad) = pad_crop; | 1375 | + *v4l2_subdev_state_get_crop(sd_state, sd_fmt->pad) = pad_crop; |
1376 | + if (sd_fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 1376 | + if (sd_fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
1377 | + return vd55g1_new_format_change_controls(sensor); | 1377 | + return vd55g1_new_format_change_controls(sensor); |
1378 | + | 1378 | + |
1379 | + return 0; | 1379 | + return 0; |
1380 | +} | 1380 | +} |
1381 | + | 1381 | + |
1382 | +static int vd55g1_init_state(struct v4l2_subdev *sd, | 1382 | +static int vd55g1_init_state(struct v4l2_subdev *sd, |
1383 | + struct v4l2_subdev_state *sd_state) | 1383 | + struct v4l2_subdev_state *sd_state) |
1384 | +{ | 1384 | +{ |
1385 | + unsigned int def_mode = VD55G1_DEFAULT_MODE; | 1385 | + unsigned int def_mode = VD55G1_DEFAULT_MODE; |
1386 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1386 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1387 | + struct v4l2_subdev_format fmt = { 0 }; | 1387 | + struct v4l2_subdev_format fmt = { 0 }; |
1388 | + struct v4l2_subdev_route routes[] = { 0 }; | 1388 | + struct v4l2_subdev_route routes[] = { 0 }; |
1389 | + struct v4l2_subdev_krouting routing = { | 1389 | + struct v4l2_subdev_krouting routing = { |
1390 | + .num_routes = ARRAY_SIZE(routes), | 1390 | + .num_routes = ARRAY_SIZE(routes), |
1391 | + .routes = routes, | 1391 | + .routes = routes, |
1392 | + }; | 1392 | + }; |
1393 | + int ret; | 1393 | + int ret; |
1394 | + | 1394 | + |
1395 | + /* Needed by v4l2_subdev_s_stream_helper(), even with 1 stream only */ | 1395 | + /* Needed by v4l2_subdev_s_stream_helper(), even with 1 stream only */ |
1396 | + routes[0].flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; | 1396 | + routes[0].flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; |
1397 | + ret = v4l2_subdev_set_routing(sd, sd_state, &routing); | 1397 | + ret = v4l2_subdev_set_routing(sd, sd_state, &routing); |
1398 | + if (ret) | 1398 | + if (ret) |
1399 | + return ret; | 1399 | + return ret; |
1400 | + | 1400 | + |
1401 | + vd55g1_update_img_pad_format(sensor, &vd55g1_supported_modes[def_mode], | 1401 | + vd55g1_update_img_pad_format(sensor, &vd55g1_supported_modes[def_mode], |
1402 | + VD55G1_MEDIA_BUS_FMT_DEF, &fmt.format); | 1402 | + VD55G1_MEDIA_BUS_FMT_DEF, &fmt.format); |
1403 | + | 1403 | + |
1404 | + return vd55g1_set_pad_fmt(sd, sd_state, &fmt); | 1404 | + return vd55g1_set_pad_fmt(sd, sd_state, &fmt); |
1405 | +} | 1405 | +} |
1406 | + | 1406 | + |
1407 | +static int vd55g1_enum_frame_size(struct v4l2_subdev *sd, | 1407 | +static int vd55g1_enum_frame_size(struct v4l2_subdev *sd, |
1408 | + struct v4l2_subdev_state *sd_state, | 1408 | + struct v4l2_subdev_state *sd_state, |
1409 | + struct v4l2_subdev_frame_size_enum *fse) | 1409 | + struct v4l2_subdev_frame_size_enum *fse) |
1410 | +{ | 1410 | +{ |
1411 | + if (fse->index >= ARRAY_SIZE(vd55g1_supported_modes)) | 1411 | + if (fse->index >= ARRAY_SIZE(vd55g1_supported_modes)) |
1412 | + return -EINVAL; | 1412 | + return -EINVAL; |
1413 | + | 1413 | + |
1414 | + fse->min_width = vd55g1_supported_modes[fse->index].width; | 1414 | + fse->min_width = vd55g1_supported_modes[fse->index].width; |
1415 | + fse->max_width = fse->min_width; | 1415 | + fse->max_width = fse->min_width; |
1416 | + fse->min_height = vd55g1_supported_modes[fse->index].height; | 1416 | + fse->min_height = vd55g1_supported_modes[fse->index].height; |
1417 | + fse->max_height = fse->min_height; | 1417 | + fse->max_height = fse->min_height; |
1418 | + | 1418 | + |
1419 | + return 0; | 1419 | + return 0; |
1420 | +} | 1420 | +} |
1421 | + | 1421 | + |
1422 | +static const struct v4l2_subdev_internal_ops vd55g1_internal_ops = { | 1422 | +static const struct v4l2_subdev_internal_ops vd55g1_internal_ops = { |
1423 | + .init_state = vd55g1_init_state, | 1423 | + .init_state = vd55g1_init_state, |
1424 | +}; | 1424 | +}; |
1425 | + | 1425 | + |
1426 | +static const struct v4l2_subdev_pad_ops vd55g1_pad_ops = { | 1426 | +static const struct v4l2_subdev_pad_ops vd55g1_pad_ops = { |
1427 | + .enum_mbus_code = vd55g1_enum_mbus_code, | 1427 | + .enum_mbus_code = vd55g1_enum_mbus_code, |
1428 | + .get_fmt = v4l2_subdev_get_fmt, | 1428 | + .get_fmt = v4l2_subdev_get_fmt, |
1429 | + .set_fmt = vd55g1_set_pad_fmt, | 1429 | + .set_fmt = vd55g1_set_pad_fmt, |
1430 | + .get_selection = vd55g1_get_selection, | 1430 | + .get_selection = vd55g1_get_selection, |
1431 | + .enum_frame_size = vd55g1_enum_frame_size, | 1431 | + .enum_frame_size = vd55g1_enum_frame_size, |
1432 | + .enable_streams = vd55g1_enable_streams, | 1432 | + .enable_streams = vd55g1_enable_streams, |
1433 | + .disable_streams = vd55g1_disable_streams, | 1433 | + .disable_streams = vd55g1_disable_streams, |
1434 | +}; | 1434 | +}; |
1435 | + | 1435 | + |
1436 | +static const struct v4l2_subdev_video_ops vd55g1_video_ops = { | 1436 | +static const struct v4l2_subdev_video_ops vd55g1_video_ops = { |
1437 | + .s_stream = v4l2_subdev_s_stream_helper, | 1437 | + .s_stream = v4l2_subdev_s_stream_helper, |
1438 | +}; | 1438 | +}; |
1439 | + | 1439 | + |
1440 | +static const struct v4l2_subdev_ops vd55g1_subdev_ops = { | 1440 | +static const struct v4l2_subdev_ops vd55g1_subdev_ops = { |
1441 | + .video = &vd55g1_video_ops, | 1441 | + .video = &vd55g1_video_ops, |
1442 | + .pad = &vd55g1_pad_ops, | 1442 | + .pad = &vd55g1_pad_ops, |
1443 | +}; | 1443 | +}; |
1444 | + | 1444 | + |
1445 | +static int vd55g1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | 1445 | +static int vd55g1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
1446 | +{ | 1446 | +{ |
1447 | + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | 1447 | + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); |
1448 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1448 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1449 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | 1449 | + struct i2c_client *client = v4l2_get_subdevdata(sd); |
1450 | + int ret = 0; | 1450 | + int ret = 0; |
1451 | + | 1451 | + |
1452 | + /* Interact with HW only when it is powered ON */ | 1452 | + /* Interact with HW only when it is powered ON */ |
1453 | + if (!pm_runtime_get_if_in_use(&client->dev)) | 1453 | + if (!pm_runtime_get_if_in_use(&client->dev)) |
1454 | + return 0; | 1454 | + return 0; |
1455 | + | 1455 | + |
1456 | + switch (ctrl->id) { | 1456 | + switch (ctrl->id) { |
1457 | + case V4L2_CID_EXPOSURE_AUTO: | 1457 | + case V4L2_CID_EXPOSURE_AUTO: |
1458 | + ret = vd55g1_read_expo_cluster(sensor); | 1458 | + ret = vd55g1_read_expo_cluster(sensor); |
1459 | + break; | 1459 | + break; |
1460 | + default: | 1460 | + default: |
1461 | + ret = -EINVAL; | 1461 | + ret = -EINVAL; |
1462 | + break; | 1462 | + break; |
1463 | + } | 1463 | + } |
1464 | + | 1464 | + |
1465 | + pm_runtime_mark_last_busy(&client->dev); | 1465 | + pm_runtime_mark_last_busy(&client->dev); |
1466 | + pm_runtime_put_autosuspend(&client->dev); | 1466 | + pm_runtime_put_autosuspend(&client->dev); |
1467 | + | 1467 | + |
1468 | + return ret; | 1468 | + return ret; |
1469 | +} | 1469 | +} |
1470 | + | 1470 | + |
1471 | +static int vd55g1_s_ctrl(struct v4l2_ctrl *ctrl) | 1471 | +static int vd55g1_s_ctrl(struct v4l2_ctrl *ctrl) |
1472 | +{ | 1472 | +{ |
1473 | + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | 1473 | + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); |
1474 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1474 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1475 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | 1475 | + struct i2c_client *client = v4l2_get_subdevdata(sd); |
1476 | + unsigned int frame_length = 0; | 1476 | + unsigned int frame_length = 0; |
1477 | + unsigned int expo_max; | 1477 | + unsigned int expo_max; |
1478 | + unsigned int hblank = get_hblank_min(sensor); | 1478 | + unsigned int hblank = get_hblank_min(sensor); |
1479 | + bool is_auto = false; | 1479 | + bool is_auto = false; |
1480 | + struct v4l2_subdev_state *state = | 1480 | + struct v4l2_subdev_state *state = |
1481 | + v4l2_subdev_get_locked_active_state(&sensor->sd); | 1481 | + v4l2_subdev_get_locked_active_state(&sensor->sd); |
1482 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); | 1482 | + const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0); |
1483 | + int ret = 0; | 1483 | + int ret = 0; |
1484 | + | 1484 | + |
1485 | + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) | 1485 | + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) |
1486 | + return 0; | 1486 | + return 0; |
1487 | + | 1487 | + |
1488 | + /* Update controls state, range, etc. whatever the state of the HW */ | 1488 | + /* Update controls state, range, etc. whatever the state of the HW */ |
1489 | + switch (ctrl->id) { | 1489 | + switch (ctrl->id) { |
1490 | + case V4L2_CID_VBLANK: | 1490 | + case V4L2_CID_VBLANK: |
1491 | + frame_length = crop->height + ctrl->val; | 1491 | + frame_length = crop->height + ctrl->val; |
1492 | + expo_max = frame_length - VD55G1_EXPO_MAX_TERM; | 1492 | + expo_max = frame_length - VD55G1_EXPO_MAX_TERM; |
1493 | + ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, | 1493 | + ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, |
1494 | + 1, VD55G1_EXPO_DEF); | 1494 | + 1, VD55G1_EXPO_DEF); |
1495 | + break; | 1495 | + break; |
1496 | + case V4L2_CID_EXPOSURE_AUTO: | 1496 | + case V4L2_CID_EXPOSURE_AUTO: |
1497 | + is_auto = (ctrl->val == V4L2_EXPOSURE_AUTO); | 1497 | + is_auto = (ctrl->val == V4L2_EXPOSURE_AUTO); |
1498 | + __v4l2_ctrl_grab(sensor->ae_lock_ctrl, !is_auto); | 1498 | + __v4l2_ctrl_grab(sensor->ae_lock_ctrl, !is_auto); |
1499 | + __v4l2_ctrl_grab(sensor->ae_bias_ctrl, !is_auto); | 1499 | + __v4l2_ctrl_grab(sensor->ae_bias_ctrl, !is_auto); |
1500 | + break; | 1500 | + break; |
1501 | + case V4L2_CID_HDR_SENSOR_MODE: | 1501 | + case V4L2_CID_HDR_SENSOR_MODE: |
1502 | + /* Discriminate if the userspace changed the control value */ | 1502 | + /* Discriminate if the userspace changed the control value */ |
1503 | + if (ctrl->val != ctrl->cur.val) { | 1503 | + if (ctrl->val != ctrl->cur.val) { |
1504 | + /* Max horizontal blanking changes with hdr mode */ | 1504 | + /* Max horizontal blanking changes with hdr mode */ |
1505 | + ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, | 1505 | + ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, |
1506 | + hblank, hblank, 1, | 1506 | + hblank, hblank, 1, |
1507 | + hblank); | 1507 | + hblank); |
1508 | + } | 1508 | + } |
1509 | + break; | 1509 | + break; |
1510 | + default: | 1510 | + default: |
1511 | + break; | 1511 | + break; |
1512 | + } | 1512 | + } |
1513 | + | 1513 | + |
1514 | + /* Don't modify hardware if controls modification failed */ | 1514 | + /* Don't modify hardware if controls modification failed */ |
1515 | + if (ret) | 1515 | + if (ret) |
1516 | + return ret; | 1516 | + return ret; |
1517 | + | 1517 | + |
1518 | + /* Interact with HW only when it is powered ON */ | 1518 | + /* Interact with HW only when it is powered ON */ |
1519 | + if (!pm_runtime_get_if_in_use(&client->dev)) | 1519 | + if (!pm_runtime_get_if_in_use(&client->dev)) |
1520 | + return 0; | 1520 | + return 0; |
1521 | + | 1521 | + |
1522 | + switch (ctrl->id) { | 1522 | + switch (ctrl->id) { |
1523 | + case V4L2_CID_HFLIP: | 1523 | + case V4L2_CID_HFLIP: |
1524 | + ret = vd55g1_write(sensor, VD55G1_REG_ORIENTATION, | 1524 | + ret = vd55g1_write(sensor, VD55G1_REG_ORIENTATION, |
1525 | + sensor->hflip_ctrl->val | | 1525 | + sensor->hflip_ctrl->val | |
1526 | + (sensor->vflip_ctrl->val << 1), | 1526 | + (sensor->vflip_ctrl->val << 1), |
1527 | + NULL); | 1527 | + NULL); |
1528 | + break; | 1528 | + break; |
1529 | + case V4L2_CID_TEST_PATTERN: | 1529 | + case V4L2_CID_TEST_PATTERN: |
1530 | + ret = vd55g1_update_patgen(sensor, ctrl->val); | 1530 | + ret = vd55g1_update_patgen(sensor, ctrl->val); |
1531 | + break; | 1531 | + break; |
1532 | + case V4L2_CID_EXPOSURE_AUTO: | 1532 | + case V4L2_CID_EXPOSURE_AUTO: |
1533 | + ret = vd55g1_update_expo_cluster(sensor, is_auto); | 1533 | + ret = vd55g1_update_expo_cluster(sensor, is_auto); |
1534 | + break; | 1534 | + break; |
1535 | + case V4L2_CID_3A_LOCK: | 1535 | + case V4L2_CID_3A_LOCK: |
1536 | + ret = vd55g1_lock_exposure(sensor, ctrl->val); | 1536 | + ret = vd55g1_lock_exposure(sensor, ctrl->val); |
1537 | + break; | 1537 | + break; |
1538 | + case V4L2_CID_AUTO_EXPOSURE_BIAS: | 1538 | + case V4L2_CID_AUTO_EXPOSURE_BIAS: |
1539 | + /* | 1539 | + /* |
1540 | + * We use auto exposure target percentage register to control | 1540 | + * We use auto exposure target percentage register to control |
1541 | + * exposure bias for more precision. | 1541 | + * exposure bias for more precision. |
1542 | + */ | 1542 | + */ |
1543 | + ret = vd55g1_update_exposure_target(sensor, ctrl->val); | 1543 | + ret = vd55g1_update_exposure_target(sensor, ctrl->val); |
1544 | + break; | 1544 | + break; |
1545 | + case V4L2_CID_VBLANK: | 1545 | + case V4L2_CID_VBLANK: |
1546 | + ret = vd55g1_update_frame_length(sensor, frame_length); | 1546 | + ret = vd55g1_update_frame_length(sensor, frame_length); |
1547 | + break; | 1547 | + break; |
1548 | + case V4L2_CID_FLASH_LED_MODE: | 1548 | + case V4L2_CID_FLASH_LED_MODE: |
1549 | + ret = vd55g1_update_gpios(sensor, sensor->ext_leds_mask); | 1549 | + ret = vd55g1_update_gpios(sensor, sensor->ext_leds_mask); |
1550 | + break; | 1550 | + break; |
1551 | + case V4L2_CID_HDR_SENSOR_MODE: | 1551 | + case V4L2_CID_HDR_SENSOR_MODE: |
1552 | + ret = vd55g1_update_hdr_mode(sensor); | 1552 | + ret = vd55g1_update_hdr_mode(sensor); |
1553 | + break; | 1553 | + break; |
1554 | + default: | 1554 | + default: |
1555 | + ret = -EINVAL; | 1555 | + ret = -EINVAL; |
1556 | + break; | 1556 | + break; |
1557 | + } | 1557 | + } |
1558 | + | 1558 | + |
1559 | + pm_runtime_mark_last_busy(&client->dev); | 1559 | + pm_runtime_mark_last_busy(&client->dev); |
1560 | + pm_runtime_put_autosuspend(&client->dev); | 1560 | + pm_runtime_put_autosuspend(&client->dev); |
1561 | + | 1561 | + |
1562 | + return ret; | 1562 | + return ret; |
1563 | +} | 1563 | +} |
1564 | + | 1564 | + |
1565 | +static const struct v4l2_ctrl_ops vd55g1_ctrl_ops = { | 1565 | +static const struct v4l2_ctrl_ops vd55g1_ctrl_ops = { |
1566 | + .g_volatile_ctrl = vd55g1_g_volatile_ctrl, | 1566 | + .g_volatile_ctrl = vd55g1_g_volatile_ctrl, |
1567 | + .s_ctrl = vd55g1_s_ctrl, | 1567 | + .s_ctrl = vd55g1_s_ctrl, |
1568 | +}; | 1568 | +}; |
1569 | + | 1569 | + |
1570 | +static int vd55g1_init_ctrls(struct vd55g1 *sensor) | 1570 | +static int vd55g1_init_ctrls(struct vd55g1 *sensor) |
1571 | +{ | 1571 | +{ |
1572 | + const struct v4l2_ctrl_ops *ops = &vd55g1_ctrl_ops; | 1572 | + const struct v4l2_ctrl_ops *ops = &vd55g1_ctrl_ops; |
1573 | + struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler; | 1573 | + struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler; |
1574 | + struct v4l2_ctrl *ctrl; | 1574 | + struct v4l2_ctrl *ctrl; |
1575 | + struct v4l2_fwnode_device_properties fwnode_props; | 1575 | + struct v4l2_fwnode_device_properties fwnode_props; |
1576 | + struct vblank_limits vblank; | 1576 | + struct vblank_limits vblank; |
1577 | + unsigned int hblank; | 1577 | + unsigned int hblank; |
1578 | + int ret; | 1578 | + int ret; |
1579 | + | 1579 | + |
1580 | + v4l2_ctrl_handler_init(hdl, 16); | 1580 | + v4l2_ctrl_handler_init(hdl, 16); |
1581 | + | 1581 | + |
1582 | + /* Flip cluster */ | 1582 | + /* Flip cluster */ |
1583 | + sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, | 1583 | + sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, |
1584 | + 0, 1, 1, 0); | 1584 | + 0, 1, 1, 0); |
1585 | + sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, | 1585 | + sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, |
1586 | + 0, 1, 1, 0); | 1586 | + 0, 1, 1, 0); |
1587 | + v4l2_ctrl_cluster(2, &sensor->hflip_ctrl); | 1587 | + v4l2_ctrl_cluster(2, &sensor->hflip_ctrl); |
1588 | + | 1588 | + |
1589 | + /* Exposition cluster */ | 1589 | + /* Exposition cluster */ |
1590 | + sensor->ae_ctrl = v4l2_ctrl_new_std_menu(hdl, ops, | 1590 | + sensor->ae_ctrl = v4l2_ctrl_new_std_menu(hdl, ops, |
1591 | + V4L2_CID_EXPOSURE_AUTO, 1, | 1591 | + V4L2_CID_EXPOSURE_AUTO, 1, |
1592 | + ~0x3, V4L2_EXPOSURE_AUTO); | 1592 | + ~0x3, V4L2_EXPOSURE_AUTO); |
1593 | + sensor->again_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, | 1593 | + sensor->again_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, |
1594 | + 0, 0x1c, 1, VD55G1_AGAIN_DEF); | 1594 | + 0, 0x1c, 1, VD55G1_AGAIN_DEF); |
1595 | + sensor->dgain_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, | 1595 | + sensor->dgain_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, |
1596 | + 256, 0xffff, 1, | 1596 | + 256, 0xffff, 1, |
1597 | + VD55G1_DGAIN_DEF); | 1597 | + VD55G1_DGAIN_DEF); |
1598 | + sensor->expo_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, | 1598 | + sensor->expo_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, |
1599 | + VD55G1_FRAME_LENGTH_DEF - | 1599 | + VD55G1_FRAME_LENGTH_DEF - |
1600 | + VD55G1_EXPO_MAX_TERM, | 1600 | + VD55G1_EXPO_MAX_TERM, |
1601 | + 1, VD55G1_EXPO_DEF); | 1601 | + 1, VD55G1_EXPO_DEF); |
1602 | + v4l2_ctrl_auto_cluster(4, &sensor->ae_ctrl, V4L2_EXPOSURE_MANUAL, true); | 1602 | + v4l2_ctrl_auto_cluster(4, &sensor->ae_ctrl, V4L2_EXPOSURE_MANUAL, true); |
1603 | + | 1603 | + |
1604 | + sensor->patgen_ctrl = | 1604 | + sensor->patgen_ctrl = |
1605 | + v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, | 1605 | + v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, |
1606 | + ARRAY_SIZE(vd55g1_tp_menu) - 1, 0, | 1606 | + ARRAY_SIZE(vd55g1_tp_menu) - 1, 0, |
1607 | + 0, vd55g1_tp_menu); | 1607 | + 0, vd55g1_tp_menu); |
1608 | + ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, | 1608 | + ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, |
1609 | + ARRAY_SIZE(link_freq) - 1, 0, link_freq); | 1609 | + ARRAY_SIZE(link_freq) - 1, 0, link_freq); |
1610 | + if (ctrl) | 1610 | + if (ctrl) |
1611 | + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 1611 | + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
1612 | + sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops, | 1612 | + sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops, |
1613 | + V4L2_CID_PIXEL_RATE, 1, | 1613 | + V4L2_CID_PIXEL_RATE, 1, |
1614 | + INT_MAX, 1, | 1614 | + INT_MAX, 1, |
1615 | + get_pixel_rate(sensor)); | 1615 | + get_pixel_rate(sensor)); |
1616 | + if (sensor->pixel_rate_ctrl) | 1616 | + if (sensor->pixel_rate_ctrl) |
1617 | + sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 1617 | + sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
1618 | + sensor->ae_lock_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, | 1618 | + sensor->ae_lock_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, |
1619 | + 0, 1, 0, 0); | 1619 | + 0, 1, 0, 0); |
1620 | + sensor->ae_bias_ctrl = | 1620 | + sensor->ae_bias_ctrl = |
1621 | + v4l2_ctrl_new_int_menu(hdl, ops, | 1621 | + v4l2_ctrl_new_int_menu(hdl, ops, |
1622 | + V4L2_CID_AUTO_EXPOSURE_BIAS, | 1622 | + V4L2_CID_AUTO_EXPOSURE_BIAS, |
1623 | + ARRAY_SIZE(vd55g1_ev_bias_menu) - 1, | 1623 | + ARRAY_SIZE(vd55g1_ev_bias_menu) - 1, |
1624 | + ARRAY_SIZE(vd55g1_ev_bias_menu) / 2, | 1624 | + ARRAY_SIZE(vd55g1_ev_bias_menu) / 2, |
1625 | + vd55g1_ev_bias_menu); | 1625 | + vd55g1_ev_bias_menu); |
1626 | + sensor->hdr_ctrl = | 1626 | + sensor->hdr_ctrl = |
1627 | + v4l2_ctrl_new_std_menu_items(hdl, ops, | 1627 | + v4l2_ctrl_new_std_menu_items(hdl, ops, |
1628 | + V4L2_CID_HDR_SENSOR_MODE, | 1628 | + V4L2_CID_HDR_SENSOR_MODE, |
1629 | + ARRAY_SIZE(vd55g1_hdr_menu) - 1, 0, | 1629 | + ARRAY_SIZE(vd55g1_hdr_menu) - 1, 0, |
1630 | + VD55G1_NO_HDR, vd55g1_hdr_menu); | 1630 | + VD55G1_NO_HDR, vd55g1_hdr_menu); |
1631 | + hblank = get_hblank_min(sensor); | 1631 | + hblank = get_hblank_min(sensor); |
1632 | + sensor->hblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, | 1632 | + sensor->hblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, |
1633 | + hblank, hblank, 1, hblank); | 1633 | + hblank, hblank, 1, hblank); |
1634 | + if (sensor->hblank_ctrl) | 1634 | + if (sensor->hblank_ctrl) |
1635 | + sensor->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 1635 | + sensor->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
1636 | + vblank = get_vblank_limits(sensor); | 1636 | + vblank = get_vblank_limits(sensor); |
1637 | + sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, | 1637 | + sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, |
1638 | + vblank.min, vblank.max, | 1638 | + vblank.min, vblank.max, |
1639 | + 1, vblank.def); | 1639 | + 1, vblank.def); |
1640 | + | 1640 | + |
1641 | + /* Additional controls based on device tree properties */ | 1641 | + /* Additional controls based on device tree properties */ |
1642 | + if (sensor->ext_leds_mask) { | 1642 | + if (sensor->ext_leds_mask) { |
1643 | + sensor->led_ctrl = | 1643 | + sensor->led_ctrl = |
1644 | + v4l2_ctrl_new_std_menu(hdl, ops, | 1644 | + v4l2_ctrl_new_std_menu(hdl, ops, |
1645 | + V4L2_CID_FLASH_LED_MODE, | 1645 | + V4L2_CID_FLASH_LED_MODE, |
1646 | + V4L2_FLASH_LED_MODE_FLASH, 0, | 1646 | + V4L2_FLASH_LED_MODE_FLASH, 0, |
1647 | + V4L2_FLASH_LED_MODE_NONE); | 1647 | + V4L2_FLASH_LED_MODE_NONE); |
1648 | + } | 1648 | + } |
1649 | + | 1649 | + |
1650 | + if (hdl->error) { | 1650 | + if (hdl->error) { |
1651 | + ret = hdl->error; | 1651 | + ret = hdl->error; |
1652 | + goto free_ctrls; | 1652 | + goto free_ctrls; |
1653 | + } | 1653 | + } |
1654 | + | 1654 | + |
1655 | + ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &fwnode_props); | 1655 | + ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &fwnode_props); |
1656 | + if (ret) | 1656 | + if (ret) |
1657 | + goto free_ctrls; | 1657 | + goto free_ctrls; |
1658 | + | 1658 | + |
1659 | + ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &fwnode_props); | 1659 | + ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &fwnode_props); |
1660 | + if (ret) | 1660 | + if (ret) |
1661 | + goto free_ctrls; | 1661 | + goto free_ctrls; |
1662 | + | 1662 | + |
1663 | + sensor->sd.ctrl_handler = hdl; | 1663 | + sensor->sd.ctrl_handler = hdl; |
1664 | + return 0; | 1664 | + return 0; |
1665 | + | 1665 | + |
1666 | +free_ctrls: | 1666 | +free_ctrls: |
1667 | + v4l2_ctrl_handler_free(hdl); | 1667 | + v4l2_ctrl_handler_free(hdl); |
1668 | + return ret; | 1668 | + return ret; |
1669 | +} | 1669 | +} |
1670 | + | 1670 | + |
1671 | +static int vd55g1_check_sensor_revision(struct vd55g1 *sensor) | 1671 | +static int vd55g1_check_sensor_revision(struct vd55g1 *sensor) |
1672 | +{ | 1672 | +{ |
1673 | + struct i2c_client *client = sensor->i2c_client; | 1673 | + struct i2c_client *client = sensor->i2c_client; |
1674 | + u64 device_rev; | 1674 | + u64 device_rev; |
1675 | + int ret; | 1675 | + int ret; |
1676 | + | 1676 | + |
1677 | + ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &device_rev, NULL); | 1677 | + ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &device_rev, NULL); |
1678 | + if (ret) | 1678 | + if (ret) |
1679 | + return ret; | 1679 | + return ret; |
1680 | + | 1680 | + |
1681 | + if (device_rev != VD55G1_REVISION_CCB) { | 1681 | + if (device_rev != VD55G1_REVISION_CCB) { |
1682 | + dev_err(&client->dev, "Unsupported sensor revision (0x%x)\n", | 1682 | + dev_err(&client->dev, "Unsupported sensor revision (0x%x)\n", |
1683 | + (u16)device_rev); | 1683 | + (u16)device_rev); |
1684 | + return -ENODEV; | 1684 | + return -ENODEV; |
1685 | + } | 1685 | + } |
1686 | + | 1686 | + |
1687 | + return 0; | 1687 | + return 0; |
1688 | +} | 1688 | +} |
1689 | + | 1689 | + |
1690 | +static int vd55g1_detect(struct vd55g1 *sensor) | 1690 | +static int vd55g1_detect(struct vd55g1 *sensor) |
1691 | +{ | 1691 | +{ |
1692 | + struct i2c_client *client = sensor->i2c_client; | 1692 | + struct i2c_client *client = sensor->i2c_client; |
1693 | + u64 id; | 1693 | + u64 id; |
1694 | + int ret; | 1694 | + int ret; |
1695 | + | 1695 | + |
1696 | + ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL); | 1696 | + ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL); |
1697 | + if (ret) | 1697 | + if (ret) |
1698 | + return ret; | 1698 | + return ret; |
1699 | + | 1699 | + |
1700 | + if (id != VD55G1_MODEL_ID) { | 1700 | + if (id != VD55G1_MODEL_ID) { |
1701 | + dev_warn(&client->dev, "Unsupported sensor id %x", (u32)id); | 1701 | + dev_warn(&client->dev, "Unsupported sensor id %x", (u32)id); |
1702 | + return -ENODEV; | 1702 | + return -ENODEV; |
1703 | + } | 1703 | + } |
1704 | + | 1704 | + |
1705 | + return vd55g1_check_sensor_revision(sensor); | 1705 | + return vd55g1_check_sensor_revision(sensor); |
1706 | +} | 1706 | +} |
1707 | + | 1707 | + |
1708 | +static int vd55g1_power_on(struct device *dev) | 1708 | +static int vd55g1_power_on(struct device *dev) |
1709 | +{ | 1709 | +{ |
1710 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | 1710 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1711 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1711 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1712 | + int ret; | 1712 | + int ret; |
1713 | + | 1713 | + |
1714 | + ret = regulator_bulk_enable(ARRAY_SIZE(vd55g1_supply_name), | 1714 | + ret = regulator_bulk_enable(ARRAY_SIZE(vd55g1_supply_name), |
1715 | + sensor->supplies); | 1715 | + sensor->supplies); |
1716 | + if (ret) { | 1716 | + if (ret) { |
1717 | + dev_err(dev, "Failed to enable regulators %d", ret); | 1717 | + dev_err(dev, "Failed to enable regulators %d", ret); |
1718 | + return ret; | 1718 | + return ret; |
1719 | + } | 1719 | + } |
1720 | + | 1720 | + |
1721 | + ret = clk_prepare_enable(sensor->xclk); | 1721 | + ret = clk_prepare_enable(sensor->xclk); |
1722 | + if (ret) { | 1722 | + if (ret) { |
1723 | + dev_err(dev, "Failed to enable clock %d", ret); | 1723 | + dev_err(dev, "Failed to enable clock %d", ret); |
1724 | + goto disable_bulk; | 1724 | + goto disable_bulk; |
1725 | + } | 1725 | + } |
1726 | + | 1726 | + |
1727 | + gpiod_set_value_cansleep(sensor->reset_gpio, 0); | 1727 | + gpiod_set_value_cansleep(sensor->reset_gpio, 0); |
1728 | + usleep_range(5000, 10000); | 1728 | + usleep_range(5000, 10000); |
1729 | + ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_READY_TO_BOOT, NULL); | 1729 | + ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_READY_TO_BOOT, NULL); |
1730 | + if (ret) { | 1730 | + if (ret) { |
1731 | + dev_err(dev, "Sensor reset failed %d\n", ret); | 1731 | + dev_err(dev, "Sensor reset failed %d\n", ret); |
1732 | + goto disable_clock; | 1732 | + goto disable_clock; |
1733 | + } | 1733 | + } |
1734 | + | 1734 | + |
1735 | + ret = vd55g1_detect(sensor); | 1735 | + ret = vd55g1_detect(sensor); |
1736 | + if (ret) { | 1736 | + if (ret) { |
1737 | + dev_err(dev, "Sensor detect failed %d", ret); | 1737 | + dev_err(dev, "Sensor detect failed %d", ret); |
1738 | + goto disable_clock; | 1738 | + goto disable_clock; |
1739 | + } | 1739 | + } |
1740 | + | 1740 | + |
1741 | + ret = vd55g1_patch(sensor); | 1741 | + ret = vd55g1_patch(sensor); |
1742 | + if (ret) { | 1742 | + if (ret) { |
1743 | + dev_err(dev, "Sensor patch failed %d", ret); | 1743 | + dev_err(dev, "Sensor patch failed %d", ret); |
1744 | + goto disable_clock; | 1744 | + goto disable_clock; |
1745 | + } | 1745 | + } |
1746 | + | 1746 | + |
1747 | + ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL); | 1747 | + ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL); |
1748 | + if (ret) { | 1748 | + if (ret) { |
1749 | + dev_err(dev, "Sensor waiting after patch failed %d", | 1749 | + dev_err(dev, "Sensor waiting after patch failed %d", |
1750 | + ret); | 1750 | + ret); |
1751 | + goto disable_clock; | 1751 | + goto disable_clock; |
1752 | + } | 1752 | + } |
1753 | + | 1753 | + |
1754 | + return 0; | 1754 | + return 0; |
1755 | + | 1755 | + |
1756 | +disable_clock: | 1756 | +disable_clock: |
1757 | + gpiod_set_value_cansleep(sensor->reset_gpio, 1); | 1757 | + gpiod_set_value_cansleep(sensor->reset_gpio, 1); |
1758 | + clk_disable_unprepare(sensor->xclk); | 1758 | + clk_disable_unprepare(sensor->xclk); |
1759 | +disable_bulk: | 1759 | +disable_bulk: |
1760 | + regulator_bulk_disable(ARRAY_SIZE(vd55g1_supply_name), | 1760 | + regulator_bulk_disable(ARRAY_SIZE(vd55g1_supply_name), |
1761 | + sensor->supplies); | 1761 | + sensor->supplies); |
1762 | + | 1762 | + |
1763 | + return ret; | 1763 | + return ret; |
1764 | +} | 1764 | +} |
1765 | + | 1765 | + |
1766 | +static int vd55g1_power_off(struct device *dev) | 1766 | +static int vd55g1_power_off(struct device *dev) |
1767 | +{ | 1767 | +{ |
1768 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | 1768 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1769 | + struct vd55g1 *sensor = to_vd55g1(sd); | 1769 | + struct vd55g1 *sensor = to_vd55g1(sd); |
1770 | + | 1770 | + |
1771 | + clk_disable_unprepare(sensor->xclk); | 1771 | + clk_disable_unprepare(sensor->xclk); |
1772 | + gpiod_set_value_cansleep(sensor->reset_gpio, 1); | 1772 | + gpiod_set_value_cansleep(sensor->reset_gpio, 1); |
1773 | + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); | 1773 | + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); |
1774 | + return 0; | 1774 | + return 0; |
1775 | +} | 1775 | +} |
1776 | + | 1776 | + |
1777 | +static int vd55g1_check_csi_conf(struct vd55g1 *sensor, | 1777 | +static int vd55g1_check_csi_conf(struct vd55g1 *sensor, |
1778 | + struct fwnode_handle *endpoint) | 1778 | + struct fwnode_handle *endpoint) |
1779 | +{ | 1779 | +{ |
1780 | + struct i2c_client *client = sensor->i2c_client; | 1780 | + struct i2c_client *client = sensor->i2c_client; |
1781 | + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; | 1781 | + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; |
1782 | + u8 n_lanes; | 1782 | + u8 n_lanes; |
1783 | + int ret = 0; | 1783 | + int ret = 0; |
1784 | + | 1784 | + |
1785 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); | 1785 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); |
1786 | + if (ret) | 1786 | + if (ret) |
1787 | + return -EINVAL; | 1787 | + return -EINVAL; |
1788 | + | 1788 | + |
1789 | + /* Check lanes number */ | 1789 | + /* Check lanes number */ |
1790 | + n_lanes = ep.bus.mipi_csi2.num_data_lanes; | 1790 | + n_lanes = ep.bus.mipi_csi2.num_data_lanes; |
1791 | + if (n_lanes != 1) { | 1791 | + if (n_lanes != 1) { |
1792 | + dev_err(&client->dev, "Sensor only supports 1 lane, found %d\n", | 1792 | + dev_err(&client->dev, "Sensor only supports 1 lane, found %d\n", |
1793 | + n_lanes); | 1793 | + n_lanes); |
1794 | + ret = -EINVAL; | 1794 | + ret = -EINVAL; |
1795 | + goto done; | 1795 | + goto done; |
1796 | + } | 1796 | + } |
1797 | + | 1797 | + |
1798 | + /* Clock lane must be first */ | 1798 | + /* Clock lane must be first */ |
1799 | + if (ep.bus.mipi_csi2.clock_lane != 0) { | 1799 | + if (ep.bus.mipi_csi2.clock_lane != 0) { |
1800 | + dev_err(&client->dev, "Clock lane must be mapped to lane 0\n"); | 1800 | + dev_err(&client->dev, "Clock lane must be mapped to lane 0\n"); |
1801 | + ret = -EINVAL; | 1801 | + ret = -EINVAL; |
1802 | + goto done; | 1802 | + goto done; |
1803 | + } | 1803 | + } |
1804 | + | 1804 | + |
1805 | + /* Handle polarities in sensor configuration */ | 1805 | + /* Handle polarities in sensor configuration */ |
1806 | + sensor->oif_ctrl = (ep.bus.mipi_csi2.lane_polarities[0] << 3) | | 1806 | + sensor->oif_ctrl = (ep.bus.mipi_csi2.lane_polarities[0] << 3) | |
1807 | + (ep.bus.mipi_csi2.lane_polarities[1] << 6); | 1807 | + (ep.bus.mipi_csi2.lane_polarities[1] << 6); |
1808 | + | 1808 | + |
1809 | + /* Check the link frequency set in device tree */ | 1809 | + /* Check the link frequency set in device tree */ |
1810 | + if (!ep.nr_of_link_frequencies) { | 1810 | + if (!ep.nr_of_link_frequencies) { |
1811 | + dev_err(&client->dev, "link-frequency property not found in DT\n"); | 1811 | + dev_err(&client->dev, "link-frequency property not found in DT\n"); |
1812 | + ret = -EINVAL; | 1812 | + ret = -EINVAL; |
1813 | + goto done; | 1813 | + goto done; |
1814 | + } | 1814 | + } |
1815 | + if (ep.nr_of_link_frequencies != 1) { | 1815 | + if (ep.nr_of_link_frequencies != 1) { |
1816 | + dev_err(&client->dev, "Multiple link frequencies not supported\n"); | 1816 | + dev_err(&client->dev, "Multiple link frequencies not supported\n"); |
1817 | + ret = -EINVAL; | 1817 | + ret = -EINVAL; |
1818 | + goto done; | 1818 | + goto done; |
1819 | + } | 1819 | + } |
1820 | + link_freq[0] = ep.link_frequencies[0]; | 1820 | + link_freq[0] = ep.link_frequencies[0]; |
1821 | + | 1821 | + |
1822 | +done: | 1822 | +done: |
1823 | + v4l2_fwnode_endpoint_free(&ep); | 1823 | + v4l2_fwnode_endpoint_free(&ep); |
1824 | + | 1824 | + |
1825 | + return ret; | 1825 | + return ret; |
1826 | +} | 1826 | +} |
1827 | + | 1827 | + |
1828 | +static int vd55g1_parse_dt_gpios_array(struct vd55g1 *sensor, | 1828 | +static int vd55g1_parse_dt_gpios_array(struct vd55g1 *sensor, |
1829 | + char *prop_name, u32 *array, int *nb) | 1829 | + char *prop_name, u32 *array, int *nb) |
1830 | +{ | 1830 | +{ |
1831 | + struct i2c_client *client = sensor->i2c_client; | 1831 | + struct i2c_client *client = sensor->i2c_client; |
1832 | + struct device_node *np = client->dev.of_node; | 1832 | + struct device_node *np = client->dev.of_node; |
1833 | + unsigned int i; | 1833 | + unsigned int i; |
1834 | + | 1834 | + |
1835 | + *nb = of_property_read_variable_u32_array(np, prop_name, array, 0, | 1835 | + *nb = of_property_read_variable_u32_array(np, prop_name, array, 0, |
1836 | + VD55G1_NB_GPIOS); | 1836 | + VD55G1_NB_GPIOS); |
1837 | + if (*nb == -EINVAL) { | 1837 | + if (*nb == -EINVAL) { |
1838 | + /* Property not found */ | 1838 | + /* Property not found */ |
1839 | + *nb = 0; | 1839 | + *nb = 0; |
1840 | + return 0; | 1840 | + return 0; |
1841 | + } else if (*nb < 0) { | 1841 | + } else if (*nb < 0) { |
1842 | + dev_err(&client->dev, "Failed to read %s prop\n", prop_name); | 1842 | + dev_err(&client->dev, "Failed to read %s prop\n", prop_name); |
1843 | + return *nb; | 1843 | + return *nb; |
1844 | + } | 1844 | + } |
1845 | + | 1845 | + |
1846 | + for (i = 0; i < *nb; i++) { | 1846 | + for (i = 0; i < *nb; i++) { |
1847 | + if (array[i] >= VD55G1_NB_GPIOS) { | 1847 | + if (array[i] >= VD55G1_NB_GPIOS) { |
1848 | + dev_err(&client->dev, "Invalid GPIO number %d\n", | 1848 | + dev_err(&client->dev, "Invalid GPIO number %d\n", |
1849 | + array[i]); | 1849 | + array[i]); |
1850 | + return -EINVAL; | 1850 | + return -EINVAL; |
1851 | + } | 1851 | + } |
1852 | + } | 1852 | + } |
1853 | + | 1853 | + |
1854 | + return 0; | 1854 | + return 0; |
1855 | +} | 1855 | +} |
1856 | + | 1856 | + |
1857 | +static int vd55g1_parse_dt_gpios(struct vd55g1 *sensor) | 1857 | +static int vd55g1_parse_dt_gpios(struct vd55g1 *sensor) |
1858 | +{ | 1858 | +{ |
1859 | + u32 led_gpios[VD55G1_NB_GPIOS]; | 1859 | + u32 led_gpios[VD55G1_NB_GPIOS]; |
1860 | + int nb_gpios_leds; | 1860 | + int nb_gpios_leds; |
1861 | + unsigned int i; | 1861 | + unsigned int i; |
1862 | + int ret; | 1862 | + int ret; |
1863 | + | 1863 | + |
1864 | + /* Initialize GPIOs to default */ | 1864 | + /* Initialize GPIOs to default */ |
1865 | + for (i = 0; i < VD55G1_NB_GPIOS; i++) | 1865 | + for (i = 0; i < VD55G1_NB_GPIOS; i++) |
1866 | + sensor->gpios[i] = VD55G1_GPIO_MODE_IN; | 1866 | + sensor->gpios[i] = VD55G1_GPIO_MODE_IN; |
1867 | + sensor->ext_leds_mask = 0; | 1867 | + sensor->ext_leds_mask = 0; |
1868 | + | 1868 | + |
1869 | + /* Take into account optional 'st,leds' output for GPIOs */ | 1869 | + /* Take into account optional 'st,leds' output for GPIOs */ |
1870 | + ret = vd55g1_parse_dt_gpios_array(sensor, "st,leds", led_gpios, | 1870 | + ret = vd55g1_parse_dt_gpios_array(sensor, "st,leds", led_gpios, |
1871 | + &nb_gpios_leds); | 1871 | + &nb_gpios_leds); |
1872 | + if (ret) | 1872 | + if (ret) |
1873 | + return ret; | 1873 | + return ret; |
1874 | + | 1874 | + |
1875 | + for (i = 0; i < nb_gpios_leds; i++) { | 1875 | + for (i = 0; i < nb_gpios_leds; i++) { |
1876 | + sensor->gpios[led_gpios[i]] = VD55G1_GPIO_MODE_STROBE; | 1876 | + sensor->gpios[led_gpios[i]] = VD55G1_GPIO_MODE_STROBE; |
1877 | + set_bit(led_gpios[i], &sensor->ext_leds_mask); | 1877 | + set_bit(led_gpios[i], &sensor->ext_leds_mask); |
1878 | + } | 1878 | + } |
1879 | + | 1879 | + |
1880 | + return 0; | 1880 | + return 0; |
1881 | +} | 1881 | +} |
1882 | + | 1882 | + |
1883 | +static int vd55g1_parse_dt(struct vd55g1 *sensor) | 1883 | +static int vd55g1_parse_dt(struct vd55g1 *sensor) |
1884 | +{ | 1884 | +{ |
1885 | + struct i2c_client *client = sensor->i2c_client; | 1885 | + struct i2c_client *client = sensor->i2c_client; |
1886 | + struct device *dev = &client->dev; | 1886 | + struct device *dev = &client->dev; |
1887 | + struct fwnode_handle *endpoint; | 1887 | + struct fwnode_handle *endpoint; |
1888 | + int ret; | 1888 | + int ret; |
1889 | + | 1889 | + |
1890 | + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); | 1890 | + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); |
1891 | + if (!endpoint) { | 1891 | + if (!endpoint) { |
1892 | + dev_err(dev, "Endpoint node not found\n"); | 1892 | + dev_err(dev, "Endpoint node not found\n"); |
1893 | + return -EINVAL; | 1893 | + return -EINVAL; |
1894 | + } | 1894 | + } |
1895 | + | 1895 | + |
1896 | + ret = vd55g1_check_csi_conf(sensor, endpoint); | 1896 | + ret = vd55g1_check_csi_conf(sensor, endpoint); |
1897 | + fwnode_handle_put(endpoint); | 1897 | + fwnode_handle_put(endpoint); |
1898 | + if (ret) | 1898 | + if (ret) |
1899 | + return ret; | 1899 | + return ret; |
1900 | + | 1900 | + |
1901 | + return vd55g1_parse_dt_gpios(sensor); | 1901 | + return vd55g1_parse_dt_gpios(sensor); |
1902 | +} | 1902 | +} |
1903 | + | 1903 | + |
1904 | +static int vd55g1_subdev_init(struct vd55g1 *sensor) | 1904 | +static int vd55g1_subdev_init(struct vd55g1 *sensor) |
1905 | +{ | 1905 | +{ |
1906 | + struct i2c_client *client = sensor->i2c_client; | 1906 | + struct i2c_client *client = sensor->i2c_client; |
1907 | + int ret; | 1907 | + int ret; |
1908 | + | 1908 | + |
1909 | + /* Init sub device */ | 1909 | + /* Init sub device */ |
1910 | + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1910 | + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1911 | + sensor->sd.internal_ops = &vd55g1_internal_ops; | 1911 | + sensor->sd.internal_ops = &vd55g1_internal_ops; |
1912 | + | 1912 | + |
1913 | + /* Init source pad */ | 1913 | + /* Init source pad */ |
1914 | + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | 1914 | + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; |
1915 | + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | 1915 | + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
1916 | + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); | 1916 | + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); |
1917 | + if (ret) { | 1917 | + if (ret) { |
1918 | + dev_err(&client->dev, "Failed to init media entity : %d", ret); | 1918 | + dev_err(&client->dev, "Failed to init media entity : %d", ret); |
1919 | + return ret; | 1919 | + return ret; |
1920 | + } | 1920 | + } |
1921 | + | 1921 | + |
1922 | + sensor->sd.state_lock = sensor->ctrl_handler.lock; | 1922 | + sensor->sd.state_lock = sensor->ctrl_handler.lock; |
1923 | + ret = v4l2_subdev_init_finalize(&sensor->sd); | 1923 | + ret = v4l2_subdev_init_finalize(&sensor->sd); |
1924 | + if (ret) { | 1924 | + if (ret) { |
1925 | + dev_err(&client->dev, "Subdev init error: %d", ret); | 1925 | + dev_err(&client->dev, "Subdev init error: %d", ret); |
1926 | + goto err_ctrls; | 1926 | + goto err_ctrls; |
1927 | + } | 1927 | + } |
1928 | + | 1928 | + |
1929 | + /* | 1929 | + /* |
1930 | + * Initiliaze controls after v4l2_subdev_init_finalize() to make sure | 1930 | + * Initiliaze controls after v4l2_subdev_init_finalize() to make sure |
1931 | + * default values are set. | 1931 | + * default values are set. |
1932 | + */ | 1932 | + */ |
1933 | + ret = vd55g1_init_ctrls(sensor); | 1933 | + ret = vd55g1_init_ctrls(sensor); |
1934 | + if (ret) { | 1934 | + if (ret) { |
1935 | + dev_err(&client->dev, "Controls initialization failed %d", ret); | 1935 | + dev_err(&client->dev, "Controls initialization failed %d", ret); |
1936 | + goto err_media; | 1936 | + goto err_media; |
1937 | + } | 1937 | + } |
1938 | + | 1938 | + |
1939 | + return ret; | 1939 | + return ret; |
1940 | + | 1940 | + |
1941 | +err_ctrls: | 1941 | +err_ctrls: |
1942 | + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); | 1942 | + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); |
1943 | + | 1943 | + |
1944 | +err_media: | 1944 | +err_media: |
1945 | + media_entity_cleanup(&sensor->sd.entity); | 1945 | + media_entity_cleanup(&sensor->sd.entity); |
1946 | + return ret; | 1946 | + return ret; |
1947 | +} | 1947 | +} |
1948 | + | 1948 | + |
1949 | +static void vd55g1_subdev_cleanup(struct vd55g1 *sensor) | 1949 | +static void vd55g1_subdev_cleanup(struct vd55g1 *sensor) |
1950 | +{ | 1950 | +{ |
1951 | + v4l2_async_unregister_subdev(&sensor->sd); | 1951 | + v4l2_async_unregister_subdev(&sensor->sd); |
1952 | + v4l2_subdev_cleanup(&sensor->sd); | 1952 | + v4l2_subdev_cleanup(&sensor->sd); |
1953 | + media_entity_cleanup(&sensor->sd.entity); | 1953 | + media_entity_cleanup(&sensor->sd.entity); |
1954 | + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); | 1954 | + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); |
1955 | +} | 1955 | +} |
1956 | + | 1956 | + |
1957 | +static int vd55g1_probe(struct i2c_client *client) | 1957 | +static int vd55g1_probe(struct i2c_client *client) |
1958 | +{ | 1958 | +{ |
1959 | + struct device *dev = &client->dev; | 1959 | + struct device *dev = &client->dev; |
1960 | + struct vd55g1 *sensor; | 1960 | + struct vd55g1 *sensor; |
1961 | + int ret; | 1961 | + int ret; |
1962 | + | 1962 | + |
1963 | + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); | 1963 | + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); |
1964 | + if (!sensor) | 1964 | + if (!sensor) |
1965 | + return -ENOMEM; | 1965 | + return -ENOMEM; |
1966 | + | 1966 | + |
1967 | + v4l2_i2c_subdev_init(&sensor->sd, client, &vd55g1_subdev_ops); | 1967 | + v4l2_i2c_subdev_init(&sensor->sd, client, &vd55g1_subdev_ops); |
1968 | + sensor->i2c_client = client; | 1968 | + sensor->i2c_client = client; |
1969 | + | 1969 | + |
1970 | + ret = vd55g1_parse_dt(sensor); | 1970 | + ret = vd55g1_parse_dt(sensor); |
1971 | + if (ret) | 1971 | + if (ret) |
1972 | + return dev_err_probe(dev, ret, "Failed to parse Device Tree."); | 1972 | + return dev_err_probe(dev, ret, "Failed to parse Device Tree."); |
1973 | + | 1973 | + |
1974 | + /* Get (and check) resources : power regs, ext clock, reset gpio */ | 1974 | + /* Get (and check) resources : power regs, ext clock, reset gpio */ |
1975 | + ret = vd55g1_get_regulators(sensor); | 1975 | + ret = vd55g1_get_regulators(sensor); |
1976 | + if (ret) | 1976 | + if (ret) |
1977 | + return dev_err_probe(dev, ret, "Failed to get regulators."); | 1977 | + return dev_err_probe(dev, ret, "Failed to get regulators."); |
1978 | + | 1978 | + |
1979 | + sensor->xclk = devm_clk_get(dev, NULL); | 1979 | + sensor->xclk = devm_clk_get(dev, NULL); |
1980 | + if (IS_ERR(sensor->xclk)) | 1980 | + if (IS_ERR(sensor->xclk)) |
1981 | + return dev_err_probe(dev, PTR_ERR(sensor->xclk), | 1981 | + return dev_err_probe(dev, PTR_ERR(sensor->xclk), |
1982 | + "Failed to get xclk."); | 1982 | + "Failed to get xclk."); |
1983 | + | 1983 | + |
1984 | + sensor->xclk_freq = clk_get_rate(sensor->xclk); | 1984 | + sensor->xclk_freq = clk_get_rate(sensor->xclk); |
1985 | + ret = vd55g1_prepare_clock_tree(sensor); | 1985 | + ret = vd55g1_prepare_clock_tree(sensor); |
1986 | + if (ret) | 1986 | + if (ret) |
1987 | + return ret; | 1987 | + return ret; |
1988 | + | 1988 | + |
1989 | + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", | 1989 | + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", |
1990 | + GPIOD_OUT_HIGH); | 1990 | + GPIOD_OUT_HIGH); |
1991 | + if (IS_ERR(sensor->reset_gpio)) | 1991 | + if (IS_ERR(sensor->reset_gpio)) |
1992 | + return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), | 1992 | + return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), |
1993 | + "Failed to get reset gpio."); | 1993 | + "Failed to get reset gpio."); |
1994 | + | 1994 | + |
1995 | + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); | 1995 | + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); |
1996 | + if (IS_ERR(sensor->regmap)) | 1996 | + if (IS_ERR(sensor->regmap)) |
1997 | + return dev_err_probe(dev, PTR_ERR(sensor->regmap), | 1997 | + return dev_err_probe(dev, PTR_ERR(sensor->regmap), |
1998 | + "Failed to init regmap."); | 1998 | + "Failed to init regmap."); |
1999 | + | 1999 | + |
2000 | + /* Detect if sensor is present and if its revision is supported */ | 2000 | + /* Detect if sensor is present and if its revision is supported */ |
2001 | + ret = vd55g1_power_on(dev); | 2001 | + ret = vd55g1_power_on(dev); |
2002 | + if (ret) | 2002 | + if (ret) |
2003 | + return ret; | 2003 | + return ret; |
2004 | + | 2004 | + |
2005 | + ret = vd55g1_subdev_init(sensor); | 2005 | + ret = vd55g1_subdev_init(sensor); |
2006 | + if (ret) { | 2006 | + if (ret) { |
2007 | + dev_err(dev, "V4l2 init failed : %d", ret); | 2007 | + dev_err(dev, "V4l2 init failed : %d", ret); |
2008 | + goto err_power_off; | 2008 | + goto err_power_off; |
2009 | + } | 2009 | + } |
2010 | + | 2010 | + |
2011 | + ret = v4l2_async_register_subdev(&sensor->sd); | 2011 | + ret = v4l2_async_register_subdev(&sensor->sd); |
2012 | + if (ret) { | 2012 | + if (ret) { |
2013 | + dev_err(dev, "async subdev register failed %d", ret); | 2013 | + dev_err(dev, "async subdev register failed %d", ret); |
2014 | + goto err_subdev; | 2014 | + goto err_subdev; |
2015 | + } | 2015 | + } |
2016 | + | 2016 | + |
2017 | + /* Enable pm_runtime and power off the sensor */ | 2017 | + /* Enable pm_runtime and power off the sensor */ |
2018 | + pm_runtime_set_active(dev); | 2018 | + pm_runtime_set_active(dev); |
2019 | + pm_runtime_get_noresume(dev); | 2019 | + pm_runtime_get_noresume(dev); |
2020 | + pm_runtime_enable(dev); | 2020 | + pm_runtime_enable(dev); |
2021 | + pm_runtime_set_autosuspend_delay(dev, 4000); | 2021 | + pm_runtime_set_autosuspend_delay(dev, 4000); |
2022 | + pm_runtime_use_autosuspend(dev); | 2022 | + pm_runtime_use_autosuspend(dev); |
2023 | + pm_runtime_mark_last_busy(dev); | 2023 | + pm_runtime_mark_last_busy(dev); |
2024 | + | 2024 | + |
2025 | + return 0; | 2025 | + return 0; |
2026 | + | 2026 | + |
2027 | +err_subdev: | 2027 | +err_subdev: |
2028 | + vd55g1_subdev_cleanup(sensor); | 2028 | + vd55g1_subdev_cleanup(sensor); |
2029 | +err_power_off: | 2029 | +err_power_off: |
2030 | + vd55g1_power_off(dev); | 2030 | + vd55g1_power_off(dev); |
2031 | + | 2031 | + |
2032 | + return ret; | 2032 | + return ret; |
2033 | +} | 2033 | +} |
2034 | + | 2034 | + |
2035 | +static void vd55g1_remove(struct i2c_client *client) | 2035 | +static void vd55g1_remove(struct i2c_client *client) |
2036 | +{ | 2036 | +{ |
2037 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | 2037 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); |
2038 | + struct vd55g1 *sensor = to_vd55g1(sd); | 2038 | + struct vd55g1 *sensor = to_vd55g1(sd); |
2039 | + | 2039 | + |
2040 | + vd55g1_subdev_cleanup(sensor); | 2040 | + vd55g1_subdev_cleanup(sensor); |
2041 | + | 2041 | + |
2042 | + pm_runtime_disable(&client->dev); | 2042 | + pm_runtime_disable(&client->dev); |
2043 | + if (!pm_runtime_status_suspended(&client->dev)) | 2043 | + if (!pm_runtime_status_suspended(&client->dev)) |
2044 | + vd55g1_power_off(&client->dev); | 2044 | + vd55g1_power_off(&client->dev); |
2045 | + pm_runtime_set_suspended(&client->dev); | 2045 | + pm_runtime_set_suspended(&client->dev); |
2046 | +} | 2046 | +} |
2047 | + | 2047 | + |
2048 | +static const struct of_device_id vd55g1_dt_ids[] = { | 2048 | +static const struct of_device_id vd55g1_dt_ids[] = { |
2049 | + { .compatible = "st,vd55g1" }, | 2049 | + { .compatible = "st,vd55g1" }, |
2050 | + { /* sentinel */ } | 2050 | + { /* sentinel */ } |
2051 | +}; | 2051 | +}; |
2052 | +MODULE_DEVICE_TABLE(of, vd55g1_dt_ids); | 2052 | +MODULE_DEVICE_TABLE(of, vd55g1_dt_ids); |
2053 | + | 2053 | + |
2054 | +static const struct dev_pm_ops vd55g1_pm_ops = { | 2054 | +static const struct dev_pm_ops vd55g1_pm_ops = { |
2055 | + SET_RUNTIME_PM_OPS(vd55g1_power_off, vd55g1_power_on, NULL) | 2055 | + SET_RUNTIME_PM_OPS(vd55g1_power_off, vd55g1_power_on, NULL) |
2056 | +}; | 2056 | +}; |
2057 | + | 2057 | + |
2058 | +static struct i2c_driver vd55g1_i2c_driver = { | 2058 | +static struct i2c_driver vd55g1_i2c_driver = { |
2059 | + .driver = { | 2059 | + .driver = { |
2060 | + .name = "vd55g1", | 2060 | + .name = "vd55g1", |
2061 | + .of_match_table = vd55g1_dt_ids, | 2061 | + .of_match_table = vd55g1_dt_ids, |
2062 | + .pm = &vd55g1_pm_ops, | 2062 | + .pm = &vd55g1_pm_ops, |
2063 | + }, | 2063 | + }, |
2064 | + .probe = vd55g1_probe, | 2064 | + .probe = vd55g1_probe, |
2065 | + .remove = vd55g1_remove, | 2065 | + .remove = vd55g1_remove, |
2066 | +}; | 2066 | +}; |
2067 | + | 2067 | + |
2068 | +module_i2c_driver(vd55g1_i2c_driver); | 2068 | +module_i2c_driver(vd55g1_i2c_driver); |
2069 | + | 2069 | + |
2070 | +MODULE_AUTHOR("Benjamin Mugnier <benjamin.mugnier@foss.st.com>"); | 2070 | +MODULE_AUTHOR("Benjamin Mugnier <benjamin.mugnier@foss.st.com>"); |
2071 | +MODULE_AUTHOR("Sylvain Petinot <sylvain.petinot@foss.st.com>"); | 2071 | +MODULE_AUTHOR("Sylvain Petinot <sylvain.petinot@foss.st.com>"); |
2072 | +MODULE_DESCRIPTION("VD55G1 camera subdev driver"); | 2072 | +MODULE_DESCRIPTION("VD55G1 camera subdev driver"); |
2073 | +MODULE_LICENSE("GPL"); | 2073 | +MODULE_LICENSE("GPL"); |
2074 | 2074 | ||
2075 | -- | 2075 | -- |
2076 | 2.25.1 | 2076 | 2.25.1 | diff view generated by jsdifflib |