static int __init s3c2410ts_probe(struct platform_device *pdev)
{
int rc;
struct s3c2410_ts_mach_info *info;
struct input_dev *input_dev;
int ret = 0;
dev_info(&pdev->dev, "Starting\n");
info = (struct s3c2410_ts_mach_info *)pdev->dev.platform_data;//获得平台设备数据
if (!info)
{
dev_err(&pdev->dev, "Hm... too bad: no platform data for ts\n");
return -EINVAL;
}
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "Entering s3c2410ts_init\n");
#endif
adc_clock = clk_get(NULL, "adc");
if (!adc_clock) {
dev_err(&pdev->dev, "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "got and enabled clock\n");
#endif
base_addr = ioremap(S3C2410_PA_ADC,0x20);//将PA_ADC寄存器重映射到内存上
if (base_addr == NULL) {
dev_err(&pdev->dev, "Failed to remap register block\n");
ret = -ENOMEM;
goto bail0;
}
/* If we acutally are a S3C2410: Configure GPIOs */
if (!strcmp(pdev->name, "s3c2410-ts"))
s3c2410_ts_connect();//初始化相关gpio口
if ((info->presc & 0xff) > 0)
writel(S3C2410_ADCCON_PRSCEN |
S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
base_addr + S3C2410_ADCCON);
else
writel(0, base_addr+S3C2410_ADCCON);
/* Initialise registers */
if ((info->delay & 0xffff) > 0)
writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);
writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);
/* Initialise input stuff */
memset(&ts, 0, sizeof(struct s3c2410ts));
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&pdev->dev, "Unable to allocate the input device\n");
ret = -ENOMEM;
goto bail1;
}
//初始化input设备
ts.dev = input_dev;
ts.dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |
BIT_MASK(EV_ABS);
ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
ts.dev->name = s3c2410ts_name;
ts.dev->id.bustype = BUS_RS232;
ts.dev->id.vendor = 0xDEAD;
ts.dev->id.product = 0xBEEF;
ts.dev->id.version = S3C2410TSVERSION;
ts.state = TS_STATE_STANDBY;//设置ts状态为就绪
ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);//为event队列申请内存空间
if (IS_ERR(ts.event_fifo)) {
ret = -EIO;
goto bail2;
}
/* create the filter chain set up for the 2 coordinates we produce */
ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);//针对android的,建立filter_chain
if (IS_ERR(ts.chain))
goto bail2;
ts_filter_chain_clear(ts.chain);
/* Get irqs */
if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
"s3c2410_action", ts.dev)) {
dev_err(&pdev->dev, "Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
ret = -EIO;
goto bail3;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action", ts.dev)) {
dev_err(&pdev->dev, "Could not allocate ts IRQ_TC !\n");
free_irq(IRQ_ADC, ts.dev);
iounmap(base_addr);
ret = -EIO;
goto bail4;
}
dev_info(&pdev->dev, "Successfully loaded\n");
/* All went ok, so register to the input system */
rc = input_register_device(ts.dev);
if (rc) {
ret = -EIO;
goto bail5;
}
return 0;
bail5:
free_irq(IRQ_TC, ts.dev);
free_irq(IRQ_ADC, ts.dev);
clk_disable(adc_clock);
iounmap(base_addr);
disable_irq(IRQ_TC);
bail4:
disable_irq(IRQ_ADC);
bail3:
ts_filter_chain_destroy(ts.chain);
kfifo_free(ts.event_fifo);
bail2:
input_unregister_device(ts.dev);
bail1:
iounmap(base_addr);
bail0:
return ret;
}
|