/* * mt9m021.c - MT9M021 driver * * Copyright (c) 2019, RidgeRun. All rights reserved. * * Author: Enrique Ramírez (enrique.ramirez@ridgerun.com) * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define DEBUG 1 #include #include #include #include #include #include #include #include #include #include #include "camera_gpio.h" #include "mt9m021_mode_tbls.h" /*************************************************** MT9M021 Image Sensor Registers ****************************************************/ #define MT9M021_CHIP_ID_REG 0x3000 #define MT9M021_RESET_REG 0x301A #define MT9M021_SEQ_CTRL_PORT 0x3088 #define MT9M021_SEQ_DATA_PORT 0x3086 #define MT9M021_ANALOG_REG 0x3ED6 #define MT9M021_TEST_RAW_MODE 0x307A #define MT9M021_DARK_CTRL 0x3044 #define MT9M021_DATA_PEDESTAL 0x301E #define MT9M021_COLUMN_CORRECTION 0x30D4 #define MT9M021_FLASH 0x3046 #define MT9M021_VT_SYS_CLK_DIV 0x302A #define MT9M021_VT_PIX_CLK_DIV 0x302C #define MT9M021_PRE_PLL_CLK_DIV 0x302E #define MT9M021_PLL_MULTIPLIER 0x3030 #define MT9M021_DIGITAL_TEST 0x30B0 #define MT9M021_Y_ADDR_START 0x3002 #define MT9M021_X_ADDR_START 0x3004 #define MT9M021_Y_ADDR_END 0x3006 #define MT9M021_X_ADDR_END 0x3008 #define MT9M021_FRAME_LENGTH_LINES 0x300A #define MT9M021_LINE_LENGTH_PCK 0x300C #define MT9M021_COARSE_INT_TIME 0x3012 #define MT9M021_FINE_INT_TIME 0x3014 #define MT9M021_COARSE_INT_TIME_CB 0x3016 #define MT9M021_FINE_INT_TIME_CB 0x3018 #define MT9M021_FRAME_LENGTH_LINES_CB 0x30AA #define MT9M021_X_ODD_INC 0x30A2 #define MT9M021_Y_ODD_INC 0x30A6 #define MT9M021_READ_MODE 0x3040 #define MT9M021_TEST_PATTERN 0x3070 #define MT9M021_DIGITAL_BINNING 0x3032 #define MT9M021_AE_CTRL_REG 0x3100 #define MT9M021_AE_LUMA_TARGET_REG 0x3102 #define MT9M021_EMBEDDED_DATA_CTRL 0x3064 #define MT9M021_DATAPATH_SELECT 0X306E #define MT9M021_GREEN1_GAIN 0x3056 #define MT9M021_BLUE_GAIN 0x3058 #define MT9M021_RED_GAIN 0x305A #define MT9M021_GREEN2_GAIN 0x305C #define MT9M021_GLOBAL_GAIN 0x305E #define MT9M021_GREEN1_GAIN_CB 0x30BC #define MT9M021_BLUE_GAIN_CB 0x30BE #define MT9M021_RED_GAIN_CB 0x30C0 #define MT9M021_GREEN2_GAIN_CB 0x30C2 #define MT9M021_GLOBAL_GAIN_CB 0x30C4 /*************************************************** MT9M021 Image Sensor Defines ****************************************************/ #define BRIDGE_I2C_ADDR 0x0e #define MT9M021_I2C_ADDR 0x10 #define MT9M021_CHIP_ID 0x2401 #define MT9M021_PIXEL_ARRAY_WIDTH 1280 #define MT9M021_PIXEL_ARRAY_HEIGHT 960 #define MT9M021_EXT_FREQ 24000000 #define MT9M021_TARGET_FREQ 74250000 #define MT9M021_PLL_M 99 #define MT9M021_PLL_N 4 #define MT9M021_PLL_P1 1 #define MT9M021_PLL_P2 8 #define MT9M021_ROW_START_MIN 0 #define MT9M021_ROW_START_MAX 960 #define MT9M021_ROW_START_DEF 0x0078 #define MT9M021_COLUMN_START_MIN 0 #define MT9M021_COLUMN_START_MAX 1280 #define MT9M021_COLUMN_START_DEF 0 #define MT9M021_WINDOW_HEIGHT_MIN 2 #define MT9M021_WINDOW_HEIGHT_MAX 720 #define MT9M021_WINDOW_HEIGHT_DEF 720 #define MT9M021_WINDOW_WIDTH_MIN 2 #define MT9M021_WINDOW_WIDTH_MAX 1280 #define MT9M021_WINDOW_WIDTH_DEF 1280 #define MT9M021_HOR_AND_VER_BIN 0x0020 #define MT9M021_HOR_BIN 0x0011 #define MT9M021_DISABLE_BINNING 0x0000 #define MT9M021_RESET 0x00D9 #define MT9M021_STREAM_OFF 0x00D8 #define MT9M021_STREAM_ON 0x00DC #define MT9M021_MASTER_MODE 0x10DC #define MT9M021_TRIGGER_MODE 0x19D8 #define MT9M021_ANALOG_GAIN_MIN 0x0 #define MT9M021_ANALOG_GAIN_MAX 0x3 #define MT9M021_ANALOG_GAIN_DEF 0x0 #define MT9M021_ANALOG_GAIN_SHIFT 4 #define MT9M021_ANALOG_GAIN_MASK 0x0030 #define MT9M021_GLOBAL_GAIN_MIN 100 #define MT9M021_GLOBAL_GAIN_MAX 762 #define MT9M021_GLOBAL_GAIN_DEF 100 #define MT9M021_COARSE_INT_TIME_MIN 0x0001 #define MT9M021_COARSE_INT_TIME_MAX 0x02A0 #define MT9M021_COARSE_INT_TIME_DEF 0x01C2 #define MT9M021_LLP_RECOMMENDED 0x0672 #define MT9M021_TEST_PATTERN_VAL 0x0 #define MT9M021_GAIN_1X 0x0 #define MT9M021_GAIN_2X 0x1 #define MT9M021_GAIN_4X 0x2 #define MT9M021_GAIN_8X 0x3 #define MT9M021_GAIN_1X_FIXED 100 #define MT9M021_GAIN_2X_FIXED 200 #define MT9M021_GAIN_4X_FIXED 400 #define MT9M021_GAIN_8X_FIXED 800 #define MT9M021_HFLIP_MASK 0x4000 #define MT9M021_VFLIP_MASK 0x8000 /*************************************************** TC358746AXBG MIPI Converter Defines ****************************************************/ struct mipi_bridge_settings { uint8_t len; uint16_t addr; uint32_t data; }; struct mipi_bridge_settings bridge_config[] = { {2, 0x0004, 0x0004}, // Parallel Data Format mode0 + PCLK Inverted {2, 0x0002, 0x0001}, // reset 1 {2, 0x0002, 0x0000}, // reset 0 {2, 0x0016, 0x50F9}, // set the input and feedback frequency division ratio {2, 0x0018, 0x0213}, // 50% maximum loop bandwidth + PLL clock enable + normal operation + PLL enable {2, 0x0006, 0x0030}, // FIFO level 3 #ifdef USE_RAW8 {2, 0x0008, 0x0000}, // data format RAW8 #else {2, 0x0008, 0x0020}, // data format RAW12 #endif {2, 0x0022, 0x0780}, // word count (bytes per line) 2560 // {4, 0x0140,0x00000000}, // {4, 0x0144,0x00000000}, // {4, 0x0148,0x00000001}, // {4, 0x014C,0x00000001}, // {4, 0x0150,0x00000001}, {4, 0x0210, 0x00002C00}, {4, 0x0214, 0x00000005}, {4, 0x0218, 0x00001E06}, {4, 0x021C, 0x00000004}, {4, 0x0220, 0x00000406}, {4, 0x0224, 0x00004988}, {4, 0x0228, 0x0000000C}, {4, 0x022C, 0x00000006}, {4, 0x0234, 0x0000001F}, // Voltage regulator enable for data 0-3 and clock lanes. // {4, 0x0238, 0x00000001}, // Continuous clock mode. Maintains the clock lane output regardless of data lane operation {4, 0x0238, 0x00000000}, // Discontinuous clock mode. {4, 0x0518, 0x00000001}, // CSI start {4, 0x0500, 0xA30080A1}, // 1 data lane // {4, 0x0500, 0xA30080A3}, // 2 data lanes // {4, 0x0500, 0xA30080A7}, // 4 data lanes {4, 0x0204, 0x00000001}, // TX PPI starts {2, 0x0004, 0x0044}, }; static int mt9m021_bridge_setup(struct i2c_client *client) { struct i2c_msg msg[2]; uint8_t buf[6]; struct mipi_bridge_settings settings; uint16_t __addr; uint32_t __data; int ret; uint8_t i; for (i = 0; i < ARRAY_SIZE(bridge_config); i++) { settings = bridge_config[i]; __addr = cpu_to_be16(settings.addr); __data = cpu_to_be32(settings.data); buf[0] = (uint8_t) (__addr); buf[1] = (uint8_t) (__addr >> 8); buf[2] = (uint8_t) (__data >> 16); buf[3] = (uint8_t) (__data >> 24); buf[4] = (uint8_t) (__data); buf[5] = (uint8_t) (__data >> 8); msg[0].addr = BRIDGE_I2C_ADDR; msg[0].flags = 0; msg[0].len = settings.len + 2; msg[0].buf = buf; ret = i2c_transfer(client->adapter, msg, 1); if (settings.len == 2) dev_dbg(&client->dev, "BRIDGE %s: 0x%04x to 0x%04x\n", __func__, settings.data, settings.addr); else dev_dbg(&client->dev, "BRIDGE %s: 0x%08x to 0x%04x\n", __func__, settings.data, settings.addr); if (ret < 0) { dev_err(&client->dev, "BRIDGE %s failed at 0x%04x error %d\n", __func__, settings.addr, ret); break; } } return ret; } static const struct of_device_id mt9m021_of_match[] = { {.compatible = "nvidia,mt9m021",}, {}, }; MODULE_DEVICE_TABLE(of, mt9m021_of_match); static const u32 ctrl_cid_list[] = { TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, TEGRA_CAMERA_CID_FRAME_RATE, TEGRA_CAMERA_CID_SENSOR_MODE_ID, V4L2_CID_ANALOGUE_GAIN, V4L2_CID_GAIN_RED, V4L2_CID_GAIN_GREENR, V4L2_CID_GAIN_GREENB, V4L2_CID_GAIN_BLUE, V4L2_CID_TEST_PATTERN, V4L2_CID_FLASH_LED_MODE, V4L2_CID_HFLIP, V4L2_CID_VFLIP, }; struct mt9m021 { struct i2c_client *i2c_client; struct v4l2_subdev *subdev; const char *trigger_mode; bool flash_en; struct camera_common_data *s_data; struct tegracam_device *tc_dev; }; static const struct regmap_config sensor_regmap_config = { .reg_bits = 16, .val_bits = 8, }; static inline int mt9m021_read_reg(struct camera_common_data *s_data, u16 addr, u8 * val) { int err = 0; u32 reg_val = 0; err = regmap_read(s_data->regmap, addr, ®_val); *val = reg_val & 0xff; return err; } static int mt9m021_read_reg16(struct camera_common_data *s_data, u16 addr, u16 * val) { u8 val_hi; u8 val_lo; int err = 0; if (!s_data) return -EFAULT; err = mt9m021_read_reg(s_data, addr, &val_hi); if (err) return err; err = mt9m021_read_reg(s_data, addr + 1, &val_lo); *val = (val_hi << 8) | val_lo; return err; } static inline int mt9m021_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) { int err = 0; err = regmap_write(s_data->regmap, addr, val); if (err) dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x", __func__, addr, val); return err; } static int mt9m021_write_reg16(struct camera_common_data *s_data, u16 addr, u16 val) { int err; u8 data[2]; dev_dbg(s_data->dev, "%s: 0x%04x to 0x%04x\n", __func__, val, addr); data[0] = (val >> 8) & 0xff;; data[1] = (val & 0xff); err = regmap_raw_write(s_data->regmap, addr, data, 2); if (err) dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x", __func__, addr, val); return err; } static int mt9m021_update_bits(struct camera_common_data *s_data, u16 addr, u16 val, u16 mask) { u16 reg16; int err; err = mt9m021_read_reg16(s_data, mask, ®16); if (err) return err; reg16 = (reg16 & ~mask) | (val & mask); err = mt9m021_write_reg16(s_data, addr, reg16); return err; } static int mt9m021_write_table(struct mt9m021 *priv, const mt9m021_reg table[]) { return regmap_util_write_table_16_as_8(priv->s_data->regmap, table, NULL, 0, MT9M021_TABLE_WAIT_MS, MT9M021_TABLE_END); } static int mt9m021_set_group_hold(struct tegracam_device *tc_dev, bool val) { /* mt9m021 does not support group hold */ return 0; } static int mt9m021_set_gain(struct tegracam_device *tc_dev, s64 val) { struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; int err = 0; u16 gain_mul; u16 reg16 = 0; u64 gain = 0; dev_dbg(dev, "Setting Gain to: %lld", val); if (val >= MT9M021_GAIN_8X_FIXED) { gain_mul = MT9M021_GAIN_8X; } else if (val >= MT9M021_GAIN_4X_FIXED) { gain_mul = MT9M021_GAIN_4X; } else if (val >= MT9M021_GAIN_2X_FIXED) { gain_mul = MT9M021_GAIN_2X; } else { gain_mul = MT9M021_GAIN_1X; } /* * Digital gain equation: * * RANGE: 1x, 7.97x * STEPS: 1/32 * * SCALE FACTOR = 3 * * min_gain_val = 102 * max_gain_val = 160 * gain_factor = 3 * * gain accepts mapping to range 32 - 53 */ gain = val / 3; /* Update analog gain multiplier */ err = mt9m021_read_reg16(s_data, MT9M021_DIGITAL_TEST, ®16); if (err) goto exit; reg16 = (reg16 & ~MT9M021_ANALOG_GAIN_MASK) | ((gain_mul << MT9M021_ANALOG_GAIN_SHIFT) & MT9M021_ANALOG_GAIN_MASK); err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16); if (err) goto exit; /* Update global gain */ err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN, gain); if (err) goto exit; err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN_CB, gain); if (err) goto exit; return 0; exit: dev_err(dev, "Gain control error: %d", err); return err; } static int mt9m021_set_frame_length(struct mt9m021 *priv, s64 val) { struct device *dev = &priv->i2c_client->dev; struct camera_common_data *s_data = priv->s_data; int err = 0; dev_dbg(dev, "Setting Frame Length to: %lld", val); err = mt9m021_write_reg16(s_data, MT9M021_FRAME_LENGTH_LINES, val); if (err) return err; msleep(30); return 0; } static int mt9m021_set_frame_rate(struct tegracam_device *tc_dev, s64 val) { struct camera_common_data *s_data = tc_dev->s_data; struct mt9m021 *priv = (struct mt9m021 *)tc_dev->priv; struct device *dev = tc_dev->dev; const struct sensor_mode_properties *mode = &s_data->sensor_props.sensor_modes[s_data->mode]; u64 frame_length; int err; dev_dbg(dev, "Setting Frame rate to: %lld", val); /* Calculate frame-length */ frame_length = mode->signal_properties.pixel_clock.val * mode->control_properties.framerate_factor / mode->image_properties.line_length / val; err = mt9m021_set_frame_length(priv, frame_length); if (err) goto exit; return 0; exit: dev_err(dev, "Frame rate control error: %d", err); return err; } static int mt9m021_set_coarse_time(struct mt9m021 *priv, s64 val) { struct device *dev = &priv->i2c_client->dev; struct camera_common_data *s_data = priv->s_data; int err = 0; dev_dbg(dev, "Setting Coarse Time to: %lld", val); err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME, val); if (err) return err; err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME_CB, val); if (err) return err; return 0; } static int mt9m021_set_exposure(struct tegracam_device *tc_dev, s64 val) { struct camera_common_data *s_data = tc_dev->s_data; struct mt9m021 *priv = (struct mt9m021 *)tc_dev->priv; struct device *dev = tc_dev->dev; const struct sensor_mode_properties *mode = &s_data->sensor_props.sensor_modes[s_data->mode]; u64 coarse_time; int err = 0; dev_dbg(dev, "Setting Exposure Time to : %lld", val); coarse_time = val * mode->signal_properties.pixel_clock.val / mode->image_properties.line_length / mode->control_properties.exposure_factor; err = mt9m021_set_coarse_time(priv, coarse_time); if (err) goto exit; return err; exit: dev_err(dev, "Exposure control error: %d", err); return err; } static int mt9m021_set_analog_gain(struct tegracam_device *tc_dev, s64 val) { struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; int err = 0; u16 reg16 = 0; dev_dbg(dev, "Setting Analog Gain to: %lld", val); /* Update analog gain multiplier */ err = mt9m021_read_reg16(s_data, MT9M021_DIGITAL_TEST, ®16); if (err) goto exit; reg16 = (reg16 & ~MT9M021_ANALOG_GAIN_MASK) | ((val << MT9M021_ANALOG_GAIN_SHIFT) & MT9M021_ANALOG_GAIN_MASK); err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16); if (err) goto exit; return 0; exit: dev_err(dev, "Analog Gain control error: %d", err); return err; } static int mt9m021_set_digital_gain(struct tegracam_device *tc_dev, s64 val, int id) { struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; u32 gain_reg; u32 gain_cb_reg; const char *gain_name; int err = 0; switch (id) { case V4L2_CID_GAIN_RED: gain_name = "Red Gain"; gain_reg = MT9M021_RED_GAIN; gain_cb_reg = MT9M021_RED_GAIN_CB; break; case V4L2_CID_GAIN_GREENR: gain_name = "GreenR Gain"; gain_reg = MT9M021_GREEN1_GAIN; gain_cb_reg = MT9M021_GREEN1_GAIN_CB; break; case V4L2_CID_GAIN_GREENB: gain_name = "GreenB Gain"; gain_reg = MT9M021_GREEN2_GAIN; gain_cb_reg = MT9M021_GREEN2_GAIN_CB; break; case V4L2_CID_GAIN_BLUE: gain_name = "Blue Gain"; gain_reg = MT9M021_BLUE_GAIN; gain_cb_reg = MT9M021_BLUE_GAIN_CB; break; default: dev_err(dev, "Unknown ctrl id %d", id); return -EINVAL; } dev_dbg(dev, "Setting %s to: %lld", gain_name, val); err = mt9m021_write_reg16(s_data, gain_reg, val); if (err) goto exit; err = mt9m021_write_reg16(s_data, gain_cb_reg, val); if (err) goto exit; return 0; exit: dev_err(dev, "Digital Gain control error: %d", err); return err; } static int mt9m021_set_test_pattern(struct tegracam_device *tc_dev, s32 val) { struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; int err = 0; dev_dbg(dev, "Setting Test Pattern to: %d", val); if (!val) err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN, MT9M021_TEST_PATTERN_VAL); else err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN, val); if (err) goto exit; return 0; exit: dev_err(dev, "Test Pattern control error: %d", err); return err; } static int mt9m021_set_flash(struct tegracam_device *tc_dev, s32 val) { struct camera_common_data *s_data = tc_dev->s_data; struct mt9m021 *priv = (struct mt9m021 *)tc_dev->priv; struct device *dev = tc_dev->dev; int err = 0; dev_dbg(dev, "Setting Flash to: %d", val); switch(val) { case V4L2_FLASH_LED_MODE_NONE: err = mt9m021_write_reg16(s_data, MT9M021_FLASH, 0x0000); priv->flash_en = false; break; case V4L2_FLASH_LED_MODE_FLASH: err = mt9m021_write_reg16(s_data, MT9M021_FLASH, 0x0100); priv->flash_en = true; break; default: dev_err(dev, "Unsupported flash mode requested: %d\n", val); err = -EINVAL; break; } if (err) goto exit; return 0; exit: dev_err(dev, "Flash control error: %d", err); return err; } static int mt9m021_set_flip(struct tegracam_device *tc_dev, s32 val, int id) { struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; int err = 0; dev_dbg(dev, "Setting Flip to: %d", val); switch(id) { case V4L2_CID_HFLIP: err = mt9m021_update_bits(s_data, MT9M021_READ_MODE, val << 14, MT9M021_HFLIP_MASK); break; case V4L2_CID_VFLIP: err = mt9m021_update_bits(s_data, MT9M021_READ_MODE, val << 15, MT9M021_VFLIP_MASK); break; default: dev_err(dev, "Unsupported flip mode requested: %d\n", val); err = -EINVAL; break; } if (err) goto exit; return 0; exit: dev_err(dev, "Flip control error: %d", err); return err; } static struct tegracam_ctrl_ops mt9m021_ctrl_ops = { .numctrls = ARRAY_SIZE(ctrl_cid_list), .ctrl_cid_list = ctrl_cid_list, .set_gain = mt9m021_set_gain, .set_exposure = mt9m021_set_exposure, .set_frame_rate = mt9m021_set_frame_rate, .set_group_hold = mt9m021_set_group_hold, .set_analog_gain = mt9m021_set_analog_gain, .set_digital_gain = mt9m021_set_digital_gain, .set_test_pattern = mt9m021_set_test_pattern, .set_flash = mt9m021_set_flash, .set_flip = mt9m021_set_flip, }; static int mt9m021_power_on(struct camera_common_data *s_data) { int err = 0; struct camera_common_power_rail *pw = s_data->power; struct camera_common_pdata *pdata = s_data->pdata; struct device *dev = s_data->dev; dev_dbg(dev, "%s: power on\n", __func__); if (pdata && pdata->power_on) { err = pdata->power_on(pw); if (err) dev_err(dev, "%s failed.\n", __func__); else pw->state = SWITCH_ON; return err; } if (pw->reset_gpio) { gpio_set_value(pw->reset_gpio, 1); usleep_range(50000, 51000); } pw->state = SWITCH_ON; return 0; } static int mt9m021_power_off(struct camera_common_data *s_data) { int err = 0; struct camera_common_power_rail *pw = s_data->power; struct camera_common_pdata *pdata = s_data->pdata; struct device *dev = s_data->dev; dev_dbg(dev, "%s: power off\n", __func__); if (pdata && pdata->power_off) { err = pdata->power_off(pw); if (!err) goto power_off_done; else dev_err(dev, "%s failed.\n", __func__); return err; } usleep_range(2000, 2010); if (pw->reset_gpio) { gpio_set_value(pw->reset_gpio, 0); usleep_range(2000, 2010); } power_off_done: pw->state = SWITCH_OFF; return 0; } static int mt9m021_power_put(struct tegracam_device *tc_dev) { struct camera_common_data *s_data = tc_dev->s_data; struct camera_common_power_rail *pw = s_data->power; if (unlikely(!pw)) return -EFAULT; if (likely(pw->dvdd)) regulator_disable(pw->dvdd); if (likely(pw->avdd)) regulator_put(pw->avdd); if (likely(pw->iovdd)) regulator_put(pw->iovdd); pw->dvdd = NULL; pw->avdd = NULL; pw->iovdd = NULL; if (likely(pw->reset_gpio)) gpio_free(pw->reset_gpio); return 0; } static int mt9m021_power_get(struct tegracam_device *tc_dev) { struct device *dev = tc_dev->dev; struct camera_common_data *s_data = tc_dev->s_data; struct camera_common_power_rail *pw = s_data->power; struct camera_common_pdata *pdata = s_data->pdata; const char *mclk_name; struct clk *parent; int err = 0; int ret = 0; mclk_name = pdata->mclk_name ? pdata->mclk_name : "extperiph1"; pw->mclk = devm_clk_get(dev, mclk_name); if (IS_ERR(pw->mclk)) { dev_err(dev, "unable to get clock %s\n", mclk_name); return PTR_ERR(pw->mclk); } parent = devm_clk_get(dev, "pllp_grtba"); if (IS_ERR(parent)) dev_err(dev, "devm_clk_get failed for pllp_grtba"); else clk_set_parent(pw->mclk, parent); pw->reset_gpio = pdata->reset_gpio; if (pdata->use_cam_gpio) { err = cam_gpio_register(dev, pw->pwdn_gpio); if (err) dev_err(dev, "%s ERR can't register cam gpio %u!\n", __func__, pw->pwdn_gpio); } else { if (gpio_is_valid(pw->reset_gpio)) { ret = gpio_request(pw->reset_gpio, "cam_reset_gpio"); if (ret < 0) { dev_dbg(dev, "%s can't request reset_gpio %d\n", __func__, ret); } gpio_direction_output(pw->reset_gpio, 1); } } pw->state = SWITCH_OFF; return err; } static struct camera_common_pdata *mt9m021_parse_dt(struct tegracam_device *tc_dev) { struct device *dev = tc_dev->dev; struct device_node *np = dev->of_node; struct camera_common_pdata *board_priv_pdata; const struct of_device_id *match; struct camera_common_pdata *ret = NULL; int err = 0; int gpio; if (!np) return NULL; match = of_match_device(mt9m021_of_match, dev); if (!match) { dev_err(dev, "Failed to find matching dt id\n"); return NULL; } board_priv_pdata = devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); if (!board_priv_pdata) return NULL; gpio = of_get_named_gpio(np, "reset-gpios", 0); if (gpio < 0) { if (gpio == -EPROBE_DEFER) ret = ERR_PTR(-EPROBE_DEFER); dev_err(dev, "reset-gpios not found\n"); goto error; } board_priv_pdata->reset_gpio = (unsigned int)gpio; err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name); if (err) dev_dbg(dev, "mclk name not present, " "assume sensor driven externally\n"); board_priv_pdata->has_eeprom = of_property_read_bool(np, "has-eeprom"); return board_priv_pdata; error: devm_kfree(dev, board_priv_pdata); return ret; } static int mt9m021_sequencer_settings(struct mt9m021 *priv) { struct device *dev = &priv->i2c_client->dev; struct camera_common_data *s_data = priv->s_data; int i, ret; dev_dbg(dev, "%s\n", __func__); ret = mt9m021_write_reg16(s_data, MT9M021_SEQ_CTRL_PORT, 0x8000); if (ret < 0) return ret; for (i = 0; i < ARRAY_SIZE(mt9m021_seq_data); i++) { ret = mt9m021_write_reg16(s_data, MT9M021_SEQ_DATA_PORT, mt9m021_seq_data[i]); if (ret < 0) return ret; } return ret; } static int mt9m021_col_correction(struct mt9m021 *priv) { struct device *dev = &priv->i2c_client->dev; struct camera_common_data *s_data = priv->s_data; int ret; dev_dbg(dev, "%s\n", __func__); /* Disable Streaming */ ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_STOP_STREAM]); if (ret < 0) return ret; /* Disable column correction */ ret = mt9m021_write_reg16(s_data, MT9M021_COLUMN_CORRECTION, 0x0007); if (ret < 0) return ret; /* Enable Streaming */ ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_START_STREAM]); if (ret < 0) return ret; /* Disable Streaming */ ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_STOP_STREAM]); if (ret < 0) return ret; /* Enable column correction */ ret = mt9m021_write_reg16(s_data, MT9M021_COLUMN_CORRECTION, 0xE007); if (ret < 0) return ret; return ret; } static int mt9m021_set_mode(struct tegracam_device *tc_dev) { struct mt9m021 *priv = (struct mt9m021 *)tegracam_get_privdata(tc_dev); struct camera_common_data *s_data = tc_dev->s_data; struct device *dev = tc_dev->dev; int ret; dev_dbg(dev, "%s\n", __func__); ret = mt9m021_bridge_setup(priv->i2c_client); if (ret < 0) { dev_err(dev, "%s: Failed to setup mipi bridge\n", __func__); return ret; } ret = mt9m021_sequencer_settings(priv); if (ret < 0) { dev_err(dev, "%s: Failed to setup sequencer\n", __func__); return ret; } ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_PLL_SETUP]); if (ret < 0) { dev_err(dev, "%s: Failed to set pll setup\n", __func__); return ret; } msleep(100); ret = mt9m021_col_correction(priv); if (ret < 0) { dev_err(dev, "%s: Failed to setup column correction\n", __func__); return ret; } ret = mt9m021_write_table(priv, mode_table[s_data->mode]); if (ret < 0) { dev_err(dev, "%s: Failed to setup sensor mode\n", __func__); return ret; } ret = mt9m021_set_flash(tc_dev, priv->flash_en); return ret; } static int mt9m021_start_streaming(struct tegracam_device *tc_dev) { struct mt9m021 *priv = (struct mt9m021 *)tegracam_get_privdata(tc_dev); struct camera_common_data *s_data = priv->s_data; dev_info(tc_dev->dev, "Starting stream\n"); if (strstr(priv->trigger_mode, "slave") != NULL) return mt9m021_write_reg16(s_data, MT9M021_RESET_REG, MT9M021_TRIGGER_MODE); else return mt9m021_write_reg16(s_data, MT9M021_RESET_REG, MT9M021_MASTER_MODE); } static int mt9m021_stop_streaming(struct tegracam_device *tc_dev) { struct mt9m021 *priv = (struct mt9m021 *)tegracam_get_privdata(tc_dev); struct device *dev = tc_dev->dev; int err; dev_info(dev, "Ending stream\n"); err = mt9m021_write_table(priv, mode_table[MT9M021_MODE_STOP_STREAM]); if (err) return err; usleep_range(50000, 51000); return err; } static struct camera_common_sensor_ops mt9m021_common_ops = { .numfrmfmts = ARRAY_SIZE(mt9m021_frmfmt), .frmfmt_table = mt9m021_frmfmt, .power_on = mt9m021_power_on, .power_off = mt9m021_power_off, .write_reg = mt9m021_write_reg, .read_reg = mt9m021_read_reg, .parse_dt = mt9m021_parse_dt, .power_get = mt9m021_power_get, .power_put = mt9m021_power_put, .set_mode = mt9m021_set_mode, .start_streaming = mt9m021_start_streaming, .stop_streaming = mt9m021_stop_streaming, }; static int mt9m021_get_trigger_mode(struct mt9m021 *priv) { int err = 0; struct i2c_client *client = priv->i2c_client; struct device_node *node = client->dev.of_node; const struct of_device_id *match; dev_dbg(&client->dev, "%s\n", __func__); if (!node) return -EFAULT; match = of_match_device(mt9m021_of_match, &client->dev); if (!match) { dev_err(&client->dev, "Failed to find matching dt id\n"); return -EFAULT; } err = of_property_read_string(node, "trigger_mode", &priv->trigger_mode); if (err == -EINVAL) { dev_warn(&client->dev, "trigger_mode not in device tree\n"); *(&priv->trigger_mode) = "master"; } return 0; } static int mt9m021_verify_chip_id(struct mt9m021 *priv) { struct i2c_client *client; struct camera_common_data *s_data; int max_retries = MT9M021_MAX_RETRIES; u16 chip_id = 0; int err; int ret; if (!priv) return -EFAULT; client = priv->i2c_client; s_data = priv->s_data; err = mt9m021_power_on(s_data); if (err) goto exit; while (max_retries) { err = mt9m021_read_reg16(s_data, MT9M021_CHIP_ID_REG, &chip_id); if (!err) break; dev_info(&client->dev, "Failed to read Chip ID, trying again\n"); max_retries--; msleep(30); } if (err) { dev_err(&client->dev, "Failed to read Chip ID\n"); goto exit; } dev_info(&client->dev, "Read Chip ID 0x%04x\n", chip_id); if (chip_id != MT9M021_CHIP_ID) { dev_err(&client->dev, "Read unknown chip ID 0x%04x\n", chip_id); err = -EINVAL; goto exit; } exit: ret = mt9m021_power_off(s_data); if (ret) return ret; return err; } static int mt9m021_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct i2c_client *client = v4l2_get_subdevdata(sd); dev_dbg(&client->dev, "%s:\n", __func__); return 0; } static const struct v4l2_subdev_internal_ops mt9m021_subdev_internal_ops = { .open = mt9m021_open, }; static int mt9m021_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct tegracam_device *tc_dev; struct mt9m021 *priv; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int err; dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr); if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return -EINVAL; priv = devm_kzalloc(dev, sizeof(struct mt9m021), GFP_KERNEL); if (!priv) return -ENOMEM; tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); if (!tc_dev) return -ENOMEM; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_err(&client->dev, "i2c-adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); return -EIO; } priv->i2c_client = tc_dev->client = client; tc_dev->dev = dev; strncpy(tc_dev->name, "mt9m021", sizeof(tc_dev->name)); tc_dev->dev_regmap_config = &sensor_regmap_config; tc_dev->sensor_ops = &mt9m021_common_ops; tc_dev->v4l2sd_internal_ops = &mt9m021_subdev_internal_ops; tc_dev->tcctrl_ops = &mt9m021_ctrl_ops; err = tegracam_device_register(tc_dev); if (err) { dev_err(dev, "tegra camera driver registration failed\n"); return err; } priv->tc_dev = tc_dev; priv->s_data = tc_dev->s_data; priv->subdev = &tc_dev->s_data->subdev; tegracam_set_privdata(tc_dev, (void *)priv); priv->flash_en = true; err = mt9m021_verify_chip_id(priv); if (err) return err; err = mt9m021_get_trigger_mode(priv); if (err) return err; if (strstr(priv->trigger_mode, "slave") != NULL) dev_info(dev, "slave mode activated\n"); err = tegracam_v4l2subdev_register(tc_dev, true); if (err) { dev_err(dev, "tegra camera subdev registration failed\n"); return err; } dev_dbg(dev, "detected mt9m021 sensor\n"); return 0; } static int mt9m021_remove(struct i2c_client *client) { struct camera_common_data *s_data = to_camera_common_data(&client->dev); struct mt9m021 *priv = (struct mt9m021 *)s_data->priv; tegracam_v4l2subdev_unregister(priv->tc_dev); tegracam_device_unregister(priv->tc_dev); return 0; } static const struct i2c_device_id mt9m021_id[] = { {"mt9m021", 0}, {} }; MODULE_DEVICE_TABLE(i2c, mt9m021_id); static struct i2c_driver mt9m021_i2c_driver = { .driver = { .name = "mt9m021", .owner = THIS_MODULE, .of_match_table = of_match_ptr(mt9m021_of_match), }, .probe = mt9m021_probe, .remove = mt9m021_remove, .id_table = mt9m021_id, }; module_i2c_driver(mt9m021_i2c_driver); MODULE_DESCRIPTION("Media Controller driver for Sony MT9M021"); MODULE_AUTHOR("Enrique Ramirez "); MODULE_LICENSE("GPL v2");