linux-stable/drivers/media/i2c/hi847.c
Uwe Kleine-König ed5c2f5fd1 i2c: Make remove callback return void
The value returned by an i2c driver's remove function is mostly ignored.
(Only an error message is printed if the value is non-zero that the
error is ignored.)

So change the prototype of the remove function to return no value. This
way driver authors are not tempted to assume that passing an error to
the upper layer is a good idea. All drivers are adapted accordingly.
There is no intended change of behaviour, all callbacks were prepared to
return 0 before.

Reviewed-by: Peter Senna Tschudin <peter.senna@gmail.com>
Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Crt Mori <cmo@melexis.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Marek Behún <kabel@kernel.org> # for leds-turris-omnia
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Petr Machata <petrm@nvidia.com> # for mlxsw
Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> # for surface3_power
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> # for bmc150-accel-i2c + kxcjk-1013
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> # for media/* + staging/media/*
Acked-by: Miguel Ojeda <ojeda@kernel.org> # for auxdisplay/ht16k33 + auxdisplay/lcd2s
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # for versaclock5
Reviewed-by: Ajay Gupta <ajayg@nvidia.com> # for ucsi_ccg
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # for iio
Acked-by: Peter Rosin <peda@axentia.se> # for i2c-mux-*, max9860
Acked-by: Adrien Grassein <adrien.grassein@gmail.com> # for lontium-lt8912b
Reviewed-by: Jean Delvare <jdelvare@suse.de> # for hwmon, i2c-core and i2c/muxes
Acked-by: Corey Minyard <cminyard@mvista.com> # for IPMI
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> # for drivers/power
Acked-by: Krzysztof Hałasa <khalasa@piap.pl>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
2022-08-16 12:46:26 +02:00

