18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * et8ek8_driver.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact: Sakari Ailus <sakari.ailus@iki.fi> 88c2ecf20Sopenharmony_ci * Tuukka Toivonen <tuukkat76@gmail.com> 98c2ecf20Sopenharmony_ci * Pavel Machek <pavel@ucw.cz> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Based on code from Toni Leinonen <toni.leinonen@offcode.fi>. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This driver is based on the Micron MT9T012 camera imager driver 148c2ecf20Sopenharmony_ci * (C) Texas Instruments. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 208c2ecf20Sopenharmony_ci#include <linux/i2c.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/mutex.h> 248c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/sort.h> 278c2ecf20Sopenharmony_ci#include <linux/v4l2-mediabus.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <media/media-entity.h> 308c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 318c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 328c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "et8ek8_reg.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define ET8EK8_NAME "et8ek8" 378c2ecf20Sopenharmony_ci#define ET8EK8_PRIV_MEM_SIZE 128 388c2ecf20Sopenharmony_ci#define ET8EK8_MAX_MSG 8 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct et8ek8_sensor { 418c2ecf20Sopenharmony_ci struct v4l2_subdev subdev; 428c2ecf20Sopenharmony_ci struct media_pad pad; 438c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 448c2ecf20Sopenharmony_ci struct gpio_desc *reset; 458c2ecf20Sopenharmony_ci struct regulator *vana; 468c2ecf20Sopenharmony_ci struct clk *ext_clk; 478c2ecf20Sopenharmony_ci u32 xclk_freq; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci u16 version; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 528c2ecf20Sopenharmony_ci struct v4l2_ctrl *exposure; 538c2ecf20Sopenharmony_ci struct v4l2_ctrl *pixel_rate; 548c2ecf20Sopenharmony_ci struct et8ek8_reglist *current_reglist; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci u8 priv_mem[ET8EK8_PRIV_MEM_SIZE]; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci struct mutex power_lock; 598c2ecf20Sopenharmony_ci int power_count; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define to_et8ek8_sensor(sd) container_of(sd, struct et8ek8_sensor, subdev) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cienum et8ek8_versions { 658c2ecf20Sopenharmony_ci ET8EK8_REV_1 = 0x0001, 668c2ecf20Sopenharmony_ci ET8EK8_REV_2, 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * This table describes what should be written to the sensor register 718c2ecf20Sopenharmony_ci * for each gain value. The gain(index in the table) is in terms of 728c2ecf20Sopenharmony_ci * 0.1EV, i.e. 10 indexes in the table give 2 time more gain [0] in 738c2ecf20Sopenharmony_ci * the *analog gain, [1] in the digital gain 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * Analog gain [dB] = 20*log10(regvalue/32); 0x20..0x100 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistatic struct et8ek8_gain { 788c2ecf20Sopenharmony_ci u16 analog; 798c2ecf20Sopenharmony_ci u16 digital; 808c2ecf20Sopenharmony_ci} const et8ek8_gain_table[] = { 818c2ecf20Sopenharmony_ci { 32, 0}, /* x1 */ 828c2ecf20Sopenharmony_ci { 34, 0}, 838c2ecf20Sopenharmony_ci { 37, 0}, 848c2ecf20Sopenharmony_ci { 39, 0}, 858c2ecf20Sopenharmony_ci { 42, 0}, 868c2ecf20Sopenharmony_ci { 45, 0}, 878c2ecf20Sopenharmony_ci { 49, 0}, 888c2ecf20Sopenharmony_ci { 52, 0}, 898c2ecf20Sopenharmony_ci { 56, 0}, 908c2ecf20Sopenharmony_ci { 60, 0}, 918c2ecf20Sopenharmony_ci { 64, 0}, /* x2 */ 928c2ecf20Sopenharmony_ci { 69, 0}, 938c2ecf20Sopenharmony_ci { 74, 0}, 948c2ecf20Sopenharmony_ci { 79, 0}, 958c2ecf20Sopenharmony_ci { 84, 0}, 968c2ecf20Sopenharmony_ci { 91, 0}, 978c2ecf20Sopenharmony_ci { 97, 0}, 988c2ecf20Sopenharmony_ci {104, 0}, 998c2ecf20Sopenharmony_ci {111, 0}, 1008c2ecf20Sopenharmony_ci {119, 0}, 1018c2ecf20Sopenharmony_ci {128, 0}, /* x4 */ 1028c2ecf20Sopenharmony_ci {137, 0}, 1038c2ecf20Sopenharmony_ci {147, 0}, 1048c2ecf20Sopenharmony_ci {158, 0}, 1058c2ecf20Sopenharmony_ci {169, 0}, 1068c2ecf20Sopenharmony_ci {181, 0}, 1078c2ecf20Sopenharmony_ci {194, 0}, 1088c2ecf20Sopenharmony_ci {208, 0}, 1098c2ecf20Sopenharmony_ci {223, 0}, 1108c2ecf20Sopenharmony_ci {239, 0}, 1118c2ecf20Sopenharmony_ci {256, 0}, /* x8 */ 1128c2ecf20Sopenharmony_ci {256, 73}, 1138c2ecf20Sopenharmony_ci {256, 152}, 1148c2ecf20Sopenharmony_ci {256, 236}, 1158c2ecf20Sopenharmony_ci {256, 327}, 1168c2ecf20Sopenharmony_ci {256, 424}, 1178c2ecf20Sopenharmony_ci {256, 528}, 1188c2ecf20Sopenharmony_ci {256, 639}, 1198c2ecf20Sopenharmony_ci {256, 758}, 1208c2ecf20Sopenharmony_ci {256, 886}, 1218c2ecf20Sopenharmony_ci {256, 1023}, /* x16 */ 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Register definitions */ 1258c2ecf20Sopenharmony_ci#define REG_REVISION_NUMBER_L 0x1200 1268c2ecf20Sopenharmony_ci#define REG_REVISION_NUMBER_H 0x1201 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define PRIV_MEM_START_REG 0x0008 1298c2ecf20Sopenharmony_ci#define PRIV_MEM_WIN_SIZE 8 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define ET8EK8_I2C_DELAY 3 /* msec delay b/w accesses */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define USE_CRC 1 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * Register access helpers 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Read a 8/16/32-bit i2c register. The value is returned in 'val'. 1398c2ecf20Sopenharmony_ci * Returns zero if successful, or non-zero otherwise. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic int et8ek8_i2c_read_reg(struct i2c_client *client, u16 data_length, 1428c2ecf20Sopenharmony_ci u16 reg, u32 *val) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci int r; 1458c2ecf20Sopenharmony_ci struct i2c_msg msg; 1468c2ecf20Sopenharmony_ci unsigned char data[4]; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!client->adapter) 1498c2ecf20Sopenharmony_ci return -ENODEV; 1508c2ecf20Sopenharmony_ci if (data_length != ET8EK8_REG_8BIT && data_length != ET8EK8_REG_16BIT) 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci msg.addr = client->addr; 1548c2ecf20Sopenharmony_ci msg.flags = 0; 1558c2ecf20Sopenharmony_ci msg.len = 2; 1568c2ecf20Sopenharmony_ci msg.buf = data; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* high byte goes out first */ 1598c2ecf20Sopenharmony_ci data[0] = (u8) (reg >> 8); 1608c2ecf20Sopenharmony_ci data[1] = (u8) (reg & 0xff); 1618c2ecf20Sopenharmony_ci r = i2c_transfer(client->adapter, &msg, 1); 1628c2ecf20Sopenharmony_ci if (r < 0) 1638c2ecf20Sopenharmony_ci goto err; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci msg.len = data_length; 1668c2ecf20Sopenharmony_ci msg.flags = I2C_M_RD; 1678c2ecf20Sopenharmony_ci r = i2c_transfer(client->adapter, &msg, 1); 1688c2ecf20Sopenharmony_ci if (r < 0) 1698c2ecf20Sopenharmony_ci goto err; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci *val = 0; 1728c2ecf20Sopenharmony_ci /* high byte comes first */ 1738c2ecf20Sopenharmony_ci if (data_length == ET8EK8_REG_8BIT) 1748c2ecf20Sopenharmony_ci *val = data[0]; 1758c2ecf20Sopenharmony_ci else 1768c2ecf20Sopenharmony_ci *val = (data[1] << 8) + data[0]; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cierr: 1818c2ecf20Sopenharmony_ci dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return r; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void et8ek8_i2c_create_msg(struct i2c_client *client, u16 len, u16 reg, 1878c2ecf20Sopenharmony_ci u32 val, struct i2c_msg *msg, 1888c2ecf20Sopenharmony_ci unsigned char *buf) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci msg->addr = client->addr; 1918c2ecf20Sopenharmony_ci msg->flags = 0; /* Write */ 1928c2ecf20Sopenharmony_ci msg->len = 2 + len; 1938c2ecf20Sopenharmony_ci msg->buf = buf; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* high byte goes out first */ 1968c2ecf20Sopenharmony_ci buf[0] = (u8) (reg >> 8); 1978c2ecf20Sopenharmony_ci buf[1] = (u8) (reg & 0xff); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci switch (len) { 2008c2ecf20Sopenharmony_ci case ET8EK8_REG_8BIT: 2018c2ecf20Sopenharmony_ci buf[2] = (u8) (val) & 0xff; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci case ET8EK8_REG_16BIT: 2048c2ecf20Sopenharmony_ci buf[2] = (u8) (val) & 0xff; 2058c2ecf20Sopenharmony_ci buf[3] = (u8) (val >> 8) & 0xff; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci WARN_ONCE(1, ET8EK8_NAME ": %s: invalid message length.\n", 2098c2ecf20Sopenharmony_ci __func__); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * A buffered write method that puts the wanted register write 2158c2ecf20Sopenharmony_ci * commands in smaller number of message lists and passes the lists to 2168c2ecf20Sopenharmony_ci * the i2c framework 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_cistatic int et8ek8_i2c_buffered_write_regs(struct i2c_client *client, 2198c2ecf20Sopenharmony_ci const struct et8ek8_reg *wnext, 2208c2ecf20Sopenharmony_ci int cnt) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct i2c_msg msg[ET8EK8_MAX_MSG]; 2238c2ecf20Sopenharmony_ci unsigned char data[ET8EK8_MAX_MSG][6]; 2248c2ecf20Sopenharmony_ci int wcnt = 0; 2258c2ecf20Sopenharmony_ci u16 reg, data_length; 2268c2ecf20Sopenharmony_ci u32 val; 2278c2ecf20Sopenharmony_ci int rval; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Create new write messages for all writes */ 2308c2ecf20Sopenharmony_ci while (wcnt < cnt) { 2318c2ecf20Sopenharmony_ci data_length = wnext->type; 2328c2ecf20Sopenharmony_ci reg = wnext->reg; 2338c2ecf20Sopenharmony_ci val = wnext->val; 2348c2ecf20Sopenharmony_ci wnext++; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci et8ek8_i2c_create_msg(client, data_length, reg, 2378c2ecf20Sopenharmony_ci val, &msg[wcnt], &data[wcnt][0]); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Update write count */ 2408c2ecf20Sopenharmony_ci wcnt++; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (wcnt < ET8EK8_MAX_MSG) 2438c2ecf20Sopenharmony_ci continue; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci rval = i2c_transfer(client->adapter, msg, wcnt); 2468c2ecf20Sopenharmony_ci if (rval < 0) 2478c2ecf20Sopenharmony_ci return rval; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci cnt -= wcnt; 2508c2ecf20Sopenharmony_ci wcnt = 0; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci rval = i2c_transfer(client->adapter, msg, wcnt); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return rval < 0 ? rval : 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* 2598c2ecf20Sopenharmony_ci * Write a list of registers to i2c device. 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * The list of registers is terminated by ET8EK8_REG_TERM. 2628c2ecf20Sopenharmony_ci * Returns zero if successful, or non-zero otherwise. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_cistatic int et8ek8_i2c_write_regs(struct i2c_client *client, 2658c2ecf20Sopenharmony_ci const struct et8ek8_reg *regs) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int r, cnt = 0; 2688c2ecf20Sopenharmony_ci const struct et8ek8_reg *next; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!client->adapter) 2718c2ecf20Sopenharmony_ci return -ENODEV; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!regs) 2748c2ecf20Sopenharmony_ci return -EINVAL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Initialize list pointers to the start of the list */ 2778c2ecf20Sopenharmony_ci next = regs; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci do { 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * We have to go through the list to figure out how 2828c2ecf20Sopenharmony_ci * many regular writes we have in a row 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci while (next->type != ET8EK8_REG_TERM && 2858c2ecf20Sopenharmony_ci next->type != ET8EK8_REG_DELAY) { 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Here we check that the actual length fields 2888c2ecf20Sopenharmony_ci * are valid 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (WARN(next->type != ET8EK8_REG_8BIT && 2918c2ecf20Sopenharmony_ci next->type != ET8EK8_REG_16BIT, 2928c2ecf20Sopenharmony_ci "Invalid type = %d", next->type)) { 2938c2ecf20Sopenharmony_ci return -EINVAL; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * Increment count of successive writes and 2978c2ecf20Sopenharmony_ci * read pointer 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci cnt++; 3008c2ecf20Sopenharmony_ci next++; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Now we start writing ... */ 3048c2ecf20Sopenharmony_ci r = et8ek8_i2c_buffered_write_regs(client, regs, cnt); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* ... and then check that everything was OK */ 3078c2ecf20Sopenharmony_ci if (r < 0) { 3088c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c transfer error!\n"); 3098c2ecf20Sopenharmony_ci return r; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * If we ran into a sleep statement when going through 3148c2ecf20Sopenharmony_ci * the list, this is where we snooze for the required time 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (next->type == ET8EK8_REG_DELAY) { 3178c2ecf20Sopenharmony_ci msleep(next->val); 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * ZZZ ... 3208c2ecf20Sopenharmony_ci * Update list pointers and cnt and start over ... 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci next++; 3238c2ecf20Sopenharmony_ci regs = next; 3248c2ecf20Sopenharmony_ci cnt = 0; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } while (next->type != ET8EK8_REG_TERM); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* 3328c2ecf20Sopenharmony_ci * Write to a 8/16-bit register. 3338c2ecf20Sopenharmony_ci * Returns zero if successful, or non-zero otherwise. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_cistatic int et8ek8_i2c_write_reg(struct i2c_client *client, u16 data_length, 3368c2ecf20Sopenharmony_ci u16 reg, u32 val) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci int r; 3398c2ecf20Sopenharmony_ci struct i2c_msg msg; 3408c2ecf20Sopenharmony_ci unsigned char data[6]; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (!client->adapter) 3438c2ecf20Sopenharmony_ci return -ENODEV; 3448c2ecf20Sopenharmony_ci if (data_length != ET8EK8_REG_8BIT && data_length != ET8EK8_REG_16BIT) 3458c2ecf20Sopenharmony_ci return -EINVAL; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci et8ek8_i2c_create_msg(client, data_length, reg, val, &msg, data); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci r = i2c_transfer(client->adapter, &msg, 1); 3508c2ecf20Sopenharmony_ci if (r < 0) { 3518c2ecf20Sopenharmony_ci dev_err(&client->dev, 3528c2ecf20Sopenharmony_ci "wrote 0x%x to offset 0x%x error %d\n", val, reg, r); 3538c2ecf20Sopenharmony_ci return r; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct et8ek8_reglist *et8ek8_reglist_find_type( 3608c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta, 3618c2ecf20Sopenharmony_ci u16 type) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct et8ek8_reglist **next = &meta->reglist[0].ptr; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci while (*next) { 3668c2ecf20Sopenharmony_ci if ((*next)->type == type) 3678c2ecf20Sopenharmony_ci return *next; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci next++; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return NULL; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int et8ek8_i2c_reglist_find_write(struct i2c_client *client, 3768c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta, 3778c2ecf20Sopenharmony_ci u16 type) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct et8ek8_reglist *reglist; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci reglist = et8ek8_reglist_find_type(meta, type); 3828c2ecf20Sopenharmony_ci if (!reglist) 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return et8ek8_i2c_write_regs(client, reglist->regs); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic struct et8ek8_reglist **et8ek8_reglist_first( 3898c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci return &meta->reglist[0].ptr; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void et8ek8_reglist_to_mbus(const struct et8ek8_reglist *reglist, 3958c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci fmt->width = reglist->mode.window_width; 3988c2ecf20Sopenharmony_ci fmt->height = reglist->mode.window_height; 3998c2ecf20Sopenharmony_ci fmt->code = reglist->mode.bus_format; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic struct et8ek8_reglist *et8ek8_reglist_find_mode_fmt( 4038c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta, 4048c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct et8ek8_reglist **list = et8ek8_reglist_first(meta); 4078c2ecf20Sopenharmony_ci struct et8ek8_reglist *best_match = NULL; 4088c2ecf20Sopenharmony_ci struct et8ek8_reglist *best_other = NULL; 4098c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 4108c2ecf20Sopenharmony_ci unsigned int max_dist_match = (unsigned int)-1; 4118c2ecf20Sopenharmony_ci unsigned int max_dist_other = (unsigned int)-1; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * Find the mode with the closest image size. The distance between 4158c2ecf20Sopenharmony_ci * image sizes is the size in pixels of the non-overlapping regions 4168c2ecf20Sopenharmony_ci * between the requested size and the frame-specified size. 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Store both the closest mode that matches the requested format, and 4198c2ecf20Sopenharmony_ci * the closest mode for all other formats. The best match is returned 4208c2ecf20Sopenharmony_ci * if found, otherwise the best mode with a non-matching format is 4218c2ecf20Sopenharmony_ci * returned. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci for (; *list; list++) { 4248c2ecf20Sopenharmony_ci unsigned int dist; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if ((*list)->type != ET8EK8_REGLIST_MODE) 4278c2ecf20Sopenharmony_ci continue; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(*list, &format); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dist = min(fmt->width, format.width) 4328c2ecf20Sopenharmony_ci * min(fmt->height, format.height); 4338c2ecf20Sopenharmony_ci dist = format.width * format.height 4348c2ecf20Sopenharmony_ci + fmt->width * fmt->height - 2 * dist; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (fmt->code == format.code) { 4388c2ecf20Sopenharmony_ci if (dist < max_dist_match || !best_match) { 4398c2ecf20Sopenharmony_ci best_match = *list; 4408c2ecf20Sopenharmony_ci max_dist_match = dist; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci if (dist < max_dist_other || !best_other) { 4448c2ecf20Sopenharmony_ci best_other = *list; 4458c2ecf20Sopenharmony_ci max_dist_other = dist; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return best_match ? best_match : best_other; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci#define TIMEPERFRAME_AVG_FPS(t) \ 4548c2ecf20Sopenharmony_ci (((t).denominator + ((t).numerator >> 1)) / (t).numerator) 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic struct et8ek8_reglist *et8ek8_reglist_find_mode_ival( 4578c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta, 4588c2ecf20Sopenharmony_ci struct et8ek8_reglist *current_reglist, 4598c2ecf20Sopenharmony_ci struct v4l2_fract *timeperframe) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci int fps = TIMEPERFRAME_AVG_FPS(*timeperframe); 4628c2ecf20Sopenharmony_ci struct et8ek8_reglist **list = et8ek8_reglist_first(meta); 4638c2ecf20Sopenharmony_ci struct et8ek8_mode *current_mode = ¤t_reglist->mode; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci for (; *list; list++) { 4668c2ecf20Sopenharmony_ci struct et8ek8_mode *mode = &(*list)->mode; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if ((*list)->type != ET8EK8_REGLIST_MODE) 4698c2ecf20Sopenharmony_ci continue; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (mode->window_width != current_mode->window_width || 4728c2ecf20Sopenharmony_ci mode->window_height != current_mode->window_height) 4738c2ecf20Sopenharmony_ci continue; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (TIMEPERFRAME_AVG_FPS(mode->timeperframe) == fps) 4768c2ecf20Sopenharmony_ci return *list; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return NULL; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int et8ek8_reglist_cmp(const void *a, const void *b) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci const struct et8ek8_reglist **list1 = (const struct et8ek8_reglist **)a, 4858c2ecf20Sopenharmony_ci **list2 = (const struct et8ek8_reglist **)b; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Put real modes in the beginning. */ 4888c2ecf20Sopenharmony_ci if ((*list1)->type == ET8EK8_REGLIST_MODE && 4898c2ecf20Sopenharmony_ci (*list2)->type != ET8EK8_REGLIST_MODE) 4908c2ecf20Sopenharmony_ci return -1; 4918c2ecf20Sopenharmony_ci if ((*list1)->type != ET8EK8_REGLIST_MODE && 4928c2ecf20Sopenharmony_ci (*list2)->type == ET8EK8_REGLIST_MODE) 4938c2ecf20Sopenharmony_ci return 1; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Descending width. */ 4968c2ecf20Sopenharmony_ci if ((*list1)->mode.window_width > (*list2)->mode.window_width) 4978c2ecf20Sopenharmony_ci return -1; 4988c2ecf20Sopenharmony_ci if ((*list1)->mode.window_width < (*list2)->mode.window_width) 4998c2ecf20Sopenharmony_ci return 1; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if ((*list1)->mode.window_height > (*list2)->mode.window_height) 5028c2ecf20Sopenharmony_ci return -1; 5038c2ecf20Sopenharmony_ci if ((*list1)->mode.window_height < (*list2)->mode.window_height) 5048c2ecf20Sopenharmony_ci return 1; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int et8ek8_reglist_import(struct i2c_client *client, 5108c2ecf20Sopenharmony_ci struct et8ek8_meta_reglist *meta) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci int nlists = 0, i; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci dev_info(&client->dev, "meta_reglist version %s\n", meta->version); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci while (meta->reglist[nlists].ptr) 5178c2ecf20Sopenharmony_ci nlists++; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (!nlists) 5208c2ecf20Sopenharmony_ci return -EINVAL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci sort(&meta->reglist[0].ptr, nlists, sizeof(meta->reglist[0].ptr), 5238c2ecf20Sopenharmony_ci et8ek8_reglist_cmp, NULL); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci i = nlists; 5268c2ecf20Sopenharmony_ci nlists = 0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci while (i--) { 5298c2ecf20Sopenharmony_ci struct et8ek8_reglist *list; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci list = meta->reglist[nlists].ptr; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 5348c2ecf20Sopenharmony_ci "%s: type %d\tw %d\th %d\tfmt %x\tival %d/%d\tptr %p\n", 5358c2ecf20Sopenharmony_ci __func__, 5368c2ecf20Sopenharmony_ci list->type, 5378c2ecf20Sopenharmony_ci list->mode.window_width, list->mode.window_height, 5388c2ecf20Sopenharmony_ci list->mode.bus_format, 5398c2ecf20Sopenharmony_ci list->mode.timeperframe.numerator, 5408c2ecf20Sopenharmony_ci list->mode.timeperframe.denominator, 5418c2ecf20Sopenharmony_ci (void *)meta->reglist[nlists].ptr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci nlists++; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* Called to change the V4L2 gain control value. This function 5508c2ecf20Sopenharmony_ci * rounds and clamps the given value and updates the V4L2 control value. 5518c2ecf20Sopenharmony_ci * If power is on, also updates the sensor analog and digital gains. 5528c2ecf20Sopenharmony_ci * gain is in 0.1 EV (exposure value) units. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_cistatic int et8ek8_set_gain(struct et8ek8_sensor *sensor, s32 gain) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); 5578c2ecf20Sopenharmony_ci struct et8ek8_gain new; 5588c2ecf20Sopenharmony_ci int r; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci new = et8ek8_gain_table[gain]; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* FIXME: optimise I2C writes! */ 5638c2ecf20Sopenharmony_ci r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 5648c2ecf20Sopenharmony_ci 0x124a, new.analog >> 8); 5658c2ecf20Sopenharmony_ci if (r) 5668c2ecf20Sopenharmony_ci return r; 5678c2ecf20Sopenharmony_ci r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 5688c2ecf20Sopenharmony_ci 0x1249, new.analog & 0xff); 5698c2ecf20Sopenharmony_ci if (r) 5708c2ecf20Sopenharmony_ci return r; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 5738c2ecf20Sopenharmony_ci 0x124d, new.digital >> 8); 5748c2ecf20Sopenharmony_ci if (r) 5758c2ecf20Sopenharmony_ci return r; 5768c2ecf20Sopenharmony_ci r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 5778c2ecf20Sopenharmony_ci 0x124c, new.digital & 0xff); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return r; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int et8ek8_set_test_pattern(struct et8ek8_sensor *sensor, s32 mode) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); 5858c2ecf20Sopenharmony_ci int cbh_mode, cbv_mode, tp_mode, din_sw, r1420, rval; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Values for normal mode */ 5888c2ecf20Sopenharmony_ci cbh_mode = 0; 5898c2ecf20Sopenharmony_ci cbv_mode = 0; 5908c2ecf20Sopenharmony_ci tp_mode = 0; 5918c2ecf20Sopenharmony_ci din_sw = 0x00; 5928c2ecf20Sopenharmony_ci r1420 = 0xF0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (mode) { 5958c2ecf20Sopenharmony_ci /* Test pattern mode */ 5968c2ecf20Sopenharmony_ci if (mode < 5) { 5978c2ecf20Sopenharmony_ci cbh_mode = 1; 5988c2ecf20Sopenharmony_ci cbv_mode = 1; 5998c2ecf20Sopenharmony_ci tp_mode = mode + 3; 6008c2ecf20Sopenharmony_ci } else { 6018c2ecf20Sopenharmony_ci cbh_mode = 0; 6028c2ecf20Sopenharmony_ci cbv_mode = 0; 6038c2ecf20Sopenharmony_ci tp_mode = mode - 4 + 3; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci din_sw = 0x01; 6078c2ecf20Sopenharmony_ci r1420 = 0xE0; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x111B, 6118c2ecf20Sopenharmony_ci tp_mode << 4); 6128c2ecf20Sopenharmony_ci if (rval) 6138c2ecf20Sopenharmony_ci return rval; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1121, 6168c2ecf20Sopenharmony_ci cbh_mode << 7); 6178c2ecf20Sopenharmony_ci if (rval) 6188c2ecf20Sopenharmony_ci return rval; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1124, 6218c2ecf20Sopenharmony_ci cbv_mode << 7); 6228c2ecf20Sopenharmony_ci if (rval) 6238c2ecf20Sopenharmony_ci return rval; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x112C, din_sw); 6268c2ecf20Sopenharmony_ci if (rval) 6278c2ecf20Sopenharmony_ci return rval; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1420, r1420); 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 6338c2ecf20Sopenharmony_ci * V4L2 controls 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic int et8ek8_set_ctrl(struct v4l2_ctrl *ctrl) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = 6398c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct et8ek8_sensor, ctrl_handler); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci switch (ctrl->id) { 6428c2ecf20Sopenharmony_ci case V4L2_CID_GAIN: 6438c2ecf20Sopenharmony_ci return et8ek8_set_gain(sensor, ctrl->val); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE: 6468c2ecf20Sopenharmony_ci { 6478c2ecf20Sopenharmony_ci struct i2c_client *client = 6488c2ecf20Sopenharmony_ci v4l2_get_subdevdata(&sensor->subdev); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return et8ek8_i2c_write_reg(client, ET8EK8_REG_16BIT, 0x1243, 6518c2ecf20Sopenharmony_ci ctrl->val); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN: 6558c2ecf20Sopenharmony_ci return et8ek8_set_test_pattern(sensor, ctrl->val); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci case V4L2_CID_PIXEL_RATE: 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci default: 6618c2ecf20Sopenharmony_ci return -EINVAL; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops et8ek8_ctrl_ops = { 6668c2ecf20Sopenharmony_ci .s_ctrl = et8ek8_set_ctrl, 6678c2ecf20Sopenharmony_ci}; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic const char * const et8ek8_test_pattern_menu[] = { 6708c2ecf20Sopenharmony_ci "Normal", 6718c2ecf20Sopenharmony_ci "Vertical colorbar", 6728c2ecf20Sopenharmony_ci "Horizontal colorbar", 6738c2ecf20Sopenharmony_ci "Scale", 6748c2ecf20Sopenharmony_ci "Ramp", 6758c2ecf20Sopenharmony_ci "Small vertical colorbar", 6768c2ecf20Sopenharmony_ci "Small horizontal colorbar", 6778c2ecf20Sopenharmony_ci "Small scale", 6788c2ecf20Sopenharmony_ci "Small ramp", 6798c2ecf20Sopenharmony_ci}; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int et8ek8_init_controls(struct et8ek8_sensor *sensor) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci s32 max_rows; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&sensor->ctrl_handler, 4); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* V4L2_CID_GAIN */ 6888c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops, 6898c2ecf20Sopenharmony_ci V4L2_CID_GAIN, 0, ARRAY_SIZE(et8ek8_gain_table) - 1, 6908c2ecf20Sopenharmony_ci 1, 0); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci max_rows = sensor->current_reglist->mode.max_exp; 6938c2ecf20Sopenharmony_ci { 6948c2ecf20Sopenharmony_ci u32 min = 1, max = max_rows; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci sensor->exposure = 6978c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&sensor->ctrl_handler, 6988c2ecf20Sopenharmony_ci &et8ek8_ctrl_ops, V4L2_CID_EXPOSURE, 6998c2ecf20Sopenharmony_ci min, max, min, max); 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* V4L2_CID_PIXEL_RATE */ 7038c2ecf20Sopenharmony_ci sensor->pixel_rate = 7048c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops, 7058c2ecf20Sopenharmony_ci V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* V4L2_CID_TEST_PATTERN */ 7088c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu_items(&sensor->ctrl_handler, 7098c2ecf20Sopenharmony_ci &et8ek8_ctrl_ops, V4L2_CID_TEST_PATTERN, 7108c2ecf20Sopenharmony_ci ARRAY_SIZE(et8ek8_test_pattern_menu) - 1, 7118c2ecf20Sopenharmony_ci 0, 0, et8ek8_test_pattern_menu); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (sensor->ctrl_handler.error) 7148c2ecf20Sopenharmony_ci return sensor->ctrl_handler.error; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci sensor->subdev.ctrl_handler = &sensor->ctrl_handler; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic void et8ek8_update_controls(struct et8ek8_sensor *sensor) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct v4l2_ctrl *ctrl; 7248c2ecf20Sopenharmony_ci struct et8ek8_mode *mode = &sensor->current_reglist->mode; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci u32 min, max, pixel_rate; 7278c2ecf20Sopenharmony_ci static const int S = 8; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ctrl = sensor->exposure; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci min = 1; 7328c2ecf20Sopenharmony_ci max = mode->max_exp; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * Calculate average pixel clock per line. Assume buffers can spread 7368c2ecf20Sopenharmony_ci * the data over horizontal blanking time. Rounding upwards. 7378c2ecf20Sopenharmony_ci * Formula taken from stock Nokia N900 kernel. 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci pixel_rate = ((mode->pixel_clock + (1 << S) - 1) >> S) + mode->width; 7408c2ecf20Sopenharmony_ci pixel_rate = mode->window_width * (pixel_rate - 1) / mode->width; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(ctrl, min, max, min, max); 7438c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate, pixel_rate << S); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int et8ek8_configure(struct et8ek8_sensor *sensor) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = &sensor->subdev; 7498c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(subdev); 7508c2ecf20Sopenharmony_ci int rval; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_regs(client, sensor->current_reglist->regs); 7538c2ecf20Sopenharmony_ci if (rval) 7548c2ecf20Sopenharmony_ci goto fail; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Controls set while the power to the sensor is turned off are saved 7578c2ecf20Sopenharmony_ci * but not applied to the hardware. Now that we're about to start 7588c2ecf20Sopenharmony_ci * streaming apply all the current values to the hardware. 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci rval = v4l2_ctrl_handler_setup(&sensor->ctrl_handler); 7618c2ecf20Sopenharmony_ci if (rval) 7628c2ecf20Sopenharmony_ci goto fail; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cifail: 7678c2ecf20Sopenharmony_ci dev_err(&client->dev, "sensor configuration failed\n"); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return rval; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int et8ek8_stream_on(struct et8ek8_sensor *sensor) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1252, 0xb0); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic int et8ek8_stream_off(struct et8ek8_sensor *sensor) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1252, 0x30); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int et8ek8_s_stream(struct v4l2_subdev *subdev, int streaming) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 7898c2ecf20Sopenharmony_ci int ret; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!streaming) 7928c2ecf20Sopenharmony_ci return et8ek8_stream_off(sensor); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci ret = et8ek8_configure(sensor); 7958c2ecf20Sopenharmony_ci if (ret < 0) 7968c2ecf20Sopenharmony_ci return ret; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return et8ek8_stream_on(sensor); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 8028c2ecf20Sopenharmony_ci * V4L2 subdev operations 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int et8ek8_power_off(struct et8ek8_sensor *sensor) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci gpiod_set_value(sensor->reset, 0); 8088c2ecf20Sopenharmony_ci udelay(1); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci clk_disable_unprepare(sensor->ext_clk); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return regulator_disable(sensor->vana); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int et8ek8_power_on(struct et8ek8_sensor *sensor) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = &sensor->subdev; 8188c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(subdev); 8198c2ecf20Sopenharmony_ci unsigned int xclk_freq; 8208c2ecf20Sopenharmony_ci int val, rval; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci rval = regulator_enable(sensor->vana); 8238c2ecf20Sopenharmony_ci if (rval) { 8248c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to enable vana regulator\n"); 8258c2ecf20Sopenharmony_ci return rval; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (sensor->current_reglist) 8298c2ecf20Sopenharmony_ci xclk_freq = sensor->current_reglist->mode.ext_clock; 8308c2ecf20Sopenharmony_ci else 8318c2ecf20Sopenharmony_ci xclk_freq = sensor->xclk_freq; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci rval = clk_set_rate(sensor->ext_clk, xclk_freq); 8348c2ecf20Sopenharmony_ci if (rval < 0) { 8358c2ecf20Sopenharmony_ci dev_err(&client->dev, "unable to set extclk clock freq to %u\n", 8368c2ecf20Sopenharmony_ci xclk_freq); 8378c2ecf20Sopenharmony_ci goto out; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci rval = clk_prepare_enable(sensor->ext_clk); 8408c2ecf20Sopenharmony_ci if (rval < 0) { 8418c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to enable extclk\n"); 8428c2ecf20Sopenharmony_ci goto out; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (rval) 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci udelay(10); /* I wish this is a good value */ 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci gpiod_set_value(sensor->reset, 1); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci msleep(5000 * 1000 / xclk_freq + 1); /* Wait 5000 cycles */ 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist, 8558c2ecf20Sopenharmony_ci ET8EK8_REGLIST_POWERON); 8568c2ecf20Sopenharmony_ci if (rval) 8578c2ecf20Sopenharmony_ci goto out; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci#ifdef USE_CRC 8608c2ecf20Sopenharmony_ci rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, 0x1263, &val); 8618c2ecf20Sopenharmony_ci if (rval) 8628c2ecf20Sopenharmony_ci goto out; 8638c2ecf20Sopenharmony_ci#if USE_CRC /* TODO get crc setting from DT */ 8648c2ecf20Sopenharmony_ci val |= BIT(4); 8658c2ecf20Sopenharmony_ci#else 8668c2ecf20Sopenharmony_ci val &= ~BIT(4); 8678c2ecf20Sopenharmony_ci#endif 8688c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1263, val); 8698c2ecf20Sopenharmony_ci if (rval) 8708c2ecf20Sopenharmony_ci goto out; 8718c2ecf20Sopenharmony_ci#endif 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ciout: 8748c2ecf20Sopenharmony_ci if (rval) 8758c2ecf20Sopenharmony_ci et8ek8_power_off(sensor); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return rval; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 8818c2ecf20Sopenharmony_ci * V4L2 subdev video operations 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_ci#define MAX_FMTS 4 8848c2ecf20Sopenharmony_cistatic int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev, 8858c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 8868c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct et8ek8_reglist **list = 8898c2ecf20Sopenharmony_ci et8ek8_reglist_first(&meta_reglist); 8908c2ecf20Sopenharmony_ci u32 pixelformat[MAX_FMTS]; 8918c2ecf20Sopenharmony_ci int npixelformat = 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (code->index >= MAX_FMTS) 8948c2ecf20Sopenharmony_ci return -EINVAL; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci for (; *list; list++) { 8978c2ecf20Sopenharmony_ci struct et8ek8_mode *mode = &(*list)->mode; 8988c2ecf20Sopenharmony_ci int i; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if ((*list)->type != ET8EK8_REGLIST_MODE) 9018c2ecf20Sopenharmony_ci continue; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci for (i = 0; i < npixelformat; i++) { 9048c2ecf20Sopenharmony_ci if (pixelformat[i] == mode->bus_format) 9058c2ecf20Sopenharmony_ci break; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci if (i != npixelformat) 9088c2ecf20Sopenharmony_ci continue; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (code->index == npixelformat) { 9118c2ecf20Sopenharmony_ci code->code = mode->bus_format; 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci pixelformat[npixelformat] = mode->bus_format; 9168c2ecf20Sopenharmony_ci npixelformat++; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return -EINVAL; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int et8ek8_enum_frame_size(struct v4l2_subdev *subdev, 9238c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9248c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct et8ek8_reglist **list = 9278c2ecf20Sopenharmony_ci et8ek8_reglist_first(&meta_reglist); 9288c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 9298c2ecf20Sopenharmony_ci int cmp_width = INT_MAX; 9308c2ecf20Sopenharmony_ci int cmp_height = INT_MAX; 9318c2ecf20Sopenharmony_ci int index = fse->index; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci for (; *list; list++) { 9348c2ecf20Sopenharmony_ci if ((*list)->type != ET8EK8_REGLIST_MODE) 9358c2ecf20Sopenharmony_ci continue; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(*list, &format); 9388c2ecf20Sopenharmony_ci if (fse->code != format.code) 9398c2ecf20Sopenharmony_ci continue; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Assume that the modes are grouped by frame size. */ 9428c2ecf20Sopenharmony_ci if (format.width == cmp_width && format.height == cmp_height) 9438c2ecf20Sopenharmony_ci continue; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci cmp_width = format.width; 9468c2ecf20Sopenharmony_ci cmp_height = format.height; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (index-- == 0) { 9498c2ecf20Sopenharmony_ci fse->min_width = format.width; 9508c2ecf20Sopenharmony_ci fse->min_height = format.height; 9518c2ecf20Sopenharmony_ci fse->max_width = format.width; 9528c2ecf20Sopenharmony_ci fse->max_height = format.height; 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev, 9618c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9628c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval_enum *fie) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct et8ek8_reglist **list = 9658c2ecf20Sopenharmony_ci et8ek8_reglist_first(&meta_reglist); 9668c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 9678c2ecf20Sopenharmony_ci int index = fie->index; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci for (; *list; list++) { 9708c2ecf20Sopenharmony_ci struct et8ek8_mode *mode = &(*list)->mode; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if ((*list)->type != ET8EK8_REGLIST_MODE) 9738c2ecf20Sopenharmony_ci continue; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(*list, &format); 9768c2ecf20Sopenharmony_ci if (fie->code != format.code) 9778c2ecf20Sopenharmony_ci continue; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (fie->width != format.width || fie->height != format.height) 9808c2ecf20Sopenharmony_ci continue; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (index-- == 0) { 9838c2ecf20Sopenharmony_ci fie->interval = mode->timeperframe; 9848c2ecf20Sopenharmony_ci return 0; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return -EINVAL; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt * 9928c2ecf20Sopenharmony_ci__et8ek8_get_pad_format(struct et8ek8_sensor *sensor, 9938c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9948c2ecf20Sopenharmony_ci unsigned int pad, enum v4l2_subdev_format_whence which) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci switch (which) { 9978c2ecf20Sopenharmony_ci case V4L2_SUBDEV_FORMAT_TRY: 9988c2ecf20Sopenharmony_ci return v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad); 9998c2ecf20Sopenharmony_ci case V4L2_SUBDEV_FORMAT_ACTIVE: 10008c2ecf20Sopenharmony_ci return &sensor->format; 10018c2ecf20Sopenharmony_ci default: 10028c2ecf20Sopenharmony_ci return NULL; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int et8ek8_get_pad_format(struct v4l2_subdev *subdev, 10078c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 10088c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 10118c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which); 10148c2ecf20Sopenharmony_ci if (!format) 10158c2ecf20Sopenharmony_ci return -EINVAL; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci fmt->format = *format; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int et8ek8_set_pad_format(struct v4l2_subdev *subdev, 10238c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 10248c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 10278c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 10288c2ecf20Sopenharmony_ci struct et8ek8_reglist *reglist; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which); 10318c2ecf20Sopenharmony_ci if (!format) 10328c2ecf20Sopenharmony_ci return -EINVAL; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci reglist = et8ek8_reglist_find_mode_fmt(&meta_reglist, &fmt->format); 10358c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(reglist, &fmt->format); 10368c2ecf20Sopenharmony_ci *format = fmt->format; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 10398c2ecf20Sopenharmony_ci sensor->current_reglist = reglist; 10408c2ecf20Sopenharmony_ci et8ek8_update_controls(sensor); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic int et8ek8_get_frame_interval(struct v4l2_subdev *subdev, 10478c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval *fi) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci memset(fi, 0, sizeof(*fi)); 10528c2ecf20Sopenharmony_ci fi->interval = sensor->current_reglist->mode.timeperframe; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic int et8ek8_set_frame_interval(struct v4l2_subdev *subdev, 10588c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval *fi) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 10618c2ecf20Sopenharmony_ci struct et8ek8_reglist *reglist; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci reglist = et8ek8_reglist_find_mode_ival(&meta_reglist, 10648c2ecf20Sopenharmony_ci sensor->current_reglist, 10658c2ecf20Sopenharmony_ci &fi->interval); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (!reglist) 10688c2ecf20Sopenharmony_ci return -EINVAL; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (sensor->current_reglist->mode.ext_clock != reglist->mode.ext_clock) 10718c2ecf20Sopenharmony_ci return -EINVAL; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci sensor->current_reglist = reglist; 10748c2ecf20Sopenharmony_ci et8ek8_update_controls(sensor); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return 0; 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic int et8ek8_g_priv_mem(struct v4l2_subdev *subdev) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 10828c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(subdev); 10838c2ecf20Sopenharmony_ci unsigned int length = ET8EK8_PRIV_MEM_SIZE; 10848c2ecf20Sopenharmony_ci unsigned int offset = 0; 10858c2ecf20Sopenharmony_ci u8 *ptr = sensor->priv_mem; 10868c2ecf20Sopenharmony_ci int rval = 0; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* Read the EEPROM window-by-window, each window 8 bytes */ 10898c2ecf20Sopenharmony_ci do { 10908c2ecf20Sopenharmony_ci u8 buffer[PRIV_MEM_WIN_SIZE]; 10918c2ecf20Sopenharmony_ci struct i2c_msg msg; 10928c2ecf20Sopenharmony_ci int bytes, i; 10938c2ecf20Sopenharmony_ci int ofs; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Set the current window */ 10968c2ecf20Sopenharmony_ci rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x0001, 10978c2ecf20Sopenharmony_ci 0xe0 | (offset >> 3)); 10988c2ecf20Sopenharmony_ci if (rval < 0) 10998c2ecf20Sopenharmony_ci return rval; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Wait for status bit */ 11028c2ecf20Sopenharmony_ci for (i = 0; i < 1000; ++i) { 11038c2ecf20Sopenharmony_ci u32 status; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, 11068c2ecf20Sopenharmony_ci 0x0003, &status); 11078c2ecf20Sopenharmony_ci if (rval < 0) 11088c2ecf20Sopenharmony_ci return rval; 11098c2ecf20Sopenharmony_ci if (!(status & 0x08)) 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (i == 1000) 11158c2ecf20Sopenharmony_ci return -EIO; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Read window, 8 bytes at once, and copy to user space */ 11188c2ecf20Sopenharmony_ci ofs = offset & 0x07; /* Offset within this window */ 11198c2ecf20Sopenharmony_ci bytes = length + ofs > 8 ? 8-ofs : length; 11208c2ecf20Sopenharmony_ci msg.addr = client->addr; 11218c2ecf20Sopenharmony_ci msg.flags = 0; 11228c2ecf20Sopenharmony_ci msg.len = 2; 11238c2ecf20Sopenharmony_ci msg.buf = buffer; 11248c2ecf20Sopenharmony_ci ofs += PRIV_MEM_START_REG; 11258c2ecf20Sopenharmony_ci buffer[0] = (u8)(ofs >> 8); 11268c2ecf20Sopenharmony_ci buffer[1] = (u8)(ofs & 0xFF); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci rval = i2c_transfer(client->adapter, &msg, 1); 11298c2ecf20Sopenharmony_ci if (rval < 0) 11308c2ecf20Sopenharmony_ci return rval; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci mdelay(ET8EK8_I2C_DELAY); 11338c2ecf20Sopenharmony_ci msg.addr = client->addr; 11348c2ecf20Sopenharmony_ci msg.len = bytes; 11358c2ecf20Sopenharmony_ci msg.flags = I2C_M_RD; 11368c2ecf20Sopenharmony_ci msg.buf = buffer; 11378c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci rval = i2c_transfer(client->adapter, &msg, 1); 11408c2ecf20Sopenharmony_ci if (rval < 0) 11418c2ecf20Sopenharmony_ci return rval; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci rval = 0; 11448c2ecf20Sopenharmony_ci memcpy(ptr, buffer, bytes); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci length -= bytes; 11478c2ecf20Sopenharmony_ci offset += bytes; 11488c2ecf20Sopenharmony_ci ptr += bytes; 11498c2ecf20Sopenharmony_ci } while (length > 0); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci return rval; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cistatic int et8ek8_dev_init(struct v4l2_subdev *subdev) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 11578c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(subdev); 11588c2ecf20Sopenharmony_ci int rval, rev_l, rev_h; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci rval = et8ek8_power_on(sensor); 11618c2ecf20Sopenharmony_ci if (rval) { 11628c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not power on\n"); 11638c2ecf20Sopenharmony_ci return rval; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, 11678c2ecf20Sopenharmony_ci REG_REVISION_NUMBER_L, &rev_l); 11688c2ecf20Sopenharmony_ci if (!rval) 11698c2ecf20Sopenharmony_ci rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, 11708c2ecf20Sopenharmony_ci REG_REVISION_NUMBER_H, &rev_h); 11718c2ecf20Sopenharmony_ci if (rval) { 11728c2ecf20Sopenharmony_ci dev_err(&client->dev, "no et8ek8 sensor detected\n"); 11738c2ecf20Sopenharmony_ci goto out_poweroff; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci sensor->version = (rev_h << 8) + rev_l; 11778c2ecf20Sopenharmony_ci if (sensor->version != ET8EK8_REV_1 && sensor->version != ET8EK8_REV_2) 11788c2ecf20Sopenharmony_ci dev_info(&client->dev, 11798c2ecf20Sopenharmony_ci "unknown version 0x%x detected, continuing anyway\n", 11808c2ecf20Sopenharmony_ci sensor->version); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci rval = et8ek8_reglist_import(client, &meta_reglist); 11838c2ecf20Sopenharmony_ci if (rval) { 11848c2ecf20Sopenharmony_ci dev_err(&client->dev, 11858c2ecf20Sopenharmony_ci "invalid register list %s, import failed\n", 11868c2ecf20Sopenharmony_ci ET8EK8_NAME); 11878c2ecf20Sopenharmony_ci goto out_poweroff; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci sensor->current_reglist = et8ek8_reglist_find_type(&meta_reglist, 11918c2ecf20Sopenharmony_ci ET8EK8_REGLIST_MODE); 11928c2ecf20Sopenharmony_ci if (!sensor->current_reglist) { 11938c2ecf20Sopenharmony_ci dev_err(&client->dev, 11948c2ecf20Sopenharmony_ci "invalid register list %s, no mode found\n", 11958c2ecf20Sopenharmony_ci ET8EK8_NAME); 11968c2ecf20Sopenharmony_ci rval = -ENODEV; 11978c2ecf20Sopenharmony_ci goto out_poweroff; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(sensor->current_reglist, &sensor->format); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist, 12038c2ecf20Sopenharmony_ci ET8EK8_REGLIST_POWERON); 12048c2ecf20Sopenharmony_ci if (rval) { 12058c2ecf20Sopenharmony_ci dev_err(&client->dev, 12068c2ecf20Sopenharmony_ci "invalid register list %s, no POWERON mode found\n", 12078c2ecf20Sopenharmony_ci ET8EK8_NAME); 12088c2ecf20Sopenharmony_ci goto out_poweroff; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci rval = et8ek8_stream_on(sensor); /* Needed to be able to read EEPROM */ 12118c2ecf20Sopenharmony_ci if (rval) 12128c2ecf20Sopenharmony_ci goto out_poweroff; 12138c2ecf20Sopenharmony_ci rval = et8ek8_g_priv_mem(subdev); 12148c2ecf20Sopenharmony_ci if (rval) 12158c2ecf20Sopenharmony_ci dev_warn(&client->dev, 12168c2ecf20Sopenharmony_ci "can not read OTP (EEPROM) memory from sensor\n"); 12178c2ecf20Sopenharmony_ci rval = et8ek8_stream_off(sensor); 12188c2ecf20Sopenharmony_ci if (rval) 12198c2ecf20Sopenharmony_ci goto out_poweroff; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci rval = et8ek8_power_off(sensor); 12228c2ecf20Sopenharmony_ci if (rval) 12238c2ecf20Sopenharmony_ci goto out_poweroff; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci return 0; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ciout_poweroff: 12288c2ecf20Sopenharmony_ci et8ek8_power_off(sensor); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci return rval; 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 12348c2ecf20Sopenharmony_ci * sysfs attributes 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_cistatic ssize_t 12378c2ecf20Sopenharmony_ciet8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, 12388c2ecf20Sopenharmony_ci char *buf) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); 12418c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci#if PAGE_SIZE < ET8EK8_PRIV_MEM_SIZE 12448c2ecf20Sopenharmony_ci#error PAGE_SIZE too small! 12458c2ecf20Sopenharmony_ci#endif 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci memcpy(buf, sensor->priv_mem, ET8EK8_PRIV_MEM_SIZE); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return ET8EK8_PRIV_MEM_SIZE; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(priv_mem, 0444, et8ek8_priv_mem_read, NULL); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 12548c2ecf20Sopenharmony_ci * V4L2 subdev core operations 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int 12588c2ecf20Sopenharmony_ciet8ek8_registered(struct v4l2_subdev *subdev) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 12618c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(subdev); 12628c2ecf20Sopenharmony_ci int rval; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "registered!"); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci rval = device_create_file(&client->dev, &dev_attr_priv_mem); 12678c2ecf20Sopenharmony_ci if (rval) { 12688c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not register sysfs entry\n"); 12698c2ecf20Sopenharmony_ci return rval; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci rval = et8ek8_dev_init(subdev); 12738c2ecf20Sopenharmony_ci if (rval) 12748c2ecf20Sopenharmony_ci goto err_file; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci rval = et8ek8_init_controls(sensor); 12778c2ecf20Sopenharmony_ci if (rval) { 12788c2ecf20Sopenharmony_ci dev_err(&client->dev, "controls initialization failed\n"); 12798c2ecf20Sopenharmony_ci goto err_file; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci __et8ek8_get_pad_format(sensor, NULL, 0, V4L2_SUBDEV_FORMAT_ACTIVE); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cierr_file: 12878c2ecf20Sopenharmony_ci device_remove_file(&client->dev, &dev_attr_priv_mem); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci return rval; 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic int __et8ek8_set_power(struct et8ek8_sensor *sensor, bool on) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci return on ? et8ek8_power_on(sensor) : et8ek8_power_off(sensor); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic int et8ek8_set_power(struct v4l2_subdev *subdev, int on) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 13008c2ecf20Sopenharmony_ci int ret = 0; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci mutex_lock(&sensor->power_lock); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* If the power count is modified from 0 to != 0 or from != 0 to 0, 13058c2ecf20Sopenharmony_ci * update the power state. 13068c2ecf20Sopenharmony_ci */ 13078c2ecf20Sopenharmony_ci if (sensor->power_count == !on) { 13088c2ecf20Sopenharmony_ci ret = __et8ek8_set_power(sensor, !!on); 13098c2ecf20Sopenharmony_ci if (ret < 0) 13108c2ecf20Sopenharmony_ci goto done; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* Update the power count. */ 13148c2ecf20Sopenharmony_ci sensor->power_count += on ? 1 : -1; 13158c2ecf20Sopenharmony_ci WARN_ON(sensor->power_count < 0); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cidone: 13188c2ecf20Sopenharmony_ci mutex_unlock(&sensor->power_lock); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci return ret; 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int et8ek8_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(sd); 13268c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 13278c2ecf20Sopenharmony_ci struct et8ek8_reglist *reglist; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci reglist = et8ek8_reglist_find_type(&meta_reglist, ET8EK8_REGLIST_MODE); 13308c2ecf20Sopenharmony_ci format = __et8ek8_get_pad_format(sensor, fh->pad, 0, 13318c2ecf20Sopenharmony_ci V4L2_SUBDEV_FORMAT_TRY); 13328c2ecf20Sopenharmony_ci et8ek8_reglist_to_mbus(reglist, format); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci return et8ek8_set_power(sd, true); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int et8ek8_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci return et8ek8_set_power(sd, false); 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops et8ek8_video_ops = { 13438c2ecf20Sopenharmony_ci .s_stream = et8ek8_s_stream, 13448c2ecf20Sopenharmony_ci .g_frame_interval = et8ek8_get_frame_interval, 13458c2ecf20Sopenharmony_ci .s_frame_interval = et8ek8_set_frame_interval, 13468c2ecf20Sopenharmony_ci}; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops et8ek8_core_ops = { 13498c2ecf20Sopenharmony_ci .s_power = et8ek8_set_power, 13508c2ecf20Sopenharmony_ci}; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops et8ek8_pad_ops = { 13538c2ecf20Sopenharmony_ci .enum_mbus_code = et8ek8_enum_mbus_code, 13548c2ecf20Sopenharmony_ci .enum_frame_size = et8ek8_enum_frame_size, 13558c2ecf20Sopenharmony_ci .enum_frame_interval = et8ek8_enum_frame_ival, 13568c2ecf20Sopenharmony_ci .get_fmt = et8ek8_get_pad_format, 13578c2ecf20Sopenharmony_ci .set_fmt = et8ek8_set_pad_format, 13588c2ecf20Sopenharmony_ci}; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops et8ek8_ops = { 13618c2ecf20Sopenharmony_ci .core = &et8ek8_core_ops, 13628c2ecf20Sopenharmony_ci .video = &et8ek8_video_ops, 13638c2ecf20Sopenharmony_ci .pad = &et8ek8_pad_ops, 13648c2ecf20Sopenharmony_ci}; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops et8ek8_internal_ops = { 13678c2ecf20Sopenharmony_ci .registered = et8ek8_registered, 13688c2ecf20Sopenharmony_ci .open = et8ek8_open, 13698c2ecf20Sopenharmony_ci .close = et8ek8_close, 13708c2ecf20Sopenharmony_ci}; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 13738c2ecf20Sopenharmony_ci * I2C driver 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_cistatic int __maybe_unused et8ek8_suspend(struct device *dev) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 13788c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = i2c_get_clientdata(client); 13798c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!sensor->power_count) 13828c2ecf20Sopenharmony_ci return 0; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci return __et8ek8_set_power(sensor, false); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int __maybe_unused et8ek8_resume(struct device *dev) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 13908c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = i2c_get_clientdata(client); 13918c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (!sensor->power_count) 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci return __et8ek8_set_power(sensor, true); 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic int et8ek8_probe(struct i2c_client *client) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor; 14028c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 14038c2ecf20Sopenharmony_ci int ret; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); 14068c2ecf20Sopenharmony_ci if (!sensor) 14078c2ecf20Sopenharmony_ci return -ENOMEM; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci sensor->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 14108c2ecf20Sopenharmony_ci if (IS_ERR(sensor->reset)) { 14118c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "could not request reset gpio\n"); 14128c2ecf20Sopenharmony_ci return PTR_ERR(sensor->reset); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci sensor->vana = devm_regulator_get(dev, "vana"); 14168c2ecf20Sopenharmony_ci if (IS_ERR(sensor->vana)) { 14178c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not get regulator for vana\n"); 14188c2ecf20Sopenharmony_ci return PTR_ERR(sensor->vana); 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci sensor->ext_clk = devm_clk_get(dev, NULL); 14228c2ecf20Sopenharmony_ci if (IS_ERR(sensor->ext_clk)) { 14238c2ecf20Sopenharmony_ci dev_err(&client->dev, "could not get clock\n"); 14248c2ecf20Sopenharmony_ci return PTR_ERR(sensor->ext_clk); 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "clock-frequency", 14288c2ecf20Sopenharmony_ci &sensor->xclk_freq); 14298c2ecf20Sopenharmony_ci if (ret) { 14308c2ecf20Sopenharmony_ci dev_warn(dev, "can't get clock-frequency\n"); 14318c2ecf20Sopenharmony_ci return ret; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci mutex_init(&sensor->power_lock); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&sensor->subdev, client, &et8ek8_ops); 14378c2ecf20Sopenharmony_ci sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 14388c2ecf20Sopenharmony_ci sensor->subdev.internal_ops = &et8ek8_internal_ops; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; 14418c2ecf20Sopenharmony_ci sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 14428c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); 14438c2ecf20Sopenharmony_ci if (ret < 0) { 14448c2ecf20Sopenharmony_ci dev_err(&client->dev, "media entity init failed!\n"); 14458c2ecf20Sopenharmony_ci goto err_mutex; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev); 14498c2ecf20Sopenharmony_ci if (ret < 0) 14508c2ecf20Sopenharmony_ci goto err_entity; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci dev_dbg(dev, "initialized!\n"); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return 0; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cierr_entity: 14578c2ecf20Sopenharmony_ci media_entity_cleanup(&sensor->subdev.entity); 14588c2ecf20Sopenharmony_cierr_mutex: 14598c2ecf20Sopenharmony_ci mutex_destroy(&sensor->power_lock); 14608c2ecf20Sopenharmony_ci return ret; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic int __exit et8ek8_remove(struct i2c_client *client) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev = i2c_get_clientdata(client); 14668c2ecf20Sopenharmony_ci struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (sensor->power_count) { 14698c2ecf20Sopenharmony_ci WARN_ON(1); 14708c2ecf20Sopenharmony_ci et8ek8_power_off(sensor); 14718c2ecf20Sopenharmony_ci sensor->power_count = 0; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(&sensor->subdev); 14758c2ecf20Sopenharmony_ci device_remove_file(&client->dev, &dev_attr_priv_mem); 14768c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&sensor->ctrl_handler); 14778c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(&sensor->subdev); 14788c2ecf20Sopenharmony_ci media_entity_cleanup(&sensor->subdev.entity); 14798c2ecf20Sopenharmony_ci mutex_destroy(&sensor->power_lock); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci return 0; 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic const struct of_device_id et8ek8_of_table[] = { 14858c2ecf20Sopenharmony_ci { .compatible = "toshiba,et8ek8" }, 14868c2ecf20Sopenharmony_ci { }, 14878c2ecf20Sopenharmony_ci}; 14888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, et8ek8_of_table); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic const struct i2c_device_id et8ek8_id_table[] = { 14918c2ecf20Sopenharmony_ci { ET8EK8_NAME, 0 }, 14928c2ecf20Sopenharmony_ci { } 14938c2ecf20Sopenharmony_ci}; 14948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, et8ek8_id_table); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic const struct dev_pm_ops et8ek8_pm_ops = { 14978c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(et8ek8_suspend, et8ek8_resume) 14988c2ecf20Sopenharmony_ci}; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_cistatic struct i2c_driver et8ek8_i2c_driver = { 15018c2ecf20Sopenharmony_ci .driver = { 15028c2ecf20Sopenharmony_ci .name = ET8EK8_NAME, 15038c2ecf20Sopenharmony_ci .pm = &et8ek8_pm_ops, 15048c2ecf20Sopenharmony_ci .of_match_table = et8ek8_of_table, 15058c2ecf20Sopenharmony_ci }, 15068c2ecf20Sopenharmony_ci .probe_new = et8ek8_probe, 15078c2ecf20Sopenharmony_ci .remove = __exit_p(et8ek8_remove), 15088c2ecf20Sopenharmony_ci .id_table = et8ek8_id_table, 15098c2ecf20Sopenharmony_ci}; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cimodule_i2c_driver(et8ek8_i2c_driver); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>, Pavel Machek <pavel@ucw.cz"); 15148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Toshiba ET8EK8 camera sensor driver"); 15158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1516