18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for the s5k83a sensor
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Erik Andrén
68c2ecf20Sopenharmony_ci * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Portions of code to USB interface and ALi driver software,
108c2ecf20Sopenharmony_ci * Copyright (c) 2006 Willem Duinker
118c2ecf20Sopenharmony_ci * v4l2 interface modeled after the V4L2 driver
128c2ecf20Sopenharmony_ci * for SN9C10x PC Camera Controllers
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/kthread.h>
188c2ecf20Sopenharmony_ci#include "m5602_s5k83a.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
238c2ecf20Sopenharmony_ci	.s_ctrl = s5k83a_s_ctrl,
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic struct v4l2_pix_format s5k83a_modes[] = {
278c2ecf20Sopenharmony_ci	{
288c2ecf20Sopenharmony_ci		640,
298c2ecf20Sopenharmony_ci		480,
308c2ecf20Sopenharmony_ci		V4L2_PIX_FMT_SBGGR8,
318c2ecf20Sopenharmony_ci		V4L2_FIELD_NONE,
328c2ecf20Sopenharmony_ci		.sizeimage =
338c2ecf20Sopenharmony_ci			640 * 480,
348c2ecf20Sopenharmony_ci		.bytesperline = 640,
358c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
368c2ecf20Sopenharmony_ci		.priv = 0
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const unsigned char preinit_s5k83a[][4] = {
418c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
428c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
438c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
448c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
458c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
468c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
478c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
508c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
518c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
528c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
538c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
548c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
558c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
568c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
578c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
588c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
598c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
608c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
618c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
628c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
638c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
648c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
658c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
668c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
678c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
688c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
698c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
708c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
718c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
728c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
738c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
748c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* This could probably be considerably shortened.
788c2ecf20Sopenharmony_ci   I don't have the hardware to experiment with it, patches welcome
798c2ecf20Sopenharmony_ci*/
808c2ecf20Sopenharmony_cistatic const unsigned char init_s5k83a[][4] = {
818c2ecf20Sopenharmony_ci	/* The following sequence is useless after a clean boot
828c2ecf20Sopenharmony_ci	   but is necessary after resume from suspend */
838c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
848c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
858c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
868c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
878c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
888c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
898c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
908c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
918c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
928c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
938c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
948c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
958c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
968c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
978c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
988c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
998c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
1008c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
1018c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
1028c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
1038c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
1048c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
1058c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
1068c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
1078c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	{SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
1108c2ecf20Sopenharmony_ci	{SENSOR, 0xaf, 0x01, 0x00},
1118c2ecf20Sopenharmony_ci	{SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
1128c2ecf20Sopenharmony_ci	{SENSOR, 0x7b, 0xff, 0x00},
1138c2ecf20Sopenharmony_ci	{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
1148c2ecf20Sopenharmony_ci	{SENSOR, 0x01, 0x50, 0x00},
1158c2ecf20Sopenharmony_ci	{SENSOR, 0x12, 0x20, 0x00},
1168c2ecf20Sopenharmony_ci	{SENSOR, 0x17, 0x40, 0x00},
1178c2ecf20Sopenharmony_ci	{SENSOR, 0x1c, 0x00, 0x00},
1188c2ecf20Sopenharmony_ci	{SENSOR, 0x02, 0x70, 0x00},
1198c2ecf20Sopenharmony_ci	{SENSOR, 0x03, 0x0b, 0x00},
1208c2ecf20Sopenharmony_ci	{SENSOR, 0x04, 0xf0, 0x00},
1218c2ecf20Sopenharmony_ci	{SENSOR, 0x05, 0x0b, 0x00},
1228c2ecf20Sopenharmony_ci	{SENSOR, 0x06, 0x71, 0x00},
1238c2ecf20Sopenharmony_ci	{SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
1248c2ecf20Sopenharmony_ci	{SENSOR, 0x08, 0x02, 0x00},
1258c2ecf20Sopenharmony_ci	{SENSOR, 0x09, 0x88, 0x00}, /* 648 */
1268c2ecf20Sopenharmony_ci	{SENSOR, 0x14, 0x00, 0x00},
1278c2ecf20Sopenharmony_ci	{SENSOR, 0x15, 0x20, 0x00}, /* 32 */
1288c2ecf20Sopenharmony_ci	{SENSOR, 0x19, 0x00, 0x00},
1298c2ecf20Sopenharmony_ci	{SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
1308c2ecf20Sopenharmony_ci	{SENSOR, 0x0f, 0x02, 0x00},
1318c2ecf20Sopenharmony_ci	{SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
1328c2ecf20Sopenharmony_ci	/* normal colors
1338c2ecf20Sopenharmony_ci	(this is value after boot, but after tries can be different) */
1348c2ecf20Sopenharmony_ci	{SENSOR, 0x00, 0x06, 0x00},
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic const unsigned char start_s5k83a[][4] = {
1388c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
1398c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
1408c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
1418c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
1428c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
1438c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
1448c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
1458c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1468c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1478c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1488c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1498c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
1508c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
1518c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1528c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
1538c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
1548c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
1558c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
1568c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
1578c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
1588c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
1598c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
1608c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
1618c2ecf20Sopenharmony_ci	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic void s5k83a_dump_registers(struct sd *sd);
1658c2ecf20Sopenharmony_cistatic int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
1668c2ecf20Sopenharmony_cistatic int s5k83a_set_led_indication(struct sd *sd, u8 val);
1678c2ecf20Sopenharmony_cistatic int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
1688c2ecf20Sopenharmony_ci				__s32 vflip, __s32 hflip);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ciint s5k83a_probe(struct sd *sd)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	u8 prod_id = 0, ver_id = 0;
1738c2ecf20Sopenharmony_ci	int i, err = 0;
1748c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (force_sensor) {
1778c2ecf20Sopenharmony_ci		if (force_sensor == S5K83A_SENSOR) {
1788c2ecf20Sopenharmony_ci			pr_info("Forcing a %s sensor\n", s5k83a.name);
1798c2ecf20Sopenharmony_ci			goto sensor_found;
1808c2ecf20Sopenharmony_ci		}
1818c2ecf20Sopenharmony_ci		/* If we want to force another sensor, don't try to probe this
1828c2ecf20Sopenharmony_ci		 * one */
1838c2ecf20Sopenharmony_ci		return -ENODEV;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n");
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* Preinit the sensor */
1898c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
1908c2ecf20Sopenharmony_ci		u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
1918c2ecf20Sopenharmony_ci		if (preinit_s5k83a[i][0] == SENSOR)
1928c2ecf20Sopenharmony_ci			err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
1938c2ecf20Sopenharmony_ci				data, 2);
1948c2ecf20Sopenharmony_ci		else
1958c2ecf20Sopenharmony_ci			err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
1968c2ecf20Sopenharmony_ci				data[0]);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* We don't know what register (if any) that contain the product id
2008c2ecf20Sopenharmony_ci	 * Just pick the first addresses that seem to produce the same results
2018c2ecf20Sopenharmony_ci	 * on multiple machines */
2028c2ecf20Sopenharmony_ci	if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
2038c2ecf20Sopenharmony_ci		return -ENODEV;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
2068c2ecf20Sopenharmony_ci		return -ENODEV;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if ((prod_id == 0xff) || (ver_id == 0xff))
2098c2ecf20Sopenharmony_ci		return -ENODEV;
2108c2ecf20Sopenharmony_ci	else
2118c2ecf20Sopenharmony_ci		pr_info("Detected a s5k83a sensor\n");
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cisensor_found:
2148c2ecf20Sopenharmony_ci	sd->gspca_dev.cam.cam_mode = s5k83a_modes;
2158c2ecf20Sopenharmony_ci	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* null the pointer! thread is't running now */
2188c2ecf20Sopenharmony_ci	sd->rotation_thread = NULL;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciint s5k83a_init(struct sd *sd)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	int i, err = 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
2288c2ecf20Sopenharmony_ci		u8 data[2] = {0x00, 0x00};
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		switch (init_s5k83a[i][0]) {
2318c2ecf20Sopenharmony_ci		case BRIDGE:
2328c2ecf20Sopenharmony_ci			err = m5602_write_bridge(sd,
2338c2ecf20Sopenharmony_ci					init_s5k83a[i][1],
2348c2ecf20Sopenharmony_ci					init_s5k83a[i][2]);
2358c2ecf20Sopenharmony_ci			break;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		case SENSOR:
2388c2ecf20Sopenharmony_ci			data[0] = init_s5k83a[i][2];
2398c2ecf20Sopenharmony_ci			err = m5602_write_sensor(sd,
2408c2ecf20Sopenharmony_ci				init_s5k83a[i][1], data, 1);
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		case SENSOR_LONG:
2448c2ecf20Sopenharmony_ci			data[0] = init_s5k83a[i][2];
2458c2ecf20Sopenharmony_ci			data[1] = init_s5k83a[i][3];
2468c2ecf20Sopenharmony_ci			err = m5602_write_sensor(sd,
2478c2ecf20Sopenharmony_ci				init_s5k83a[i][1], data, 2);
2488c2ecf20Sopenharmony_ci			break;
2498c2ecf20Sopenharmony_ci		default:
2508c2ecf20Sopenharmony_ci			pr_info("Invalid stream command, exiting init\n");
2518c2ecf20Sopenharmony_ci			return -EINVAL;
2528c2ecf20Sopenharmony_ci		}
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (dump_sensor)
2568c2ecf20Sopenharmony_ci		s5k83a_dump_registers(sd);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return err;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciint s5k83a_init_controls(struct sd *sd)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	sd->gspca_dev.vdev.ctrl_handler = hdl;
2668c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 6);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
2698c2ecf20Sopenharmony_ci			  0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
2728c2ecf20Sopenharmony_ci			  0, S5K83A_MAXIMUM_EXPOSURE, 1,
2738c2ecf20Sopenharmony_ci			  S5K83A_DEFAULT_EXPOSURE);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
2768c2ecf20Sopenharmony_ci			  0, 255, 1, S5K83A_DEFAULT_GAIN);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
2798c2ecf20Sopenharmony_ci				      0, 1, 1, 0);
2808c2ecf20Sopenharmony_ci	sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
2818c2ecf20Sopenharmony_ci				      0, 1, 1, 0);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (hdl->error) {
2848c2ecf20Sopenharmony_ci		pr_err("Could not initialize controls\n");
2858c2ecf20Sopenharmony_ci		return hdl->error;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	v4l2_ctrl_cluster(2, &sd->hflip);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int rotation_thread_function(void *data)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) data;
2968c2ecf20Sopenharmony_ci	u8 reg, previous_rotation = 0;
2978c2ecf20Sopenharmony_ci	__s32 vflip, hflip;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	set_current_state(TASK_INTERRUPTIBLE);
3008c2ecf20Sopenharmony_ci	while (!schedule_timeout(msecs_to_jiffies(100))) {
3018c2ecf20Sopenharmony_ci		if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		s5k83a_get_rotation(sd, &reg);
3058c2ecf20Sopenharmony_ci		if (previous_rotation != reg) {
3068c2ecf20Sopenharmony_ci			previous_rotation = reg;
3078c2ecf20Sopenharmony_ci			pr_info("Camera was flipped\n");
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci			hflip = sd->hflip->val;
3108c2ecf20Sopenharmony_ci			vflip = sd->vflip->val;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci			if (reg) {
3138c2ecf20Sopenharmony_ci				vflip = !vflip;
3148c2ecf20Sopenharmony_ci				hflip = !hflip;
3158c2ecf20Sopenharmony_ci			}
3168c2ecf20Sopenharmony_ci			s5k83a_set_flip_real((struct gspca_dev *) sd,
3178c2ecf20Sopenharmony_ci					      vflip, hflip);
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		mutex_unlock(&sd->gspca_dev.usb_lock);
3218c2ecf20Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* return to "front" flip */
3258c2ecf20Sopenharmony_ci	if (previous_rotation) {
3268c2ecf20Sopenharmony_ci		hflip = sd->hflip->val;
3278c2ecf20Sopenharmony_ci		vflip = sd->vflip->val;
3288c2ecf20Sopenharmony_ci		s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	sd->rotation_thread = NULL;
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ciint s5k83a_start(struct sd *sd)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int i, err = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* Create another thread, polling the GPIO ports of the camera to check
3408c2ecf20Sopenharmony_ci	   if it got rotated. This is how the windows driver does it so we have
3418c2ecf20Sopenharmony_ci	   to assume that there is no better way of accomplishing this */
3428c2ecf20Sopenharmony_ci	sd->rotation_thread = kthread_create(rotation_thread_function,
3438c2ecf20Sopenharmony_ci					     sd, "rotation thread");
3448c2ecf20Sopenharmony_ci	if (IS_ERR(sd->rotation_thread)) {
3458c2ecf20Sopenharmony_ci		err = PTR_ERR(sd->rotation_thread);
3468c2ecf20Sopenharmony_ci		sd->rotation_thread = NULL;
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	wake_up_process(sd->rotation_thread);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* Preinit the sensor */
3528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
3538c2ecf20Sopenharmony_ci		u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
3548c2ecf20Sopenharmony_ci		if (start_s5k83a[i][0] == SENSOR)
3558c2ecf20Sopenharmony_ci			err = m5602_write_sensor(sd, start_s5k83a[i][1],
3568c2ecf20Sopenharmony_ci				data, 2);
3578c2ecf20Sopenharmony_ci		else
3588c2ecf20Sopenharmony_ci			err = m5602_write_bridge(sd, start_s5k83a[i][1],
3598c2ecf20Sopenharmony_ci				data[0]);
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	if (err < 0)
3628c2ecf20Sopenharmony_ci		return err;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return s5k83a_set_led_indication(sd, 1);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ciint s5k83a_stop(struct sd *sd)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	if (sd->rotation_thread)
3708c2ecf20Sopenharmony_ci		kthread_stop(sd->rotation_thread);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	return s5k83a_set_led_indication(sd, 0);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_civoid s5k83a_disconnect(struct sd *sd)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	s5k83a_stop(sd);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	sd->sensor = NULL;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	int err;
3858c2ecf20Sopenharmony_ci	u8 data[2];
3868c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	data[0] = 0x00;
3898c2ecf20Sopenharmony_ci	data[1] = 0x20;
3908c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, 0x14, data, 2);
3918c2ecf20Sopenharmony_ci	if (err < 0)
3928c2ecf20Sopenharmony_ci		return err;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	data[0] = 0x01;
3958c2ecf20Sopenharmony_ci	data[1] = 0x00;
3968c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, 0x0d, data, 2);
3978c2ecf20Sopenharmony_ci	if (err < 0)
3988c2ecf20Sopenharmony_ci		return err;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* FIXME: This is not sane, we need to figure out the composition
4018c2ecf20Sopenharmony_ci		  of these registers */
4028c2ecf20Sopenharmony_ci	data[0] = val >> 3; /* gain, high 5 bits */
4038c2ecf20Sopenharmony_ci	data[1] = val >> 1; /* gain, high 7 bits */
4048c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	return err;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	int err;
4128c2ecf20Sopenharmony_ci	u8 data[1];
4138c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	data[0] = val;
4168c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
4178c2ecf20Sopenharmony_ci	return err;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	int err;
4238c2ecf20Sopenharmony_ci	u8 data[2];
4248c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	data[0] = 0;
4278c2ecf20Sopenharmony_ci	data[1] = val;
4288c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
4298c2ecf20Sopenharmony_ci	return err;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
4338c2ecf20Sopenharmony_ci				__s32 vflip, __s32 hflip)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	int err;
4368c2ecf20Sopenharmony_ci	u8 data[1];
4378c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	data[0] = 0x05;
4408c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
4418c2ecf20Sopenharmony_ci	if (err < 0)
4428c2ecf20Sopenharmony_ci		return err;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* six bit is vflip, seven is hflip */
4458c2ecf20Sopenharmony_ci	data[0] = S5K83A_FLIP_MASK;
4468c2ecf20Sopenharmony_ci	data[0] = (vflip) ? data[0] | 0x40 : data[0];
4478c2ecf20Sopenharmony_ci	data[0] = (hflip) ? data[0] | 0x80 : data[0];
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
4508c2ecf20Sopenharmony_ci	if (err < 0)
4518c2ecf20Sopenharmony_ci		return err;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	data[0] = (vflip) ? 0x0b : 0x0a;
4548c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
4558c2ecf20Sopenharmony_ci	if (err < 0)
4568c2ecf20Sopenharmony_ci		return err;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	data[0] = (hflip) ? 0x0a : 0x0b;
4598c2ecf20Sopenharmony_ci	err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
4608c2ecf20Sopenharmony_ci	return err;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int err;
4668c2ecf20Sopenharmony_ci	u8 reg;
4678c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
4688c2ecf20Sopenharmony_ci	int hflip = sd->hflip->val;
4698c2ecf20Sopenharmony_ci	int vflip = sd->vflip->val;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	err = s5k83a_get_rotation(sd, &reg);
4728c2ecf20Sopenharmony_ci	if (err < 0)
4738c2ecf20Sopenharmony_ci		return err;
4748c2ecf20Sopenharmony_ci	if (reg) {
4758c2ecf20Sopenharmony_ci		hflip = !hflip;
4768c2ecf20Sopenharmony_ci		vflip = !vflip;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
4808c2ecf20Sopenharmony_ci	return err;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev =
4868c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
4878c2ecf20Sopenharmony_ci	int err;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (!gspca_dev->streaming)
4908c2ecf20Sopenharmony_ci		return 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	switch (ctrl->id) {
4938c2ecf20Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
4948c2ecf20Sopenharmony_ci		err = s5k83a_set_brightness(gspca_dev, ctrl->val);
4958c2ecf20Sopenharmony_ci		break;
4968c2ecf20Sopenharmony_ci	case V4L2_CID_EXPOSURE:
4978c2ecf20Sopenharmony_ci		err = s5k83a_set_exposure(gspca_dev, ctrl->val);
4988c2ecf20Sopenharmony_ci		break;
4998c2ecf20Sopenharmony_ci	case V4L2_CID_GAIN:
5008c2ecf20Sopenharmony_ci		err = s5k83a_set_gain(gspca_dev, ctrl->val);
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	case V4L2_CID_HFLIP:
5038c2ecf20Sopenharmony_ci		err = s5k83a_set_hvflip(gspca_dev);
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci	default:
5068c2ecf20Sopenharmony_ci		return -EINVAL;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return err;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic int s5k83a_set_led_indication(struct sd *sd, u8 val)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	int err = 0;
5158c2ecf20Sopenharmony_ci	u8 data[1];
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
5188c2ecf20Sopenharmony_ci	if (err < 0)
5198c2ecf20Sopenharmony_ci		return err;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (val)
5228c2ecf20Sopenharmony_ci		data[0] = data[0] | S5K83A_GPIO_LED_MASK;
5238c2ecf20Sopenharmony_ci	else
5248c2ecf20Sopenharmony_ci		data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return err;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci/* Get camera rotation on Acer notebooks */
5328c2ecf20Sopenharmony_cistatic int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
5358c2ecf20Sopenharmony_ci	*reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
5368c2ecf20Sopenharmony_ci	return err;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic void s5k83a_dump_registers(struct sd *sd)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	int address;
5428c2ecf20Sopenharmony_ci	u8 page, old_page;
5438c2ecf20Sopenharmony_ci	m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	for (page = 0; page < 16; page++) {
5468c2ecf20Sopenharmony_ci		m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
5478c2ecf20Sopenharmony_ci		pr_info("Dumping the s5k83a register state for page 0x%x\n",
5488c2ecf20Sopenharmony_ci			page);
5498c2ecf20Sopenharmony_ci		for (address = 0; address <= 0xff; address++) {
5508c2ecf20Sopenharmony_ci			u8 val = 0;
5518c2ecf20Sopenharmony_ci			m5602_read_sensor(sd, address, &val, 1);
5528c2ecf20Sopenharmony_ci			pr_info("register 0x%x contains 0x%x\n", address, val);
5538c2ecf20Sopenharmony_ci		}
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci	pr_info("s5k83a register state dump complete\n");
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	for (page = 0; page < 16; page++) {
5588c2ecf20Sopenharmony_ci		m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
5598c2ecf20Sopenharmony_ci		pr_info("Probing for which registers that are read/write for page 0x%x\n",
5608c2ecf20Sopenharmony_ci			page);
5618c2ecf20Sopenharmony_ci		for (address = 0; address <= 0xff; address++) {
5628c2ecf20Sopenharmony_ci			u8 old_val, ctrl_val, test_val = 0xff;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci			m5602_read_sensor(sd, address, &old_val, 1);
5658c2ecf20Sopenharmony_ci			m5602_write_sensor(sd, address, &test_val, 1);
5668c2ecf20Sopenharmony_ci			m5602_read_sensor(sd, address, &ctrl_val, 1);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			if (ctrl_val == test_val)
5698c2ecf20Sopenharmony_ci				pr_info("register 0x%x is writeable\n",
5708c2ecf20Sopenharmony_ci					address);
5718c2ecf20Sopenharmony_ci			else
5728c2ecf20Sopenharmony_ci				pr_info("register 0x%x is read only\n",
5738c2ecf20Sopenharmony_ci					address);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci			/* Restore original val */
5768c2ecf20Sopenharmony_ci			m5602_write_sensor(sd, address, &old_val, 1);
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci	pr_info("Read/write register probing complete\n");
5808c2ecf20Sopenharmony_ci	m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
5818c2ecf20Sopenharmony_ci}
582