static int msm_ts_hw_init(struct msm_ts *ts) { uint32_t tmp; tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL); tssc_writel(ts, TSSC_CTL_SW_RESET, TSSC_CTL); tmp = (TSSC_OPN_4WIRE_X << 16) | (2 << 8) | (2 << 0); tmp |= (TSSC_OPN_4WIRE_Y << 20) | (2 << 10) | (2 << 2); tmp |= (TSSC_OPN_4WIRE_Z1 << 24) | (2 << 12) | (0 << 4); tmp |= (TSSC_OPN_4WIRE_Z2 << 28) | (0 << 14) | (0 << 6); tssc_writel(ts, tmp, TSSC_OPN); tssc_writel(ts, 16, TSSC_SAMPLING_INT); tssc_writel(ts, TSSC_TEST_1_EN_GATE_DEBOUNCE, TSSC_TEST_1); setup_next_sample(ts); return 0; }
static int __devinit msm_ts_hw_init(struct msm_ts *ts) { uint32_t tmp; /* Enable the register clock to tssc so we can configure it. */ tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL); /* op1 - measure X, 1 sample, 12bit resolution */ tmp = (TSSC_OPN_4WIRE_X << 16) | (2 << 8) | (2 << 0); /* op2 - measure Y, 1 sample, 12bit resolution */ tmp |= (TSSC_OPN_4WIRE_Y << 20) | (2 << 10) | (2 << 2); /* op3 - measure Z1, 1 sample, 8bit resolution */ tmp |= (TSSC_OPN_4WIRE_Z1 << 24) | (2 << 12) | (0 << 4); /* XXX: we don't actually need to measure Z2 (thus 0 samples) when * doing voltage-driven measurement */ /* op4 - measure Z2, 0 samples, 8bit resolution */ tmp |= (TSSC_OPN_4WIRE_Z2 << 28) | (0 << 14) | (0 << 6); tssc_writel(ts, tmp, TSSC_OPN); /* 16ms sampling interval */ tssc_writel(ts, 16, TSSC_SAMPLING_INT); setup_next_sample(ts); return 0; }
static int __devinit msm_ts_hw_init(struct msm_ts *ts) { #if 0 //wly uint32_t tmp; /* Enable the register clock to tssc so we can configure it. */ tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL); /* Enable software reset*/ tssc_writel(ts, TSSC_CTL_SW_RESET, TSSC_CTL); /* op1 - measure X, 1 sample, 12bit resolution */ tmp = (TSSC_OPN_4WIRE_X << 16) | (2 << 8) | (2 << 0); /* op2 - measure Y, 1 sample, 12bit resolution */ tmp |= (TSSC_OPN_4WIRE_Y << 20) | (2 << 10) | (2 << 2); /* op3 - measure Z1, 1 sample, 8bit resolution */ tmp |= (TSSC_OPN_4WIRE_Z1 << 24) | (2 << 12) | (0 << 4); /* XXX: we don't actually need to measure Z2 (thus 0 samples) when * doing voltage-driven measurement */ /* op4 - measure Z2, 0 samples, 8bit resolution */ tmp |= (TSSC_OPN_4WIRE_Z2 << 28) | (0 << 14) | (0 << 6); tssc_writel(ts, tmp, TSSC_OPN); /* 16ms sampling interval */ tssc_writel(ts, 16, TSSC_SAMPLING_INT); /* Enable gating logic to fix the timing delays caused because of * enabling debounce logic */ tssc_writel(ts, TSSC_TEST_1_EN_GATE_DEBOUNCE, TSSC_TEST_1); #endif setup_next_sample(ts); return 0; }
static void setup_next_sample(struct msm_ts *ts) { uint32_t tmp; /* 1.2ms debounce time */ tmp = ((2 << 7) | TSSC_CTL_DEBOUNCE_EN | TSSC_CTL_EN_AVERAGE | TSSC_CTL_MODE_MASTER | TSSC_CTL_ENABLE); tssc_writel(ts, tmp, TSSC_CTL); }
static void setup_next_sample(struct msm_ts *ts) { uint32_t tmp; /* 1.2ms debounce time */ tmp = ((2 << 7) | TSSC_CTL_DEBOUNCE_EN | TSSC_CTL_EN_AVERAGE | TSSC_CTL_MODE_MASTER | TSSC_CTL_ENABLE); tssc_writel(ts, tmp, TSSC_CTL); /* barrier: Make sure the write completes before the next sample */ mb(); }
static void msm_ts_enable(struct msm_ts *ts, bool enable) { uint32_t val; if (enable == true) msm_ts_hw_init(ts); else { val = tssc_readl(ts, TSSC_CTL); val &= ~TSSC_CTL_ENABLE; tssc_writel(ts, val, TSSC_CTL); } }
static int msm_ts_suspend(struct device *dev) { struct msm_ts *ts = dev_get_drvdata(dev); uint32_t val; disable_irq(ts->sample_irq); disable_irq(ts->pen_up_irq); val = tssc_readl(ts, TSSC_CTL); val &= ~TSSC_CTL_ENABLE; tssc_writel(ts, val, TSSC_CTL); return 0; }
static int __devinit msm_ts_probe(struct platform_device *pdev) { struct msm_ts_platform_data *pdata = pdev->dev.platform_data; struct msm_ts *ts; struct resource *tssc_res; struct resource *irq1_res; struct resource *irq2_res; int err = 0; int i; struct marimba_tsadc_client *ts_client; printk("%s\n", __func__); tssc_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tssc"); irq1_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc1"); irq2_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc2"); if (!tssc_res || !irq1_res || !irq2_res) { pr_err("%s: required resources not defined\n", __func__); return -ENODEV; } if (pdata == NULL) { pr_err("%s: missing platform_data\n", __func__); return -ENODEV; } ts = kzalloc(sizeof(struct msm_ts), GFP_KERNEL); if (ts == NULL) { pr_err("%s: No memory for struct msm_ts\n", __func__); return -ENOMEM; } ts->pdata = pdata; ts->dev = &pdev->dev; ts->sample_irq = irq1_res->start; ts->pen_up_irq = irq2_res->start; ts->tssc_base = ioremap(tssc_res->start, resource_size(tssc_res)); if (ts->tssc_base == NULL) { pr_err("%s: Can't ioremap region (0x%08x - 0x%08x)\n", __func__, (uint32_t)tssc_res->start, (uint32_t)tssc_res->end); err = -ENOMEM; goto err_ioremap_tssc; } ts_client = marimba_tsadc_register(pdev, 1); if (IS_ERR(ts_client)) { pr_err("%s: Unable to register with TSADC\n", __func__); err = -ENOMEM; goto err_tsadc_register; } ts->ts_client = ts_client; err = marimba_tsadc_start(ts_client); if (err) { pr_err("%s: Unable to start TSADC\n", __func__); err = -EINVAL; goto err_start_tsadc; } ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { pr_err("failed to allocate touchscreen input device\n"); err = -ENOMEM; goto err_alloc_input_dev; } ts->input_dev->name = "msm-touchscreen"; ts->input_dev->dev.parent = &pdev->dev; input_set_drvdata(ts->input_dev, ts); input_set_capability(ts->input_dev, EV_KEY, BTN_TOUCH); set_bit(EV_ABS, ts->input_dev->evbit); set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); input_set_abs_params(ts->input_dev, ABS_X, pdata->min_x, pdata->max_x, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, pdata->min_y, pdata->max_y, 0, 0); input_set_abs_params(ts->input_dev, ABS_PRESSURE, pdata->min_press, pdata->max_press, 0, 0); for (i = 0; pdata->vkeys_x && (i < pdata->vkeys_x->num_keys); ++i) input_set_capability(ts->input_dev, EV_KEY, pdata->vkeys_x->keys[i].key); for (i = 0; pdata->vkeys_y && (i < pdata->vkeys_y->num_keys); ++i) input_set_capability(ts->input_dev, EV_KEY, pdata->vkeys_y->keys[i].key); err = input_register_device(ts->input_dev); if (err != 0) { pr_err("%s: failed to register input device\n", __func__); goto err_input_dev_reg; } msm_ts_hw_init(ts); err = request_irq(ts->sample_irq, msm_ts_irq, (irq1_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED, "msm_touchscreen", ts); if (err != 0) { pr_err("%s: Cannot register irq1 (%d)\n", __func__, err); goto err_request_irq1; } err = request_irq(ts->pen_up_irq, msm_ts_irq, (irq2_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED, "msm_touchscreen", ts); if (err != 0) { pr_err("%s: Cannot register irq2 (%d)\n", __func__, err); goto err_request_irq2; } platform_set_drvdata(pdev, ts); #ifdef CONFIG_HAS_EARLYSUSPEND ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + TSSC_SUSPEND_LEVEL; ts->early_suspend.suspend = msm_ts_early_suspend; ts->early_suspend.resume = msm_ts_late_resume; register_early_suspend(&ts->early_suspend); #endif device_init_wakeup(&pdev->dev, pdata->can_wakeup); pr_info("%s: tssc_base=%p irq1=%d irq2=%d\n", __func__, ts->tssc_base, (int)ts->sample_irq, (int)ts->pen_up_irq); dump_tssc_regs(ts); return 0; err_request_irq2: free_irq(ts->sample_irq, ts); err_request_irq1: tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL); err_input_dev_reg: input_set_drvdata(ts->input_dev, NULL); input_free_device(ts->input_dev); err_alloc_input_dev: err_start_tsadc: marimba_tsadc_unregister(ts->ts_client); err_tsadc_register: iounmap(ts->tssc_base); err_ioremap_tssc: kfree(ts); return err; }
static int __devinit msm_ts_probe(struct platform_device *pdev) { struct msm_ts_platform_data *pdata = pdev->dev.platform_data; struct msm_ts *ts; struct resource *tssc_res; struct resource *irq1_res; struct resource *irq2_res; int err = 0; int i; tssc_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tssc"); irq1_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc1"); irq2_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tssc2"); if (!tssc_res || !irq1_res || !irq2_res) { pr_err("%s: required resources not defined\n", __func__); return -ENODEV; } if (pdata == NULL) { pr_err("%s: missing platform_data\n", __func__); return -ENODEV; } ts = kzalloc(sizeof(struct msm_ts), GFP_KERNEL); if (ts == NULL) { pr_err("%s: No memory for struct msm_ts\n", __func__); return -ENOMEM; } ts->pdata = pdata; ts->tssc_base = ioremap(tssc_res->start, resource_size(tssc_res)); if (ts->tssc_base == NULL) { pr_err("%s: Can't ioremap region (0x%08x - 0x%08x)\n", __func__, (uint32_t)tssc_res->start, (uint32_t)tssc_res->end); err = -ENOMEM; goto err_ioremap_tssc; } ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { pr_err("failed to allocate touchscreen input device\n"); err = -ENOMEM; goto err_alloc_input_dev; } ts->input_dev->name = "msm-touchscreen"; input_set_drvdata(ts->input_dev, ts); input_set_capability(ts->input_dev, EV_KEY, BTN_TOUCH); set_bit(EV_ABS, ts->input_dev->evbit); input_set_abs_params(ts->input_dev, ABS_X, pdata->min_x, pdata->max_x, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, pdata->min_y, pdata->max_y, 0, 0); input_set_abs_params(ts->input_dev, ABS_PRESSURE, pdata->min_press, pdata->max_press, 0, 0); for (i = 0; pdata->vkeys_x && (i < pdata->vkeys_x->num_keys); ++i) input_set_capability(ts->input_dev, EV_KEY, pdata->vkeys_x->keys[i].key); for (i = 0; pdata->vkeys_y && (i < pdata->vkeys_y->num_keys); ++i) input_set_capability(ts->input_dev, EV_KEY, pdata->vkeys_y->keys[i].key); err = input_register_device(ts->input_dev); if (err != 0) { pr_err("%s: failed to register input device\n", __func__); goto err_input_dev_reg; } msm_ts_hw_init(ts); err = request_irq(irq1_res->start, msm_ts_irq, (irq1_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED, "msm_touchscreen", ts); if (err != 0) { pr_err("%s: Cannot register irq1 (%d)\n", __func__, err); goto err_request_irq1; } err = request_irq(irq2_res->start, msm_ts_irq, (irq2_res->flags & ~IORESOURCE_IRQ) | IRQF_DISABLED, "msm_touchscreen", ts); if (err != 0) { pr_err("%s: Cannot register irq2 (%d)\n", __func__, err); goto err_request_irq2; } platform_set_drvdata(pdev, ts); pr_info("%s: tssc_base=%p irq1=%d irq2=%d\n", __func__, ts->tssc_base, (int)irq1_res->start, (int)irq2_res->start); return 0; err_request_irq2: free_irq(irq1_res->start, ts); err_request_irq1: /* disable the tssc */ tssc_writel(ts, TSSC_CTL_ENABLE, TSSC_CTL); err_input_dev_reg: input_set_drvdata(ts->input_dev, NULL); input_free_device(ts->input_dev); err_alloc_input_dev: iounmap(ts->tssc_base); err_ioremap_tssc: kfree(ts); return err; }
static irqreturn_t msm_ts_irq(int irq, void *dev_id) { struct msm_ts *ts = dev_id; struct msm_ts_platform_data *pdata = ts->pdata; uint32_t tmp, num_op, num_samp; uint32_t tssc_avg12, tssc_avg34, tssc_status, tssc_ctl; int x, y, z1, z2; int was_down; int down; tssc_ctl = tssc_readl(ts, TSSC_CTL); tssc_status = tssc_readl(ts, TSSC_STATUS); tssc_avg12 = tssc_readl(ts, TSSC_AVG_12); tssc_avg34 = tssc_readl(ts, TSSC_AVG_34); tssc_writel(ts, s_sampling_int, TSSC_SAMPLING_INT); setup_next_sample(ts); #if defined(CONFIG_MACH_MSM7X27_SWIFT) y = tssc_avg12 & 0xffff; x = tssc_avg12 >> 16; z1 = 255; z2 = 0; #else /* original */ x = tssc_avg12 & 0xffff; y = tssc_avg12 >> 16; z1 = tssc_avg34 & 0xffff; z2 = tssc_avg34 >> 16; #endif /* invert the inputs if necessary */ if (pdata->inv_x) x = pdata->inv_x - x; if (pdata->inv_y) y = pdata->inv_y - y; if (x < 0) x = 0; if (y < 0) y = 0; down = !(tssc_ctl & TSSC_CTL_PENUP_IRQ); was_down = ts->ts_down; ts->ts_down = down; /* no valid data */ if (down && !(tssc_ctl & TSSC_CTL_DATA_FLAG)) return IRQ_HANDLED; if (msm_tsdebug & 2) printk("%s: down=%d, x=%d, y=%d, z1=%d, z2=%d, status %x\n", __func__, down, x, y, z1, z2, tssc_status); if (!was_down && down) { struct ts_virt_key *vkey = NULL; if (pdata->vkeys_y && (y > pdata->virt_y_start)) vkey = find_virt_key(ts, pdata->vkeys_y, x); if (!vkey && ts->pdata->vkeys_x && (x > pdata->virt_x_start)) vkey = find_virt_key(ts, pdata->vkeys_x, y); if (vkey) { WARN_ON(ts->vkey_down != NULL); if (msm_tsdebug) printk(KERN_INFO "%s: virtual key down %d\n", __func__, vkey->key); ts->vkey_down = vkey; input_report_key(ts->input_dev, vkey->key, 1); input_sync(ts->input_dev); return IRQ_HANDLED; } } else if (ts->vkey_down != NULL) { if (!down) { if (msm_tsdebug) printk(KERN_INFO "%s: virtual key up %d\n", __func__, ts->vkey_down->key); input_report_key(ts->input_dev, ts->vkey_down->key, 0); input_sync(ts->input_dev); ts->vkey_down = NULL; } if (y > 650) mod_timer(&ts->timer, jiffies + msecs_to_jiffies(s_penup_time)); return IRQ_HANDLED; } if (down) { if ((check_count(ts, x, y) != false) && (ts_check_region(ts, x, y) != false)) { input_report_abs(ts->input_dev, ABS_X, x); input_report_abs(ts->input_dev, ABS_Y, y); input_report_abs(ts->input_dev, ABS_PRESSURE, z1); input_report_key(ts->input_dev, BTN_TOUCH, down); input_sync(ts->input_dev); } mod_timer(&ts->timer, jiffies + msecs_to_jiffies(TS_PENUP_TIMEOUT_MS)); } else { input_report_key(ts->input_dev, BTN_TOUCH, down); input_sync(ts->input_dev); } ts->count = down; touch_press = down; if (down == 0) ts->count1 = down; return IRQ_HANDLED; }