aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/wacom/wacom_i2c_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/wacom/wacom_i2c_flash.c')
-rw-r--r--drivers/input/touchscreen/wacom/wacom_i2c_flash.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/wacom/wacom_i2c_flash.c b/drivers/input/touchscreen/wacom/wacom_i2c_flash.c
new file mode 100644
index 0000000..c8eb9b1
--- /dev/null
+++ b/drivers/input/touchscreen/wacom/wacom_i2c_flash.c
@@ -0,0 +1,502 @@
+/*
+ * wacom_i2c_flash.c - Wacom G5 Digitizer Controller (I2C bus)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/wacom_i2c.h>
+
+#include "wacom_i2c_flash.h"
+
+int wacom_i2c_flash_chksum(struct wacom_i2c *wac_i2c, unsigned char *flash_data,
+ unsigned long *max_address)
+{
+ unsigned long i;
+ unsigned long chksum = 0;
+
+ for (i = 0x0000; i <= *max_address; i++)
+ chksum += flash_data[i];
+
+ chksum &= 0xFFFF;
+
+ return (int)chksum;
+}
+
+int wacom_i2c_flash_cmd(struct wacom_i2c *wac_i2c)
+{
+
+ int ret, len, i;
+ u8 buf[10], flashq;
+
+ buf[0] = 0x0d;
+ buf[1] = FLASH_START0;
+ buf[2] = FLASH_START1;
+ buf[3] = FLASH_START2;
+ buf[4] = FLASH_START3;
+ buf[5] = FLASH_START4;
+ buf[6] = FLASH_START5;
+ buf[7] = 0x0d;
+ flashq = 0xE0;
+ len = 1;
+
+ ret = wacom_i2c_master_send(wac_i2c->client, &flashq, len,
+ WACOM_I2C_BOOT);
+ if (ret >= 0) {
+
+ i = 0;
+ do {
+ msleep(20);
+ ret = wacom_i2c_master_recv(wac_i2c->client, &flashq,
+ len, WACOM_I2C_BOOT);
+ i++;
+
+ if (i > RETRY)
+ return -1;
+ } while (flashq == 0xff);
+ } else {
+ msleep(20);
+ len = 8;
+ ret = i2c_master_send(wac_i2c->client, buf, len);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "[E-PEN]: Sending flash command failed\n");
+ return -1;
+ }
+ printk(KERN_DEBUG "[E-PEN]: flash send?:%d\n", ret);
+ msleep(270);
+ }
+
+ return 0;
+}
+
+int wacom_i2c_flash_query(struct wacom_i2c *wac_i2c, u8 query, u8 recvdQuery)
+{
+ int ret, len, i;
+ u8 flashq;
+
+ flashq = query;
+ len = 1;
+
+ ret = wacom_i2c_master_send(wac_i2c->client, &flashq, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR "[E-PEN]: query unsent:%d\n", ret);
+ return -1;
+ }
+
+ /*sleep */
+ msleep(20);
+ i = 0;
+ do {
+ msleep(20);
+ flashq = query;
+ ret = wacom_i2c_master_recv(wac_i2c->client, &flashq, len,
+ WACOM_I2C_BOOT);
+ i++;
+
+ if (i > RETRY)
+ return -1;
+ printk(KERN_DEBUG "[E-PEN]: ret:%d flashq:%x\n", ret, flashq);
+ } while (recvdQuery == 0xff && flashq != recvdQuery);
+ printk(KERN_DEBUG "[E-PEN]: query:%x\n", flashq);
+
+ return flashq;
+}
+
+int wacom_i2c_flash_end(struct wacom_i2c *wac_i2c)
+{
+ if (wacom_i2c_flash_query(wac_i2c, FLASH_END, FLASH_END) == -1)
+ return ERR_FAILED_EXIT;
+ printk(KERN_DEBUG "[E-PEN]: Digitizer activated\n");
+ return 0;
+}
+
+int wacom_i2c_flash_enter(struct wacom_i2c *wac_i2c)
+{
+ if (wacom_i2c_flash_query(wac_i2c, FLASH_QUERY, FLASH_ACK) == -1)
+ return ERR_NOT_FLASH;
+ return 0;
+}
+
+int wacom_i2c_flash_BLVer(struct wacom_i2c *wac_i2c)
+{
+ int ret = 0;
+ ret = wacom_i2c_flash_query(wac_i2c, FLASH_BLVER, 0x40);
+ if (ret == -1)
+ return ERR_UNSENT;
+
+ return ret;
+}
+
+int wacom_i2c_flash_mcuId(struct wacom_i2c *wac_i2c)
+{
+ int ret = 0;
+
+ ret = wacom_i2c_flash_query(wac_i2c, FLASH_MPU, 0x26);
+ if (ret == -1)
+ return ERR_UNSENT;
+
+ return ret;
+}
+
+int wacom_i2c_flash_erase(struct wacom_i2c *wac_i2c, u8 cmd_erase,
+ u8 cmd_block, u8 endBlock)
+{
+ int len, ret, i, j;
+ u8 buf[3], sum, block, flashq;
+
+ ret = 0;
+
+ for (i = cmd_block; i >= endBlock; i--) {
+ block = i;
+ block |= 0x80;
+
+ sum = cmd_erase;
+ sum += block;
+ sum = ~sum + 1;
+
+ buf[0] = cmd_erase;
+ buf[1] = block;
+ buf[2] = sum;
+
+ len = 3;
+ ret = wacom_i2c_master_send(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR "[E-PEN]: Erase failed\n");
+ return -1;
+ }
+
+ len = 1;
+ flashq = 0;
+ j = 0;
+
+ do {
+ /*sleep */
+ msleep(100);
+ ret = wacom_i2c_master_recv(wac_i2c->client, &flashq,
+ len, WACOM_I2C_BOOT);
+ j++;
+
+ if (j > RETRY || flashq == 0x84 || flashq == 0x88
+ || flashq == 0x8A || flashq == 0x90) {
+ /*
+ 0xff:No data
+ 0x84:Erase failure
+ 0x88:Erase time parameter error
+ 0x8A:Write time parameter error
+ 0x90:Checksum error
+ */
+ printk(KERN_ERR "[E-PEN]: Error:%x\n", flashq);
+ return -1;
+ }
+ } while (flashq == 0xff);
+ printk(KERN_DEBUG "[E-PEN]: Erasing at %d, ", i);
+ /*sleep */
+ msleep(20);
+ }
+ printk(KERN_DEBUG "Erasing done\n");
+ return ret;
+}
+
+int wacom_i2c_flash_write(struct wacom_i2c *wac_i2c, unsigned long startAddr,
+ u8 size, unsigned long maxAddr)
+{
+ unsigned long ulAddr;
+ int ret, len, i, j;
+ char sum;
+ u8 buf[WRITE_BUFF], bank;
+
+ ret = len = i = 0;
+ bank = BANK;
+
+ for (ulAddr = startAddr; ulAddr <= maxAddr; ulAddr += BLOCK_SIZE_W) {
+
+ sum = 0;
+ buf[0] = FLASH_WRITE;
+ buf[1] = (u8) (ulAddr & 0xff);
+ buf[2] = (u8) ((ulAddr & 0xff00) >> 8);
+ buf[3] = size;
+ buf[4] = bank;
+
+ for (i = 0; i < 5; i++)
+ sum += buf[i];
+
+ sum = ~sum + 1;
+ buf[5] = sum;
+
+ len = 6;
+
+ ret = wacom_i2c_master_send(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR "[E-PEN]: Write process aborted\n");
+ return ERR_FAILED_ENTER;
+ }
+
+ msleep(20);
+ len = 1;
+ j = 0;
+ do {
+ ret = wacom_i2c_master_recv(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ j++;
+
+ if (j > RETRY || buf[0] == 0x90) {
+ /*0xff:No data 0x90:Checksum error */
+ printk(KERN_ERR "[E-PEN]: Error:%x\n", buf[0]);
+ return -1;
+ }
+ msleep(20);
+ } while (buf[0] == 0xff);
+
+ msleep(20);
+ sum = 0;
+ for (i = 0; i < BLOCK_SIZE_W; i++) {
+ buf[i] = Binary[ulAddr + i];
+ sum += Binary[ulAddr + i];
+ }
+ sum = ~sum + 1;
+ buf[BLOCK_SIZE_W] = sum;
+ len = BLOCK_SIZE_W + 1;
+
+ ret = wacom_i2c_master_send(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "[E-PEN]: Firmware flash aborted while writing\n");
+ return ERR_NOT_FLASH;
+ }
+
+ msleep(100);
+ len = 1;
+ j = 0;
+
+ do {
+ msleep(20);
+ ret = wacom_i2c_master_recv(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ j++;
+
+ if (j > RETRY || buf[0] == 0x82 || buf[0] == 0x90) {
+ /*
+ 0xff:No data
+ 0x82:Write error
+ 0x90:Checksum error
+ */
+ printk(KERN_ERR "[E-PEN]: Error:%x\n", buf[0]);
+ return -1;
+ }
+ } while (buf[0] == 0xff);
+ printk(KERN_DEBUG "[E-PEN]: Written on:0x%lx", ulAddr);
+ msleep(20);
+ }
+ printk(KERN_DEBUG "\nWriting done\n");
+
+ return 0;
+}
+
+int wacom_i2c_flash_verify(struct wacom_i2c *wac_i2c, unsigned long startAddr,
+ u8 size, unsigned long maxAddr)
+{
+ unsigned long ulAddr;
+ int ret, len, i, j;
+ char sum;
+ u8 buf[WRITE_BUFF], bank;
+
+ ret = len = i = 0;
+ bank = BANK;
+
+ for (ulAddr = startAddr; ulAddr <= maxAddr; ulAddr += BLOCK_SIZE_W) {
+
+ sum = 0;
+ buf[0] = FLASH_VERIFY;
+ buf[1] = (u8) (ulAddr & 0xff);
+ buf[2] = (u8) ((ulAddr & 0xff00) >> 8);
+ buf[3] = size;
+ buf[4] = bank;
+
+ for (i = 0; i < 5; i++)
+ sum += buf[i];
+ sum = ~sum + 1;
+ buf[5] = sum;
+
+ len = 6;
+ j = 0;
+ /*sleep */
+
+ ret = wacom_i2c_master_send(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR "[E-PEN]: Write process aborted\n");
+ return ERR_FAILED_ENTER;
+ }
+
+ len = 1;
+
+ do {
+ msleep(20);
+ ret = wacom_i2c_master_recv(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ j++;
+ if (j > RETRY || buf[0] == 0x90) {
+ /*0xff:No data 0x90:Checksum error */
+ printk(KERN_ERR "[E-PEN]: Error:%x\n", buf[0]);
+ return -1;
+ }
+ } while (buf[0] == 0xff);
+
+ msleep(20);
+ sum = 0;
+ for (i = 0; i < BLOCK_SIZE_W; i++) {
+ buf[i] = Binary[ulAddr + i];
+ sum += Binary[ulAddr + i];
+ }
+ sum = ~sum + 1;
+ buf[BLOCK_SIZE_W] = sum;
+ len = BLOCK_SIZE_W + 1;
+
+ ret = wacom_i2c_master_send(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "[E-PEN]: Firmware flash aborted while writing\n");
+ return ERR_NOT_FLASH;
+ }
+
+ msleep(20);
+ len = 1;
+ j = 0;
+ do {
+ msleep(20);
+ ret = wacom_i2c_master_recv(wac_i2c->client, buf, len,
+ WACOM_I2C_BOOT);
+ j++;
+
+ if (j > RETRY || buf[0] == 0x81 || buf[0] == 0x90) {
+ /*
+ 0xff:No data
+ 0x82:Write error
+ 0x90:Checksum error
+ */
+ printk(KERN_ERR "[E-PEN]: Error:%x", buf[0]);
+ return -1;
+ }
+ } while (buf[0] == 0xff);
+ printk(KERN_DEBUG "[E-PEN]: Verified:0x%lx", ulAddr);
+ msleep(20);
+ }
+ printk("\n[E-PEN]: Verifying done\n");
+
+ return 0;
+}
+
+int wacom_i2c_flash(struct wacom_i2c *wac_i2c)
+{
+ int ret, blver, mcu;
+ unsigned long i, maxAddr;
+ ret = blver = mcu = 0;
+ i = maxAddr = 0;
+
+ wake_lock(&wac_i2c->wakelock);
+
+ ret = wacom_i2c_flash_cmd(wac_i2c);
+ msleep(20);
+ ret = wacom_i2c_flash_enter(wac_i2c);
+ printk(KERN_DEBUG "[E-PEN]: flashEnter:%d\n", ret);
+
+ /*sleep */
+ msleep(20);
+
+ blver = wacom_i2c_flash_BLVer(wac_i2c);
+ printk(KERN_DEBUG "[E-PEN]: blver:%d\n", blver);
+
+ /*sleep */
+ msleep(20);
+
+ mcu = wacom_i2c_flash_mcuId(wac_i2c);
+ printk(KERN_DEBUG "[E-PEN]: mcu:%x\n", mcu);
+ if (Mpu_type != mcu) {
+ wacom_i2c_flash_end(wac_i2c);
+ return -1;
+ }
+
+ /*sleep */
+ msleep(20);
+
+ switch (mcu) {
+ case MPUVER_W8501:
+ printk(KERN_DEBUG "[E-PEN]: flashing for w8501 started\n");
+ maxAddr = MAX_ADDR_W8501;
+ ret = wacom_i2c_flash_erase(wac_i2c, FLASH_ERASE,
+ MAX_BLOCK_W8501, END_BLOCK);
+ if (ret < 0)
+ return -1;
+ printk(KERN_DEBUG "[E-PEN]: erased:%d\n", ret);
+
+ msleep(20);
+
+ ret = wacom_i2c_flash_write(wac_i2c, START_ADDR,
+ NUM_BLOCK_2WRITE, maxAddr);
+ if (ret < 0)
+ return -1;
+
+ msleep(20);
+
+ ret = wacom_i2c_flash_verify(wac_i2c, START_ADDR,
+ NUM_BLOCK_2WRITE, maxAddr);
+ if (ret < 0)
+ return -1;
+
+ break;
+
+ case MPUVER_514:
+ printk(KERN_DEBUG "[E-PEN]: Flashing for 514 started\n");
+ maxAddr = MAX_ADDR_514;
+ ret = wacom_i2c_flash_erase(wac_i2c, FLASH_ERASE,
+ MAX_BLOCK_514, END_BLOCK);
+ if (ret < 0)
+ return -1;
+ printk(KERN_DEBUG "[E-PEN]: erased:%d\n", ret);
+
+ msleep(20);
+
+ ret = wacom_i2c_flash_write(wac_i2c, START_ADDR,
+ NUM_BLOCK_2WRITE, maxAddr);
+ if (ret < 0)
+ return -1;
+
+ msleep(20);
+
+ ret = wacom_i2c_flash_verify(wac_i2c, START_ADDR,
+ NUM_BLOCK_2WRITE, maxAddr);
+ if (ret < 0)
+ return -1;
+
+ break;
+
+ default:
+ printk(KERN_DEBUG "[E-PEN]: default called\n");
+ break;
+ }
+ msleep(20);
+
+ ret = wacom_i2c_flash_end(wac_i2c);
+ wake_unlock(&wac_i2c->wakelock);
+ printk(KERN_DEBUG "[E-PEN]: Firmware successfully updated:%x\n", ret);
+
+ return 0;
+}