12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775 |
- /*
- *
- * FocalTech ft5x06 TouchScreen driver.
- *
- * Copyright (c) 2010 Focal tech Ltd.
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that 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.
- *
- */
- #include <linux/i2c.h>
- #include <linux/input.h>
- #include <linux/input/mt.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/gpio.h>
- #include <linux/of_gpio.h>
- #include <linux/regulator/consumer.h>
- #include <linux/firmware.h>
- #include <linux/debugfs.h>
- #include <linux/input/ft5x06_ts.h>
- #if defined(CONFIG_FB)
- #include <linux/notifier.h>
- #include <linux/fb.h>
- #elif defined(CONFIG_HAS_EARLYSUSPEND)
- #include <linux/earlysuspend.h>
- /* Early-suspend level */
- #define FT_SUSPEND_LEVEL 1
- #endif
- #define FT_DRIVER_VERSION 0x02
- #define FT_META_REGS 3
- #define FT_ONE_TCH_LEN 6
- #define FT_TCH_LEN(x) (FT_META_REGS + FT_ONE_TCH_LEN * x)
- #define FT_PRESS 0x7F
- #define FT_MAX_ID 0x0F
- #define FT_TOUCH_X_H_POS 3
- #define FT_TOUCH_X_L_POS 4
- #define FT_TOUCH_Y_H_POS 5
- #define FT_TOUCH_Y_L_POS 6
- #define FT_TD_STATUS 2
- #define FT_TOUCH_EVENT_POS 3
- #define FT_TOUCH_ID_POS 5
- #define FT_TOUCH_DOWN 0
- #define FT_TOUCH_CONTACT 2
- /*register address*/
- #define FT_REG_DEV_MODE 0x00
- #define FT_DEV_MODE_REG_CAL 0x02
- #define FT_REG_ID 0xA3
- #define FT_REG_PMODE 0xA5
- #define FT_REG_FW_VER 0xA6
- #define FT_REG_POINT_RATE 0x88
- #define FT_REG_THGROUP 0x80
- #define FT_REG_ECC 0xCC
- #define FT_REG_RESET_FW 0x07
- #define FT_REG_FW_MIN_VER 0xB2
- #define FT_REG_FW_SUB_MIN_VER 0xB3
- /* power register bits*/
- #define FT_PMODE_ACTIVE 0x00
- #define FT_PMODE_MONITOR 0x01
- #define FT_PMODE_STANDBY 0x02
- #define FT_PMODE_HIBERNATE 0x03
- #define FT_FACTORYMODE_VALUE 0x40
- #define FT_WORKMODE_VALUE 0x00
- #define FT_RST_CMD_REG1 0xFC
- #define FT_RST_CMD_REG2 0xBC
- #define FT_READ_ID_REG 0x90
- #define FT_ERASE_APP_REG 0x61
- #define FT_ERASE_PANEL_REG 0x63
- #define FT_FW_START_REG 0xBF
- #define FT_STATUS_NUM_TP_MASK 0x0F
- #define FT_VTG_MIN_UV 2600000
- #define FT_VTG_MAX_UV 3300000
- #define FT_I2C_VTG_MIN_UV 1800000
- #define FT_I2C_VTG_MAX_UV 1800000
- #define FT_COORDS_ARR_SIZE 4
- #define MAX_BUTTONS 4
- #define FT_8BIT_SHIFT 8
- #define FT_4BIT_SHIFT 4
- #define FT_FW_NAME_MAX_LEN 50
- #define FT5316_ID 0x0A
- #define FT5306I_ID 0x55
- #define FT6X06_ID 0x06
- #define FT_UPGRADE_AA 0xAA
- #define FT_UPGRADE_55 0x55
- #define FT_FW_MIN_SIZE 8
- #define FT_FW_MAX_SIZE 32768
- /* Firmware file is not supporting minor and sub minor so use 0 */
- #define FT_FW_FILE_MAJ_VER(x) ((x)->data[(x)->size - 2])
- #define FT_FW_FILE_MIN_VER(x) 0
- #define FT_FW_FILE_SUB_MIN_VER(x) 0
- #define FT_FW_CHECK(x) \
- (((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
- && (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
- && (((x)->data[(x)->size - 3] ^ (x)->data[(x)->size - 4]) == 0xFF)))
- #define FT_MAX_TRIES 5
- #define FT_RETRY_DLY 20
- #define FT_MAX_WR_BUF 10
- #define FT_MAX_RD_BUF 2
- #define FT_FW_PKT_LEN 128
- #define FT_FW_PKT_META_LEN 6
- #define FT_FW_PKT_DLY_MS 20
- #define FT_FW_LAST_PKT 0x6ffa
- #define FT_EARSE_DLY_MS 100
- #define FT_55_AA_DLY_NS 5000
- #define FT_UPGRADE_LOOP 30
- #define FT_CAL_START 0x04
- #define FT_CAL_FIN 0x00
- #define FT_CAL_STORE 0x05
- #define FT_CAL_RETRY 100
- #define FT_REG_CAL 0x00
- #define FT_CAL_MASK 0x70
- #define FT_INFO_MAX_LEN 512
- #define FT_BLOADER_SIZE_OFF 12
- #define FT_BLOADER_NEW_SIZE 30
- #define FT_DATA_LEN_OFF_OLD_FW 8
- #define FT_DATA_LEN_OFF_NEW_FW 14
- #define FT_FINISHING_PKT_LEN_OLD_FW 6
- #define FT_FINISHING_PKT_LEN_NEW_FW 12
- #define FT_MAGIC_BLOADER_Z7 0x7bfa
- #define FT_MAGIC_BLOADER_LZ4 0x6ffa
- #define FT_MAGIC_BLOADER_GZF_30 0x7ff4
- #define FT_MAGIC_BLOADER_GZF 0x7bf4
- enum {
- FT_BLOADER_VERSION_LZ4 = 0,
- FT_BLOADER_VERSION_Z7 = 1,
- FT_BLOADER_VERSION_GZF = 2,
- };
- enum {
- FT_FT5336_FAMILY_ID_0x11 = 0x11,
- FT_FT5336_FAMILY_ID_0x12 = 0x12,
- FT_FT5336_FAMILY_ID_0x13 = 0x13,
- FT_FT5336_FAMILY_ID_0x14 = 0x14,
- };
- #define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
- fw_name, fw_maj, fw_min, fw_sub_min) \
- snprintf(buf, FT_INFO_MAX_LEN, \
- "controller\t= focaltech\n" \
- "model\t\t= 0x%x\n" \
- "name\t\t= %s\n" \
- "max_touches\t= %d\n" \
- "drv_ver\t\t= 0x%x\n" \
- "group_id\t= 0x%x\n" \
- "fw_vkey_support\t= %s\n" \
- "fw_name\t\t= %s\n" \
- "fw_ver\t\t= %d.%d.%d\n", id, name, \
- max_tch, FT_DRIVER_VERSION, group_id, \
- fw_vkey_support, fw_name, fw_maj, fw_min, \
- fw_sub_min)
- #define FT_DEBUG_DIR_NAME "ts_debug"
- struct ft5x06_ts_data {
- struct i2c_client *client;
- struct input_dev *input_dev;
- const struct ft5x06_ts_platform_data *pdata;
- struct regulator *vdd;
- struct regulator *vcc_i2c;
- char fw_name[FT_FW_NAME_MAX_LEN];
- bool loading_fw;
- u8 family_id;
- struct dentry *dir;
- u16 addr;
- bool suspended;
- char *ts_info;
- u8 *tch_data;
- u32 tch_data_len;
- u8 fw_ver[3];
- #if defined(CONFIG_FB)
- struct notifier_block fb_notif;
- #elif defined(CONFIG_HAS_EARLYSUSPEND)
- struct early_suspend early_suspend;
- #endif
- };
- static int ft5x06_i2c_read(struct i2c_client *client, char *writebuf,
- int writelen, char *readbuf, int readlen)
- {
- int ret;
- if (writelen > 0) {
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = writelen,
- .buf = writebuf,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = readlen,
- .buf = readbuf,
- },
- };
- ret = i2c_transfer(client->adapter, msgs, 2);
- if (ret < 0)
- dev_err(&client->dev, "%s: i2c read error.\n",
- __func__);
- } else {
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = readlen,
- .buf = readbuf,
- },
- };
- ret = i2c_transfer(client->adapter, msgs, 1);
- if (ret < 0)
- dev_err(&client->dev, "%s:i2c read error.\n", __func__);
- }
- return ret;
- }
- static int ft5x06_i2c_write(struct i2c_client *client, char *writebuf,
- int writelen)
- {
- int ret;
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = writelen,
- .buf = writebuf,
- },
- };
- ret = i2c_transfer(client->adapter, msgs, 1);
- if (ret < 0)
- dev_err(&client->dev, "%s: i2c write error.\n", __func__);
- return ret;
- }
- static int ft5x0x_write_reg(struct i2c_client *client, u8 addr, const u8 val)
- {
- u8 buf[2] = {0};
- buf[0] = addr;
- buf[1] = val;
- return ft5x06_i2c_write(client, buf, sizeof(buf));
- }
- static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
- {
- return ft5x06_i2c_read(client, &addr, 1, val, 1);
- }
- static void ft5x06_update_fw_ver(struct ft5x06_ts_data *data)
- {
- struct i2c_client *client = data->client;
- u8 reg_addr;
- int err;
- reg_addr = FT_REG_FW_VER;
- err = ft5x06_i2c_read(client, ®_addr, 1, &data->fw_ver[0], 1);
- if (err < 0)
- dev_err(&client->dev, "fw major version read failed");
- reg_addr = FT_REG_FW_MIN_VER;
- err = ft5x06_i2c_read(client, ®_addr, 1, &data->fw_ver[1], 1);
- if (err < 0)
- dev_err(&client->dev, "fw minor version read failed");
- reg_addr = FT_REG_FW_SUB_MIN_VER;
- err = ft5x06_i2c_read(client, ®_addr, 1, &data->fw_ver[2], 1);
- if (err < 0)
- dev_err(&client->dev, "fw sub minor version read failed");
- dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
- data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]);
- }
- static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
- {
- struct ft5x06_ts_data *data = dev_id;
- struct input_dev *ip_dev;
- int rc, i;
- u32 id, x, y, status, num_touches;
- u8 reg = 0x00, *buf;
- bool update_input = false;
- if (!data) {
- pr_err("%s: Invalid data\n", __func__);
- return IRQ_HANDLED;
- }
- ip_dev = data->input_dev;
- buf = data->tch_data;
- rc = ft5x06_i2c_read(data->client, ®, 1,
- buf, data->tch_data_len);
- if (rc < 0) {
- dev_err(&data->client->dev, "%s: read data fail\n", __func__);
- return IRQ_HANDLED;
- }
- for (i = 0; i < data->pdata->num_max_touches; i++) {
- id = (buf[FT_TOUCH_ID_POS + FT_ONE_TCH_LEN * i]) >> 4;
- if (id >= FT_MAX_ID)
- break;
- update_input = true;
- x = (buf[FT_TOUCH_X_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
- (buf[FT_TOUCH_X_L_POS + FT_ONE_TCH_LEN * i]);
- y = (buf[FT_TOUCH_Y_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
- (buf[FT_TOUCH_Y_L_POS + FT_ONE_TCH_LEN * i]);
- status = buf[FT_TOUCH_EVENT_POS + FT_ONE_TCH_LEN * i] >> 6;
- num_touches = buf[FT_TD_STATUS] & FT_STATUS_NUM_TP_MASK;
- /* invalid combination */
- if (!num_touches && !status && !id)
- break;
- input_mt_slot(ip_dev, id);
- if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) {
- input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1);
- input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
- input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
- } else {
- input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
- }
- }
- if (update_input) {
- input_mt_report_pointer_emulation(ip_dev, false);
- input_sync(ip_dev);
- }
- return IRQ_HANDLED;
- }
- static int ft5x06_power_on(struct ft5x06_ts_data *data, bool on)
- {
- int rc;
- if (!on)
- goto power_off;
- rc = regulator_enable(data->vdd);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator vdd enable failed rc=%d\n", rc);
- return rc;
- }
- rc = regulator_enable(data->vcc_i2c);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator vcc_i2c enable failed rc=%d\n", rc);
- regulator_disable(data->vdd);
- }
- return rc;
- power_off:
- rc = regulator_disable(data->vdd);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator vdd disable failed rc=%d\n", rc);
- return rc;
- }
- rc = regulator_disable(data->vcc_i2c);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator vcc_i2c disable failed rc=%d\n", rc);
- regulator_enable(data->vdd);
- }
- return rc;
- }
- static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on)
- {
- int rc;
- if (!on)
- goto pwr_deinit;
- data->vdd = regulator_get(&data->client->dev, "vdd");
- if (IS_ERR(data->vdd)) {
- rc = PTR_ERR(data->vdd);
- dev_err(&data->client->dev,
- "Regulator get failed vdd rc=%d\n", rc);
- return rc;
- }
- if (regulator_count_voltages(data->vdd) > 0) {
- rc = regulator_set_voltage(data->vdd, FT_VTG_MIN_UV,
- FT_VTG_MAX_UV);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator set_vtg failed vdd rc=%d\n", rc);
- goto reg_vdd_put;
- }
- }
- data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
- if (IS_ERR(data->vcc_i2c)) {
- rc = PTR_ERR(data->vcc_i2c);
- dev_err(&data->client->dev,
- "Regulator get failed vcc_i2c rc=%d\n", rc);
- goto reg_vdd_set_vtg;
- }
- if (regulator_count_voltages(data->vcc_i2c) > 0) {
- rc = regulator_set_voltage(data->vcc_i2c, FT_I2C_VTG_MIN_UV,
- FT_I2C_VTG_MAX_UV);
- if (rc) {
- dev_err(&data->client->dev,
- "Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
- goto reg_vcc_i2c_put;
- }
- }
- return 0;
- reg_vcc_i2c_put:
- regulator_put(data->vcc_i2c);
- reg_vdd_set_vtg:
- if (regulator_count_voltages(data->vdd) > 0)
- regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
- reg_vdd_put:
- regulator_put(data->vdd);
- return rc;
- pwr_deinit:
- if (regulator_count_voltages(data->vdd) > 0)
- regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
- regulator_put(data->vdd);
- if (regulator_count_voltages(data->vcc_i2c) > 0)
- regulator_set_voltage(data->vcc_i2c, 0, FT_I2C_VTG_MAX_UV);
- regulator_put(data->vcc_i2c);
- return 0;
- }
- #ifdef CONFIG_PM
- static int ft5x06_ts_suspend(struct device *dev)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- char txbuf[2], i;
- int err;
- if (data->loading_fw) {
- dev_info(dev, "Firmware loading in process...\n");
- return 0;
- }
- if (data->suspended) {
- dev_info(dev, "Already in suspend state\n");
- return 0;
- }
- disable_irq(data->client->irq);
- /* release all touches */
- for (i = 0; i < data->pdata->num_max_touches; i++) {
- input_mt_slot(data->input_dev, i);
- input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
- }
- input_mt_report_pointer_emulation(data->input_dev, false);
- input_sync(data->input_dev);
- if (gpio_is_valid(data->pdata->reset_gpio)) {
- txbuf[0] = FT_REG_PMODE;
- txbuf[1] = FT_PMODE_HIBERNATE;
- ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
- }
- if (data->pdata->power_on) {
- err = data->pdata->power_on(false);
- if (err) {
- dev_err(dev, "power off failed");
- goto pwr_off_fail;
- }
- } else {
- err = ft5x06_power_on(data, false);
- if (err) {
- dev_err(dev, "power off failed");
- goto pwr_off_fail;
- }
- }
- data->suspended = true;
- return 0;
- pwr_off_fail:
- if (gpio_is_valid(data->pdata->reset_gpio)) {
- gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
- msleep(data->pdata->hard_rst_dly);
- gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
- }
- enable_irq(data->client->irq);
- return err;
- }
- static int ft5x06_ts_resume(struct device *dev)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- int err;
- if (!data->suspended) {
- dev_dbg(dev, "Already in awake state\n");
- return 0;
- }
- if (data->pdata->power_on) {
- err = data->pdata->power_on(true);
- if (err) {
- dev_err(dev, "power on failed");
- return err;
- }
- } else {
- err = ft5x06_power_on(data, true);
- if (err) {
- dev_err(dev, "power on failed");
- return err;
- }
- }
- if (gpio_is_valid(data->pdata->reset_gpio)) {
- gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
- msleep(data->pdata->hard_rst_dly);
- gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
- }
- msleep(data->pdata->soft_rst_dly);
- enable_irq(data->client->irq);
- data->suspended = false;
- return 0;
- }
- #if defined(CONFIG_FB)
- static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
- {
- struct fb_event *evdata = data;
- int *blank;
- struct ft5x06_ts_data *ft5x06_data =
- container_of(self, struct ft5x06_ts_data, fb_notif);
- if (evdata && evdata->data && event == FB_EVENT_BLANK &&
- ft5x06_data && ft5x06_data->client) {
- blank = evdata->data;
- if (*blank == FB_BLANK_UNBLANK)
- ft5x06_ts_resume(&ft5x06_data->client->dev);
- else if (*blank == FB_BLANK_POWERDOWN)
- ft5x06_ts_suspend(&ft5x06_data->client->dev);
- }
- return 0;
- }
- #elif defined(CONFIG_HAS_EARLYSUSPEND)
- static void ft5x06_ts_early_suspend(struct early_suspend *handler)
- {
- struct ft5x06_ts_data *data = container_of(handler,
- struct ft5x06_ts_data,
- early_suspend);
- ft5x06_ts_suspend(&data->client->dev);
- }
- static void ft5x06_ts_late_resume(struct early_suspend *handler)
- {
- struct ft5x06_ts_data *data = container_of(handler,
- struct ft5x06_ts_data,
- early_suspend);
- ft5x06_ts_resume(&data->client->dev);
- }
- #endif
- static const struct dev_pm_ops ft5x06_ts_pm_ops = {
- #if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
- .suspend = ft5x06_ts_suspend,
- .resume = ft5x06_ts_resume,
- #endif
- };
- #endif
- static int ft5x06_auto_cal(struct i2c_client *client)
- {
- struct ft5x06_ts_data *data = i2c_get_clientdata(client);
- u8 temp = 0, i;
- /* set to factory mode */
- msleep(2 * data->pdata->soft_rst_dly);
- ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
- msleep(data->pdata->soft_rst_dly);
- /* start calibration */
- ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
- msleep(2 * data->pdata->soft_rst_dly);
- for (i = 0; i < FT_CAL_RETRY; i++) {
- ft5x0x_read_reg(client, FT_REG_CAL, &temp);
- /*return to normal mode, calibration finish */
- if (((temp & FT_CAL_MASK) >> FT_4BIT_SHIFT) == FT_CAL_FIN)
- break;
- }
- /*calibration OK */
- msleep(2 * data->pdata->soft_rst_dly);
- ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
- msleep(data->pdata->soft_rst_dly);
- /* store calibration data */
- ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
- msleep(2 * data->pdata->soft_rst_dly);
- /* set to normal mode */
- ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
- msleep(2 * data->pdata->soft_rst_dly);
- return 0;
- }
- static int ft5x06_fw_upgrade_start(struct i2c_client *client,
- const u8 *data, u32 data_len)
- {
- struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
- struct fw_upgrade_info info = ts_data->pdata->info;
- u8 reset_reg;
- u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
- u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
- int i, j, temp;
- u32 pkt_num, pkt_len;
- u8 is_5336_new_bootloader = false;
- u8 is_5336_fwsize_30 = false;
- u8 fw_ecc;
- /* determine firmware size */
- if (*(data + data_len - FT_BLOADER_SIZE_OFF) == FT_BLOADER_NEW_SIZE)
- is_5336_fwsize_30 = true;
- else
- is_5336_fwsize_30 = false;
- for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
- msleep(FT_EARSE_DLY_MS);
- /* reset - write 0xaa and 0x55 to reset register */
- if (ts_data->family_id == FT6X06_ID)
- reset_reg = FT_RST_CMD_REG2;
- else
- reset_reg = FT_RST_CMD_REG1;
- ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_AA);
- msleep(info.delay_aa);
- ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
- if (i <= (FT_UPGRADE_LOOP / 2))
- msleep(info.delay_55 + i * 3);
- else
- msleep(info.delay_55 - (i - (FT_UPGRADE_LOOP / 2)) * 2);
- /* Enter upgrade mode */
- w_buf[0] = FT_UPGRADE_55;
- ft5x06_i2c_write(client, w_buf, 1);
- usleep(FT_55_AA_DLY_NS);
- w_buf[0] = FT_UPGRADE_AA;
- ft5x06_i2c_write(client, w_buf, 1);
- /* check READ_ID */
- msleep(info.delay_readid);
- w_buf[0] = FT_READ_ID_REG;
- w_buf[1] = 0x00;
- w_buf[2] = 0x00;
- w_buf[3] = 0x00;
- ft5x06_i2c_read(client, w_buf, 4, r_buf, 2);
- if (r_buf[0] != info.upgrade_id_1
- || r_buf[1] != info.upgrade_id_2) {
- dev_err(&client->dev, "Upgrade ID mismatch(%d), IC=0x%x 0x%x, info=0x%x 0x%x\n",
- i, r_buf[0], r_buf[1],
- info.upgrade_id_1, info.upgrade_id_2);
- } else
- break;
- }
- if (i >= FT_UPGRADE_LOOP) {
- dev_err(&client->dev, "Abort upgrade\n");
- return -EIO;
- }
- w_buf[0] = 0xcd;
- ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
- if (r_buf[0] <= 4)
- is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
- else if (r_buf[0] == 7)
- is_5336_new_bootloader = FT_BLOADER_VERSION_Z7;
- else if (r_buf[0] >= 0x0f &&
- ((ts_data->family_id == FT_FT5336_FAMILY_ID_0x11) ||
- (ts_data->family_id == FT_FT5336_FAMILY_ID_0x12) ||
- (ts_data->family_id == FT_FT5336_FAMILY_ID_0x13) ||
- (ts_data->family_id == FT_FT5336_FAMILY_ID_0x14)))
- is_5336_new_bootloader = FT_BLOADER_VERSION_GZF;
- else
- is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
- dev_dbg(&client->dev, "bootloader type=%d, r_buf=0x%x, family_id=0x%x\n",
- is_5336_new_bootloader, r_buf[0], ts_data->family_id);
- /* is_5336_new_bootloader = FT_BLOADER_VERSION_GZF; */
- /* erase app and panel paramenter area */
- w_buf[0] = FT_ERASE_APP_REG;
- ft5x06_i2c_write(client, w_buf, 1);
- msleep(info.delay_erase_flash);
- if (is_5336_fwsize_30) {
- w_buf[0] = FT_ERASE_PANEL_REG;
- ft5x06_i2c_write(client, w_buf, 1);
- }
- msleep(FT_EARSE_DLY_MS);
- /* program firmware */
- if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4
- || is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
- data_len = data_len - FT_DATA_LEN_OFF_OLD_FW;
- else
- data_len = data_len - FT_DATA_LEN_OFF_NEW_FW;
- pkt_num = (data_len) / FT_FW_PKT_LEN;
- pkt_len = FT_FW_PKT_LEN;
- pkt_buf[0] = FT_FW_START_REG;
- pkt_buf[1] = 0x00;
- fw_ecc = 0;
- for (i = 0; i < pkt_num; i++) {
- temp = i * FT_FW_PKT_LEN;
- pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
- pkt_buf[3] = (u8) temp;
- pkt_buf[4] = (u8) (pkt_len >> FT_8BIT_SHIFT);
- pkt_buf[5] = (u8) pkt_len;
- for (j = 0; j < FT_FW_PKT_LEN; j++) {
- pkt_buf[6 + j] = data[i * FT_FW_PKT_LEN + j];
- fw_ecc ^= pkt_buf[6 + j];
- }
- ft5x06_i2c_write(client, pkt_buf,
- FT_FW_PKT_LEN + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
- }
- /* send remaining bytes */
- if ((data_len) % FT_FW_PKT_LEN > 0) {
- temp = pkt_num * FT_FW_PKT_LEN;
- pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
- pkt_buf[3] = (u8) temp;
- temp = (data_len) % FT_FW_PKT_LEN;
- pkt_buf[4] = (u8) (temp >> FT_8BIT_SHIFT);
- pkt_buf[5] = (u8) temp;
- for (i = 0; i < temp; i++) {
- pkt_buf[6 + i] = data[pkt_num * FT_FW_PKT_LEN + i];
- fw_ecc ^= pkt_buf[6 + i];
- }
- ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
- }
- /* send the finishing packet */
- if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4 ||
- is_5336_new_bootloader == FT_BLOADER_VERSION_Z7) {
- for (i = 0; i < FT_FINISHING_PKT_LEN_OLD_FW; i++) {
- if (is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
- temp = FT_MAGIC_BLOADER_Z7 + i;
- else if (is_5336_new_bootloader ==
- FT_BLOADER_VERSION_LZ4)
- temp = FT_MAGIC_BLOADER_LZ4 + i;
- pkt_buf[2] = (u8)(temp >> 8);
- pkt_buf[3] = (u8)temp;
- temp = 1;
- pkt_buf[4] = (u8)(temp >> 8);
- pkt_buf[5] = (u8)temp;
- pkt_buf[6] = data[data_len + i];
- fw_ecc ^= pkt_buf[6];
- ft5x06_i2c_write(client,
- pkt_buf, temp + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
- }
- } else if (is_5336_new_bootloader == FT_BLOADER_VERSION_GZF) {
- for (i = 0; i < FT_FINISHING_PKT_LEN_NEW_FW; i++) {
- if (is_5336_fwsize_30)
- temp = FT_MAGIC_BLOADER_GZF_30 + i;
- else
- temp = FT_MAGIC_BLOADER_GZF + i;
- pkt_buf[2] = (u8)(temp >> 8);
- pkt_buf[3] = (u8)temp;
- temp = 1;
- pkt_buf[4] = (u8)(temp >> 8);
- pkt_buf[5] = (u8)temp;
- pkt_buf[6] = data[data_len + i];
- fw_ecc ^= pkt_buf[6];
- ft5x06_i2c_write(client,
- pkt_buf, temp + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
- }
- }
- /* verify checksum */
- w_buf[0] = FT_REG_ECC;
- ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
- if (r_buf[0] != fw_ecc) {
- dev_err(&client->dev, "ECC error! dev_ecc=%02x fw_ecc=%02x\n",
- r_buf[0], fw_ecc);
- return -EIO;
- }
- /* reset */
- w_buf[0] = FT_REG_RESET_FW;
- ft5x06_i2c_write(client, w_buf, 1);
- msleep(ts_data->pdata->soft_rst_dly);
- dev_info(&client->dev, "Firmware upgrade successful\n");
- return 0;
- }
- static int ft5x06_fw_upgrade(struct device *dev, bool force)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- const struct firmware *fw = NULL;
- int rc;
- u8 fw_file_maj, fw_file_min, fw_file_sub_min;
- bool fw_upgrade = false;
- if (data->suspended) {
- dev_info(dev, "Device is in suspend state: Exit FW upgrade\n");
- return -EBUSY;
- }
- rc = request_firmware(&fw, data->fw_name, dev);
- if (rc < 0) {
- dev_err(dev, "Request firmware failed - %s (%d)\n",
- data->fw_name, rc);
- return rc;
- }
- if (fw->size < FT_FW_MIN_SIZE || fw->size > FT_FW_MAX_SIZE) {
- dev_err(dev, "Invalid firmware size (%d)\n", fw->size);
- rc = -EIO;
- goto rel_fw;
- }
- fw_file_maj = FT_FW_FILE_MAJ_VER(fw);
- fw_file_min = FT_FW_FILE_MIN_VER(fw);
- fw_file_sub_min = FT_FW_FILE_SUB_MIN_VER(fw);
- dev_info(dev, "Current firmware: %d.%d.%d", data->fw_ver[0],
- data->fw_ver[1], data->fw_ver[2]);
- dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
- fw_file_min, fw_file_sub_min);
- if (force)
- fw_upgrade = true;
- else if (data->fw_ver[0] < fw_file_maj)
- fw_upgrade = true;
- if (!fw_upgrade) {
- dev_info(dev, "Exiting fw upgrade...\n");
- rc = -EFAULT;
- goto rel_fw;
- }
- /* start firmware upgrade */
- if (FT_FW_CHECK(fw)) {
- rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
- if (rc < 0)
- dev_err(dev, "update failed (%d). try later...\n", rc);
- else if (data->pdata->info.auto_cal)
- ft5x06_auto_cal(data->client);
- } else {
- dev_err(dev, "FW format error\n");
- rc = -EIO;
- }
- ft5x06_update_fw_ver(data);
- FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
- data->pdata->num_max_touches, data->pdata->group_id,
- data->pdata->fw_vkey_support ? "yes" : "no",
- data->pdata->fw_name, data->fw_ver[0],
- data->fw_ver[1], data->fw_ver[2]);
- rel_fw:
- release_firmware(fw);
- return rc;
- }
- static ssize_t ft5x06_update_fw_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- return snprintf(buf, 2, "%d\n", data->loading_fw);
- }
- static ssize_t ft5x06_update_fw_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int rc;
- if (size > 2)
- return -EINVAL;
- rc = kstrtoul(buf, 10, &val);
- if (rc != 0)
- return rc;
- if (data->suspended) {
- dev_info(dev, "In suspend state, try again later...\n");
- return size;
- }
- mutex_lock(&data->input_dev->mutex);
- if (!data->loading_fw && val) {
- data->loading_fw = true;
- ft5x06_fw_upgrade(dev, false);
- data->loading_fw = false;
- }
- mutex_unlock(&data->input_dev->mutex);
- return size;
- }
- static DEVICE_ATTR(update_fw, 0664, ft5x06_update_fw_show,
- ft5x06_update_fw_store);
- static ssize_t ft5x06_force_update_fw_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int rc;
- if (size > 2)
- return -EINVAL;
- rc = kstrtoul(buf, 10, &val);
- if (rc != 0)
- return rc;
- mutex_lock(&data->input_dev->mutex);
- if (!data->loading_fw && val) {
- data->loading_fw = true;
- ft5x06_fw_upgrade(dev, true);
- data->loading_fw = false;
- }
- mutex_unlock(&data->input_dev->mutex);
- return size;
- }
- static DEVICE_ATTR(force_update_fw, 0664, ft5x06_update_fw_show,
- ft5x06_force_update_fw_store);
- static ssize_t ft5x06_fw_name_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- return snprintf(buf, FT_FW_NAME_MAX_LEN - 1, "%s\n", data->fw_name);
- }
- static ssize_t ft5x06_fw_name_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
- {
- struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- if (size > FT_FW_NAME_MAX_LEN - 1)
- return -EINVAL;
- strlcpy(data->fw_name, buf, size);
- if (data->fw_name[size-1] == '\n')
- data->fw_name[size-1] = 0;
- return size;
- }
- static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store);
- static bool ft5x06_debug_addr_is_valid(int addr)
- {
- if (addr < 0 || addr > 0xFF) {
- pr_err("FT reg address is invalid: 0x%x\n", addr);
- return false;
- }
- return true;
- }
- static int ft5x06_debug_data_set(void *_data, u64 val)
- {
- struct ft5x06_ts_data *data = _data;
- mutex_lock(&data->input_dev->mutex);
- if (ft5x06_debug_addr_is_valid(data->addr))
- dev_info(&data->client->dev,
- "Writing into FT registers not supported\n");
- mutex_unlock(&data->input_dev->mutex);
- return 0;
- }
- static int ft5x06_debug_data_get(void *_data, u64 *val)
- {
- struct ft5x06_ts_data *data = _data;
- int rc;
- u8 reg;
- mutex_lock(&data->input_dev->mutex);
- if (ft5x06_debug_addr_is_valid(data->addr)) {
- rc = ft5x0x_read_reg(data->client, data->addr, ®);
- if (rc < 0)
- dev_err(&data->client->dev,
- "FT read register 0x%x failed (%d)\n",
- data->addr, rc);
- else
- *val = reg;
- }
- mutex_unlock(&data->input_dev->mutex);
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, ft5x06_debug_data_get,
- ft5x06_debug_data_set, "0x%02llX\n");
- static int ft5x06_debug_addr_set(void *_data, u64 val)
- {
- struct ft5x06_ts_data *data = _data;
- if (ft5x06_debug_addr_is_valid(val)) {
- mutex_lock(&data->input_dev->mutex);
- data->addr = val;
- mutex_unlock(&data->input_dev->mutex);
- }
- return 0;
- }
- static int ft5x06_debug_addr_get(void *_data, u64 *val)
- {
- struct ft5x06_ts_data *data = _data;
- mutex_lock(&data->input_dev->mutex);
- if (ft5x06_debug_addr_is_valid(data->addr))
- *val = data->addr;
- mutex_unlock(&data->input_dev->mutex);
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, ft5x06_debug_addr_get,
- ft5x06_debug_addr_set, "0x%02llX\n");
- static int ft5x06_debug_suspend_set(void *_data, u64 val)
- {
- struct ft5x06_ts_data *data = _data;
- mutex_lock(&data->input_dev->mutex);
- if (val)
- ft5x06_ts_suspend(&data->client->dev);
- else
- ft5x06_ts_resume(&data->client->dev);
- mutex_unlock(&data->input_dev->mutex);
- return 0;
- }
- static int ft5x06_debug_suspend_get(void *_data, u64 *val)
- {
- struct ft5x06_ts_data *data = _data;
- mutex_lock(&data->input_dev->mutex);
- *val = data->suspended;
- mutex_unlock(&data->input_dev->mutex);
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, ft5x06_debug_suspend_get,
- ft5x06_debug_suspend_set, "%lld\n");
- static int ft5x06_debug_dump_info(struct seq_file *m, void *v)
- {
- struct ft5x06_ts_data *data = m->private;
- seq_printf(m, "%s\n", data->ts_info);
- return 0;
- }
- static int debugfs_dump_info_open(struct inode *inode, struct file *file)
- {
- return single_open(file, ft5x06_debug_dump_info, inode->i_private);
- }
- static const struct file_operations debug_dump_info_fops = {
- .owner = THIS_MODULE,
- .open = debugfs_dump_info_open,
- .read = seq_read,
- .release = single_release,
- };
- #ifdef CONFIG_OF
- static int ft5x06_get_dt_coords(struct device *dev, char *name,
- struct ft5x06_ts_platform_data *pdata)
- {
- u32 coords[FT_COORDS_ARR_SIZE];
- struct property *prop;
- struct device_node *np = dev->of_node;
- int coords_size, rc;
- prop = of_find_property(np, name, NULL);
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- coords_size = prop->length / sizeof(u32);
- if (coords_size != FT_COORDS_ARR_SIZE) {
- dev_err(dev, "invalid %s\n", name);
- return -EINVAL;
- }
- rc = of_property_read_u32_array(np, name, coords, coords_size);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read %s\n", name);
- return rc;
- }
- if (!strcmp(name, "focaltech,panel-coords")) {
- pdata->panel_minx = coords[0];
- pdata->panel_miny = coords[1];
- pdata->panel_maxx = coords[2];
- pdata->panel_maxy = coords[3];
- } else if (!strcmp(name, "focaltech,display-coords")) {
- pdata->x_min = coords[0];
- pdata->y_min = coords[1];
- pdata->x_max = coords[2];
- pdata->y_max = coords[3];
- } else {
- dev_err(dev, "unsupported property %s\n", name);
- return -EINVAL;
- }
- return 0;
- }
- static int ft5x06_parse_dt(struct device *dev,
- struct ft5x06_ts_platform_data *pdata)
- {
- int rc;
- struct device_node *np = dev->of_node;
- struct property *prop;
- u32 temp_val, num_buttons;
- u32 button_map[MAX_BUTTONS];
- pdata->name = "focaltech";
- rc = of_property_read_string(np, "focaltech,name", &pdata->name);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read name\n");
- return rc;
- }
- rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata);
- if (rc && (rc != -EINVAL))
- return rc;
- rc = ft5x06_get_dt_coords(dev, "focaltech,display-coords", pdata);
- if (rc)
- return rc;
- pdata->i2c_pull_up = of_property_read_bool(np,
- "focaltech,i2c-pull-up");
- pdata->no_force_update = of_property_read_bool(np,
- "focaltech,no-force-update");
- /* reset, irq gpio info */
- pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio",
- 0, &pdata->reset_gpio_flags);
- if (pdata->reset_gpio < 0)
- return pdata->reset_gpio;
- pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio",
- 0, &pdata->irq_gpio_flags);
- if (pdata->irq_gpio < 0)
- return pdata->irq_gpio;
- pdata->fw_name = "ft_fw.bin";
- rc = of_property_read_string(np, "focaltech,fw-name", &pdata->fw_name);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw name\n");
- return rc;
- }
- rc = of_property_read_u32(np, "focaltech,group-id", &temp_val);
- if (!rc)
- pdata->group_id = temp_val;
- else
- return rc;
- rc = of_property_read_u32(np, "focaltech,hard-reset-delay-ms",
- &temp_val);
- if (!rc)
- pdata->hard_rst_dly = temp_val;
- else
- return rc;
- rc = of_property_read_u32(np, "focaltech,soft-reset-delay-ms",
- &temp_val);
- if (!rc)
- pdata->soft_rst_dly = temp_val;
- else
- return rc;
- rc = of_property_read_u32(np, "focaltech,num-max-touches", &temp_val);
- if (!rc)
- pdata->num_max_touches = temp_val;
- else
- return rc;
- rc = of_property_read_u32(np, "focaltech,fw-delay-aa-ms", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw delay aa\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.delay_aa = temp_val;
- rc = of_property_read_u32(np, "focaltech,fw-delay-55-ms", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw delay 55\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.delay_55 = temp_val;
- rc = of_property_read_u32(np, "focaltech,fw-upgrade-id1", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw upgrade id1\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.upgrade_id_1 = temp_val;
- rc = of_property_read_u32(np, "focaltech,fw-upgrade-id2", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw upgrade id2\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.upgrade_id_2 = temp_val;
- rc = of_property_read_u32(np, "focaltech,fw-delay-readid-ms",
- &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw delay read id\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.delay_readid = temp_val;
- rc = of_property_read_u32(np, "focaltech,fw-delay-era-flsh-ms",
- &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read fw delay erase flash\n");
- return rc;
- } else if (rc != -EINVAL)
- pdata->info.delay_erase_flash = temp_val;
- pdata->info.auto_cal = of_property_read_bool(np,
- "focaltech,fw-auto-cal");
- pdata->fw_vkey_support = of_property_read_bool(np,
- "focaltech,fw-vkey-support");
- pdata->ignore_id_check = of_property_read_bool(np,
- "focaltech,ignore-id-check");
- rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
- if (!rc)
- pdata->family_id = temp_val;
- else
- return rc;
- prop = of_find_property(np, "focaltech,button-map", NULL);
- if (prop) {
- num_buttons = prop->length / sizeof(temp_val);
- if (num_buttons > MAX_BUTTONS)
- return -EINVAL;
- rc = of_property_read_u32_array(np,
- "focaltech,button-map", button_map,
- num_buttons);
- if (rc) {
- dev_err(dev, "Unable to read key codes\n");
- return rc;
- }
- }
- return 0;
- }
- #else
- static int ft5x06_parse_dt(struct device *dev,
- struct ft5x06_ts_platform_data *pdata)
- {
- return -ENODEV;
- }
- #endif
- static int ft5x06_ts_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct ft5x06_ts_platform_data *pdata;
- struct ft5x06_ts_data *data;
- struct input_dev *input_dev;
- struct dentry *temp;
- u8 reg_value;
- u8 reg_addr;
- int err, len;
- if (client->dev.of_node) {
- pdata = devm_kzalloc(&client->dev,
- sizeof(struct ft5x06_ts_platform_data), GFP_KERNEL);
- if (!pdata) {
- dev_err(&client->dev, "Failed to allocate memory\n");
- return -ENOMEM;
- }
- err = ft5x06_parse_dt(&client->dev, pdata);
- if (err) {
- dev_err(&client->dev, "DT parsing failed\n");
- return err;
- }
- } else
- pdata = client->dev.platform_data;
- if (!pdata) {
- dev_err(&client->dev, "Invalid pdata\n");
- return -EINVAL;
- }
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "I2C not supported\n");
- return -ENODEV;
- }
- data = devm_kzalloc(&client->dev,
- sizeof(struct ft5x06_ts_data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "Not enough memory\n");
- return -ENOMEM;
- }
- if (pdata->fw_name) {
- len = strlen(pdata->fw_name);
- if (len > FT_FW_NAME_MAX_LEN - 1) {
- dev_err(&client->dev, "Invalid firmware name\n");
- return -EINVAL;
- }
- strlcpy(data->fw_name, pdata->fw_name, len + 1);
- }
- data->tch_data_len = FT_TCH_LEN(pdata->num_max_touches);
- data->tch_data = devm_kzalloc(&client->dev,
- data->tch_data_len, GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "Not enough memory\n");
- return -ENOMEM;
- }
- input_dev = input_allocate_device();
- if (!input_dev) {
- dev_err(&client->dev, "failed to allocate input device\n");
- return -ENOMEM;
- }
- data->input_dev = input_dev;
- data->client = client;
- data->pdata = pdata;
- input_dev->name = "ft5x06_ts";
- input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
- input_set_drvdata(input_dev, data);
- i2c_set_clientdata(client, data);
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(EV_ABS, input_dev->evbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
- input_mt_init_slots(input_dev, pdata->num_max_touches);
- input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
- pdata->x_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
- pdata->y_max, 0, 0);
- err = input_register_device(input_dev);
- if (err) {
- dev_err(&client->dev, "Input device registration failed\n");
- goto free_inputdev;
- }
- if (pdata->power_init) {
- err = pdata->power_init(true);
- if (err) {
- dev_err(&client->dev, "power init failed");
- goto unreg_inputdev;
- }
- } else {
- err = ft5x06_power_init(data, true);
- if (err) {
- dev_err(&client->dev, "power init failed");
- goto unreg_inputdev;
- }
- }
- if (pdata->power_on) {
- err = pdata->power_on(true);
- if (err) {
- dev_err(&client->dev, "power on failed");
- goto pwr_deinit;
- }
- } else {
- err = ft5x06_power_on(data, true);
- if (err) {
- dev_err(&client->dev, "power on failed");
- goto pwr_deinit;
- }
- }
- if (gpio_is_valid(pdata->irq_gpio)) {
- err = gpio_request(pdata->irq_gpio, "ft5x06_irq_gpio");
- if (err) {
- dev_err(&client->dev, "irq gpio request failed");
- goto pwr_off;
- }
- err = gpio_direction_input(pdata->irq_gpio);
- if (err) {
- dev_err(&client->dev,
- "set_direction for irq gpio failed\n");
- goto free_irq_gpio;
- }
- }
- if (gpio_is_valid(pdata->reset_gpio)) {
- err = gpio_request(pdata->reset_gpio, "ft5x06_reset_gpio");
- if (err) {
- dev_err(&client->dev, "reset gpio request failed");
- goto free_irq_gpio;
- }
- err = gpio_direction_output(pdata->reset_gpio, 0);
- if (err) {
- dev_err(&client->dev,
- "set_direction for reset gpio failed\n");
- goto free_reset_gpio;
- }
- msleep(data->pdata->hard_rst_dly);
- gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
- }
- /* make sure CTP already finish startup process */
- msleep(data->pdata->soft_rst_dly);
- /* check the controller id */
- reg_addr = FT_REG_ID;
- err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err < 0) {
- dev_err(&client->dev, "version read failed");
- goto free_reset_gpio;
- }
- dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
- if ((pdata->family_id != reg_value) && (!pdata->ignore_id_check)) {
- dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
- goto free_reset_gpio;
- }
- data->family_id = pdata->family_id;
- err = request_threaded_irq(client->irq, NULL,
- ft5x06_ts_interrupt,
- pdata->irqflags | IRQF_ONESHOT,
- client->dev.driver->name, data);
- if (err) {
- dev_err(&client->dev, "request irq failed\n");
- goto free_reset_gpio;
- }
- err = device_create_file(&client->dev, &dev_attr_fw_name);
- if (err) {
- dev_err(&client->dev, "sys file creation failed\n");
- goto irq_free;
- }
- err = device_create_file(&client->dev, &dev_attr_update_fw);
- if (err) {
- dev_err(&client->dev, "sys file creation failed\n");
- goto free_fw_name_sys;
- }
- err = device_create_file(&client->dev, &dev_attr_force_update_fw);
- if (err) {
- dev_err(&client->dev, "sys file creation failed\n");
- goto free_update_fw_sys;
- }
- data->dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
- if (data->dir == NULL || IS_ERR(data->dir)) {
- pr_err("debugfs_create_dir failed(%ld)\n", PTR_ERR(data->dir));
- err = PTR_ERR(data->dir);
- goto free_force_update_fw_sys;
- }
- temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, data->dir, data,
- &debug_addr_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
- err = PTR_ERR(temp);
- goto free_debug_dir;
- }
- temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, data->dir, data,
- &debug_data_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
- err = PTR_ERR(temp);
- goto free_debug_dir;
- }
- temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, data->dir,
- data, &debug_suspend_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
- err = PTR_ERR(temp);
- goto free_debug_dir;
- }
- temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR, data->dir,
- data, &debug_dump_info_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
- err = PTR_ERR(temp);
- goto free_debug_dir;
- }
- data->ts_info = devm_kzalloc(&client->dev,
- FT_INFO_MAX_LEN, GFP_KERNEL);
- if (!data->ts_info) {
- dev_err(&client->dev, "Not enough memory\n");
- goto free_debug_dir;
- }
- /*get some register information */
- reg_addr = FT_REG_POINT_RATE;
- ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err < 0)
- dev_err(&client->dev, "report rate read failed");
- dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
- reg_addr = FT_REG_THGROUP;
- err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err < 0)
- dev_err(&client->dev, "threshold read failed");
- dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
- ft5x06_update_fw_ver(data);
- FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
- data->pdata->num_max_touches, data->pdata->group_id,
- data->pdata->fw_vkey_support ? "yes" : "no",
- data->pdata->fw_name, data->fw_ver[0],
- data->fw_ver[1], data->fw_ver[2]);
- #if defined(CONFIG_FB)
- data->fb_notif.notifier_call = fb_notifier_callback;
- err = fb_register_client(&data->fb_notif);
- if (err)
- dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
- err);
- #elif defined(CONFIG_HAS_EARLYSUSPEND)
- data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
- FT_SUSPEND_LEVEL;
- data->early_suspend.suspend = ft5x06_ts_early_suspend;
- data->early_suspend.resume = ft5x06_ts_late_resume;
- register_early_suspend(&data->early_suspend);
- #endif
- return 0;
- free_debug_dir:
- debugfs_remove_recursive(data->dir);
- free_force_update_fw_sys:
- device_remove_file(&client->dev, &dev_attr_force_update_fw);
- free_update_fw_sys:
- device_remove_file(&client->dev, &dev_attr_update_fw);
- free_fw_name_sys:
- device_remove_file(&client->dev, &dev_attr_fw_name);
- irq_free:
- free_irq(client->irq, data);
- free_reset_gpio:
- if (gpio_is_valid(pdata->reset_gpio))
- gpio_free(pdata->reset_gpio);
- free_irq_gpio:
- if (gpio_is_valid(pdata->irq_gpio))
- gpio_free(pdata->irq_gpio);
- pwr_off:
- if (pdata->power_on)
- pdata->power_on(false);
- else
- ft5x06_power_on(data, false);
- pwr_deinit:
- if (pdata->power_init)
- pdata->power_init(false);
- else
- ft5x06_power_init(data, false);
- unreg_inputdev:
- input_unregister_device(input_dev);
- input_dev = NULL;
- free_inputdev:
- input_free_device(input_dev);
- return err;
- }
- static int __devexit ft5x06_ts_remove(struct i2c_client *client)
- {
- struct ft5x06_ts_data *data = i2c_get_clientdata(client);
- debugfs_remove_recursive(data->dir);
- device_remove_file(&client->dev, &dev_attr_force_update_fw);
- device_remove_file(&client->dev, &dev_attr_update_fw);
- device_remove_file(&client->dev, &dev_attr_fw_name);
- #if defined(CONFIG_FB)
- if (fb_unregister_client(&data->fb_notif))
- dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
- #elif defined(CONFIG_HAS_EARLYSUSPEND)
- unregister_early_suspend(&data->early_suspend);
- #endif
- free_irq(client->irq, data);
- if (gpio_is_valid(data->pdata->reset_gpio))
- gpio_free(data->pdata->reset_gpio);
- if (gpio_is_valid(data->pdata->irq_gpio))
- gpio_free(data->pdata->irq_gpio);
- if (data->pdata->power_on)
- data->pdata->power_on(false);
- else
- ft5x06_power_on(data, false);
- if (data->pdata->power_init)
- data->pdata->power_init(false);
- else
- ft5x06_power_init(data, false);
- input_unregister_device(data->input_dev);
- return 0;
- }
- static const struct i2c_device_id ft5x06_ts_id[] = {
- {"ft5x06_ts", 0},
- {},
- };
- MODULE_DEVICE_TABLE(i2c, ft5x06_ts_id);
- #ifdef CONFIG_OF
- static struct of_device_id ft5x06_match_table[] = {
- { .compatible = "focaltech,5x06",},
- { },
- };
- #else
- #define ft5x06_match_table NULL
- #endif
- static struct i2c_driver ft5x06_ts_driver = {
- .probe = ft5x06_ts_probe,
- .remove = __devexit_p(ft5x06_ts_remove),
- .driver = {
- .name = "ft5x06_ts",
- .owner = THIS_MODULE,
- .of_match_table = ft5x06_match_table,
- #ifdef CONFIG_PM
- .pm = &ft5x06_ts_pm_ops,
- #endif
- },
- .id_table = ft5x06_ts_id,
- };
- static int __init ft5x06_ts_init(void)
- {
- return i2c_add_driver(&ft5x06_ts_driver);
- }
- module_init(ft5x06_ts_init);
- static void __exit ft5x06_ts_exit(void)
- {
- i2c_del_driver(&ft5x06_ts_driver);
- }
- module_exit(ft5x06_ts_exit);
- MODULE_DESCRIPTION("FocalTech ft5x06 TouchScreen driver");
- MODULE_LICENSE("GPL v2");
|