#define EDT_RAW_DATA_DELAY             1000 /* usec */
 
 enum edt_ver {
-       M06,
-       M09,
+       EDT_M06,
+       EDT_M09,
+       GENERIC_FT,
 };
 
 struct edt_reg_addr {
        int error;
 
        switch (tsdata->version) {
-       case M06:
+       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 M09:
+       case EDT_M09:
+       case GENERIC_FT:
                cmd = 0x0;
                offset = 3;
                tplen = 6;
        }
 
        /* M09 does not send header or CRC */
-       if (tsdata->version == M06) {
+       if (tsdata->version == EDT_M06) {
                if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
                        rdbuf[2] != datalen) {
                        dev_err_ratelimited(dev,
                        continue;
 
                /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
-               if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
+               if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
                        continue;
 
                x = ((buf[0] << 8) | buf[1]) & 0x0fff;
        u8 wrbuf[4];
 
        switch (tsdata->version) {
-       case M06:
+       case EDT_M06:
                wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
                wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
                wrbuf[2] = value;
                wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
                return edt_ft5x06_ts_readwrite(tsdata->client, 4,
                                        wrbuf, 0, NULL);
-       case M09:
+       case EDT_M09:
+       case GENERIC_FT:
                wrbuf[0] = addr;
                wrbuf[1] = value;
 
        int error;
 
        switch (tsdata->version) {
-       case M06:
+       case EDT_M06:
                wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
                wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
                wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
                }
                break;
 
-       case M09:
+       case EDT_M09:
+       case GENERIC_FT:
                wrbuf[0] = addr;
                error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
                                                wrbuf, 1, rdbuf);
        }
 
        switch (tsdata->version) {
-       case M06:
+       case EDT_M06:
                addr = attr->addr_m06;
                break;
 
-       case M09:
+       case EDT_M09:
+       case GENERIC_FT:
                addr = attr->addr_m09;
                break;
 
        }
 
        switch (tsdata->version) {
-       case M06:
+       case EDT_M06:
                addr = attr->addr_m06;
                break;
 
-       case M09:
+       case EDT_M09:
+       case GENERIC_FT:
                addr = attr->addr_m09;
                break;
 
        }
 
        /* mode register is 0x3c when in the work mode */
-       if (tsdata->version == M09)
+       if (tsdata->version != EDT_M06)
                goto m09_out;
 
        error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
        return error;
 
 m09_out:
-       dev_err(&client->dev, "No factory mode support for M09\n");
+       dev_err(&client->dev, "No factory mode support for M09/GENERIC_FT\n");
        return -EINVAL;
 
 }
         * at least M09 won't send 3 bytes here
         */
        if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
-               tsdata->version = M06;
+               tsdata->version = EDT_M06;
 
                /* remove last '$' end marker */
                rdbuf[EDT_NAME_LEN - 1] = '\0';
                strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
                strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
        } else {
-               /* since there are only two versions around (M06, M09) */
-               tsdata->version = M09;
+               /* If it is not an EDT M06 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.
+                */
+               tsdata->version = GENERIC_FT;
 
                error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
                                                2, rdbuf);
                if (error)
                        return error;
 
-               snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
-                       rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+               /* 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 */
+                       tsdata->version = EDT_M09;
+                       snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
+                               rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+                       break;
+               case 0xa1:   /* EDT EP1010ML00 */
+                       tsdata->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;
        if (reg_addr->reg_report_rate != NO_REGISTER)
                tsdata->report_rate = edt_ft5x06_register_read(tsdata,
                                                reg_addr->reg_report_rate);
-       tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
-       tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
+       if (tsdata->version == EDT_M06 ||
+           tsdata->version == EDT_M09) {
+               tsdata->num_x = edt_ft5x06_register_read(tsdata,
+                                                        reg_addr->reg_num_x);
+               tsdata->num_y = edt_ft5x06_register_read(tsdata,
+                                                        reg_addr->reg_num_y);
+       } else {
+               tsdata->num_x = -1;
+               tsdata->num_y = -1;
+       }
 }
 
 static void
        struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
 
        switch (tsdata->version) {
-       case M06:
+       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_num_y = WORK_REGISTER_NUM_Y;
                break;
 
-       case M09:
+       case EDT_M09:
                reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
                reg_addr->reg_report_rate = NO_REGISTER;
                reg_addr->reg_gain = M09_REGISTER_GAIN;
                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;
        }
 }
 
        input->id.bustype = BUS_I2C;
        input->dev.parent = &client->dev;
 
-       input_set_abs_params(input, ABS_MT_POSITION_X,
-                            0, tsdata->num_x * 64 - 1, 0, 0);
-       input_set_abs_params(input, ABS_MT_POSITION_Y,
-                            0, tsdata->num_y * 64 - 1, 0, 0);
+       if (tsdata->version == EDT_M06 ||
+           tsdata->version == EDT_M09) {
+               input_set_abs_params(input, ABS_MT_POSITION_X,
+                                    0, tsdata->num_x * 64 - 1, 0, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_Y,
+                                    0, tsdata->num_y * 64 - 1, 0, 0);
+       } else {
+               /* Unknown maximum values. Specify via devicetree */
+               input_set_abs_params(input, ABS_MT_POSITION_X,
+                                    0, 65535, 0, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_Y,
+                                    0, 65535, 0, 0);
+       }
 
        touchscreen_parse_properties(input, true, &tsdata->prop);