3010 lines
61 KiB
C

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022 Intel Corporation.
#include <asm/unaligned.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#define HI847_REG_VALUE_08BIT 1
#define HI847_REG_VALUE_16BIT 2
#define HI847_REG_VALUE_24BIT 3
#define HI847_LINK_FREQ_400MHZ 400000000ULL
#define HI847_LINK_FREQ_200MHZ 200000000ULL
#define HI847_SCLK 72000000ULL
#define HI847_MCLK 19200000
#define HI847_DATA_LANES 4
#define HI847_RGB_DEPTH 10
#define HI847_REG_CHIP_ID 0x0716
#define HI847_CHIP_ID 0x0847
#define HI847_REG_MODE_SELECT 0x0B00
#define HI847_MODE_STANDBY 0x0000
#define HI847_MODE_STREAMING 0x0100
#define HI847_REG_MODE_TG 0x027E
#define HI847_REG_MODE_TG_ENABLE 0x0100
#define HI847_REG_MODE_TG_DISABLE 0x0000
/* vertical-timings from sensor */
#define HI847_REG_FLL 0x020E
#define HI847_FLL_30FPS 0x0B51
#define HI847_FLL_30FPS_MIN 0x0B51
#define HI847_FLL_60FPS 0x05A9
#define HI847_FLL_60FPS_MIN 0x05A9
#define HI847_FLL_MAX 0x7fff
/* horizontal-timings from sensor */
#define HI847_REG_LLP 0x0206
/* Exposure controls from sensor */
#define HI847_REG_EXPOSURE 0x020A
#define HI847_EXPOSURE_MIN 4
#define HI847_EXPOSURE_MAX_MARGIN 4
#define HI847_EXPOSURE_STEP 1
/* Analog gain controls from sensor */
#define HI847_REG_ANALOG_GAIN 0x0212
#define HI847_ANAL_GAIN_MIN 0
#define HI847_ANAL_GAIN_MAX 240
#define HI847_ANAL_GAIN_STEP 1
/* Digital gain controls from sensor */
#define HI847_REG_MWB_GR_GAIN 0x0214
#define HI847_REG_MWB_GB_GAIN 0x0216
#define HI847_REG_MWB_R_GAIN 0x0218
#define HI847_REG_MWB_B_GAIN 0x021A
#define HI847_DGTL_GAIN_MIN 1
#define HI847_DGTL_GAIN_MAX 8191
#define HI847_DGTL_GAIN_STEP 1
#define HI847_DGTL_GAIN_DEFAULT 512
/* Test Pattern Control */
#define HI847_REG_ISP 0X0B04
#define HI847_REG_ISP_TPG_EN 0x0001
#define HI847_REG_TEST_PATTERN 0x0C0A
/* Flip Mirror Controls from sensor */
#define HI847_REG_MIRROR_FLIP 0x0202
#define HI847_REG_FORMAT_X 0x0F04
#define HI847_REG_FORMAT_Y 0x0F06
enum {
HI847_LINK_FREQ_400MHZ_INDEX,
HI847_LINK_FREQ_200MHZ_INDEX,
};
struct hi847_reg {
u16 address;
u16 val;
};
struct hi847_reg_list {
u32 num_of_regs;
const struct hi847_reg *regs;
};
struct hi847_link_freq_config {
const struct hi847_reg_list reg_list;
};
struct hi847_mode {
/* Frame width in pixels */
u32 width;
/* Frame height in pixels */
u32 height;
/* Horizontal timining size */
u32 llp;
/* Default vertical timining size */
u32 fll_def;
/* Min vertical timining size */
u32 fll_min;
/* Link frequency needed for this resolution */
u32 link_freq_index;
/* Sensor register settings for this resolution */
const struct hi847_reg_list reg_list;
};
#define to_hi847(_sd) container_of(_sd, struct hi847, sd)
//SENSOR_INITIALIZATION
static const struct hi847_reg mipi_data_rate_lane_4[] = {
{0x0790, 0x0100},
{0x2000, 0x0000},
{0x2002, 0x0058},
{0x2006, 0x40B2},
{0x2008, 0xB05C},
{0x200A, 0x8446},
{0x200C, 0x40B2},
{0x200E, 0xB082},
{0x2010, 0x8450},
{0x2012, 0x40B2},
{0x2014, 0xB0AE},
{0x2016, 0x84C6},
{0x2018, 0x40B2},
{0x201A, 0xB11A},
{0x201C, 0x84BC},
{0x201E, 0x40B2},
{0x2020, 0xB34A},
{0x2022, 0x84B4},
{0x2024, 0x40B2},
{0x2026, 0xB386},
{0x2028, 0x84B0},
{0x202A, 0x40B2},
{0x202C, 0xB3B4},
{0x202E, 0x84B8},
{0x2030, 0x40B2},
{0x2032, 0xB0F4},
{0x2034, 0x8470},
{0x2036, 0x40B2},
{0x2038, 0xB3EA},
{0x203A, 0x847C},
{0x203C, 0x40B2},
{0x203E, 0xB658},
{0x2040, 0x8478},
{0x2042, 0x40B2},
{0x2044, 0xB67E},
{0x2046, 0x847E},
{0x2048, 0x40B2},
{0x204A, 0xB78E},
{0x204C, 0x843A},
{0x204E, 0x40B2},
{0x2050, 0xB980},
{0x2052, 0x845C},
{0x2054, 0x40B2},
{0x2056, 0xB9B0},
{0x2058, 0x845E},
{0x205A, 0x4130},
{0x205C, 0x1292},
{0x205E, 0xD016},
{0x2060, 0xB3D2},
{0x2062, 0x0B00},
{0x2064, 0x2002},
{0x2066, 0xD2E2},
{0x2068, 0x0381},
{0x206A, 0x93C2},
{0x206C, 0x0263},
{0x206E, 0x2001},
{0x2070, 0x4130},
{0x2072, 0x422D},
{0x2074, 0x403E},
{0x2076, 0x888E},
{0x2078, 0x403F},
{0x207A, 0x192A},
{0x207C, 0x1292},
{0x207E, 0x843E},
{0x2080, 0x3FF7},
{0x2082, 0x422D},
{0x2084, 0x403E},
{0x2086, 0x192A},
{0x2088, 0x403F},
{0x208A, 0x888E},
{0x208C, 0x1292},
{0x208E, 0x843E},
{0x2090, 0xB3D2},
{0x2092, 0x0267},
{0x2094, 0x2403},
{0x2096, 0xD0F2},
{0x2098, 0x0040},
{0x209A, 0x0381},
{0x209C, 0x90F2},
{0x209E, 0x0010},
{0x20A0, 0x0260},
{0x20A2, 0x2002},
{0x20A4, 0x1292},
{0x20A6, 0x84BC},
{0x20A8, 0x1292},
{0x20AA, 0xD020},
{0x20AC, 0x4130},
{0x20AE, 0x1292},
{0x20B0, 0x8470},
{0x20B2, 0x1292},
{0x20B4, 0x8452},
{0x20B6, 0x0900},
{0x20B8, 0x7118},
{0x20BA, 0x1292},
{0x20BC, 0x848E},
{0x20BE, 0x0900},
{0x20C0, 0x7112},
{0x20C2, 0x0800},
{0x20C4, 0x7A20},
{0x20C6, 0x4292},
{0x20C8, 0x87DE},
{0x20CA, 0x7334},
{0x20CC, 0x0F00},
{0x20CE, 0x7304},
{0x20D0, 0x421F},
{0x20D2, 0x8718},
{0x20D4, 0x1292},
{0x20D6, 0x846E},
{0x20D8, 0x1292},
{0x20DA, 0x8488},
{0x20DC, 0x0B00},
{0x20DE, 0x7114},
{0x20E0, 0x0002},
{0x20E2, 0x1292},
{0x20E4, 0x848C},
{0x20E6, 0x1292},
{0x20E8, 0x8454},
{0x20EA, 0x43C2},
{0x20EC, 0x86EE},
{0x20EE, 0x1292},
{0x20F0, 0x8444},
{0x20F2, 0x4130},
{0x20F4, 0x4392},
{0x20F6, 0x7360},
{0x20F8, 0xB3D2},
{0x20FA, 0x0B00},
{0x20FC, 0x2402},
{0x20FE, 0xC2E2},
{0x2100, 0x0381},
{0x2102, 0x0900},
{0x2104, 0x732C},
{0x2106, 0x4382},
{0x2108, 0x7360},
{0x210A, 0x422D},
{0x210C, 0x403E},
{0x210E, 0x87F0},
{0x2110, 0x403F},
{0x2112, 0x87E8},
{0x2114, 0x1292},
{0x2116, 0x843E},
{0x2118, 0x4130},
{0x211A, 0x120B},
{0x211C, 0x120A},
{0x211E, 0x4392},
{0x2120, 0x87FA},
{0x2122, 0x4392},
{0x2124, 0x760E},
{0x2126, 0x0900},
{0x2128, 0x760C},
{0x212A, 0x421B},
{0x212C, 0x760A},
{0x212E, 0x903B},
{0x2130, 0x0201},
{0x2132, 0x2408},
{0x2134, 0x903B},
{0x2136, 0x0102},
{0x2138, 0x2405},
{0x213A, 0x4292},
{0x213C, 0x030A},
{0x213E, 0x87F8},
{0x2140, 0x1292},
{0x2142, 0x849A},
{0x2144, 0x903B},
{0x2146, 0x0020},
{0x2148, 0x2010},
{0x214A, 0x403B},
{0x214C, 0x8498},
{0x214E, 0x422F},
{0x2150, 0x12AB},
{0x2152, 0x403F},
{0x2154, 0x0028},
{0x2156, 0x12AB},
{0x2158, 0x403B},
{0x215A, 0x84C4},
{0x215C, 0x407F},
{0x215E, 0xFFAA},
{0x2160, 0x12AB},
{0x2162, 0x407F},
{0x2164, 0x0055},
{0x2166, 0x12AB},
{0x2168, 0x3FDC},
{0x216A, 0x903B},
{0x216C, 0x0021},
{0x216E, 0x2890},
{0x2170, 0x903B},
{0x2172, 0x0100},
{0x2174, 0x200D},
{0x2176, 0x403F},
{0x2178, 0x0028},
{0x217A, 0x1292},
{0x217C, 0x8498},
{0x217E, 0x425F},
{0x2180, 0x0306},
{0x2182, 0x1292},
{0x2184, 0x84C4},
{0x2186, 0x4FC2},
{0x2188, 0x0318},
{0x218A, 0x0261},
{0x218C, 0x0000},
{0x218E, 0x3FC9},
{0x2190, 0x903B},
{0x2192, 0x0101},
{0x2194, 0x2858},
{0x2196, 0x903B},
{0x2198, 0x0200},
{0x219A, 0x2450},
{0x219C, 0x903B},
{0x219E, 0x0201},
{0x21A0, 0x2C47},
{0x21A2, 0x903B},
{0x21A4, 0x0102},
{0x21A6, 0x2041},
{0x21A8, 0x93E2},
{0x21AA, 0x0262},
{0x21AC, 0x240A},
{0x21AE, 0x425F},
{0x21B0, 0x0306},
{0x21B2, 0x1292},
{0x21B4, 0x84C4},
{0x21B6, 0x4F4E},
{0x21B8, 0x4EC2},
{0x21BA, 0x0318},
{0x21BC, 0x0260},
{0x21BE, 0x0000},
{0x21C0, 0x3FB0},
{0x21C2, 0x403A},
{0x21C4, 0x8030},
{0x21C6, 0x4382},
{0x21C8, 0x0326},
{0x21CA, 0x4382},
{0x21CC, 0x0328},
{0x21CE, 0x421B},
{0x21D0, 0x030C},
{0x21D2, 0x930B},
{0x21D4, 0x2420},
{0x21D6, 0x4A5F},
{0x21D8, 0x0001},
{0x21DA, 0x1292},
{0x21DC, 0x84C4},
{0x21DE, 0x4F4E},
{0x21E0, 0x4A5F},
{0x21E2, 0x0001},
{0x21E4, 0x9F0E},
{0x21E6, 0x2402},
{0x21E8, 0x5392},
{0x21EA, 0x0326},
{0x21EC, 0x4ECA},
{0x21EE, 0x0001},
{0x21F0, 0x533B},
{0x21F2, 0x2411},
{0x21F4, 0x4A6F},
{0x21F6, 0x1292},
{0x21F8, 0x84C4},
{0x21FA, 0x4F4E},
{0x21FC, 0x4A6F},
{0x21FE, 0x9F0E},
{0x2200, 0x2402},
{0x2202, 0x5392},
{0x2204, 0x0326},
{0x2206, 0x4ECA},
{0x2208, 0x0000},
{0x220A, 0x533B},
{0x220C, 0x532A},
{0x220E, 0x0260},
{0x2210, 0x0000},
{0x2212, 0x930B},
{0x2214, 0x23E0},
{0x2216, 0x40B2},
{0x2218, 0xAA55},
{0x221A, 0x0328},
{0x221C, 0xB0F2},
{0x221E, 0x0040},
{0x2220, 0x0381},
{0x2222, 0x277F},
{0x2224, 0xD3D2},
{0x2226, 0x0267},
{0x2228, 0x3F7C},
{0x222A, 0x0261},
{0x222C, 0x0000},
{0x222E, 0x3F79},
{0x2230, 0x903B},
{0x2232, 0x0201},
{0x2234, 0x23FA},
{0x2236, 0x1292},
{0x2238, 0x84C0},
{0x223A, 0x3F73},
{0x223C, 0x1292},
{0x223E, 0x84C0},
{0x2240, 0x0261},
{0x2242, 0x0000},
{0x2244, 0x3F6E},
{0x2246, 0x903B},
{0x2248, 0x0040},
{0x224A, 0x2018},
{0x224C, 0x422F},
{0x224E, 0x1292},
{0x2250, 0x8498},
{0x2252, 0x12B0},
{0x2254, 0xF0EA},
{0x2256, 0x907F},
{0x2258, 0xFFAA},
{0x225A, 0x240D},
{0x225C, 0x5392},
{0x225E, 0x0312},
{0x2260, 0x12B0},
{0x2262, 0xF0EA},
{0x2264, 0x907F},
{0x2266, 0x0055},
{0x2268, 0x2403},
{0x226A, 0x5392},
{0x226C, 0x0312},
{0x226E, 0x3F59},
{0x2270, 0x5392},
{0x2272, 0x0310},
{0x2274, 0x3F56},
{0x2276, 0x5392},
{0x2278, 0x0310},
{0x227A, 0x3FF2},
{0x227C, 0x903B},
{0x227E, 0x0080},
{0x2280, 0x23D4},
{0x2282, 0x4382},
{0x2284, 0x0312},
{0x2286, 0x4382},
{0x2288, 0x0310},
{0x228A, 0x0261},
{0x228C, 0x0000},
{0x228E, 0x3F49},
{0x2290, 0x932B},
{0x2292, 0x2005},
{0x2294, 0x403F},
{0x2296, 0x0028},
{0x2298, 0x1292},
{0x229A, 0x8498},
{0x229C, 0x3F42},
{0x229E, 0x903B},
{0x22A0, 0x0003},
{0x22A2, 0x284B},
{0x22A4, 0x923B},
{0x22A6, 0x2015},
{0x22A8, 0x403F},
{0x22AA, 0x0023},
{0x22AC, 0x1292},
{0x22AE, 0x8498},
{0x22B0, 0x421B},
{0x22B2, 0x87F8},
{0x22B4, 0x421F},
{0x22B6, 0x030C},
{0x22B8, 0x9F0B},
{0x22BA, 0x2F33},
{0x22BC, 0x1292},
{0x22BE, 0x84BA},
{0x22C0, 0x930F},
{0x22C2, 0x2004},
{0x22C4, 0x5392},
{0x22C6, 0x0312},
{0x22C8, 0x531B},
{0x22CA, 0x3FF4},
{0x22CC, 0x5392},
{0x22CE, 0x0310},
{0x22D0, 0x3FFB},
{0x22D2, 0x903B},
{0x22D4, 0x0009},
{0x22D6, 0x2818},
{0x22D8, 0x903B},
{0x22DA, 0x0010},
{0x22DC, 0x23A6},
{0x22DE, 0x403F},
{0x22E0, 0x0027},
{0x22E2, 0x1292},
{0x22E4, 0x8498},
{0x22E6, 0x421B},
{0x22E8, 0x87F8},
{0x22EA, 0x421F},
{0x22EC, 0x030C},
{0x22EE, 0x9F0B},
{0x22F0, 0x2F18},
{0x22F2, 0x1292},
{0x22F4, 0x84BA},
{0x22F6, 0x930F},
{0x22F8, 0x2004},
{0x22FA, 0x5392},
{0x22FC, 0x0312},
{0x22FE, 0x531B},
{0x2300, 0x3FF4},
{0x2302, 0x5392},
{0x2304, 0x0310},
{0x2306, 0x3FFB},
{0x2308, 0x922B},
{0x230A, 0x238F},
{0x230C, 0x421B},
{0x230E, 0x87F8},
{0x2310, 0x421F},
{0x2312, 0x030C},
{0x2314, 0x9F0B},
{0x2316, 0x2C0B},
{0x2318, 0x1292},
{0x231A, 0x84C2},
{0x231C, 0x934F},
{0x231E, 0x240A},
{0x2320, 0x5392},
{0x2322, 0x0312},
{0x2324, 0x531B},
{0x2326, 0x421F},
{0x2328, 0x030C},
{0x232A, 0x9F0B},
{0x232C, 0x2BF5},
{0x232E, 0x0261},
{0x2330, 0x0000},
{0x2332, 0x3EF7},
{0x2334, 0x5392},
{0x2336, 0x0310},
{0x2338, 0x3FF5},
{0x233A, 0x930B},
{0x233C, 0x277F},
{0x233E, 0x931B},
{0x2340, 0x277A},
{0x2342, 0x3F73},
{0x2344, 0x413A},
{0x2346, 0x413B},
{0x2348, 0x4130},
{0x234A, 0x4F0C},
{0x234C, 0x403F},
{0x234E, 0x0267},
{0x2350, 0xF0FF},
{0x2352, 0xFFDF},
{0x2354, 0x0000},
{0x2356, 0xF0FF},
{0x2358, 0xFFEF},
{0x235A, 0x0000},
{0x235C, 0x421D},
{0x235E, 0x84B0},
{0x2360, 0x403E},
{0x2362, 0x06F9},
{0x2364, 0x4C0F},
{0x2366, 0x1292},
{0x2368, 0x84AC},
{0x236A, 0x4F4E},
{0x236C, 0xB31E},
{0x236E, 0x2403},
{0x2370, 0xD0F2},
{0x2372, 0x0020},
{0x2374, 0x0267},
{0x2376, 0xB32E},
{0x2378, 0x2403},
{0x237A, 0xD0F2},
{0x237C, 0x0010},
{0x237E, 0x0267},
{0x2380, 0xC3E2},
{0x2382, 0x0267},
{0x2384, 0x4130},
{0x2386, 0x120B},
{0x2388, 0x120A},
{0x238A, 0x403A},
{0x238C, 0x1140},
{0x238E, 0x1292},
{0x2390, 0xD080},
{0x2392, 0x430B},
{0x2394, 0x4A0F},
{0x2396, 0x532A},
{0x2398, 0x1292},
{0x239A, 0x84A4},
{0x239C, 0x4F0E},
{0x239E, 0x430F},
{0x23A0, 0x5E82},
{0x23A2, 0x87FC},
{0x23A4, 0x6F82},
{0x23A6, 0x87FE},
{0x23A8, 0x531B},
{0x23AA, 0x923B},
{0x23AC, 0x2BF3},
{0x23AE, 0x413A},
{0x23B0, 0x413B},
{0x23B2, 0x4130},
{0x23B4, 0xF0F2},
{0x23B6, 0x007F},
{0x23B8, 0x0267},
{0x23BA, 0x421D},
{0x23BC, 0x84B6},
{0x23BE, 0x403E},
{0x23C0, 0x01F9},
{0x23C2, 0x1292},
{0x23C4, 0x84AC},
{0x23C6, 0x4F4E},
{0x23C8, 0xF35F},
{0x23CA, 0x2403},
{0x23CC, 0xD0F2},
{0x23CE, 0xFF80},
{0x23D0, 0x0267},
{0x23D2, 0xB36E},
{0x23D4, 0x2404},
{0x23D6, 0xD0F2},
{0x23D8, 0x0040},
{0x23DA, 0x0267},
{0x23DC, 0x3C03},
{0x23DE, 0xF0F2},
{0x23E0, 0xFFBF},
{0x23E2, 0x0267},
{0x23E4, 0xC2E2},
{0x23E6, 0x0267},
{0x23E8, 0x4130},
{0x23EA, 0x120B},
{0x23EC, 0x120A},
{0x23EE, 0x8231},
{0x23F0, 0x430B},
{0x23F2, 0x93C2},
{0x23F4, 0x0C0A},
{0x23F6, 0x2404},
{0x23F8, 0xB3D2},
{0x23FA, 0x0B05},
{0x23FC, 0x2401},
{0x23FE, 0x431B},
{0x2400, 0x422D},
{0x2402, 0x403E},
{0x2404, 0x192A},
{0x2406, 0x403F},
{0x2408, 0x888E},
{0x240A, 0x1292},
{0x240C, 0x843E},
{0x240E, 0x930B},
{0x2410, 0x20F4},
{0x2412, 0x93E2},
{0x2414, 0x0241},
{0x2416, 0x24EB},
{0x2418, 0x403A},
{0x241A, 0x0292},
{0x241C, 0x4AA2},
{0x241E, 0x0A00},
{0x2420, 0xB2E2},
{0x2422, 0x0361},
{0x2424, 0x2405},
{0x2426, 0x4A2F},
{0x2428, 0x1292},
{0x242A, 0x8474},
{0x242C, 0x4F82},
{0x242E, 0x0A1C},
{0x2430, 0x93C2},
{0x2432, 0x0360},
{0x2434, 0x34CD},
{0x2436, 0x430C},
{0x2438, 0x4C0F},
{0x243A, 0x5F0F},
{0x243C, 0x4F0D},
{0x243E, 0x510D},
{0x2440, 0x4F0E},
{0x2442, 0x5A0E},
{0x2444, 0x4E1E},
{0x2446, 0x0002},
{0x2448, 0x4F1F},
{0x244A, 0x192A},
{0x244C, 0x1202},
{0x244E, 0xC232},
{0x2450, 0x4303},
{0x2452, 0x4E82},
{0x2454, 0x0130},
{0x2456, 0x4F82},
{0x2458, 0x0138},
{0x245A, 0x421E},
{0x245C, 0x013A},
{0x245E, 0x421F},
{0x2460, 0x013C},
{0x2462, 0x4132},
{0x2464, 0x108E},
{0x2466, 0x108F},
{0x2468, 0xEF4E},
{0x246A, 0xEF0E},
{0x246C, 0xF37F},
{0x246E, 0xC312},
{0x2470, 0x100F},
{0x2472, 0x100E},
{0x2474, 0x4E8D},
{0x2476, 0x0000},
{0x2478, 0x531C},
{0x247A, 0x922C},
{0x247C, 0x2BDD},
{0x247E, 0xB3D2},
{0x2480, 0x1921},
{0x2482, 0x2403},
{0x2484, 0x410F},
{0x2486, 0x1292},
{0x2488, 0x847E},
{0x248A, 0x403B},
{0x248C, 0x843E},
{0x248E, 0x422D},
{0x2490, 0x410E},
{0x2492, 0x403F},
{0x2494, 0x1908},
{0x2496, 0x12AB},
{0x2498, 0x403D},
{0x249A, 0x0005},
{0x249C, 0x403E},
{0x249E, 0x0292},
{0x24A0, 0x403F},
{0x24A2, 0x86E4},
{0x24A4, 0x12AB},
{0x24A6, 0x421F},
{0x24A8, 0x060E},
{0x24AA, 0x9F82},
{0x24AC, 0x8720},
{0x24AE, 0x288D},
{0x24B0, 0x9382},
{0x24B2, 0x060E},
{0x24B4, 0x248A},
{0x24B6, 0x90BA},
{0x24B8, 0x0010},
{0x24BA, 0x0000},
{0x24BC, 0x2C0B},
{0x24BE, 0x93C2},
{0x24C0, 0x86EE},
{0x24C2, 0x2008},
{0x24C4, 0x403F},
{0x24C6, 0x06A7},
{0x24C8, 0xD0FF},
{0x24CA, 0x0007},
{0x24CC, 0x0000},
{0x24CE, 0xF0FF},
{0x24D0, 0xFFF8},
{0x24D2, 0x0000},
{0x24D4, 0x4392},
{0x24D6, 0x8720},
{0x24D8, 0x403F},
{0x24DA, 0x06A7},
{0x24DC, 0xD2EF},
{0x24DE, 0x0000},
{0x24E0, 0xC2EF},
{0x24E2, 0x0000},
{0x24E4, 0x93C2},
{0x24E6, 0x87D3},
{0x24E8, 0x2068},
{0x24EA, 0xB0F2},
{0x24EC, 0x0040},
{0x24EE, 0x0B05},
{0x24F0, 0x2461},
{0x24F2, 0xD3D2},
{0x24F4, 0x0410},
{0x24F6, 0xB3E2},
{0x24F8, 0x0381},
{0x24FA, 0x2089},
{0x24FC, 0x90B2},
{0x24FE, 0x0030},
{0x2500, 0x0A00},
{0x2502, 0x2C52},
{0x2504, 0x93C2},
{0x2506, 0x86EE},
{0x2508, 0x204F},
{0x250A, 0x430E},
{0x250C, 0x430C},
{0x250E, 0x4C0F},
{0x2510, 0x5F0F},
{0x2512, 0x5F0F},
{0x2514, 0x5F0F},
{0x2516, 0x4F1F},
{0x2518, 0x8668},
{0x251A, 0xF03F},
{0x251C, 0x07FF},
{0x251E, 0x903F},
{0x2520, 0x0400},
{0x2522, 0x343E},
{0x2524, 0x5F0E},
{0x2526, 0x531C},
{0x2528, 0x923C},
{0x252A, 0x2BF1},
{0x252C, 0x4E0F},
{0x252E, 0x930E},
{0x2530, 0x3834},
{0x2532, 0x110F},
{0x2534, 0x110F},
{0x2536, 0x110F},
{0x2538, 0x9382},
{0x253A, 0x86EE},
{0x253C, 0x2023},
{0x253E, 0x5F82},
{0x2540, 0x87D6},
{0x2542, 0x403B},
{0x2544, 0x87D6},
{0x2546, 0x4B2F},
{0x2548, 0x12B0},
{0x254A, 0xB624},
{0x254C, 0x4F8B},
{0x254E, 0x0000},
{0x2550, 0x430C},
{0x2552, 0x4C0D},
{0x2554, 0x5D0D},
{0x2556, 0x5D0D},
{0x2558, 0x5D0D},
{0x255A, 0x403A},
{0x255C, 0x87D8},
{0x255E, 0x421B},
{0x2560, 0x87D6},
{0x2562, 0x4B0F},
{0x2564, 0x8A2F},
{0x2566, 0x4F0E},
{0x2568, 0x4E0F},
{0x256A, 0x5F0F},
{0x256C, 0x7F0F},
{0x256E, 0xE33F},
{0x2570, 0x8E8D},
{0x2572, 0x8668},
{0x2574, 0x7F8D},
{0x2576, 0x866A},
{0x2578, 0x531C},
{0x257A, 0x923C},
{0x257C, 0x2BEA},
{0x257E, 0x4B8A},
{0x2580, 0x0000},
{0x2582, 0x3C45},
{0x2584, 0x9382},
{0x2586, 0x86F0},
{0x2588, 0x2005},
{0x258A, 0x4382},
{0x258C, 0x87D6},
{0x258E, 0x4382},
{0x2590, 0x87D8},
{0x2592, 0x3FD7},
{0x2594, 0x4F82},
{0x2596, 0x87D6},
{0x2598, 0x3FD4},
{0x259A, 0x503F},
{0x259C, 0x0007},
{0x259E, 0x3FC9},
{0x25A0, 0x5F0E},
{0x25A2, 0x503E},
{0x25A4, 0xF800},
{0x25A6, 0x3FBF},
{0x25A8, 0x430F},
{0x25AA, 0x12B0},
{0x25AC, 0xB624},
{0x25AE, 0x4382},
{0x25B0, 0x87D6},
{0x25B2, 0x3C2D},
{0x25B4, 0xC3D2},
{0x25B6, 0x0410},
{0x25B8, 0x3F9E},
{0x25BA, 0x430D},
{0x25BC, 0x403E},
{0x25BE, 0x0050},
{0x25C0, 0x403F},
{0x25C2, 0x85C8},
{0x25C4, 0x1292},
{0x25C6, 0x844E},
{0x25C8, 0x3F90},
{0x25CA, 0x5392},
{0x25CC, 0x8720},
{0x25CE, 0x3F84},
{0x25D0, 0x403B},
{0x25D2, 0x843E},
{0x25D4, 0x4A0F},
{0x25D6, 0x532F},
{0x25D8, 0x422D},
{0x25DA, 0x4F0E},
{0x25DC, 0x403F},
{0x25DE, 0x0E08},
{0x25E0, 0x12AB},
{0x25E2, 0x422D},
{0x25E4, 0x403E},
{0x25E6, 0x192A},
{0x25E8, 0x410F},
{0x25EA, 0x12AB},
{0x25EC, 0x3F48},
{0x25EE, 0x93C2},
{0x25F0, 0x86EE},
{0x25F2, 0x2312},
{0x25F4, 0x403A},
{0x25F6, 0x86E4},
{0x25F8, 0x3F11},
{0x25FA, 0x403D},
{0x25FC, 0x0200},
{0x25FE, 0x422E},
{0x2600, 0x403F},
{0x2602, 0x192A},
{0x2604, 0x1292},
{0x2606, 0x844E},
{0x2608, 0xC3D2},
{0x260A, 0x1921},
{0x260C, 0x3F02},
{0x260E, 0x422D},
{0x2610, 0x403E},
{0x2612, 0x888E},
{0x2614, 0x403F},
{0x2616, 0x192A},
{0x2618, 0x1292},
{0x261A, 0x843E},
{0x261C, 0x5231},
{0x261E, 0x413A},
{0x2620, 0x413B},
{0x2622, 0x4130},
{0x2624, 0x4382},
{0x2626, 0x052C},
{0x2628, 0x4F0D},
{0x262A, 0x930D},
{0x262C, 0x3402},
{0x262E, 0xE33D},
{0x2630, 0x531D},
{0x2632, 0xF03D},
{0x2634, 0x07F0},
{0x2636, 0x4D0E},
{0x2638, 0xC312},
{0x263A, 0x100E},
{0x263C, 0x110E},
{0x263E, 0x110E},
{0x2640, 0x110E},
{0x2642, 0x930F},
{0x2644, 0x3803},
{0x2646, 0x4EC2},
{0x2648, 0x052C},
{0x264A, 0x3C04},
{0x264C, 0x4EC2},
{0x264E, 0x052D},
{0x2650, 0xE33D},
{0x2652, 0x531D},
{0x2654, 0x4D0F},
{0x2656, 0x4130},
{0x2658, 0x1292},
{0x265A, 0xD048},
{0x265C, 0x93C2},
{0x265E, 0x86EE},
{0x2660, 0x200D},
{0x2662, 0xB0F2},
{0x2664, 0x0020},
{0x2666, 0x0381},
{0x2668, 0x2407},
{0x266A, 0x9292},
{0x266C, 0x8722},
{0x266E, 0x0384},
{0x2670, 0x2C03},
{0x2672, 0xD3D2},
{0x2674, 0x0649},
{0x2676, 0x4130},
{0x2678, 0xC3D2},
{0x267A, 0x0649},
{0x267C, 0x4130},
{0x267E, 0x120B},
{0x2680, 0x120A},
{0x2682, 0x1209},
{0x2684, 0x1208},
{0x2686, 0x1207},
{0x2688, 0x1206},
{0x268A, 0x1205},
{0x268C, 0x1204},
{0x268E, 0x8231},
{0x2690, 0x4F81},
{0x2692, 0x0000},
{0x2694, 0x4381},
{0x2696, 0x0002},
{0x2698, 0x4304},
{0x269A, 0x411C},
{0x269C, 0x0002},
{0x269E, 0x5C0C},
{0x26A0, 0x4C0F},
{0x26A2, 0x5F0F},
{0x26A4, 0x5F0F},
{0x26A6, 0x5F0F},
{0x26A8, 0x5F0F},
{0x26AA, 0x5F0F},
{0x26AC, 0x503F},
{0x26AE, 0x1980},
{0x26B0, 0x440D},
{0x26B2, 0x5D0D},
{0x26B4, 0x4D0E},
{0x26B6, 0x5F0E},
{0x26B8, 0x4E2E},
{0x26BA, 0x4D05},
{0x26BC, 0x5505},
{0x26BE, 0x5F05},
{0x26C0, 0x4516},
{0x26C2, 0x0008},
{0x26C4, 0x4517},
{0x26C6, 0x000A},
{0x26C8, 0x460A},
{0x26CA, 0x470B},
{0x26CC, 0xF30A},
{0x26CE, 0xF32B},
{0x26D0, 0x4A81},
{0x26D2, 0x0004},
{0x26D4, 0x4B81},
{0x26D6, 0x0006},
{0x26D8, 0xB03E},
{0x26DA, 0x2000},
{0x26DC, 0x2404},
{0x26DE, 0xF03E},
{0x26E0, 0x1FFF},
{0x26E2, 0xE33E},
{0x26E4, 0x531E},
{0x26E6, 0xF317},
{0x26E8, 0x503E},
{0x26EA, 0x2000},
{0x26EC, 0x4E0F},
{0x26EE, 0x5F0F},
{0x26F0, 0x7F0F},
{0x26F2, 0xE33F},
{0x26F4, 0x512C},
{0x26F6, 0x4C28},
{0x26F8, 0x4309},
{0x26FA, 0x4E0A},
{0x26FC, 0x4F0B},
{0x26FE, 0x480C},
{0x2700, 0x490D},
{0x2702, 0x1202},
{0x2704, 0xC232},
{0x2706, 0x12B0},
{0x2708, 0xFFC0},
{0x270A, 0x4132},
{0x270C, 0x108E},
{0x270E, 0x108F},
{0x2710, 0xEF4E},
{0x2712, 0xEF0E},
{0x2714, 0xF37F},
{0x2716, 0xC312},
{0x2718, 0x100F},
{0x271A, 0x100E},
{0x271C, 0x4E85},
{0x271E, 0x0018},
{0x2720, 0x4F85},
{0x2722, 0x001A},
{0x2724, 0x480A},
{0x2726, 0x490B},
{0x2728, 0x460C},
{0x272A, 0x470D},
{0x272C, 0x1202},
{0x272E, 0xC232},
{0x2730, 0x12B0},
{0x2732, 0xFFC0},
{0x2734, 0x4132},
{0x2736, 0x4E0C},
{0x2738, 0x4F0D},
{0x273A, 0x108C},
{0x273C, 0x108D},
{0x273E, 0xED4C},
{0x2740, 0xED0C},
{0x2742, 0xF37D},
{0x2744, 0xC312},
{0x2746, 0x100D},
{0x2748, 0x100C},
{0x274A, 0x411E},
{0x274C, 0x0004},
{0x274E, 0x411F},
{0x2750, 0x0006},
{0x2752, 0x5E0E},
{0x2754, 0x6F0F},
{0x2756, 0x5E0E},
{0x2758, 0x6F0F},
{0x275A, 0x5E0E},
{0x275C, 0x6F0F},
{0x275E, 0xDE0C},
{0x2760, 0xDF0D},
{0x2762, 0x4C85},
{0x2764, 0x002C},
{0x2766, 0x4D85},
{0x2768, 0x002E},
{0x276A, 0x5314},
{0x276C, 0x9224},
{0x276E, 0x2B95},
{0x2770, 0x5391},
{0x2772, 0x0002},
{0x2774, 0x92A1},
{0x2776, 0x0002},
{0x2778, 0x2B8F},
{0x277A, 0x5231},
{0x277C, 0x4134},
{0x277E, 0x4135},
{0x2780, 0x4136},
{0x2782, 0x4137},
{0x2784, 0x4138},
{0x2786, 0x4139},
{0x2788, 0x413A},
{0x278A, 0x413B},
{0x278C, 0x4130},
{0x278E, 0x120B},
{0x2790, 0x120A},
{0x2792, 0x1209},
{0x2794, 0x8031},
{0x2796, 0x000C},
{0x2798, 0x425F},
{0x279A, 0x0205},
{0x279C, 0xC312},
{0x279E, 0x104F},
{0x27A0, 0x114F},
{0x27A2, 0x114F},
{0x27A4, 0x114F},
{0x27A6, 0x114F},
{0x27A8, 0x114F},
{0x27AA, 0xF37F},
{0x27AC, 0x4F0B},
{0x27AE, 0xF31B},
{0x27B0, 0x5B0B},
{0x27B2, 0x5B0B},
{0x27B4, 0x5B0B},
{0x27B6, 0x503B},
{0x27B8, 0xD194},
{0x27BA, 0x4219},
{0x27BC, 0x0508},
{0x27BE, 0xF039},
{0x27C0, 0x2000},
{0x27C2, 0x4F0A},
{0x27C4, 0xC312},
{0x27C6, 0x100A},
{0x27C8, 0xE31A},
{0x27CA, 0x421F},
{0x27CC, 0x87DE},
{0x27CE, 0x503F},
{0x27D0, 0xFF60},
{0x27D2, 0x903F},
{0x27D4, 0x00C8},
{0x27D6, 0x2C02},
{0x27D8, 0x403F},
{0x27DA, 0x00C8},
{0x27DC, 0x4F82},
{0x27DE, 0x7322},
{0x27E0, 0xB3D2},
{0x27E2, 0x0381},
{0x27E4, 0x2009},
{0x27E6, 0x421F},
{0x27E8, 0x86F0},
{0x27EA, 0xD21F},
{0x27EC, 0x86EE},
{0x27EE, 0x930F},
{0x27F0, 0x24B9},
{0x27F2, 0x40F2},
{0x27F4, 0xFF80},
{0x27F6, 0x0619},
{0x27F8, 0x1292},
{0x27FA, 0xD00A},
{0x27FC, 0xB3D2},
{0x27FE, 0x0385},
{0x2800, 0x2405},
{0x2802, 0x421F},
{0x2804, 0x880A},
{0x2806, 0x4F92},
{0x2808, 0x0002},
{0x280A, 0x8714},
{0x280C, 0x430D},
{0x280E, 0x93C2},
{0x2810, 0x87D0},
{0x2812, 0x2003},
{0x2814, 0xB2F2},
{0x2816, 0x0360},
{0x2818, 0x2001},
{0x281A, 0x431D},
{0x281C, 0x425F},
{0x281E, 0x87D3},
{0x2820, 0xD25F},
{0x2822, 0x87D2},
{0x2824, 0xF37F},
{0x2826, 0x5F0F},
{0x2828, 0x425E},
{0x282A, 0x87CD},
{0x282C, 0xDE0F},
{0x282E, 0x5F0F},
{0x2830, 0x5B0F},
{0x2832, 0x4FA2},
{0x2834, 0x0402},
{0x2836, 0x930D},
{0x2838, 0x2007},
{0x283A, 0x930A},
{0x283C, 0x248E},
{0x283E, 0x4F5F},
{0x2840, 0x0001},
{0x2842, 0xF37F},
{0x2844, 0x4FC2},
{0x2846, 0x0403},
{0x2848, 0x93C2},
{0x284A, 0x87CD},
{0x284C, 0x2483},
{0x284E, 0xC2F2},
{0x2850, 0x0400},
{0x2852, 0xB2E2},
{0x2854, 0x0265},
{0x2856, 0x2407},
{0x2858, 0x421F},
{0x285A, 0x0508},
{0x285C, 0xF03F},
{0x285E, 0xFFDF},
{0x2860, 0xD90F},
{0x2862, 0x4F82},
{0x2864, 0x0508},
{0x2866, 0xB3D2},
{0x2868, 0x0383},
{0x286A, 0x2484},
{0x286C, 0x403F},
{0x286E, 0x0508},
{0x2870, 0x4FB1},
{0x2872, 0x0000},
{0x2874, 0x4FB1},
{0x2876, 0x0002},
{0x2878, 0x4FB1},
{0x287A, 0x0004},
{0x287C, 0x403F},
{0x287E, 0x0500},
{0x2880, 0x4FB1},
{0x2882, 0x0006},
{0x2884, 0x4FB1},
{0x2886, 0x0008},
{0x2888, 0x4FB1},
{0x288A, 0x000A},
{0x288C, 0xB3E2},
{0x288E, 0x0383},
{0x2890, 0x2412},
{0x2892, 0xC2E1},
{0x2894, 0x0002},
{0x2896, 0xB2E2},
{0x2898, 0x0383},
{0x289A, 0x434F},
{0x289C, 0x634F},
{0x289E, 0xF37F},
{0x28A0, 0x4F4E},
{0x28A2, 0x114E},
{0x28A4, 0x434E},
{0x28A6, 0x104E},
{0x28A8, 0x415F},
{0x28AA, 0x0007},
{0x28AC, 0xF07F},
{0x28AE, 0x007F},
{0x28B0, 0xDE4F},
{0x28B2, 0x4FC1},
{0x28B4, 0x0007},
{0x28B6, 0xB2F2},
{0x28B8, 0x0383},
{0x28BA, 0x2415},
{0x28BC, 0xF0F1},
{0x28BE, 0xFFBF},
{0x28C0, 0x0000},
{0x28C2, 0xB0F2},
{0x28C4, 0x0010},
{0x28C6, 0x0383},
{0x28C8, 0x434E},
{0x28CA, 0x634E},
{0x28CC, 0x5E4E},
{0x28CE, 0x5E4E},
{0x28D0, 0x5E4E},
{0x28D2, 0x5E4E},
{0x28D4, 0x5E4E},
{0x28D6, 0x5E4E},
{0x28D8, 0x415F},
{0x28DA, 0x0006},
{0x28DC, 0xF07F},
{0x28DE, 0xFFBF},
{0x28E0, 0xDE4F},
{0x28E2, 0x4FC1},
{0x28E4, 0x0006},
{0x28E6, 0xB0F2},
{0x28E8, 0x0020},
{0x28EA, 0x0383},
{0x28EC, 0x2410},
{0x28EE, 0xF0F1},
{0x28F0, 0xFFDF},
{0x28F2, 0x0002},
{0x28F4, 0xB0F2},
{0x28F6, 0x0040},
{0x28F8, 0x0383},
{0x28FA, 0x434E},
{0x28FC, 0x634E},
{0x28FE, 0x5E4E},
{0x2900, 0x5E4E},
{0x2902, 0x415F},
{0x2904, 0x0008},
{0x2906, 0xC26F},
{0x2908, 0xDE4F},
{0x290A, 0x4FC1},
{0x290C, 0x0008},
{0x290E, 0x93C2},
{0x2910, 0x0383},
{0x2912, 0x3412},
{0x2914, 0xF0F1},
{0x2916, 0xFFDF},
{0x2918, 0x0000},
{0x291A, 0x425E},
{0x291C, 0x0382},
{0x291E, 0xF35E},
{0x2920, 0x5E4E},
{0x2922, 0x5E4E},
{0x2924, 0x5E4E},
{0x2926, 0x5E4E},
{0x2928, 0x5E4E},
{0x292A, 0x415F},
{0x292C, 0x0006},
{0x292E, 0xF07F},
{0x2930, 0xFFDF},
{0x2932, 0xDE4F},
{0x2934, 0x4FC1},
{0x2936, 0x0006},
{0x2938, 0x410F},
{0x293A, 0x4FB2},
{0x293C, 0x0508},
{0x293E, 0x4FB2},
{0x2940, 0x050A},
{0x2942, 0x4FB2},
{0x2944, 0x050C},
{0x2946, 0x4FB2},
{0x2948, 0x0500},
{0x294A, 0x4FB2},
{0x294C, 0x0502},
{0x294E, 0x4FB2},
{0x2950, 0x0504},
{0x2952, 0x3C10},
{0x2954, 0xD2F2},
{0x2956, 0x0400},
{0x2958, 0x3F7C},
{0x295A, 0x4F6F},
{0x295C, 0xF37F},
{0x295E, 0x4FC2},
{0x2960, 0x0402},
{0x2962, 0x3F72},
{0x2964, 0x90F2},
{0x2966, 0x0011},
{0x2968, 0x0619},
{0x296A, 0x2B46},
{0x296C, 0x50F2},
{0x296E, 0xFFF0},
{0x2970, 0x0619},
{0x2972, 0x3F42},
{0x2974, 0x5031},
{0x2976, 0x000C},
{0x2978, 0x4139},
{0x297A, 0x413A},
{0x297C, 0x413B},
{0x297E, 0x4130},
{0x2980, 0x0900},
{0x2982, 0x7312},
{0x2984, 0x421F},
{0x2986, 0x0A08},
{0x2988, 0xF03F},
{0x298A, 0xF7FF},
{0x298C, 0x4F82},
{0x298E, 0x0A88},
{0x2990, 0x0900},
{0x2992, 0x7312},
{0x2994, 0x421F},
{0x2996, 0x0A0E},
{0x2998, 0xF03F},
{0x299A, 0x7FFF},
{0x299C, 0x4F82},
{0x299E, 0x0A8E},
{0x29A0, 0x0900},
{0x29A2, 0x7312},
{0x29A4, 0x421F},
{0x29A6, 0x0A1E},
{0x29A8, 0xC31F},
{0x29AA, 0x4F82},
{0x29AC, 0x0A9E},
{0x29AE, 0x4130},
{0x29B0, 0x4292},
{0x29B2, 0x0A08},
{0x29B4, 0x0A88},
{0x29B6, 0x0900},
{0x29B8, 0x7312},
{0x29BA, 0x4292},
{0x29BC, 0x0A0E},
{0x29BE, 0x0A8E},
{0x29C0, 0x0900},
{0x29C2, 0x7312},
{0x29C4, 0x4292},
{0x29C6, 0x0A1E},
{0x29C8, 0x0A9E},
{0x29CA, 0x4130},
{0x29CC, 0x7400},
{0x29CE, 0x8058},
{0x29D0, 0x1807},
{0x29D2, 0x00E0},
{0x29D4, 0x7002},
{0x29D6, 0x17C7},
{0x29D8, 0x0045},
{0x29DA, 0x0006},
{0x29DC, 0x17CC},
{0x29DE, 0x0015},
{0x29E0, 0x1512},
{0x29E2, 0x216F},
{0x29E4, 0x005B},
{0x29E6, 0x005D},
{0x29E8, 0x00DE},
{0x29EA, 0x00DD},
{0x29EC, 0x5023},
{0x29EE, 0x00DE},
{0x29F0, 0x005B},
{0x29F2, 0x0410},
{0x29F4, 0x0091},
{0x29F6, 0x0015},
{0x29F8, 0x0040},
{0x29FA, 0x7023},
{0x29FC, 0x1653},
{0x29FE, 0x0156},
{0x2A00, 0x0001},
{0x2A02, 0x2081},
{0x2A04, 0x7020},
{0x2A06, 0x2F99},
{0x2A08, 0x005C},
{0x2A0A, 0x0000},
{0x2A0C, 0x5040},
{0x2A0E, 0x0045},
{0x2A10, 0x213A},
{0x2A12, 0x0303},
{0x2A14, 0x0148},
{0x2A16, 0x0049},
{0x2A18, 0x0045},
{0x2A1A, 0x0046},
{0x2A1C, 0x05DD},
{0x2A1E, 0x00DE},
{0x2A20, 0x00DD},
{0x2A22, 0x00DC},
{0x2A24, 0x00DE},
{0x2A26, 0x04D6},
{0x2A28, 0x2014},
{0x2A2A, 0x2081},
{0x2A2C, 0x7087},
{0x2A2E, 0x2F99},
{0x2A30, 0x005C},
{0x2A32, 0x0002},
{0x2A34, 0x5060},
{0x2A36, 0x31C0},
{0x2A38, 0x2122},
{0x2A3A, 0x7800},
{0x2A3C, 0xC08C},
{0x2A3E, 0x0001},
{0x2A40, 0x9038},
{0x2A42, 0x59F7},
{0x2A44, 0x907A},
{0x2A46, 0x03D8},
{0x2A48, 0x8D90},
{0x2A4A, 0x01C0},
{0x2A4C, 0x7400},
{0x2A4E, 0x8058},
{0x2A50, 0x1807},
{0x2A52, 0x00E0},
{0x2A54, 0x7002},
{0x2A56, 0x17C7},
{0x2A58, 0x0045},
{0x2A5A, 0x0006},
{0x2A5C, 0x17CC},
{0x2A5E, 0x0015},
{0x2A60, 0x1512},
{0x2A62, 0x216F},
{0x2A64, 0x005B},
{0x2A66, 0x005D},
{0x2A68, 0x00DE},
{0x2A6A, 0x00DD},
{0x2A6C, 0x5023},
{0x2A6E, 0x00DE},
{0x2A70, 0x005B},
{0x2A72, 0x0410},
{0x2A74, 0x0091},
{0x2A76, 0x0015},
{0x2A78, 0x0040},
{0x2A7A, 0x7023},
{0x2A7C, 0x1653},
{0x2A7E, 0x0156},
{0x2A80, 0x0001},
{0x2A82, 0x2081},
{0x2A84, 0x7020},
{0x2A86, 0x2F99},
{0x2A88, 0x005C},
{0x2A8A, 0x0000},
{0x2A8C, 0x5040},
{0x2A8E, 0x0045},
{0x2A90, 0x213A},
{0x2A92, 0x0303},
{0x2A94, 0x0148},
{0x2A96, 0x0049},
{0x2A98, 0x0045},
{0x2A9A, 0x0046},
{0x2A9C, 0x05DD},
{0x2A9E, 0x00DE},
{0x2AA0, 0x00DD},
{0x2AA2, 0x00DC},
{0x2AA4, 0x00DE},
{0x2AA6, 0x0296},
{0x2AA8, 0x2014},
{0x2AAA, 0x2081},
{0x2AAC, 0x7087},
{0x2AAE, 0x2F99},
{0x2AB0, 0x005C},
{0x2AB2, 0x0002},
{0x2AB4, 0x5060},
{0x2AB6, 0x31C0},
{0x2AB8, 0x2122},
{0x2ABA, 0x7800},
{0x2ABC, 0xC08C},
{0x2ABE, 0x0001},
{0x2AC0, 0x9038},
{0x2AC2, 0x59F7},
{0x2AC4, 0x907A},
{0x2AC6, 0x03D8},
{0x2AC8, 0x8D90},
{0x2ACA, 0x01C0},
{0x2ACC, 0x7400},
{0x2ACE, 0x2002},
{0x2AD0, 0x70DF},
{0x2AD2, 0x2F21},
{0x2AD4, 0x04C1},
{0x2AD6, 0x0D80},
{0x2AD8, 0x7800},
{0x2ADA, 0x0041},
{0x2ADC, 0x7400},
{0x2ADE, 0x2004},
{0x2AE0, 0x70DF},
{0x2AE2, 0x2F21},
{0x2AE4, 0x04C2},
{0x2AE6, 0x0D80},
{0x2AE8, 0x7800},
{0x2AEA, 0x7400},
{0x2AEC, 0x2008},
{0x2AEE, 0x70DF},
{0x2AF0, 0x2F21},
{0x2AF2, 0x04C3},
{0x2AF4, 0x0D80},
{0x2AF6, 0x7800},
{0x2AF8, 0x7400},
{0x2AFA, 0x0004},
{0x2AFC, 0x70DF},
{0x2AFE, 0x2F22},
{0x2B00, 0x7008},
{0x2B02, 0x2F1F},
{0x2B04, 0x7021},
{0x2B06, 0x2F01},
{0x2B08, 0x7800},
{0x2B0A, 0x7400},
{0x2B0C, 0x0002},
{0x2B0E, 0x70DF},
{0x2B10, 0x3F5F},
{0x2B12, 0x703A},
{0x2B14, 0x2F01},
{0x2B16, 0x7800},
{0x2B18, 0x7400},
{0x2B1A, 0x2010},
{0x2B1C, 0x70DF},
{0x2B1E, 0x3F40},
{0x2B20, 0x700A},
{0x2B22, 0x0FC0},
{0x2B24, 0x7800},
{0x2B26, 0x7400},
{0x2B28, 0x2004},
{0x2B2A, 0x70DF},
{0x2B2C, 0x2F21},
{0x2B2E, 0x04C2},
{0x2B30, 0x0D80},
{0x2B32, 0x7800},
{0x2B34, 0x0041},
{0x2B36, 0x7400},
{0x2B38, 0x2002},
{0x2B3A, 0x70DF},
{0x2B3C, 0x2F22},
{0x2B3E, 0x04C1},
{0x2B40, 0x0D80},
{0x2B42, 0x7800},
{0x2B44, 0x7400},
{0x2B46, 0x0001},
{0x2B48, 0x70DF},
{0x2B4A, 0x3F5F},
{0x2B4C, 0x703A},
{0x2B4E, 0x2F01},
{0x2B50, 0x7800},
{0x2B52, 0x7400},
{0x2B54, 0x200A},
{0x2B56, 0x70DF},
{0x2B58, 0x3F40},
{0x2B5A, 0x700A},
{0x2B5C, 0x0FC0},
{0x2B5E, 0x7800},
{0x2B60, 0x7400},
{0x2B62, 0x2015},
{0x2B64, 0x70DF},
{0x2B66, 0x3F5F},
{0x2B68, 0x703A},
{0x2B6A, 0x2F01},
{0x2B6C, 0x7800},
{0x2B6E, 0x7400},
{0x2B70, 0x7800},
{0x2B72, 0x007F},
{0x2B74, 0x0000},
{0x2B76, 0xB9CC},
{0x2B78, 0x0000},
{0x2B7A, 0xB9CC},
{0x2B7C, 0xBA3C},
{0x2B7E, 0x0002},
{0x2B80, 0x0000},
{0x2B82, 0xBA4C},
{0x2B84, 0x0000},
{0x2B86, 0xBA4C},
{0x2B88, 0xBABC},
{0x2B8A, 0x0002},
{0x2B8C, 0x0063},
{0x2B8E, 0xBB26},
{0x2B90, 0x0063},
{0x2B92, 0xBB36},
{0x2B94, 0x0063},
{0x2B96, 0xBAEA},
{0x2B98, 0x0063},
{0x2B9A, 0xBAF8},
{0x2B9C, 0xBADA},
{0x2B9E, 0x0004},
{0x2BA0, 0x0063},
{0x2BA2, 0xBAEA},
{0x2BA4, 0x0063},
{0x2BA6, 0xBB18},
{0x2BA8, 0x0063},
{0x2BAA, 0xBB26},
{0x2BAC, 0x0063},
{0x2BAE, 0xBB44},
{0x2BB0, 0xBADA},
{0x2BB2, 0x0004},
{0x2BB4, 0x0063},
{0x2BB6, 0xBACC},
{0x2BB8, 0x0063},
{0x2BBA, 0xBADC},
{0x2BBC, 0x0063},
{0x2BBE, 0xBAEA},
{0x2BC0, 0x0063},
{0x2BC2, 0xBAF8},
{0x2BC4, 0xBADA},
{0x2BC6, 0x0004},
{0x2BC8, 0x0063},
{0x2BCA, 0xBAEA},
{0x2BCC, 0x0063},
{0x2BCE, 0xBB18},
{0x2BD0, 0x0063},
{0x2BD2, 0xBACC},
{0x2BD4, 0x0063},
{0x2BD6, 0xBB0A},
{0x2BD8, 0xBADA},
{0x2BDA, 0x0004},
{0x2BDC, 0x0063},
{0x2BDE, 0xBACC},
{0x2BE0, 0x0063},
{0x2BE2, 0xBADC},
{0x2BE4, 0x0063},
{0x2BE6, 0xBAEA},
{0x2BE8, 0x0063},
{0x2BEA, 0xBB18},
{0x2BEC, 0xBADA},
{0x2BEE, 0x0004},
{0x2BF0, 0xFFFF},
{0x2BF2, 0xBB6E},
{0x2BF4, 0x0000},
{0x2BF6, 0x0000},
{0x2BF8, 0x0000},
{0x2BFA, 0x0000},
{0x2BFC, 0x0000},
{0x2BFE, 0x0000},
{0x2C00, 0xBB72},
{0x2C02, 0x0001},
{0x2C04, 0x0063},
{0x2C06, 0xBB52},
{0x2C08, 0x0063},
{0x2C0A, 0xBB60},
{0x2C0C, 0x0000},
{0x2C0E, 0x0000},
{0x2C10, 0x0000},
{0x2C12, 0x0000},
{0x2C14, 0xBADA},
{0x2C16, 0x0002},
{0x2C18, 0x0066},
{0x2C1A, 0x0067},
{0x2C1C, 0x00AF},
{0x2C1E, 0x01CF},
{0x2C20, 0x0087},
{0x2C22, 0x0083},
{0x2C24, 0x011B},
{0x2C26, 0x035A},
{0x2C28, 0x00FA},
{0x2C2A, 0x00F2},
{0x2C2C, 0x00A6},
{0x2C2E, 0x00A4},
{0x2C30, 0xFFFF},
{0x2C32, 0x002C},
{0x2C34, 0x0058},
{0x2C36, 0x0000},
{0x2C38, 0x0000},
{0x2C3A, 0xBC18},
{0x2C3C, 0xBB74},
{0x2C3E, 0xBB80},
{0x2C40, 0xBC32},
{0x2C42, 0xBB8C},
{0x2C44, 0xBBA0},
{0x2C46, 0xBB8C},
{0x2C48, 0xBBA0},
{0x2C4A, 0xBC04},
{0x2C4C, 0xBC04},
{0x2C4E, 0xBBF0},
{0x2C50, 0xBBF0},
{0x2C52, 0xBBB4},
{0x2C54, 0xBBC8},
{0x2C56, 0xBBB4},
{0x2C58, 0xBBC8},
{0x2C5A, 0xBC04},
{0x2C5C, 0xBC04},
{0x2C5E, 0xBBF0},
{0x2C60, 0xBBF0},
{0x2C62, 0xBB8C},
{0x2C64, 0xBBA0},
{0x2C66, 0xBB8C},
{0x2C68, 0xBBA0},
{0x2C6A, 0xBC04},
{0x2C6C, 0xBC04},
{0x2C6E, 0xBBF0},
{0x2C70, 0xBBF0},
{0x2C72, 0xBBB4},
{0x2C74, 0xBBC8},
{0x2C76, 0xBBB4},
{0x2C78, 0xBBC8},
{0x2C7A, 0xBC04},
{0x2C7C, 0xBC04},
{0x2C7E, 0xBBF0},
{0x2C80, 0xBBF0},
{0x3800, 0x880E},
{0x3802, 0xBC62},
{0x3804, 0xBC40},
{0x3806, 0xD13E},
{0x3808, 0xBC42},
{0x380A, 0xBC3C},
{0x380C, 0x0000},
{0x380E, 0x0040},
{0x3810, 0x0040},
{0x3812, 0x0040},
{0x3814, 0x0043},
{0x3816, 0x0046},
{0x3818, 0x004B},
{0x381A, 0x004D},
{0x381C, 0x0051},
{0x381E, 0x0055},
{0x3820, 0x005A},
{0x3822, 0x005E},
{0x3824, 0x0062},
{0x3826, 0x0067},
{0x3828, 0x006C},
{0x382A, 0x0070},
{0x382C, 0x0078},
{0x382E, 0x0086},
{0x3830, 0x0090},
{0x3832, 0x0096},
{0x3834, 0x009D},
{0x3836, 0x00A5},
{0x3838, 0x00AD},
{0x383A, 0x00B4},
{0x383C, 0x00B9},
{0x383E, 0x00BE},
{0x3840, 0x00C3},
{0x3842, 0x00C8},
{0x3844, 0x00CD},
{0x3846, 0x00D2},
{0x3848, 0x00D7},
{0x384A, 0x00DC},
{0x384C, 0x00DC},
{0x384E, 0x0000},
{0x3850, 0x0000},
{0x3852, 0x0000},
{0x3854, 0x0000},
{0x3856, 0x0000},
{0x3858, 0x0000},
{0x385A, 0x0000},
{0x385C, 0x0000},
{0x385E, 0x0000},
{0x3860, 0x0000},
{0x3862, 0x0000},
{0x3864, 0x0000},
{0x3866, 0x0000},
{0x3868, 0x0000},
{0x386A, 0x0000},
{0x386C, 0x0000},
{0x386E, 0x0000},
{0x3870, 0x0000},
{0x3872, 0x0000},
{0x3874, 0x0000},
{0x3876, 0x0000},
{0x3878, 0x0000},
{0x387A, 0x0000},
{0x387C, 0x0000},
{0x387E, 0x0000},
{0x3880, 0x0000},
{0x3882, 0x0000},
{0x3884, 0x0000},
{0x3886, 0x0000},
{0x3888, 0x0000},
{0x388A, 0x0000},
{0x388C, 0x0000},
{0x026A, 0xFFFF},
{0x026C, 0x00FF},
{0x026E, 0x0000},
{0x0360, 0x1E8E},
{0x040E, 0x01EB},
{0x0600, 0x1130},
{0x0602, 0x3112},
{0x0604, 0x8048},
{0x0606, 0x00E9},
{0x067A, 0x0404},
{0x067C, 0x0404},
{0x06A8, 0x0240},
{0x06AA, 0x00CA},
{0x06AC, 0x0041},
{0x06B4, 0x3FFF},
{0x06DE, 0x0404},
{0x06E0, 0x0404},
{0x06E2, 0xFF00},
{0x06E4, 0x8333},
{0x06E6, 0x8333},
{0x06E8, 0x8333},
{0x06EA, 0x8333},
{0x052A, 0x0000},
{0x052C, 0x0000},
{0x0F06, 0x0002},
{0x0A04, 0xB4C5},
{0x0A06, 0xC400},
{0x0A08, 0x988A},
{0x0A0A, 0xA387},
{0x0A0E, 0xEEC0},
{0x0A12, 0x0000},
{0x0A18, 0x0010},
{0x0A1C, 0x0040},
{0x0A20, 0x0015},
{0x0C00, 0x0021},
{0x0C16, 0x0002},
{0x0708, 0x6FC0},
{0x070C, 0x0000},
{0x120C, 0x1428},
{0x121A, 0x0000},
{0x121C, 0x1896},
{0x121E, 0x0032},
{0x1220, 0x0000},
{0x1222, 0x96FF},
{0x1244, 0x0000},
{0x105C, 0x0F0B},
{0x1958, 0x0000},
{0x195A, 0x004C},
{0x195C, 0x0097},
{0x195E, 0x0221},
{0x1960, 0x03FE},
{0x1980, 0x00E0},
{0x1982, 0x0010},
{0x1984, 0x2018},
{0x1986, 0x0008},
{0x1988, 0x0000},
{0x198A, 0x0000},
{0x198C, 0x0880},
{0x198E, 0x0000},
{0x1990, 0x1A00},
{0x1992, 0x0000},
{0x1994, 0x2800},
{0x1996, 0x0002},
{0x1962, 0x0000},
{0x1964, 0x004C},
{0x1966, 0x0097},
{0x1968, 0x0221},
{0x196A, 0x03FE},
{0x19C0, 0x00E0},
{0x19C2, 0x0010},
{0x19C4, 0x2018},
{0x19C6, 0x0008},
{0x19C8, 0x0000},
{0x19CA, 0x0000},
{0x19CC, 0x0880},
{0x19CE, 0x0000},
{0x19D0, 0x1A00},
{0x19D2, 0x0000},
{0x19D4, 0x2800},
{0x19D6, 0x0002},
{0x196C, 0x0000},
{0x196E, 0x004C},
{0x1970, 0x0097},
{0x1972, 0x0221},
{0x1974, 0x03FE},
{0x1A00, 0x00E0},
{0x1A02, 0x0010},
{0x1A04, 0x2018},
{0x1A06, 0x0008},
{0x1A08, 0x0000},
{0x1A0A, 0x0000},
{0x1A0C, 0x0880},
{0x1A0E, 0x0000},
{0x1A10, 0x1A00},
{0x1A12, 0x0000},
{0x1A14, 0x2800},
{0x1A16, 0x0002},
{0x1976, 0x0000},
{0x1978, 0x004C},
{0x197A, 0x0097},
{0x197C, 0x0221},
{0x197E, 0x03FE},
{0x1A40, 0x00E0},
{0x1A42, 0x0010},
{0x1A44, 0x2018},
{0x1A46, 0x0008},
{0x1A48, 0x0000},
{0x1A4A, 0x0000},
{0x1A4C, 0x0880},
{0x1A4E, 0x0000},
{0x1A50, 0x1A00},
{0x1A52, 0x0000},
{0x1A54, 0x2800},
{0x1A56, 0x0002},
{0x192A, 0x0201},
{0x0384, 0x0001},
{0x027E, 0x0100},
};
static const struct hi847_reg mode_3264x2448_regs[] = {
{0x0B00, 0x0000},
{0x0204, 0x0000},
{0x0206, 0x033C},
{0x020A, 0x0B4D},
{0x020E, 0x0B51},
{0x0214, 0x0200},
{0x0216, 0x0200},
{0x0218, 0x0200},
{0x021A, 0x0200},
{0x0224, 0x002E},
{0x022A, 0x0017},
{0x022C, 0x0E1F},
{0x022E, 0x09C1},
{0x0234, 0x1111},
{0x0236, 0x1111},
{0x0238, 0x1111},
{0x023A, 0x1111},
{0x0250, 0x0000},
{0x0252, 0x0006},
{0x0254, 0x0000},
{0x0256, 0x0000},
{0x0258, 0x0000},
{0x025A, 0x0000},
{0x025C, 0x0000},
{0x025E, 0x0202},
{0x0268, 0x00CD},
{0x0440, 0x0002},
{0x0F00, 0x0000},
{0x0F04, 0x0008},
{0x0F06, 0x0002},
{0x0B02, 0x0100},
{0x0B04, 0x00DC},
{0x0B12, 0x0CC0},
{0x0B14, 0x0990},
{0x0B20, 0x0100},
{0x1100, 0x1100},
{0x1102, 0x0008},
{0x1108, 0x0202},
{0x1118, 0x0000},
{0x0A10, 0xB040},
{0x0C14, 0x0008},
{0x0C18, 0x0CC0},
{0x0C1A, 0x0990},
{0x0730, 0x0001},
{0x0732, 0x0000},
{0x0734, 0x0300},
{0x0736, 0x004B},
{0x0738, 0x0001},
{0x073C, 0x0900},
{0x0740, 0x0000},
{0x0742, 0x0000},
{0x0744, 0x0300},
{0x0746, 0x007D},
{0x0748, 0x0002},
{0x074A, 0x0900},
{0x074C, 0x0000},
{0x074E, 0x0100},
{0x0750, 0x0000},
{0x1200, 0x0946},
{0x1202, 0x1A00},
{0x120E, 0x6027},
{0x1210, 0x8027},
{0x1246, 0x0105},
{0x1000, 0x0300},
{0x1002, 0xC311},
{0x1004, 0x2BB0},
{0x1010, 0x087B},
{0x1012, 0x0040},
{0x1014, 0x0020},
{0x1016, 0x0020},
{0x101A, 0x0020},
{0x1020, 0xC107},
{0x1022, 0x081E},
{0x1024, 0x0509},
{0x1026, 0x0B0A},
{0x1028, 0x1409},
{0x102A, 0x0B05},
{0x102C, 0x1400},
{0x1038, 0x0000},
{0x103E, 0x0001},
{0x1040, 0x0000},
{0x1042, 0x0008},
{0x1044, 0x0120},
{0x1046, 0x01B0},
{0x1048, 0x0090},
{0x1066, 0x089C},
{0x1600, 0x0000},
{0x1608, 0x0028},
{0x160A, 0x0C80},
{0x160C, 0x001A},
{0x160E, 0x0960},
{0x0252, 0x0009},
{0x0202, 0x0000},
};
static const struct hi847_reg mode_1632x1224_regs[] = {
{0x0B00, 0x0000},
{0x0204, 0x0200},
{0x0206, 0x033C},
{0x020A, 0x05A5},
{0x020E, 0x05A9},
{0x0214, 0x0200},
{0x0216, 0x0200},
{0x0218, 0x0200},
{0x021A, 0x0200},
{0x0224, 0x002C},
{0x022A, 0x0015},
{0x022C, 0x0E2D},
{0x022E, 0x09C1},
{0x0234, 0x3311},
{0x0236, 0x3311},
{0x0238, 0x3311},
{0x023A, 0x2222},
{0x0250, 0x0000},
{0x0252, 0x0006},
{0x0254, 0x0000},
{0x0256, 0x0000},
{0x0258, 0x0000},
{0x025A, 0x0000},
{0x025C, 0x0000},
{0x025E, 0x0202},
{0x0268, 0x00CD},
{0x0440, 0x0002},
{0x0F00, 0x0400},
{0x0F04, 0x0004},
{0x0F06, 0x0002},
{0x0B02, 0x0100},
{0x0B04, 0x00FC},
{0x0B12, 0x0660},
{0x0B14, 0x04C8},
{0x0B20, 0x0200},
{0x1100, 0x1100},
{0x1102, 0x0008},
{0x1108, 0x0402},
{0x1118, 0x0000},
{0x0A10, 0xB060},
{0x0C14, 0x0008},
{0x0C18, 0x0CC0},
{0x0C1A, 0x04C8},
{0x0730, 0x0001},
{0x0732, 0x0000},
{0x0734, 0x0300},
{0x0736, 0x004B},
{0x0738, 0x0001},
{0x073C, 0x0900},
{0x0740, 0x0000},
{0x0742, 0x0000},
{0x0744, 0x0300},
{0x0746, 0x007D},
{0x0748, 0x0002},
{0x074A, 0x0900},
{0x074C, 0x0100},
{0x074E, 0x0100},
{0x0750, 0x0000},
{0x1200, 0x0946},
{0x1202, 0x1A00},
{0x120E, 0x6027},
{0x1210, 0x8027},
{0x1246, 0x0105},
{0x1000, 0x0300},
{0x1002, 0xC311},
{0x1004, 0x2BB0},
{0x1010, 0x042B},
{0x1012, 0x0012},
{0x1014, 0x0020},
{0x1016, 0x0020},
{0x101A, 0x0020},
{0x1020, 0xC103},
{0x1022, 0x040F},
{0x1024, 0x0304},
{0x1026, 0x0607},
{0x1028, 0x0D06},
{0x102A, 0x0605},
{0x102C, 0x0C00},
{0x1038, 0x0000},
{0x103E, 0x0101},
{0x1040, 0x0000},
{0x1042, 0x0008},
{0x1044, 0x0120},
{0x1046, 0x01B0},
{0x1048, 0x0090},
{0x1066, 0x043B},
{0x1600, 0x0400},
{0x1608, 0x0028},
{0x160A, 0x0C80},
{0x160C, 0x001A},
{0x160E, 0x0960},
{0x0252, 0x0009},
{0x0202, 0x0000},
};
static const char * const hi847_test_pattern_menu[] = {
"No Pattern",
"Solid Colour",
"100% Colour Bars",
"Fade To Grey Colour Bars",
"PN9",
"Horizontal Gradient Pattern",
"Vertical Gradient Pattern",
"Check Board",
"Slant Pattern",
};
static const s64 link_freq_menu_items[] = {
HI847_LINK_FREQ_400MHZ,
HI847_LINK_FREQ_200MHZ,
};
static const struct hi847_link_freq_config link_freq_configs[] = {
[HI847_LINK_FREQ_400MHZ_INDEX] = {
.reg_list = {
.num_of_regs = ARRAY_SIZE(mipi_data_rate_lane_4),
.regs = mipi_data_rate_lane_4,
}
},
[HI847_LINK_FREQ_200MHZ_INDEX] = {
.reg_list = {
.num_of_regs = ARRAY_SIZE(mipi_data_rate_lane_4),
.regs = mipi_data_rate_lane_4,
}
}
};
static const struct hi847_mode supported_modes[] = {
{
.width = 3264,
.height = 2448,
.fll_def = HI847_FLL_30FPS,
.fll_min = HI847_FLL_30FPS_MIN,
.llp = 0x033C,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
.regs = mode_3264x2448_regs,
},
.link_freq_index = HI847_LINK_FREQ_400MHZ_INDEX,
},
{
.width = 1632,
.height = 1224,
.fll_def = HI847_FLL_60FPS,
.fll_min = HI847_FLL_60FPS_MIN,
.llp = 0x033C,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1632x1224_regs),
.regs = mode_1632x1224_regs,
},
.link_freq_index = HI847_LINK_FREQ_200MHZ_INDEX,
}
};
struct hi847 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *hflip;
/* Current mode */
const struct hi847_mode *cur_mode;
/* To serialize asynchronus callbacks */
struct mutex mutex;
/* Streaming on/off */
bool streaming;
};
static u64 to_pixel_rate(u32 f_index)
{
u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HI847_DATA_LANES;
do_div(pixel_rate, HI847_RGB_DEPTH);
return pixel_rate;
}
static int hi847_read_reg(struct hi847 *hi847, u16 reg, u16 len, u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
struct i2c_msg msgs[2];
u8 addr_buf[2];
u8 data_buf[4] = {0};
int ret;
if (len > 4)
return -EINVAL;
put_unaligned_be16(reg, addr_buf);
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = sizeof(addr_buf);
msgs[0].buf = addr_buf;
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = len;
msgs[1].buf = &data_buf[4 - len];
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs))
return -EIO;
*val = get_unaligned_be32(data_buf);
return 0;
}
static int hi847_write_reg(struct hi847 *hi847, u16 reg, u16 len, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
u8 buf[6];
if (len > 4)
return -EINVAL;
put_unaligned_be16(reg, buf);
put_unaligned_be32(val << 8 * (4 - len), buf + 2);
if (i2c_master_send(client, buf, len + 2) != len + 2)
return -EIO;
return 0;
}
static int hi847_write_reg_list(struct hi847 *hi847,
const struct hi847_reg_list *r_list)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
unsigned int i;
int ret;
for (i = 0; i < r_list->num_of_regs; i++) {
ret = hi847_write_reg(hi847, r_list->regs[i].address,
HI847_REG_VALUE_16BIT,
r_list->regs[i].val);
if (ret) {
dev_err_ratelimited(&client->dev,
"failed to write reg 0x%4.4x. error = %d",
r_list->regs[i].address, ret);
return ret;
}
}
return 0;
}
static int hi847_update_digital_gain(struct hi847 *hi847, u32 d_gain)
{
int ret;
ret = hi847_write_reg(hi847, HI847_REG_MWB_GR_GAIN,
HI847_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
ret = hi847_write_reg(hi847, HI847_REG_MWB_GB_GAIN,
HI847_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
ret = hi847_write_reg(hi847, HI847_REG_MWB_R_GAIN,
HI847_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_MWB_B_GAIN,
HI847_REG_VALUE_16BIT, d_gain);
}
static int hi847_test_pattern(struct hi847 *hi847, u32 pattern)
{
int ret;
u32 val;
if (pattern) {
ret = hi847_read_reg(hi847, HI847_REG_ISP,
HI847_REG_VALUE_16BIT, &val);
if (ret)
return ret;
ret = hi847_write_reg(hi847, HI847_REG_ISP,
HI847_REG_VALUE_16BIT,
val | HI847_REG_ISP_TPG_EN);
if (ret)
return ret;
}
ret = hi847_read_reg(hi847, HI847_REG_TEST_PATTERN,
HI847_REG_VALUE_16BIT, &val);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_TEST_PATTERN,
HI847_REG_VALUE_16BIT, val | pattern << 8);
}
static int hi847_grbg_shift(struct hi847 *hi847)
{
int ret;
int hflip, vflip;
/* regs shift for full size */
static const u32 FORMAT_X_SHIFT_1[2][2] = {
{ 0x0008, 0x0007, },
{ 0x0008, 0x0007, },
};
static const u32 FORMAT_Y_SHIFT_1[2][2] = {
{ 0x0002, 0x0002, },
{ 0x0001, 0x0001, },
};
/* regs shift for binning size */
static const u32 FORMAT_X_SHIFT_2[2][2] = {
{ 0x0004, 0x0003, },
{ 0x0004, 0x0003, },
};
static const u32 FORMAT_Y_SHIFT_2[2][2] = {
{ 0x0002, 0x0002, },
{ 0x0001, 0x0001, },
};
hflip = hi847->hflip->val;
vflip = hi847->vflip->val;
if (hi847->cur_mode->width == 3264) {
ret = hi847_write_reg(hi847, HI847_REG_FORMAT_X,
HI847_REG_VALUE_16BIT,
FORMAT_X_SHIFT_1[vflip][hflip]);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_FORMAT_Y,
HI847_REG_VALUE_16BIT,
FORMAT_Y_SHIFT_1[vflip][hflip]);
} else {
ret = hi847_write_reg(hi847, HI847_REG_FORMAT_X,
HI847_REG_VALUE_16BIT,
FORMAT_X_SHIFT_2[vflip][hflip]);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_FORMAT_Y,
HI847_REG_VALUE_16BIT,
FORMAT_Y_SHIFT_2[vflip][hflip]);
}
}
static int hi847_set_ctrl_hflip(struct hi847 *hi847, u32 ctrl_val)
{
int ret;
u32 val;
ret = hi847_read_reg(hi847, HI847_REG_MIRROR_FLIP,
HI847_REG_VALUE_16BIT, &val);
if (ret)
return ret;
ret = hi847_grbg_shift(hi847);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_MIRROR_FLIP,
HI847_REG_VALUE_16BIT,
ctrl_val ? val | BIT(8) : val & ~BIT(8));
}
static int hi847_set_ctrl_vflip(struct hi847 *hi847, u8 ctrl_val)
{
int ret;
u32 val;
ret = hi847_read_reg(hi847, HI847_REG_MIRROR_FLIP,
HI847_REG_VALUE_16BIT, &val);
if (ret)
return ret;
ret = hi847_grbg_shift(hi847);
if (ret)
return ret;
return hi847_write_reg(hi847, HI847_REG_MIRROR_FLIP,
HI847_REG_VALUE_16BIT,
ctrl_val ? val | BIT(9) : val & ~BIT(9));
}
static int hi847_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct hi847 *hi847 = container_of(ctrl->handler,
struct hi847, ctrl_handler);
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
s64 exposure_max;
int ret = 0;
/* Propagate change of current control to all related controls */
if (ctrl->id == V4L2_CID_VBLANK) {
/* Update max exposure while meeting expected vblanking */
exposure_max = hi847->cur_mode->height + ctrl->val -
HI847_EXPOSURE_MAX_MARGIN;
__v4l2_ctrl_modify_range(hi847->exposure,
hi847->exposure->minimum,
exposure_max, hi847->exposure->step,
exposure_max);
}
/* V4L2 controls values will be applied only when power is already up */
if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
ret = hi847_write_reg(hi847, HI847_REG_ANALOG_GAIN,
HI847_REG_VALUE_16BIT, ctrl->val);
break;
case V4L2_CID_DIGITAL_GAIN:
ret = hi847_update_digital_gain(hi847, ctrl->val);
break;
case V4L2_CID_EXPOSURE:
ret = hi847_write_reg(hi847, HI847_REG_EXPOSURE,
HI847_REG_VALUE_16BIT, ctrl->val);
break;
case V4L2_CID_VBLANK:
/* Update FLL that meets expected vertical blanking */
ret = hi847_write_reg(hi847, HI847_REG_FLL,
HI847_REG_VALUE_16BIT,
hi847->cur_mode->height + ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
ret = hi847_test_pattern(hi847, ctrl->val);
break;
case V4L2_CID_HFLIP:
hi847_set_ctrl_hflip(hi847, ctrl->val);
break;
case V4L2_CID_VFLIP:
hi847_set_ctrl_vflip(hi847, ctrl->val);
break;
default:
ret = -EINVAL;
break;
}
pm_runtime_put(&client->dev);
return ret;
}
static const struct v4l2_ctrl_ops hi847_ctrl_ops = {
.s_ctrl = hi847_set_ctrl,
};
static int hi847_init_controls(struct hi847 *hi847)
{
struct v4l2_ctrl_handler *ctrl_hdlr;
s64 exposure_max, h_blank;
int ret;
ctrl_hdlr = &hi847->ctrl_handler;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
if (ret)
return ret;
ctrl_hdlr->lock = &hi847->mutex;
hi847->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(link_freq_menu_items) - 1,
0, link_freq_menu_items);
if (hi847->link_freq)
hi847->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
hi847->pixel_rate = v4l2_ctrl_new_std
(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_PIXEL_RATE, 0,
to_pixel_rate(HI847_LINK_FREQ_400MHZ_INDEX),
1,
to_pixel_rate(HI847_LINK_FREQ_400MHZ_INDEX));
hi847->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_VBLANK,
hi847->cur_mode->fll_min -
hi847->cur_mode->height,
HI847_FLL_MAX -
hi847->cur_mode->height, 1,
hi847->cur_mode->fll_def -
hi847->cur_mode->height);
h_blank = hi847->cur_mode->llp - hi847->cur_mode->width;
hi847->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_HBLANK, h_blank, h_blank, 1,
h_blank);
if (hi847->hblank)
hi847->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
HI847_ANAL_GAIN_MIN, HI847_ANAL_GAIN_MAX,
HI847_ANAL_GAIN_STEP, HI847_ANAL_GAIN_MIN);
v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
HI847_DGTL_GAIN_MIN, HI847_DGTL_GAIN_MAX,
HI847_DGTL_GAIN_STEP, HI847_DGTL_GAIN_DEFAULT);
exposure_max = hi847->cur_mode->fll_def - HI847_EXPOSURE_MAX_MARGIN;
hi847->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_EXPOSURE,
HI847_EXPOSURE_MIN, exposure_max,
HI847_EXPOSURE_STEP,
exposure_max);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(hi847_test_pattern_menu) - 1,
0, 0, hi847_test_pattern_menu);
hi847->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
hi847->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &hi847_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
if (ctrl_hdlr->error)
return ctrl_hdlr->error;
hi847->sd.ctrl_handler = ctrl_hdlr;
return 0;
}
static void hi847_assign_pad_format(const struct hi847_mode *mode,
struct v4l2_mbus_framefmt *fmt)
{
fmt->width = mode->width;
fmt->height = mode->height;
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
fmt->field = V4L2_FIELD_NONE;
}
static int hi847_start_streaming(struct hi847 *hi847)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
const struct hi847_reg_list *reg_list;
int link_freq_index, ret;
link_freq_index = hi847->cur_mode->link_freq_index;
reg_list = &link_freq_configs[link_freq_index].reg_list;
ret = hi847_write_reg_list(hi847, reg_list);
if (ret) {
dev_err(&client->dev, "failed to set plls");
return ret;
}
reg_list = &hi847->cur_mode->reg_list;
ret = hi847_write_reg_list(hi847, reg_list);
if (ret) {
dev_err(&client->dev, "failed to set mode");
return ret;
}
ret = __v4l2_ctrl_handler_setup(hi847->sd.ctrl_handler);
if (ret)
return ret;
ret = hi847_write_reg(hi847, HI847_REG_MODE_TG,
HI847_REG_VALUE_16BIT, HI847_REG_MODE_TG_ENABLE);
ret = hi847_write_reg(hi847, HI847_REG_MODE_SELECT,
HI847_REG_VALUE_16BIT, HI847_MODE_STREAMING);
if (ret) {
dev_err(&client->dev, "failed to set stream");
return ret;
}
return 0;
}
static void hi847_stop_streaming(struct hi847 *hi847)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
if (hi847_write_reg(hi847, HI847_REG_MODE_TG,
HI847_REG_VALUE_16BIT, HI847_REG_MODE_TG_DISABLE))
dev_err(&client->dev, "failed to set stream 0x%x",
HI847_REG_MODE_TG);
if (hi847_write_reg(hi847, HI847_REG_MODE_SELECT,
HI847_REG_VALUE_16BIT, HI847_MODE_STANDBY))
dev_err(&client->dev, "failed to set stream 0x%x",
HI847_REG_MODE_SELECT);
}
static int hi847_set_stream(struct v4l2_subdev *sd, int enable)
{
struct hi847 *hi847 = to_hi847(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
if (hi847->streaming == enable)
return 0;
mutex_lock(&hi847->mutex);
if (enable) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
mutex_unlock(&hi847->mutex);
return ret;
}
ret = hi847_start_streaming(hi847);
if (ret) {
enable = 0;
hi847_stop_streaming(hi847);
pm_runtime_put(&client->dev);
}
} else {
hi847_stop_streaming(hi847);
pm_runtime_put(&client->dev);
}
hi847->streaming = enable;
mutex_unlock(&hi847->mutex);
return ret;
}
static int __maybe_unused hi847_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct hi847 *hi847 = to_hi847(sd);
mutex_lock(&hi847->mutex);
if (hi847->streaming)
hi847_stop_streaming(hi847);
mutex_unlock(&hi847->mutex);
return 0;
}
static int __maybe_unused hi847_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct hi847 *hi847 = to_hi847(sd);
int ret;
mutex_lock(&hi847->mutex);
if (hi847->streaming) {
ret = hi847_start_streaming(hi847);
if (ret)
goto error;
}
mutex_unlock(&hi847->mutex);
return 0;
error:
hi847_stop_streaming(hi847);
hi847->streaming = 0;
mutex_unlock(&hi847->mutex);
return ret;
}
static int hi847_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct hi847 *hi847 = to_hi847(sd);
const struct hi847_mode *mode;
s32 vblank_def, h_blank;
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes), width,
height, fmt->format.width,
fmt->format.height);
mutex_lock(&hi847->mutex);
hi847_assign_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) =
fmt->format;
} else {
hi847->cur_mode = mode;
__v4l2_ctrl_s_ctrl(hi847->link_freq, mode->link_freq_index);
__v4l2_ctrl_s_ctrl_int64(hi847->pixel_rate,
to_pixel_rate(mode->link_freq_index));
/* Update limits and set FPS to default */
vblank_def = mode->fll_def - mode->height;
__v4l2_ctrl_modify_range(hi847->vblank,
mode->fll_min - mode->height,
HI847_FLL_MAX - mode->height, 1,
vblank_def);
__v4l2_ctrl_s_ctrl(hi847->vblank, vblank_def);
h_blank = hi847->cur_mode->llp - hi847->cur_mode->width;
__v4l2_ctrl_modify_range(hi847->hblank, h_blank, h_blank, 1,
h_blank);
}
mutex_unlock(&hi847->mutex);
return 0;
}
static int hi847_get_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct hi847 *hi847 = to_hi847(sd);
mutex_lock(&hi847->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
fmt->format = *v4l2_subdev_get_try_format(&hi847->sd,
sd_state,
fmt->pad);
else
hi847_assign_pad_format(hi847->cur_mode, &fmt->format);
mutex_unlock(&hi847->mutex);
return 0;
}
static int hi847_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
return 0;
}
static int hi847_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
fse->max_width = fse->min_width;
fse->min_height = supported_modes[fse->index].height;
fse->max_height = fse->min_height;
return 0;
}
static int hi847_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct hi847 *hi847 = to_hi847(sd);
mutex_lock(&hi847->mutex);
hi847_assign_pad_format(&supported_modes[0],
v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&hi847->mutex);
return 0;
}
static const struct v4l2_subdev_video_ops hi847_video_ops = {
.s_stream = hi847_set_stream,
};
static const struct v4l2_subdev_pad_ops hi847_pad_ops = {
.set_fmt = hi847_set_format,
.get_fmt = hi847_get_format,
.enum_mbus_code = hi847_enum_mbus_code,
.enum_frame_size = hi847_enum_frame_size,
};
static const struct v4l2_subdev_ops hi847_subdev_ops = {
.video = &hi847_video_ops,
.pad = &hi847_pad_ops,
};
static const struct media_entity_operations hi847_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
static const struct v4l2_subdev_internal_ops hi847_internal_ops = {
.open = hi847_open,
};
static int hi847_identify_module(struct hi847 *hi847)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd);
int ret;
u32 val;
ret = hi847_read_reg(hi847, HI847_REG_CHIP_ID,
HI847_REG_VALUE_16BIT, &val);
if (ret)
return ret;
if (val != HI847_CHIP_ID) {
dev_err(&client->dev, "chip id mismatch: %x!=%x",
HI847_CHIP_ID, val);
return -ENXIO;
}
return 0;
}
static int hi847_check_hwcfg(struct device *dev)
{
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
u32 mclk;
int ret;
unsigned int i, j;
if (!fwnode)
return -ENXIO;
ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
if (ret) {
dev_err(dev, "can't get clock frequency");
return ret;
}
if (mclk != HI847_MCLK) {
dev_err(dev, "external clock %d is not supported", mclk);
return -EINVAL;
}
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
return -ENXIO;
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
fwnode_handle_put(ep);
if (ret)
return ret;
if (bus_cfg.bus.mipi_csi2.num_data_lanes != HI847_DATA_LANES) {
dev_err(dev, "number of CSI2 data lanes %d is not supported",
bus_cfg.bus.mipi_csi2.num_data_lanes);
ret = -EINVAL;
goto check_hwcfg_error;
}
if (!bus_cfg.nr_of_link_frequencies) {
dev_err(dev, "no link frequencies defined");
ret = -EINVAL;
goto check_hwcfg_error;
}
for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
if (link_freq_menu_items[i] ==
bus_cfg.link_frequencies[j])
break;
}
if (j == bus_cfg.nr_of_link_frequencies) {
dev_err(dev, "no link frequency %lld supported",
link_freq_menu_items[i]);
ret = -EINVAL;
goto check_hwcfg_error;
}
}
check_hwcfg_error:
v4l2_fwnode_endpoint_free(&bus_cfg);
return ret;
}
static void hi847_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct hi847 *hi847 = to_hi847(sd);
v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(&client->dev);
mutex_destroy(&hi847->mutex);
}
static int hi847_probe(struct i2c_client *client)
{
struct hi847 *hi847;
int ret;
hi847 = devm_kzalloc(&client->dev, sizeof(*hi847), GFP_KERNEL);
if (!hi847)
return -ENOMEM;
ret = hi847_check_hwcfg(&client->dev);
if (ret) {
dev_err(&client->dev, "failed to get HW configuration: %d",
ret);
return ret;
}
v4l2_i2c_subdev_init(&hi847->sd, client, &hi847_subdev_ops);
ret = hi847_identify_module(hi847);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d", ret);
return ret;
}
mutex_init(&hi847->mutex);
hi847->cur_mode = &supported_modes[0];
ret = hi847_init_controls(hi847);
if (ret) {
dev_err(&client->dev, "failed to init controls: %d", ret);
goto probe_error_v4l2_ctrl_handler_free;
}
hi847->sd.internal_ops = &hi847_internal_ops;
hi847->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
hi847->sd.entity.ops = &hi847_subdev_entity_ops;
hi847->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
hi847->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&hi847->sd.entity, 1, &hi847->pad);
if (ret) {
dev_err(&client->dev, "failed to init entity pads: %d", ret);
goto probe_error_v4l2_ctrl_handler_free;
}
ret = v4l2_async_register_subdev_sensor(&hi847->sd);
if (ret < 0) {
dev_err(&client->dev, "failed to register V4L2 subdev: %d",
ret);
goto probe_error_media_entity_cleanup;
}
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
return 0;
probe_error_media_entity_cleanup:
media_entity_cleanup(&hi847->sd.entity);
probe_error_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(hi847->sd.ctrl_handler);
mutex_destroy(&hi847->mutex);
return ret;
}
static const struct dev_pm_ops hi847_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(hi847_suspend, hi847_resume)
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id hi847_acpi_ids[] = {
{"HYV0847"},
{}
};
MODULE_DEVICE_TABLE(acpi, hi847_acpi_ids);
#endif
static struct i2c_driver hi847_i2c_driver = {
.driver = {
.name = "hi847",
.pm = &hi847_pm_ops,
.acpi_match_table = ACPI_PTR(hi847_acpi_ids),
},
.probe_new = hi847_probe,
.remove = hi847_remove,
};
module_i2c_driver(hi847_i2c_driver);
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
MODULE_DESCRIPTION("Hynix HI847 sensor driver");
MODULE_LICENSE("GPL v2");