/* ****************************************************************************** * @file adv7513.c * @author StarFive Technology * @version V1.0 * @date 09/21/2020 * @brief ****************************************************************************** * @copy * * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *

© COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.

*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "adv7513.h" static int adv7513_write(struct i2c_client *client, u16 reg, u8 val) { struct i2c_msg msg; u8 buf[2]; int ret; buf[0] = reg; buf[1] = val; msg.addr = client->addr; msg.flags = 0; msg.buf = buf; msg.len = 2; ret = i2c_transfer(client->adapter, &msg, 1); if (ret >= 0) return 0; dev_err(&client->dev, "adv7513 write reg(0x%x val:0x%x) failed !\n", reg, val); return ret; } static int adv7513_read(struct i2c_client *client, u8 reg, u8 *val) { struct i2c_msg msg[2]; u8 buf[2]; int ret; buf[0] = reg; msg[0].addr = client->addr; msg[0].flags = 0; msg[0].buf = buf; msg[0].len = 1; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].buf = val; msg[1].len = 1; ret = i2c_transfer(client->adapter, msg, 2); if (ret >= 0) { return 0; } dev_err(&client->dev, "adv7513 read reg(0x%x val:0x%x) failed,ret = %d !\n", reg, *val, ret); return ret; } /*============================================================================ * Read up to 8-bit field from a single 8-bit register * ________ * Example |___***__| Mask = 0x1C BitPos = 2 * * * Entry: DevAddr = Device Address * RegAddr = 8-bit register address * Mask = Field mask * BitPos = Field LSBit position in the register (0-7) * * Return: Field value in the LSBits of the return value * *===========================================================================*/ static u8 adv7513_I2CReadField8 (struct i2c_client *client, u8 RegAddr, u8 Mask, u8 BitPos) { u8 data; adv7513_read(client, RegAddr, &data); return (data&Mask)>>BitPos; } /*============================================================================ * Write up to 8-bit field to a single 8-bit register * ________ * Example |___****_| Mask = 0x1E BitPos = 1 * * Entry: DevAddr = Device Address * RegAddr = 8-bit register address * Mask = Field mask * BitPos = Field LSBit position in the register (0-7) * Set to 0 if FieldVal is in correct position of the reg * FieldVal= Value (in the LSBits) of the field to be written * If FieldVal is already in the correct position (i.e., * does not need to be shifted,) set BitPos to 0 * * Return: None * *===========================================================================*/ static void adv7513_I2CWriteField8 (struct i2c_client *client,u8 RegAddr, u8 Mask, u8 BitPos, u8 FieldVal) { u8 rdata, wdata; adv7513_read(client, RegAddr, &rdata); rdata &= (~Mask); wdata = rdata | ((FieldVal<dev; u8 value; int ret = 0; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_warn(&client->dev, "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); return -EIO; } adv7513 = devm_kzalloc(&client->dev, sizeof(*adv7513), GFP_KERNEL); if (!adv7513) return -ENOMEM; if (of_property_read_u32(dev->of_node, "def-width", &adv7513->def_width)) { dev_err(dev,"Missing def_width property in the DT \n"); ret = -EINVAL; } adv7513->client = client; i2c_set_clientdata(client, adv7513); adv7513_read(client, 0x00, &value); if (value != 0x13) { dev_info(&client->dev, "%s[%d],version = 0x%x(NOT 0x13), not find device !\n",__func__,__LINE__,value); return -ENODEV; } adv7513_I2CWriteField8(client, 0x41, 0x40, 0x6, 0x00); adv7513_I2CWriteField8(client, 0x98, 0xFF, 0x0, 0x03); adv7513_I2CWriteField8(client, 0x9A, 0xE0, 0x5, 0x07); adv7513_I2CWriteField8(client, 0x9C, 0xFF, 0x0, 0x30); adv7513_I2CWriteField8(client, 0x9D, 0x03, 0x0, 0x01); adv7513_I2CWriteField8(client, 0xA2, 0xFF, 0x0, 0xA4); adv7513_I2CWriteField8(client, 0xA3, 0xFF, 0x0, 0xA4); adv7513_I2CWriteField8(client, 0xE0, 0xFF, 0x0, 0xD0); adv7513_I2CWriteField8(client, 0xF9, 0xFF, 0x0, 0x00); adv7513_I2CWriteField8(client, 0x15, 0x0F, 0x0, 0x00); adv7513_I2CWriteField8(client, 0x16, 0x30, 0x4, 0x03); adv7513_I2CWriteField8(client, 0x16, 0x0C, 0x2, 0x00); adv7513_I2CWriteField8(client, 0x17, 0x02, 0x1, 0x00); adv7513_I2CWriteField8(client, 0x16, 0xC0, 0x6, 0x00); adv7513_I2CWriteField8(client, 0x18, 0x80, 0x7, 0x00); adv7513_I2CWriteField8(client, 0x18, 0x60, 0x5, 0x00); adv7513_I2CWriteField8(client, 0xAF, 0x02, 0x1, 0x01); adv7513_I2CWriteField8(client, 0x3C, 0x3F, 0x0, 0x01); switch(adv7513->def_width) { case 288: adv7513_I2CWriteField8(client, 0x3C, 0x3F, 0x0, 0x18);//288P adv7513_I2CWriteField8(client, 0x3B, 0xFF, 0x0, 0x00); break; case 640: adv7513_I2CWriteField8(client, 0x3C, 0x3F, 0x0, 0x01); adv7513_I2CWriteField8(client, 0x3B, 0xFF, 0x0, 0x4A); //b01001010 break; case 1280: adv7513_I2CWriteField8(client, 0x3C, 0x3F, 0x0, 0x04);//720P adv7513_I2CWriteField8(client, 0x3B, 0xFF, 0x0, 0x00);//b01011000 break; case 1920: adv7513_I2CWriteField8(client, 0x3C, 0x3F, 0x0, 0x10);//1080P adv7513_I2CWriteField8(client, 0x3B, 0xFF, 0x0, 0x00);//b01011000 break; default: dev_err(dev,"not support width %d \n",adv7513->def_width); } return ret; } static int adv7513_remove(struct i2c_client *client) { struct adv7513 *adv7513 = i2c_get_clientdata(client); return 0; } static const struct i2c_device_id adv7513_id[] = { { "adv7513", 0 }, { } }; static const struct of_device_id dvp_adv7513_dt_ids[] = { { .compatible = "adv7513", }, { /* sentinel */ } }; static struct i2c_driver adv7513_driver = { .driver = { .owner = THIS_MODULE, .name = "adv7513", .of_match_table = dvp_adv7513_dt_ids, }, .probe = adv7513_probe, .remove = adv7513_remove, .id_table = adv7513_id, }; static __init int init_adv7513(void) { int err; err = i2c_add_driver(&adv7513_driver); if (err != 0) printk("i2c driver registration failed, error=%d\n", err); return err; } static __exit void exit_adv7513(void) { i2c_del_driver(&adv7513_driver); } //late_initcall(init_adv7513); fs_initcall(init_adv7513); module_exit(exit_adv7513); MODULE_DESCRIPTION("A driver for adv7513"); MODULE_LICENSE("GPL");