misc: lt7911d-fb-notifier: add firmware upgrade support
Signed-off-by: Luo Wei <lw@rock-chips.com> Change-Id: I4deb3a0b61d4fa0605da637cf41423995ce4be0e
This commit is contained in:
parent
cae91899b6
commit
1a2e751d9f
2 changed files with 1618 additions and 38 deletions
|
|
@ -5,28 +5,465 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include "lt7911d-fw.h"
|
||||
|
||||
struct lt7911d {
|
||||
struct device *dev;
|
||||
struct gpio_descs *gpios;
|
||||
struct regmap *regmap;
|
||||
struct serdes_init_seq *serdes_init_seq;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct notifier_block fb_notif;
|
||||
int fb_blank;
|
||||
};
|
||||
|
||||
static int Datalen = 17594;
|
||||
/*to save hdcp key */
|
||||
static unsigned char HdcpKey[286];
|
||||
/*the buffer to read flash, its size should be equal the size of bin, max size is 24KB*/
|
||||
static unsigned char ReadFirmware[17594];
|
||||
/*The buffer to read flash, hex->bin->txt*/
|
||||
//static unsigned char FirmwareData[17594];
|
||||
|
||||
static int I2C_Write_Byte(struct lt7911d *lt7911d, unsigned char reg, unsigned char val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(lt7911d->regmap, reg, val);
|
||||
if (ret < 0) {
|
||||
pr_info("failed to write lt7911d register 0x%x: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char I2C_Read_Byte(struct lt7911d *lt7911d, unsigned char reg)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(lt7911d->regmap, reg, &val);
|
||||
if (ret < 0) {
|
||||
pr_info("failed to read lt7911d register 0x%x: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (unsigned char)val;
|
||||
}
|
||||
|
||||
static bool lt7911d_check_chip_id(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned char id_h, id_l;
|
||||
|
||||
/*0x80ee=0x01 to enable i2c interface*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
/*write bank 0xa0, read 0xa000 and 0xa001*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0xA0);
|
||||
id_h = I2C_Read_Byte(lt7911d, 0x00);
|
||||
id_l = I2C_Read_Byte(lt7911d, 0x01);
|
||||
|
||||
/*chip id=0x1605*/
|
||||
if ((id_h == 0x16) && (id_l == 0x05)) {
|
||||
pr_info("%s chip id =0x1605\n", __func__);
|
||||
/*0x80ee=0x00 to disable i2c*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x00);
|
||||
return true;
|
||||
} else {
|
||||
pr_info("%s chip id 0x%x is not 0x1605\n", __func__, (id_h << 8) | id_l);
|
||||
/*0x80ee=0x00 to disable i2c*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x00);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int lt7911d_check_fw_version(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned char fw;
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
|
||||
/*read 0xD211*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0xD2);
|
||||
fw = I2C_Read_Byte(lt7911d, 0x11);
|
||||
|
||||
/*fw version address is 0x1dfb*/
|
||||
if (fw < FirmwareData[0x1dfb]) {
|
||||
pr_info("%s fw %d<%d, need to upgrade\n", __func__, fw, FirmwareData[0x1dfb]);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x00);
|
||||
return 0;
|
||||
} else {
|
||||
pr_info("%s fw %d>=%d, no need upgrade\n", __func__, fw, FirmwareData[0x1dfb]);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x00);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void lt7911d_config_para(struct lt7911d *lt7911d)
|
||||
{
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0xC0);
|
||||
I2C_Write_Byte(lt7911d, 0x58, 0x00);
|
||||
I2C_Write_Byte(lt7911d, 0x59, 0x51);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x92);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
}
|
||||
|
||||
static void lt7911d_block_erase(struct lt7911d *lt7911d)
|
||||
{
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x5B, 0x00);
|
||||
I2C_Write_Byte(lt7911d, 0x5C, 0x00);
|
||||
I2C_Write_Byte(lt7911d, 0x5D, 0x00);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x83);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
|
||||
/*The time to waiting for earse flash*/
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
/*If earse flash will erase the hdcp key, so need to backup firstly*/
|
||||
static void SaveHdcpKeyFromFlash(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned int StartAddr;
|
||||
unsigned int npage, i, j;
|
||||
unsigned char npagelen = 0;
|
||||
unsigned char addr[3] = {0};
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xdf);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xff);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*The first address of HDCP KEY*/
|
||||
StartAddr = 0x006000;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
|
||||
/*hdcp key size is 286 byte*/
|
||||
npage = 18;
|
||||
npagelen = 16;
|
||||
|
||||
for (i = 0; i < npage; i++) {
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0x6f);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0xA2);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x5B, addr[0]);
|
||||
I2C_Write_Byte(lt7911d, 0x5C, addr[1]);
|
||||
I2C_Write_Byte(lt7911d, 0x5D, addr[2]);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x92);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x58, 0x01);
|
||||
|
||||
if (i == 17)
|
||||
npagelen = 14;
|
||||
|
||||
for (j = 0; j < npagelen; j++)
|
||||
HdcpKey[i * 16 + j] = I2C_Read_Byte(lt7911d, 0x5F);
|
||||
|
||||
StartAddr += 16;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
}
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x8a);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
}
|
||||
|
||||
static void lt7911d_write_firmware_to_flash(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned int StartAddr;
|
||||
unsigned int npage, i, j;
|
||||
unsigned char npagelen = 0;
|
||||
unsigned char addr[3] = {0};
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xdf);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xff);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*The first address of flash£¬Max Size 24K*/
|
||||
StartAddr = 0x000000;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
|
||||
if (Datalen % 16) {
|
||||
/*Datalen is the length of the firmware.*/
|
||||
npage = Datalen / 16 + 1;
|
||||
} else {
|
||||
npage = Datalen / 16;
|
||||
}
|
||||
npagelen = 16;
|
||||
|
||||
for (i = 0; i < npage; i++) {
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0xef);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0xA2);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x58, 0x01);
|
||||
|
||||
if ((Datalen - i * 16) < 16)
|
||||
npagelen = Datalen - i*16;
|
||||
|
||||
for (j = 0; j < npagelen; j++) {
|
||||
/*please just continue to write data to 0x59,*/
|
||||
/*and lt7911d will increase the address auto use 0xff*/
|
||||
/*as insufficient data if datelen%16 is not zero*/
|
||||
I2C_Write_Byte(lt7911d, 0x59, FirmwareData[i*16 + j]);
|
||||
}
|
||||
|
||||
/*change the first address*/
|
||||
I2C_Write_Byte(lt7911d, 0x5B, addr[0]);
|
||||
I2C_Write_Byte(lt7911d, 0x5C, addr[1]);
|
||||
I2C_Write_Byte(lt7911d, 0x5D, addr[2]);
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0xE0);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x92);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
|
||||
StartAddr += 16;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
}
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x8a);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*reset fifo*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xDF);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xFF);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void lt7911d_write_hdcpkey_to_flash(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned int StartAddr;
|
||||
unsigned int npage, i, j;
|
||||
unsigned char npagelen = 0;
|
||||
unsigned char addr[3] = {0};
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xdf);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xff);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*hdcp key first address*/
|
||||
StartAddr = 0x006000;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
|
||||
npage = 18;
|
||||
npagelen = 16;
|
||||
|
||||
for (i = 0; i < npage; i++) {
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0xef);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0xA2);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x58, 0x01);
|
||||
|
||||
if (i == 17)
|
||||
npagelen = 14;
|
||||
|
||||
for (j = 0; j < npagelen; j++) {
|
||||
/*please just continue to write data to 0x59,*/
|
||||
/*and lt7911d will increase the address auto use 0xff*/
|
||||
/*as insufficient data if datelen%16 is not zero .*/
|
||||
I2C_Write_Byte(lt7911d, 0x59, HdcpKey[i*16 + j]);
|
||||
}
|
||||
|
||||
if (npagelen == 14) {
|
||||
I2C_Write_Byte(lt7911d, 0x59, 0xFF);
|
||||
I2C_Write_Byte(lt7911d, 0x59, 0xFF);
|
||||
}
|
||||
|
||||
/*change the first address*/
|
||||
I2C_Write_Byte(lt7911d, 0x5B, addr[0]);
|
||||
I2C_Write_Byte(lt7911d, 0x5C, addr[1]);
|
||||
I2C_Write_Byte(lt7911d, 0x5D, addr[2]);
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0xE0);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x92);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
|
||||
StartAddr += 16;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
}
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x8a);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*reset fifo*/
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xDF);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xFF);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void lt7911d_read_firmware_from_flash(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned int StartAddr;
|
||||
unsigned int npage, i, j;
|
||||
unsigned char npagelen = 0;
|
||||
unsigned char addr[3] = {0};
|
||||
|
||||
memset(ReadFirmware, 0, sizeof(ReadFirmware));
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x01);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x90);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xdf);
|
||||
I2C_Write_Byte(lt7911d, 0x02, 0xff);
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x86);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
|
||||
/*the first address of firmware*/
|
||||
StartAddr = 0x000000;
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
|
||||
if (Datalen % 16)
|
||||
npage = Datalen / 16 + 1;
|
||||
else
|
||||
npage = Datalen / 16;
|
||||
|
||||
npagelen = 16;
|
||||
|
||||
for (i = 0; i < npage; i++) {
|
||||
I2C_Write_Byte(lt7911d, 0x5E, 0x6f);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0xA2);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x5B, addr[0]);
|
||||
I2C_Write_Byte(lt7911d, 0x5C, addr[1]);
|
||||
I2C_Write_Byte(lt7911d, 0x5D, addr[2]);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x92);
|
||||
I2C_Write_Byte(lt7911d, 0x5A, 0x82);
|
||||
I2C_Write_Byte(lt7911d, 0x58, 0x01);
|
||||
|
||||
if ((Datalen - i * 16) < 16)
|
||||
npagelen = Datalen - i*16;
|
||||
|
||||
for (j = 0; j < npagelen; j++) {
|
||||
/*please just continue to read data from 0x5f*/
|
||||
/*lt7911d will increase the address auto*/
|
||||
ReadFirmware[i*16 + j] = I2C_Read_Byte(lt7911d, 0x5F);
|
||||
}
|
||||
|
||||
StartAddr += 16;
|
||||
/*change the first address*/
|
||||
addr[0] = (StartAddr & 0xFF0000) >> 16;
|
||||
addr[1] = (StartAddr & 0xFF00) >> 8;
|
||||
addr[2] = StartAddr & 0xFF;
|
||||
}
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x8a);
|
||||
I2C_Write_Byte(lt7911d, 0x5a, 0x82);
|
||||
}
|
||||
|
||||
static int lt7911_compare_firmware(struct lt7911d *lt7911d)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
for (len = 0; len < Datalen; len++) {
|
||||
if (ReadFirmware[len] != FirmwareData[len]) {
|
||||
pr_info("%s: ReadFirmware[%d] 0x%x != 0x%x FirmwareData[%d]\n",
|
||||
__func__, len, ReadFirmware[len], FirmwareData[len], len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt7911d_firmware_upgrade(struct lt7911d *lt7911d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (lt7911d_check_chip_id(lt7911d)) {
|
||||
if (lt7911d_check_fw_version(lt7911d) == 0) {
|
||||
lt7911d_config_para(lt7911d);
|
||||
SaveHdcpKeyFromFlash(lt7911d);
|
||||
lt7911d_block_erase(lt7911d);
|
||||
lt7911d_write_firmware_to_flash(lt7911d);
|
||||
lt7911d_write_hdcpkey_to_flash(lt7911d);
|
||||
lt7911d_read_firmware_from_flash(lt7911d);
|
||||
|
||||
if (!lt7911_compare_firmware(lt7911d)) {
|
||||
pr_info("%s: upgrade success\n", __func__);
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_info("%s: upgrade Fail\n", __func__);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_info("the chip lt7911d is offline\n");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
I2C_Write_Byte(lt7911d, 0xFF, 0x80);
|
||||
I2C_Write_Byte(lt7911d, 0xEE, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct regmap_config lt7911d_regmap_config = {
|
||||
.name = "lt7911d",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x100,
|
||||
};
|
||||
|
||||
static int lt7911d_fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct lt7911d *lt7911d = container_of(self, struct lt7911d, fb_notif);
|
||||
struct fb_event *evdata = data;
|
||||
int fb_blank = *(int *)evdata->data;
|
||||
int i;
|
||||
|
||||
if (event != FB_EVENT_BLANK)
|
||||
return 0;
|
||||
|
|
@ -35,12 +472,12 @@ static int lt7911d_fb_notifier_callback(struct notifier_block *self,
|
|||
return 0;
|
||||
|
||||
if (fb_blank == FB_BLANK_UNBLANK) {
|
||||
for (i = 0; i < lt7911d->gpios->ndescs; i++)
|
||||
gpiod_direction_output(lt7911d->gpios->desc[i], 1);
|
||||
msleep(20);
|
||||
for (i = 0; i < lt7911d->gpios->ndescs; i++)
|
||||
gpiod_direction_output(lt7911d->gpios->desc[i], 0);
|
||||
msleep(500);
|
||||
if (lt7911d->reset_gpio) {
|
||||
gpiod_direction_output(lt7911d->reset_gpio, 1);
|
||||
msleep(20);
|
||||
gpiod_direction_output(lt7911d->reset_gpio, 0);
|
||||
msleep(400);
|
||||
}
|
||||
}
|
||||
|
||||
lt7911d->fb_blank = fb_blank;
|
||||
|
|
@ -48,26 +485,36 @@ static int lt7911d_fb_notifier_callback(struct notifier_block *self,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lt7911d_fb_notifier_probe(struct platform_device *pdev)
|
||||
static int lt7911d_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *dev = &client->dev;
|
||||
struct lt7911d *lt7911d;
|
||||
int i, ret;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
lt7911d = devm_kzalloc(dev, sizeof(*lt7911d), GFP_KERNEL);
|
||||
if (!lt7911d)
|
||||
return -ENOMEM;
|
||||
|
||||
lt7911d->dev = dev;
|
||||
platform_set_drvdata(pdev, lt7911d);
|
||||
i2c_set_clientdata(client, lt7911d);
|
||||
|
||||
lt7911d->gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lt7911d->gpios))
|
||||
return dev_err_probe(dev, PTR_ERR(lt7911d->gpios),
|
||||
lt7911d->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lt7911d->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(lt7911d->reset_gpio),
|
||||
"failed to acquire reset gpio\n");
|
||||
|
||||
for (i = 0; i < lt7911d->gpios->ndescs; i++)
|
||||
gpiod_set_consumer_name(lt7911d->gpios->desc[i], "lt7911d-reset");
|
||||
gpiod_set_consumer_name(lt7911d->reset_gpio, "lt7911d-reset");
|
||||
|
||||
lt7911d->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lt7911d->enable_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(lt7911d->enable_gpio),
|
||||
"failed to acquire enable gpio\n");
|
||||
|
||||
lt7911d->regmap = devm_regmap_init_i2c(client, <7911d_regmap_config);
|
||||
if (IS_ERR(lt7911d->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(lt7911d->regmap),
|
||||
"failed to initialize regmap\n");
|
||||
|
||||
lt7911d->fb_blank = FB_BLANK_UNBLANK;
|
||||
lt7911d->fb_notif.notifier_call = lt7911d_fb_notifier_callback;
|
||||
|
|
@ -75,45 +522,69 @@ static int lt7911d_fb_notifier_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register fb client\n");
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!lt7911d_firmware_upgrade(lt7911d))
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(dev, "%s end\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt7911d_fb_notifier_remove(struct platform_device *pdev)
|
||||
static void lt7911d_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct lt7911d *lt7911d = platform_get_drvdata(pdev);
|
||||
struct lt7911d *lt7911d = i2c_get_clientdata(client);
|
||||
|
||||
gpiod_direction_output(lt7911d->reset_gpio, 1);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static int lt7911d_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lt7911d *lt7911d = i2c_get_clientdata(client);
|
||||
|
||||
fb_unregister_client(<7911d->fb_notif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lt7911d_fb_notifier_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct lt7911d *lt7911d = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
static const struct i2c_device_id lt7911d_i2c_table[] = {
|
||||
{ "lt7911d", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lt7911d_i2c_table);
|
||||
|
||||
for (i = 0; i < lt7911d->gpios->ndescs; i++)
|
||||
gpiod_direction_output(lt7911d->gpios->desc[i], 1);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static const struct of_device_id lt7911d_fb_notifier_of_match[] = {
|
||||
static const struct of_device_id lt7911d_of_match[] = {
|
||||
{ .compatible = "lontium,lt7911d-fb-notifier" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lt7911d_fb_notifier_of_match);
|
||||
MODULE_DEVICE_TABLE(of, lt7911d_of_match);
|
||||
|
||||
static struct platform_driver lt7911d_fb_notifier_driver = {
|
||||
static struct i2c_driver lt7911d_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "lt7911d-fb-notifier",
|
||||
.of_match_table = lt7911d_fb_notifier_of_match,
|
||||
.name = "lt7911d",
|
||||
.of_match_table = lt7911d_of_match,
|
||||
},
|
||||
.probe = lt7911d_fb_notifier_probe,
|
||||
.remove = lt7911d_fb_notifier_remove,
|
||||
.shutdown = lt7911d_fb_notifier_shutdown,
|
||||
.probe = lt7911d_i2c_probe,
|
||||
.remove = lt7911d_i2c_remove,
|
||||
.shutdown = lt7911d_i2c_shutdown,
|
||||
.id_table = lt7911d_i2c_table,
|
||||
};
|
||||
|
||||
module_platform_driver(lt7911d_fb_notifier_driver);
|
||||
static int __init lt7911d_i2c_driver_init(void)
|
||||
{
|
||||
i2c_add_driver(<7911d_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Lontium LT7911D FB Notifier");
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall_sync(lt7911d_i2c_driver_init);
|
||||
|
||||
static void __exit lt7911d_i2c_driver_exit(void)
|
||||
{
|
||||
i2c_del_driver(<7911d_i2c_driver);
|
||||
}
|
||||
module_exit(lt7911d_i2c_driver_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Lontium lt7911dD driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
1109
drivers/misc/lt7911d-fw.h
Normal file
1109
drivers/misc/lt7911d-fw.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue