⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ads7846.c

📁 Touchright serial touchscreen driver
💻 C
📖 第 1 页 / 共 2 页
字号:
			ts->read_rep = 0;			m++;		} else			/* Read more values that are consistent. */			ts->read_cnt++;	}	status = spi_async(ts->spi, m);	if (status)		dev_err(&ts->spi->dev, "spi_async --> %d\n",				status);}static void ads7846_timer(unsigned long handle){	struct ads7846	*ts = (void *)handle;	int		status = 0;	int		alt_end_cycle = 0; /* ads7843 alternative cycle end */	if (ts->model == 7843) {		/* get sample */		ts->pendown = ts->get_pendown_state();		alt_end_cycle = ts->pending;	}	spin_lock_irq(&ts->lock);	if (unlikely(!ts->pendown && (ts->msg_idx || alt_end_cycle))) {		/* measurement cycle ended */		if (ts->model == 7843) {			status = spi_async(ts->spi, ts->last_msg);			if (status)				dev_err(&ts->spi->dev,					"spi_async --> %d\n", status);		}		if (!device_suspended(&ts->spi->dev)) {			ts->irq_disabled = 0;			enable_irq(ts->spi->irq);		}		ts->pending = 0;		ts->msg_idx = 0;	} else {		/* pen is still down, continue with the measurement */		ts->msg_idx = 0;		status = spi_async(ts->spi, &ts->msg[0]);		if (status)			dev_err(&ts->spi->dev, "spi_async --> %d\n", status);	}	spin_unlock_irq(&ts->lock);}static irqreturn_t ads7846_irq(int irq, void *handle){	struct ads7846 *ts = handle;	unsigned long flags;	spin_lock_irqsave(&ts->lock, flags);	if (likely(ts->get_pendown_state())) {		if (!ts->irq_disabled) {			/* The ARM do_simple_IRQ() dispatcher doesn't act			 * like the other dispatchers:  it will report IRQs			 * even after they've been disabled.  We work around			 * that here.  (The "generic irq" framework may help...)			 */			ts->irq_disabled = 1;			disable_irq(ts->spi->irq);			ts->pending = 1;			mod_timer(&ts->timer, jiffies);		}	}	spin_unlock_irqrestore(&ts->lock, flags);	return IRQ_HANDLED;}/*--------------------------------------------------------------------------*//* Must be called with ts->lock held */static void ads7846_disable(struct ads7846 *ts){	if (ts->disabled)		return;	ts->disabled = 1;	/* are we waiting for IRQ, or polling? */	if (!ts->pending) {		ts->irq_disabled = 1;		disable_irq(ts->spi->irq);	} else {		/* the timer will run at least once more, and		 * leave everything in a clean state, IRQ disabled		 */		while (ts->pending) {			spin_unlock_irq(&ts->lock);			msleep(1);			spin_lock_irq(&ts->lock);		}	}	/* we know the chip's in lowpower mode since we always	 * leave it that way after every request	 */}/* Must be called with ts->lock held */static void ads7846_enable(struct ads7846 *ts){	if (!ts->disabled)		return;	ts->disabled = 0;	ts->irq_disabled = 0;	enable_irq(ts->spi->irq);}static int ads7846_suspend(struct spi_device *spi, pm_message_t message){	struct ads7846 *ts = dev_get_drvdata(&spi->dev);	spin_lock_irq(&ts->lock);	spi->dev.power.power_state = message;	ads7846_disable(ts);	spin_unlock_irq(&ts->lock);	return 0;}static int ads7846_resume(struct spi_device *spi){	struct ads7846 *ts = dev_get_drvdata(&spi->dev);	spin_lock_irq(&ts->lock);	spi->dev.power.power_state = PMSG_ON;	ads7846_enable(ts);	spin_unlock_irq(&ts->lock);	return 0;}static int __devinit ads7846_probe(struct spi_device *spi){	struct ads7846			*ts;	struct input_dev		*input_dev;	struct ads7846_platform_data	*pdata = spi->dev.platform_data;	struct spi_message		*m;	struct spi_transfer		*x;	int				err;	if (!spi->irq) {		dev_dbg(&spi->dev, "no IRQ?\n");		return -ENODEV;	}	if (!pdata) {		dev_dbg(&spi->dev, "no platform data?\n");		return -ENODEV;	}	/* don't exceed max specified sample rate */	if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {		dev_dbg(&spi->dev, "f(sample) %d KHz?\n",				(spi->max_speed_hz/SAMPLE_BITS)/1000);		return -EINVAL;	}	/* REVISIT when the irq can be triggered active-low, or if for some	 * reason the touchscreen isn't hooked up, we don't need to access	 * the pendown state.	 */	if (pdata->get_pendown_state == NULL) {		dev_dbg(&spi->dev, "no get_pendown_state function?\n");		return -EINVAL;	}	/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except	 * that even if the hardware can do that, the SPI controller driver	 * may not.  So we stick to very-portable 8 bit words, both RX and TX.	 */	spi->bits_per_word = 8;	ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);	input_dev = input_allocate_device();	if (!ts || !input_dev) {		err = -ENOMEM;		goto err_free_mem;	}	dev_set_drvdata(&spi->dev, ts);	spi->dev.power.power_state = PMSG_ON;	ts->spi = spi;	ts->input = input_dev;	init_timer(&ts->timer);	ts->timer.data = (unsigned long) ts;	ts->timer.function = ads7846_timer;	spin_lock_init(&ts->lock);	ts->model = pdata->model ? : 7846;	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;	ts->pressure_max = pdata->pressure_max ? : ~0;	if (pdata->debounce_max) {		ts->debounce_max = pdata->debounce_max;		ts->debounce_tol = pdata->debounce_tol;		ts->debounce_rep = pdata->debounce_rep;		if (ts->debounce_rep > ts->debounce_max + 1)			ts->debounce_rep = ts->debounce_max - 1;	} else		ts->debounce_tol = ~0;	ts->get_pendown_state = pdata->get_pendown_state;	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);	input_dev->name = "ADS784x Touchscreen";	input_dev->phys = ts->phys;	input_dev->cdev.dev = &spi->dev;	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);	input_set_abs_params(input_dev, ABS_X,			pdata->x_min ? : 0,			pdata->x_max ? : MAX_12BIT,			0, 0);	input_set_abs_params(input_dev, ABS_Y,			pdata->y_min ? : 0,			pdata->y_max ? : MAX_12BIT,			0, 0);	input_set_abs_params(input_dev, ABS_PRESSURE,			pdata->pressure_min, pdata->pressure_max, 0, 0);	/* set up the transfers to read touchscreen state; this assumes we	 * use formula #2 for pressure, not #3.	 */	m = &ts->msg[0];	x = ts->xfer;	spi_message_init(m);	/* y- still on; turn on only y+ (and ADC) */	if (ts->model == 7843) {		ts->read_y = ALT_READ_Y;	} else {		ts->read_y = READ_Y;	}	x->tx_buf = &ts->read_y;	x->len = 1;	spi_message_add_tail(x, m);	x++;	x->tx_buf = &ts->zerro;	x->rx_buf = &ts->tc.y;	x->len = 2;	spi_message_add_tail(x, m);	m->complete = ads7846_debounce;	m->context = ts;	m++;	spi_message_init(m);	/* turn y- off, x+ on, then leave in lowpower */	x++;	if (ts->model == 7843) {		ts->read_x = ALT_READ_X;	} else {		ts->read_x = READ_X;	}	x->tx_buf = &ts->read_x;	x->len = 1;	spi_message_add_tail(x, m);	x++;	x->tx_buf = &ts->zerro;	x->rx_buf = &ts->tc.x;	x->len = 2;	spi_message_add_tail(x, m);	m->complete = ads7846_debounce;	m->context = ts;	/* turn y+ off, x- on; we'll use formula #2 */	if (ts->model == 7846) {		m++;		spi_message_init(m);		x++;		ts->read_z1 = READ_Z1;		x->tx_buf = &ts->read_z1;		x->len = 1;		spi_message_add_tail(x, m);		x++;		x->rx_buf = &ts->tc.z1;		x->len = 2;		spi_message_add_tail(x, m);		m->complete = ads7846_debounce;		m->context = ts;		m++;		spi_message_init(m);		x++;		ts->read_z2 = READ_Z2;		x->tx_buf = &ts->read_z2;		x->len = 1;		spi_message_add_tail(x, m);		x++;		x->rx_buf = &ts->tc.z2;		x->len = 2;		spi_message_add_tail(x, m);		m->complete = ads7846_debounce;		m->context = ts;	}	/* power down */	m++;	spi_message_init(m);	x++;	ts->pwrdown = PWRDOWN;	x->tx_buf = &ts->pwrdown;	x->len = 1;	spi_message_add_tail(x, m);	x++;	x->tx_buf = &ts->zerro;	x->rx_buf = &ts->dummy;	x->len = 2;	CS_CHANGE(*x);	spi_message_add_tail(x, m);	if (ts->model == 7843) {		m->complete = ads7843_rx;	} else {		m->complete = ads7846_rx;	}	m->context = ts;	ts->last_msg = m;	if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,			spi->dev.driver->name, ts)) {		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);		err = -EBUSY;		goto err_free_mem;	}	dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);	if (ts->model != 7843) {		/* take a first sample, leaving nPENIRQ active; avoid		 * the touchscreen, in case it's not connected.		 */		(void) ads7846_read12_ser(&spi->dev,				  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);	} else {		(void) ads7846_read12_ser(&spi->dev,				  READ_12BIT_DFR(y) | ADS_PD10_ALL_ON);	}	/* ads7843/7845 don't have temperature sensors, and	 * use the other sensors a bit differently too	 */	if (ts->model == 7846) {		device_create_file(&spi->dev, &dev_attr_temp0);		device_create_file(&spi->dev, &dev_attr_temp1);	}	if (ts->model != 7845 && ts->model != 7843)		device_create_file(&spi->dev, &dev_attr_vbatt);	if (ts->model != 7843) {		device_create_file(&spi->dev, &dev_attr_vaux);	}	device_create_file(&spi->dev, &dev_attr_pen_down);	device_create_file(&spi->dev, &dev_attr_disable);	err = input_register_device(input_dev);	if (err)		goto err_remove_attr;	return 0; err_remove_attr:	device_remove_file(&spi->dev, &dev_attr_disable);	device_remove_file(&spi->dev, &dev_attr_pen_down);	if (ts->model == 7846) {		device_remove_file(&spi->dev, &dev_attr_temp1);		device_remove_file(&spi->dev, &dev_attr_temp0);	}	if (ts->model != 7845 && ts->model != 7843)		device_remove_file(&spi->dev, &dev_attr_vbatt);	if (ts->model != 7843) {		device_remove_file(&spi->dev, &dev_attr_vaux);	}	free_irq(spi->irq, ts); err_free_mem:	input_free_device(input_dev);	kfree(ts);	return err;}static int __devexit ads7846_remove(struct spi_device *spi){	struct ads7846		*ts = dev_get_drvdata(&spi->dev);	input_unregister_device(ts->input);	ads7846_suspend(spi, PMSG_SUSPEND);	device_remove_file(&spi->dev, &dev_attr_disable);	device_remove_file(&spi->dev, &dev_attr_pen_down);	if (ts->model == 7846) {		device_remove_file(&spi->dev, &dev_attr_temp1);		device_remove_file(&spi->dev, &dev_attr_temp0);	}	if (ts->model != 7845 && ts->model != 7843)		device_remove_file(&spi->dev, &dev_attr_vbatt);	if (ts->model != 7843) {		device_remove_file(&spi->dev, &dev_attr_vaux);	}	free_irq(ts->spi->irq, ts);	/* suspend left the IRQ disabled */	enable_irq(ts->spi->irq);	kfree(ts);	dev_dbg(&spi->dev, "unregistered touchscreen\n");	return 0;}static struct spi_driver ads7846_driver = {	.driver = {		.name	= "ads7846",		.bus	= &spi_bus_type,		.owner	= THIS_MODULE,	},	.probe		= ads7846_probe,	.remove		= __devexit_p(ads7846_remove),	.suspend	= ads7846_suspend,	.resume		= ads7846_resume,};static int __init ads7846_init(void){	/* grr, board-specific init should stay out of drivers!! */#ifdef	CONFIG_ARCH_OMAP	if (machine_is_omap_osk()) {		/* GPIO4 = PENIRQ; GPIO6 = BUSY */		omap_request_gpio(4);		omap_set_gpio_direction(4, 1);		omap_request_gpio(6);		omap_set_gpio_direction(6, 1);	}	// also TI 1510 Innovator, bitbanging through FPGA	// also Nokia 770	// also Palm Tungsten T2#endif	// PXA:	// also Dell Axim X50	// also HP iPaq H191x/H192x/H415x/H435x	// also Intel Lubbock (additional to UCB1400; as temperature sensor)	// also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)	// Atmel at91sam9261-EK uses ads7843	// also various AMD Au1x00 devel boards	return spi_register_driver(&ads7846_driver);}module_init(ads7846_init);static void __exit ads7846_exit(void){	spi_unregister_driver(&ads7846_driver);#ifdef	CONFIG_ARCH_OMAP	if (machine_is_omap_osk()) {		omap_free_gpio(4);		omap_free_gpio(6);	}#endif}module_exit(ads7846_exit);MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -