mirror of
https://xff.cz/git/u-boot/
synced 2025-09-01 16:52:14 +02:00
input: edt-ft5x06: Add support for edt,edt-ft5x06 touchpanel controller
This is a direct port of the Linux driver from Linux v4.18. Signed-off-by: Ondrej Jirman <megous@megous.com>
This commit is contained in:
committed by
Ondrej Jirman
parent
15b23000bb
commit
29c1412851
@@ -109,3 +109,10 @@ config DM_TOUCHPANEL
|
||||
using driver model. The API is implemented by touchpanel.h and
|
||||
includes methods to start/stop the device and check for available
|
||||
input.
|
||||
|
||||
config EDT_FT5X06_TOUCHPANEL
|
||||
bool "Enable EDT FT5x06 touchpanel support"
|
||||
depends on DM_TOUCHPANEL
|
||||
help
|
||||
This adds a support for EDT FT5x06 touch panels that can be used
|
||||
for controlling u-boot on tablets using touch input only.
|
||||
|
@@ -15,5 +15,6 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o
|
||||
obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o
|
||||
obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
|
||||
obj-$(CONFIG_DM_TOUCHPANEL) += touchpanel-uclass.o
|
||||
obj-$(CONFIG_EDT_FT5X06_TOUCHPANEL) += edt-ft5x06.o
|
||||
|
||||
endif
|
||||
|
599
drivers/input/edt-ft5x06.c
Normal file
599
drivers/input/edt-ft5x06.c
Normal file
@@ -0,0 +1,599 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) Copyright 2018 Ondrej Jirman <megous@megous.com>
|
||||
*
|
||||
* Based on the Linux driver drivers/input/touchscreen/edt-ft5x06.c (v4.18):
|
||||
*
|
||||
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
|
||||
* Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
|
||||
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <errno.h>
|
||||
#include <input.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <command.h>
|
||||
#include <i2c.h>
|
||||
#include <touchpanel.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define WORK_REGISTER_THRESHOLD 0x00
|
||||
#define WORK_REGISTER_REPORT_RATE 0x08
|
||||
#define WORK_REGISTER_GAIN 0x30
|
||||
#define WORK_REGISTER_OFFSET 0x31
|
||||
#define WORK_REGISTER_NUM_X 0x33
|
||||
#define WORK_REGISTER_NUM_Y 0x34
|
||||
|
||||
#define M09_REGISTER_THRESHOLD 0x80
|
||||
#define M09_REGISTER_GAIN 0x92
|
||||
#define M09_REGISTER_OFFSET 0x93
|
||||
#define M09_REGISTER_NUM_X 0x94
|
||||
#define M09_REGISTER_NUM_Y 0x95
|
||||
|
||||
#define NO_REGISTER 0xff
|
||||
|
||||
#define WORK_REGISTER_OPMODE 0x3c
|
||||
#define FACTORY_REGISTER_OPMODE 0x01
|
||||
|
||||
#define TOUCH_EVENT_DOWN 0x00
|
||||
#define TOUCH_EVENT_UP 0x01
|
||||
#define TOUCH_EVENT_ON 0x02
|
||||
#define TOUCH_EVENT_RESERVED 0x03
|
||||
|
||||
#define EDT_NAME_LEN 23
|
||||
#define EDT_SWITCH_MODE_RETRIES 10
|
||||
#define EDT_SWITCH_MODE_DELAY 5 /* msec */
|
||||
#define EDT_RAW_DATA_RETRIES 100
|
||||
#define EDT_RAW_DATA_DELAY 1000 /* usec */
|
||||
|
||||
enum edt_ver {
|
||||
EDT_M06,
|
||||
EDT_M09,
|
||||
EDT_M12,
|
||||
GENERIC_FT,
|
||||
};
|
||||
|
||||
struct edt_reg_addr {
|
||||
int reg_threshold;
|
||||
int reg_report_rate;
|
||||
int reg_gain;
|
||||
int reg_offset;
|
||||
int reg_num_x;
|
||||
int reg_num_y;
|
||||
};
|
||||
|
||||
struct ft5x06_priv {
|
||||
struct udevice *reg;
|
||||
struct gpio_desc reset_gpio;
|
||||
|
||||
u16 num_x;
|
||||
u16 num_y;
|
||||
|
||||
int threshold;
|
||||
int gain;
|
||||
int offset;
|
||||
int report_rate;
|
||||
int max_support_points;
|
||||
|
||||
char name[EDT_NAME_LEN];
|
||||
|
||||
struct edt_reg_addr reg_addr;
|
||||
enum edt_ver version;
|
||||
};
|
||||
|
||||
static int ft5x06_readwrite(struct udevice *dev,
|
||||
u16 wr_len, void *wr_buf,
|
||||
u16 rd_len, void *rd_buf)
|
||||
{
|
||||
struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
|
||||
struct i2c_msg wrmsg[2];
|
||||
int ret, i = 0;
|
||||
|
||||
if (wr_len) {
|
||||
wrmsg[i].addr = chip->chip_addr;
|
||||
wrmsg[i].flags = 0;
|
||||
wrmsg[i].len = wr_len;
|
||||
wrmsg[i].buf = wr_buf;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (rd_len) {
|
||||
wrmsg[i].addr = chip->chip_addr;
|
||||
wrmsg[i].flags = I2C_M_RD;
|
||||
wrmsg[i].len = rd_len;
|
||||
wrmsg[i].buf = rd_buf;
|
||||
i++;
|
||||
}
|
||||
|
||||
ret = dm_i2c_xfer(dev, wrmsg, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static int ft5x06_register_write(struct udevice *dev, u8 addr, u8 value)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
u8 wrbuf[4];
|
||||
|
||||
switch (priv->version) {
|
||||
case EDT_M06:
|
||||
wrbuf[0] = 0xfc;
|
||||
wrbuf[1] = addr & 0x3f;
|
||||
wrbuf[2] = value;
|
||||
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
|
||||
return ft5x06_readwrite(dev, 4, wrbuf, 0, NULL);
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
wrbuf[1] = value;
|
||||
|
||||
return ft5x06_readwrite(dev, 2, wrbuf, 0, NULL);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ft5x06_register_read(struct udevice *dev, u8 addr)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
u8 wrbuf[2], rdbuf[2];
|
||||
int error;
|
||||
|
||||
switch (priv->version) {
|
||||
case EDT_M06:
|
||||
wrbuf[0] = 0xfc;
|
||||
wrbuf[1] = addr & 0x3f;
|
||||
wrbuf[1] |= 0x40;
|
||||
|
||||
error = ft5x06_readwrite(dev, 2, wrbuf, 2, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
|
||||
dev_err(dev,
|
||||
"crc error: 0x%02x expected, got 0x%02x\n",
|
||||
wrbuf[0] ^ wrbuf[1] ^ rdbuf[0],
|
||||
rdbuf[1]);
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
error = ft5x06_readwrite(dev, 1, wrbuf, 1, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rdbuf[0];
|
||||
}
|
||||
|
||||
static int ft5x06_identify(struct udevice *dev, char *fw_version)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
u8 rdbuf[EDT_NAME_LEN];
|
||||
char *p;
|
||||
int error;
|
||||
char *model_name = priv->name;
|
||||
|
||||
/* see what we find if we assume it is a M06 *
|
||||
* if we get less than EDT_NAME_LEN, we don't want
|
||||
* to have garbage in there
|
||||
*/
|
||||
memset(rdbuf, 0, sizeof(rdbuf));
|
||||
error = ft5x06_readwrite(dev, 1, "\xBB", EDT_NAME_LEN - 1, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Probe content for something consistent.
|
||||
* M06 starts with a response byte, M12 gives the data directly.
|
||||
* M09/Generic does not provide model number information.
|
||||
*/
|
||||
if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
|
||||
priv->version = EDT_M06;
|
||||
|
||||
/* remove last '$' end marker */
|
||||
rdbuf[EDT_NAME_LEN - 1] = '\0';
|
||||
if (rdbuf[EDT_NAME_LEN - 2] == '$')
|
||||
rdbuf[EDT_NAME_LEN - 2] = '\0';
|
||||
|
||||
/* look for Model/Version separator */
|
||||
p = strchr(rdbuf, '*');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
|
||||
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
||||
} else if (!strncasecmp(rdbuf, "EP0", 3)) {
|
||||
priv->version = EDT_M12;
|
||||
|
||||
/* remove last '$' end marker */
|
||||
rdbuf[EDT_NAME_LEN - 2] = '\0';
|
||||
if (rdbuf[EDT_NAME_LEN - 3] == '$')
|
||||
rdbuf[EDT_NAME_LEN - 3] = '\0';
|
||||
|
||||
/* look for Model/Version separator */
|
||||
p = strchr(rdbuf, '*');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
strlcpy(model_name, rdbuf, EDT_NAME_LEN);
|
||||
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
||||
} else {
|
||||
/* If it is not an EDT M06/M12 touchscreen, then the model
|
||||
* detection is a bit hairy. The different ft5x06
|
||||
* firmares around don't reliably implement the
|
||||
* identification registers. Well, we'll take a shot.
|
||||
*
|
||||
* The main difference between generic focaltec based
|
||||
* touches and EDT M09 is that we know how to retrieve
|
||||
* the max coordinates for the latter.
|
||||
*/
|
||||
priv->version = GENERIC_FT;
|
||||
|
||||
error = ft5x06_readwrite(dev, 1, "\xA6", 2, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
strlcpy(fw_version, rdbuf, 2);
|
||||
|
||||
error = ft5x06_readwrite(dev, 1, "\xA8", 1, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* This "model identification" is not exact. Unfortunately
|
||||
* not all firmwares for the ft5x06 put useful values in
|
||||
* the identification registers.
|
||||
*/
|
||||
switch (rdbuf[0]) {
|
||||
case 0x35: /* EDT EP0350M09 */
|
||||
case 0x43: /* EDT EP0430M09 */
|
||||
case 0x50: /* EDT EP0500M09 */
|
||||
case 0x57: /* EDT EP0570M09 */
|
||||
case 0x70: /* EDT EP0700M09 */
|
||||
priv->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0xa1: /* EDT EP1010ML00 */
|
||||
priv->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0x5a: /* Solomon Goldentek Display */
|
||||
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
|
||||
break;
|
||||
default:
|
||||
snprintf(model_name, EDT_NAME_LEN,
|
||||
"generic ft5x06 (%02x)",
|
||||
rdbuf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ft5x06_get_defaults(struct udevice *dev)
|
||||
{
|
||||
//XXX: not supported yet, should be read from DT
|
||||
#if 0
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
struct edt_reg_addr *reg_addr = &priv->reg_addr;
|
||||
u32 val;
|
||||
int error;
|
||||
|
||||
error = device_property_read_u32(dev, "threshold", &val);
|
||||
if (!error) {
|
||||
ft5x06_register_write(dev, reg_addr->reg_threshold, val);
|
||||
priv->threshold = val;
|
||||
}
|
||||
|
||||
error = device_property_read_u32(dev, "gain", &val);
|
||||
if (!error) {
|
||||
ft5x06_register_write(dev, reg_addr->reg_gain, val);
|
||||
priv->gain = val;
|
||||
}
|
||||
|
||||
error = device_property_read_u32(dev, "offset", &val);
|
||||
if (!error) {
|
||||
ft5x06_register_write(dev, reg_addr->reg_offset, val);
|
||||
priv->offset = val;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ft5x06_get_parameters(struct udevice *dev)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
struct edt_reg_addr *reg_addr = &priv->reg_addr;
|
||||
|
||||
priv->threshold = ft5x06_register_read(dev, reg_addr->reg_threshold);
|
||||
priv->gain = ft5x06_register_read(dev, reg_addr->reg_gain);
|
||||
priv->offset = ft5x06_register_read(dev, reg_addr->reg_offset);
|
||||
if (reg_addr->reg_report_rate != NO_REGISTER)
|
||||
priv->report_rate = ft5x06_register_read(dev,
|
||||
reg_addr->reg_report_rate);
|
||||
if (priv->version == EDT_M06 ||
|
||||
priv->version == EDT_M09 ||
|
||||
priv->version == EDT_M12) {
|
||||
priv->num_x = ft5x06_register_read(dev, reg_addr->reg_num_x);
|
||||
priv->num_y = ft5x06_register_read(dev, reg_addr->reg_num_y);
|
||||
} else {
|
||||
priv->num_x = -1;
|
||||
priv->num_y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ft5x06_set_regs(struct udevice *dev)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
struct edt_reg_addr *reg_addr = &priv->reg_addr;
|
||||
|
||||
switch (priv->version) {
|
||||
case EDT_M06:
|
||||
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
|
||||
reg_addr->reg_gain = WORK_REGISTER_GAIN;
|
||||
reg_addr->reg_offset = WORK_REGISTER_OFFSET;
|
||||
reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
|
||||
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = NO_REGISTER;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
reg_addr->reg_offset = M09_REGISTER_OFFSET;
|
||||
reg_addr->reg_num_x = M09_REGISTER_NUM_X;
|
||||
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case GENERIC_FT:
|
||||
/* this is a guesswork */
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
reg_addr->reg_offset = M09_REGISTER_OFFSET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ft5x06_check_crc(struct udevice *dev, u8 *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
u8 crc = 0;
|
||||
|
||||
for (i = 0; i < buflen - 1; i++)
|
||||
crc ^= buf[i];
|
||||
|
||||
if (crc != buf[buflen-1]) {
|
||||
dev_err(dev, "crc error: 0x%02x expected, got 0x%02x\n",
|
||||
crc, buf[buflen-1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ft5x06_get_touches(struct udevice* dev,
|
||||
struct touchpanel_touch* touches, int max_touches)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
u8 cmd;
|
||||
u8 rdbuf[63];
|
||||
int i, type, x, y, id;
|
||||
int offset, tplen, datalen, crclen;
|
||||
int error;
|
||||
int touches_count = 0;
|
||||
|
||||
switch (priv->version) {
|
||||
case EDT_M06:
|
||||
cmd = 0xf9; /* tell the controller to send touch data */
|
||||
offset = 5; /* where the actual touch data starts */
|
||||
tplen = 4; /* data comes in so called frames */
|
||||
crclen = 1; /* length of the crc data */
|
||||
break;
|
||||
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
cmd = 0x0;
|
||||
offset = 3;
|
||||
tplen = 6;
|
||||
crclen = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(rdbuf, 0, sizeof(rdbuf));
|
||||
datalen = tplen * priv->max_support_points + offset + crclen;
|
||||
|
||||
error = ft5x06_readwrite(dev, sizeof(cmd), &cmd, datalen, rdbuf);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to fetch data, error: %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* M09/M12 does not send header or CRC */
|
||||
if (priv->version == EDT_M06) {
|
||||
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
|
||||
rdbuf[2] != datalen) {
|
||||
dev_err(dev, "Unexpected header: %02x%02x%02x!\n",
|
||||
rdbuf[0], rdbuf[1], rdbuf[2]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ft5x06_check_crc(dev, rdbuf, datalen))
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->max_support_points; i++) {
|
||||
u8 *buf = &rdbuf[i * tplen + offset];
|
||||
bool down;
|
||||
|
||||
type = buf[0] >> 6;
|
||||
/* ignore Reserved events */
|
||||
if (type == TOUCH_EVENT_RESERVED)
|
||||
continue;
|
||||
|
||||
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
|
||||
if (priv->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
|
||||
continue;
|
||||
|
||||
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
|
||||
y = ((buf[2] << 8) | buf[3]) & 0x0fff;
|
||||
id = (buf[2] >> 4) & 0x0f;
|
||||
down = type != TOUCH_EVENT_UP;
|
||||
|
||||
if (!down)
|
||||
continue;
|
||||
|
||||
if (max_touches > touches_count) {
|
||||
touches[touches_count].x = x;
|
||||
touches[touches_count].y = y;
|
||||
touches[touches_count].id = id;
|
||||
touches_count++;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return touches_count;
|
||||
}
|
||||
|
||||
static int ft5x06_start(struct udevice *dev)
|
||||
{
|
||||
debug("%s: started\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ft5x06_stop(struct udevice *dev)
|
||||
{
|
||||
debug("%s: stopped\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the touch panel.
|
||||
*
|
||||
* @return 0 if ok, -ERRNO on error
|
||||
*/
|
||||
static int ft5x06_probe(struct udevice *dev)
|
||||
{
|
||||
struct touchpanel_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
priv->max_support_points = 5;
|
||||
|
||||
if (priv->reg && CONFIG_IS_ENABLED(DM_REGULATOR)) {
|
||||
ret = regulator_set_enable(priv->reg, true);
|
||||
if (ret) {
|
||||
debug("%s: Cannot enable regulator for touchpanel '%s'\n",
|
||||
__func__, dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(20 * 1000);
|
||||
}
|
||||
|
||||
if (dm_gpio_is_valid(&priv->reset_gpio)) {
|
||||
ret = dm_gpio_set_value(&priv->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
udelay(300 * 1000);
|
||||
|
||||
char fw_version[EDT_NAME_LEN];
|
||||
ret = ft5x06_identify(dev, fw_version);
|
||||
if (ret) {
|
||||
dev_err(dev, "touchscreen probe failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ft5x06_set_regs(dev);
|
||||
ft5x06_get_defaults(dev);
|
||||
ft5x06_get_parameters(dev);
|
||||
|
||||
debug("Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
|
||||
priv->name, fw_version, priv->num_x, priv->num_y);
|
||||
|
||||
if (priv->version == EDT_M06 ||
|
||||
priv->version == EDT_M09 ||
|
||||
priv->version == EDT_M12) {
|
||||
uc_priv->size_x = priv->num_x * 64;
|
||||
uc_priv->size_y = priv->num_y * 64;
|
||||
} else {
|
||||
//XXX: perhaps check that the user set the values in DT
|
||||
}
|
||||
|
||||
debug("%s: ready\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ft5x06_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct ft5x06_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
debug("%s: start\n", __func__);
|
||||
|
||||
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
|
||||
"power-supply", &priv->reg);
|
||||
if (ret) {
|
||||
debug("%s: Cannot get power supply: ret=%d\n", __func__, ret);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
|
||||
GPIOD_IS_OUT);
|
||||
if (ret) {
|
||||
debug("%s: Warning: cannot get enable GPIO: ret=%d\n",
|
||||
__func__, ret);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
}
|
||||
|
||||
debug("%s: done\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct touchpanel_ops ft5x06_ops = {
|
||||
.start = ft5x06_start,
|
||||
.stop = ft5x06_stop,
|
||||
.get_touches = ft5x06_get_touches,
|
||||
};
|
||||
|
||||
static const struct udevice_id ft5x06_ids[] = {
|
||||
{ .compatible = "edt,edt-ft5x06" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ft5x06) = {
|
||||
.name = "touchpanel-ft5x06",
|
||||
.id = UCLASS_TOUCHPANEL,
|
||||
.of_match = ft5x06_ids,
|
||||
.probe = ft5x06_probe,
|
||||
.ops = &ft5x06_ops,
|
||||
.of_to_plat = ft5x06_of_to_plat,
|
||||
.priv_auto = sizeof(struct ft5x06_priv),
|
||||
};
|
Reference in New Issue
Block a user