/************************************************************************************
* I.MX6 ar1020 SPI device driver hacking
* 声明:
* 1. 本文主要是解读I.MX6中ar1020 SPI设备注册,以及驱动调用流程;
* 2. 本文主要使用了vim+ctags进行代码跟踪,所以几乎都是函数原型之间的调用;
*
* 2015-9-5 晴 深圳 南山平山村 曾剑锋
***********************************************************************************/ /*
* initialize __mach_desc_MX6Q_SABRESD data structure.
*/
MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.boot_params = MX6_PHYS_OFFSET + 0x100,
.fixup = fixup_mxc_board,
.map_io = mx6_map_io,
.init_irq = mx6_init_irq,
.init_machine = mx6_sabresd_board_init, ---------------+
.timer = &mx6_sabresd_timer, |
.reserve = mx6q_sabresd_reserve, |
MACHINE_END |
|
/*! |
* Board specific initialization. |
*/ |
static void __init mx6_sabresd_board_init(void) <----------+
{
......
imx6q_add_ecspi(, &mx6q_sabresd_spi_data); ---------------+---+
imx6q_add_ecspi(, &mx6q_sabresd_spi2_data); ---------------*-+ |
spi_device_init(); ---------------*-*-*-+
...... | | | |
gpio_request(SABRESD_AR1020_INT, "ar1020-interrupt"); | | | |
gpio_direction_input(SABRESD_AR1020_INT); | | | |
...... | | | |
} | | | |
| | | |
static const struct spi_imx_master mx6q_sabresd_spi_data __initconst = { <--+ | | |
.chipselect = mx6q_sabresd_spi_cs, -----+ | | |
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs), | | | |
}; | | | |
| | | |
static int mx6q_sabresd_spi_cs[] = { <----------+ | | |
SABRESD_ECSPI1_CS1, | | |
}; | | |
| | |
static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = { <----+ | |
.chipselect = mx6q_sabresd_spi2_cs, ------+ | |
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi2_cs), | | |
}; | | |
| | |
static int mx6q_sabresd_spi2_cs[] = { <----------+ | |
SABRESD_ECSPI2_CS0, | |
}; | |
| |
extern const struct imx_spi_imx_data imx6q_ecspi_data[] __initconst; ------+ | |
#define imx6q_add_ecspi(id, pdata) \ <----------------*----+ |
imx_add_spi_imx(&imx6q_ecspi_data[id], pdata) <-----+ ---*-----+
| | |
const struct imx_spi_imx_data imx6q_ecspi_data[] __initconst = { <-----+ | |
#define imx6q_ecspi_data_entry(_id, _hwid) \ | |
imx_spi_imx_data_entry(MX6Q, ECSPI, "imx6q-ecspi", _id, _hwid, SZ_4K) ----+ | |
imx6q_ecspi_data_entry(, ), | | |
imx6q_ecspi_data_entry(, ), | | |
imx6q_ecspi_data_entry(, ), | | |
imx6q_ecspi_data_entry(, ), | | |
imx6q_ecspi_data_entry(, ), | | |
}; | | |
#endif /* ifdef CONFIG_SOC_IMX6Q */ | | |
| | |
#define imx_spi_imx_data_entry_single(soc, type, _devid, _id, hwid, _size) \ | <-*--+ |
{ \ | | | |
.devid = _devid, \ | | | |
.id = _id, \ | | | |
.iobase = soc ## _ ## type ## hwid ## _BASE_ADDR, \ | | | |
.iosize = _size, \ | | | |
.irq = soc ## _INT_ ## type ## hwid, \ | | | |
} | | | |
| | | |
#define imx_spi_imx_data_entry(soc, type, devid, id, hwid, size) \ <-----+ | | |
[id] = imx_spi_imx_data_entry_single(soc, type, devid, id, hwid, size) --------*--+ |
| |
struct platform_device *__init imx_add_spi_imx( <-------------------------*-----+
const struct imx_spi_imx_data *data, |
const struct spi_imx_master *pdata) |
{ |
struct resource res[] = { |
{ |
.start = data->iobase, |
.end = data->iobase + data->iosize - , |
.flags = IORESOURCE_MEM, |
}, { |
.start = data->irq, |
.end = data->irq, |
.flags = IORESOURCE_IRQ, |
}, |
}; |
return imx_add_platform_device(data->devid, data->id, ------+ |
res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); | |
} | |
| |
static inline struct platform_device *imx_add_platform_device( <----+ |
const char *name, int id, |
const struct resource *res, unsigned int num_resources, |
const void *data, size_t size_data) |
{ |
return imx_add_platform_device_dmamask( -----+ |
name, id, res, num_resources, data, size_data, ); | |
} | |
| |
struct platform_device *__init imx_add_platform_device_dmamask( <----+ |
const char *name, int id, |
const struct resource *res, unsigned int num_resources, |
const void *data, size_t size_data, u64 dmamask) |
{ |
int ret = -ENOMEM; |
struct platform_device *pdev; |
|
pdev = platform_device_alloc(name, id); |
if (!pdev) |
goto err; |
|
if (dmamask) { |
/* |
* This memory isn't freed when the device is put, |
* I don't have a nice idea for that though. Conceptually |
* dma_mask in struct device should not be a pointer. |
* See http://thread.gmane.org/gmane.linux.kernel.pci/9081 |
*/ |
pdev->dev.dma_mask = |
kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); |
if (!pdev->dev.dma_mask) |
/* ret is still -ENOMEM; */ |
goto err; |
|
*pdev->dev.dma_mask = dmamask; |
pdev->dev.coherent_dma_mask = dmamask; |
} |
|
if (res) { |
ret = platform_device_add_resources(pdev, res, num_resources); |
if (ret) |
goto err; |
} |
|
if (data) { |
ret = platform_device_add_data(pdev, data, size_data); |
if (ret) |
goto err; |
} |
|
ret = platform_device_add(pdev); ------------------------+ |
if (ret) { | |
err: | |
if (dmamask) | |
kfree(pdev->dev.dma_mask); | |
platform_device_put(pdev); | |
return ERR_PTR(ret); | |
} | |
| |
return pdev; | |
} | |
| |
/** | |
* platform_device_add - add a platform device to device hierarchy | |
* @pdev: platform device we're adding | |
* | |
* This is part 2 of platform_device_register(), though may be called | |
* separately _iff_ pdev was allocated by platform_device_alloc(). | |
*/ | |
int platform_device_add(struct platform_device *pdev) <-----------+ |
{ |
int i, ret = ; |
|
if (!pdev) |
return -EINVAL; |
|
if (!pdev->dev.parent) |
pdev->dev.parent = &platform_bus; |
|
pdev->dev.bus = &platform_bus_type; |
|
if (pdev->id != -) |
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); |
else |
dev_set_name(&pdev->dev, "%s", pdev->name); |
|
for (i = ; i < pdev->num_resources; i++) { |
struct resource *p, *r = &pdev->resource[i]; |
|
if (r->name == NULL) |
r->name = dev_name(&pdev->dev); |
|
p = r->parent; |
if (!p) { |
if (resource_type(r) == IORESOURCE_MEM) |
p = &iomem_resource; |
else if (resource_type(r) == IORESOURCE_IO) |
p = &ioport_resource; |
} |
|
if (p && insert_resource(p, r)) { |
printk(KERN_ERR |
"%s: failed to claim resource %d\n", |
dev_name(&pdev->dev), i); |
ret = -EBUSY; |
goto failed; |
} |
} |
|
pr_debug("Registering platform device '%s'. Parent at %s\n", |
dev_name(&pdev->dev), dev_name(pdev->dev.parent)); |
|
ret = device_add(&pdev->dev); |
if (ret == ) |
return ret; |
|
failed: |
while (--i >= ) { |
struct resource *r = &pdev->resource[i]; |
unsigned long type = resource_type(r); |
|
if (type == IORESOURCE_MEM || type == IORESOURCE_IO) |
release_resource(r); |
} |
|
return ret; |
} |
EXPORT_SYMBOL_GPL(platform_device_add); |
|
static void spi_device_init(void) <--------------------------+
{
spi_register_board_info(imx6_sabresd_spi_nor_device, -----------------+
ARRAY_SIZE(imx6_sabresd_spi_nor_device)); |
} |
|
static struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = { <-----+
{ ^-----------------------------------------------------+ |
.modalias = "ar1020-spi", | |
.max_speed_hz = , /* max spi clock (SCK) speed in HZ */ | |
.bus_num = , | |
.chip_select = , | |
.mode = SPI_MODE_1, | |
.irq = gpio_to_irq(SABRESD_AR1020_INT), ----------------+ | |
| | |
//.platform_data = &imx6_sabresd__spi_flash_data, | | |
}, | | |
+---------------------------------------------------------|-+ |
}; | | |
V | |
struct spi_board_info { | |
/* the device name and module name are coupled, like platform_bus; | |
* "modalias" is normally the driver name. | |
* | |
* platform_data goes to spi_device.dev.platform_data, | |
* controller_data goes to spi_device.controller_data, | |
* irq is copied too | |
*/ | |
char modalias[SPI_NAME_SIZE]; | |
const void *platform_data; | |
void *controller_data; | |
int irq; | |
| |
/* slower signaling on noisy or low voltage boards */ | |
u32 max_speed_hz; | |
| |
| |
/* bus_num is board specific and matches the bus_num of some | |
* spi_master that will probably be registered later. | |
* | |
* chip_select reflects how this chip is wired to that master; | |
* it's less than num_chipselect. | |
*/ | |
u16 bus_num; | |
u16 chip_select; | |
| |
/* mode becomes spi_device.mode, and is essential for chips | |
* where the default of SPI_CS_HIGH = 0 is wrong. | |
*/ | |
u8 mode; | |
| |
/* ... may need additional spi_device chip config data here. | |
* avoid stuff protocol drivers can set; but include stuff | |
* needed to behave without being bound to a driver: | |
* - quirks like clock rate mattering when not selected | |
*/ | |
}; | |
| |
#define SABRESD_AR1020_INT IMX_GPIO_NR(1, 17) <------------+ |
|
int __init |
spi_register_board_info(struct spi_board_info const *info, unsigned n) <-------+
{
struct boardinfo *bi;
int i; bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM; for (i = ; i < n; i++, bi++, info++) {
struct spi_master *master; memcpy(&bi->board_info, info, sizeof(*info));
mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
list_for_each_entry(master, &spi_master_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info); -----+
mutex_unlock(&board_lock); |
} |
|
return ; |
} |
|
static void spi_match_master_to_boardinfo(struct spi_master *master, <----+
struct spi_board_info *bi)
{
struct spi_device *dev; if (master->bus_num != bi->bus_num)
return; dev = spi_new_device(master, bi); -----------+
if (!dev) |
dev_err(master->dev.parent, "can't create new device for %s\n", |
bi->modalias); |
} |
|
struct spi_device *spi_new_device(struct spi_master *master, <----------+
struct spi_board_info *chip)
{
struct spi_device *proxy;
int status; /* NOTE: caller did any chip->bus_num checks necessary.
*
* Also, unless we change the return value convention to use
* error-or-pointer (not NULL-or-pointer), troubleshootability
* suggests syslogged diagnostics are best here (ugh).
*/ proxy = spi_alloc_device(master); -------------+
if (!proxy) |
return NULL; |
|
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias)); |
|
proxy->chip_select = chip->chip_select; |
proxy->max_speed_hz = chip->max_speed_hz; |
proxy->mode = chip->mode; |
proxy->irq = chip->irq; |
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); |
proxy->dev.platform_data = (void *) chip->platform_data; |
proxy->controller_data = chip->controller_data; |
proxy->controller_state = NULL; |
|
status = spi_add_device(proxy); ---------------*----------+
if (status < ) { | |
spi_dev_put(proxy); | |
return NULL; | |
} | |
| |
return proxy; | |
} | |
EXPORT_SYMBOL_GPL(spi_new_device); | |
| |
struct spi_device *spi_alloc_device(struct spi_master *master) <------+ |
{ |
struct spi_device *spi; |
struct device *dev = master->dev.parent; |
|
if (!spi_master_get(master)) |
return NULL; |
|
spi = kzalloc(sizeof *spi, GFP_KERNEL); |
if (!spi) { |
dev_err(dev, "cannot alloc spi_device\n"); |
spi_master_put(master); |
return NULL; |
} |
|
spi->master = master; |
spi->dev.parent = &master->dev; |
spi->dev.bus = &spi_bus_type; -----+ |
spi->dev.release = spidev_release; | |
device_initialize(&spi->dev); | |
return spi; | |
} | |
EXPORT_SYMBOL_GPL(spi_alloc_device); | |
| |
struct bus_type spi_bus_type = { <----+ |
.name = "spi", |
.dev_attrs = spi_dev_attrs, |
.match = spi_match_device, ----------------------------------+ |
.uevent = spi_uevent, | |
.pm = &spi_pm, | |
}; | |
EXPORT_SYMBOL_GPL(spi_bus_type); | |
| |
static int spi_match_device(struct device *dev, struct device_driver *drv) <--+ |
{ |
const struct spi_device *spi = to_spi_device(dev); |
const struct spi_driver *sdrv = to_spi_driver(drv); |
|
/* Attempt an OF style match */ |
if (of_driver_match_device(dev, drv)) |
return ; |
|
if (sdrv->id_table) |
return !!spi_match_id(sdrv->id_table, spi); --------------------------+ |
| |
return strcmp(spi->modalias, drv->name) == ; | |
} | |
| |
/** | |
* modalias support makes "modprobe $MODALIAS" new-style hotplug work, | |
* and the sysfs version makes coldplug work too. | |
*/ | |
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, <-+ |
const struct spi_device *sdev) |
{ |
while (id->name[]) { |
if (!strcmp(sdev->modalias, id->name)) // this very important |
return id; // for match driver name |
id++; |
} |
return NULL; |
} |
|
int spi_add_device(struct spi_device *spi) <----------------------------+
{
static DEFINE_MUTEX(spi_add_lock);
struct device *dev = spi->master->dev.parent;
struct device *d;
int status; /* Chipselects are numbered 0..max; validate. */
if (spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
spi->master->num_chipselect);
return -EINVAL;
} /* Set the bus ID string */
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select); /* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
* its configuration. Lock against concurrent add() calls.
*/
mutex_lock(&spi_add_lock); d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));
if (d != NULL) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
put_device(d);
status = -EBUSY;
goto done;
} /* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
status = spi_setup(spi);
if (status < ) {
dev_err(dev, "can't setup %s, status %d\n",
dev_name(&spi->dev), status);
goto done;
} /* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < )
dev_err(dev, "can't add %s, status %d\n",
dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev)); done:
mutex_unlock(&spi_add_lock);
return status;
}
EXPORT_SYMBOL_GPL(spi_add_device); hacking ar1020-spi driver: cat drivers/input/touchscreen/ar1020-spi.c
/* Enable the ar1020_spi_init() to be run by the kernel during initialization */
module_init(ar1020_spi_init); -----------------------+
|
/* Enables the ar1020_spi_exit() to be called during cleanup. This only |
has an effect if the driver is compiled as a kernel module. */ |
module_exit(ar1020_spi_exit); |
|
static int __init ar1020_spi_init(void) <----------------------+
{
int retval; printk("AR1020 SPI: ar1020_spi_init: begin\n");
strcpy(receiveBuffer,"");
strcpy(sendBuffer,""); /*
* Creates a kobject "ar1020" that appears as a sub-directory
* under "/sys/kernel".
*/
ar1020_kobj = kobject_create_and_add("ar1020", kernel_kobj);
if (!ar1020_kobj)
{
printk(KERN_ERR "AR1020 SPI: cannot create kobject\n");
return -ENOMEM;
} /* Create the files associated with this kobject */
retval = sysfs_create_group(ar1020_kobj, &attr_group);
if (retval)
{
printk(KERN_ERR "AR1020 SPI: error registering ar1020-spi driver's sysfs interface\n");
kobject_put(ar1020_kobj);
} return spi_register_driver(&ar1020_spi_driver); --------+
} |
|
static struct spi_driver ar1020_spi_driver = { <-------+
.driver = {
.name = "ar1020-spi",
.bus = &spi_bus_type, -------------------------+
.owner = THIS_MODULE, |
}, |
.probe = ar1020_spi_probe, -------------------------*-+
.remove = ar1020_spi_remove, | |
/* suspend/resume functions not needed since controller automatically | |
put's itself to sleep mode after configurable short period of time */ | |
.suspend = NULL, | |
.resume = NULL, | |
}; | |
| |
struct bus_type spi_bus_type = { <-------------------------+ |
.name = "spi", |
.dev_attrs = spi_dev_attrs, |
.match = spi_match_device, |
.uevent = spi_uevent, |
.pm = &spi_pm, |
}; |
EXPORT_SYMBOL_GPL(spi_bus_type); |
|
static int __devinit ar1020_spi_probe(struct spi_device *client) <-------------+
{
struct ar1020_spi_priv *priv=NULL;
struct input_dev *input_dev=NULL;
int err=;
int i;
int j;
char buff[];
int ret; printk("AR1020 SPI: ar1020_spi_probe: begin\n"); for (i=;i<;i++)
{
buff[i]=;
} if (!client) {
printk(KERN_ERR "AR1020 SPI: client pointer is NULL\n");
err = -EINVAL;
goto error;
} if ((!client->irq) && (touchIRQ == -) && (!testSPIdata) && (!probeForIRQ)) {
printk(KERN_ERR "AR1020 SPI: no IRQ set for touch controller\n");
err = -EINVAL;
goto error;
} priv = kzalloc(sizeof(struct ar1020_spi_priv), GFP_KERNEL);
input_dev = input_allocate_device();
if (!priv) {
printk(KERN_ERR "AR1020 SPI: kzalloc error\n");
err = -ENOMEM;
goto error;
} /* Backup pointer so sysfs helper functions may also have access to private data */
privRef=priv; if (!input_dev)
{
printk(KERN_ERR "AR1020 SPI: input allocate error\n");
err = -ENOMEM;
goto error;
} priv->client = client;
priv->irq = client->irq;
priv->input = input_dev; /* Verify raw SPI data stream to ensure bus is setup correctly in the platform settings. */
if (testSPIdata)
{
printk("AR1020 SPI: In testing mode to verify packet. To inhibit this mode,\n");
printk("unset the \"testSPIdata\" kernel parameter.\n");
while ()
{
msleep();
spi_read(priv->client,&buff[],); if (!(0x80 & buff[]))
{
if ((buff[]!= 0x4d) && (buff[]!=0x00))
{
printk("0x%02x ",buff[]);
}
}
else
{
printk("\n0x%02x ",buff[]);
for (i=;i<;i++)
{
spi_read(priv->client,&buff[i],);
printk("0x%02x ",buff[i]);
}
printk("\n");
} } } /* Detect IRQ id that controller IRQ line is attached to. This detection only works
if the controller's IRQ line is attached to a GPIO line configured as an input.
These lines are often marked as EINT (external interrupt) on the board schematic.
This probe assumes that SPI read communication with the controller is working
correctly.
*/
if (probeForIRQ)
{
printk("AR1020 SPI: Probing for interrupt id.\n");
printk("AR1020 SPI: Please touch screen before IRQ probe for successful detection.\n");
printk("AR1020 SPI: Probing will commence in five seconds.\n\n");
printk("AR1020 SPI: Kernel exception messages may appear during the\n");
printk("AR1020 SPI: probing process.\n"); msleep();
for (i=probeMin;i<probeMax;i++)
{
printk("AR1020 SPI: Testing IRQ %d\n",i);
priv->irq=i; /* set type on new handler and register gpio pin as our interrupt */
//danny modify //set_irq_type(i, IRQ_TYPE_EDGE_RISING);
//err = request_threaded_irq(client->irq, NULL,
// ft5x06_ts_interrupt, IRQF_TRIGGER_FALLING,
// client->dev.driver->name, data); // if (0 >= (ret=request_threaded_irq(i, NULL,
// test_irq_handler_func,IRQF_TRIGGER_RISING, "AR1020 IRQ", priv)))
if ( >= (ret=request_irq(i, test_irq_handler_func,IRQF_TRIGGER_RISING, "AR1020 IRQ", priv)))
{
priv->testCount=; /* read SPI data to ensure IRQ line is not asserted */
for (j=;j<;j++)
{
spi_read(priv->client,&buff[j],);
} msleep();
if (ret>=)
{
free_irq(i, priv);
} /* successful detection if count within this range */
if ((priv->testCount > ) && (priv->testCount < ))
{
printk("AR1020 SPI: Touch IRQ detected at ID: %d.\n",i);
priv->irq=i;
break;
}
}
else
{
printk("AR1020 SPI: IRQ %d not available.\n", i);
}
}
if (i==probeMax)
{
printk("AR1020 SPI: Touch IRQ not detected. Using IRQ %d.\n",priv->irq);
} }
/* Use default settings */
else if (touchIRQ == -)
{
printk("AR1020 SPI: Using IRQ %d set via board's platform setting.\n", priv->irq);
}
else
{
printk("AR1020 SPI: Using IRQ %d set via kernel parameter\n", touchIRQ);
priv->irq=touchIRQ;
} INIT_WORK(&priv->work, ar1020_spi_readdata); --------------------------------------+
|
input_dev->name = "AR1020 Touchscreen"; |
|
input_dev->open = ar1020_spi_open; |
input_dev->close = ar1020_spi_close; |
|
__set_bit(EV_KEY, input_dev->evbit); |
__set_bit(EV_ABS, input_dev->evbit); |
__set_bit(BTN_TOUCH, input_dev->keybit); |
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); |
//-------------add for virtualkeys |
set_bit(EV_SYN, input_dev->evbit); |
set_bit(KEY_HOME, input_dev->keybit); |
//set_bit(KEY_SEARCH, input_dev->keybit); |
set_bit(KEY_BACK, input_dev->keybit); |
set_bit(KEY_MENU, input_dev->keybit); |
|
/* |
// input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
// input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
|
input_set_abs_params(input_dev, ABS_X, 0, 4095, 0, 0); |
input_set_abs_params(input_dev, ABS_Y, 0, 4095, 0, 0); |
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0x7f, 0, 0); |
*/ |
input_set_abs_params(input_dev, ABS_MT_POSITION_X, , |
, , ); |
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, , |
, , ); |
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, , |
, , ); |
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, , 0X7F, , ); |
input_set_abs_params(input_dev, ABS_MT_PRESSURE, , 0x7f, , ); |
|
err = input_register_device(input_dev); |
if (err) |
{ |
printk(KERN_ERR "AR1020 SPI: error registering input device\n"); |
goto error; |
} |
|
for (i=;i<;i++) |
{ |
spi_read(priv->client,&buff[i],); |
} |
|
/* set type and register gpio pin as our interrupt */ |
//danny modify |
//err = request_threaded_irq(client->irq, NULL, |
// ft5x06_ts_interrupt, IRQF_TRIGGER_FALLING, |
// client->dev.driver->name, data); |
//set_irq_type(priv->irq, IRQ_TYPE_EDGE_RISING); |
request_irq(priv->irq, touch_irq_handler_func, IRQF_TRIGGER_RISING, "AR1020 SPI IRQ", priv); |
// request_threaded_irq(priv->irq, NULL, ^----------------------------------+ |
// touch_irq_handler_func, IRQF_TRIGGER_RISING, | |
// "AR1020 SPI IRQ", priv); | |
printk("zengjf AR1020 SPI probe over.\n"); | |
| |
return ; | |
| |
error: | |
| |
if (input_dev) | |
input_free_device(input_dev); | |
| |
if (priv) | |
kfree(priv); | |
| |
return err; | |
| |
return ; | |
} | |
| |
static irqreturn_t touch_irq_handler_func(int irq, void *dev_id) <------------+ |
{ |
struct ar1020_spi_priv *priv = (struct ar1020_spi_priv *)dev_id; |
char buff[]; |
int i; |
int err; |
for (i=;i<;i++) |
{ |
buff[i]=; |
} |
|
printk("<danny debug> ar1020 interrupt up\n"); |
if (!priv) { |
printk(KERN_ERR "AR1020 SPI: touch_irq_handler_funct: no private data\n"); |
err = -EINVAL; |
return err; |
} |
|
/* delegate SPI transactions since hardware interupts need to be handled very fast */ |
schedule_work(&priv->work); |
|
return IRQ_HANDLED; |
} |
|
static void ar1020_spi_readdata(struct work_struct *work) <-----------------------------+
{
struct ar1020_spi_priv *priv =
container_of(work, struct ar1020_spi_priv, work);
int index=;
char buff[];
int ret;
int i; /* We want to ensure we only read packets when we are not in the middle of command communication.
Disable command mode after receiving command response to resume receiving packets. */
if (commandMode)
{
commandDataPending=;
/* process up to 9 bytes */
strcpy(receiveBuffer,""); /* header byte */
spi_read(priv->client,&buff[],);
snprintf(receiveBuffer,sizeof(receiveBuffer),"0x%02x",0xff&buff[]); if (0x55 != buff[])
{
printk("AR1020 SPI: invalid header byte\n");
return;
} /* num data bytes */
spi_read(priv->client,&buff[],);
snprintf(receiveBuffer,sizeof(receiveBuffer),"%s 0x%02x",receiveBuffer,0xff&buff[]);
if (buff[] > )
{
printk("AR1020 SPI: invalid byte count\n");
return;
} for (i=;i<buff[];i++)
{
spi_read(priv->client,&buff[i+],);
snprintf(receiveBuffer,sizeof(receiveBuffer),"%s 0x%02x",receiveBuffer,0xff&buff[i+]);
}
snprintf(receiveBuffer,sizeof(receiveBuffer),"%s\n",receiveBuffer);
printk(KERN_DEBUG "AR1020 SPI: command response: %s",receiveBuffer);
return;
} for (i=;i<;i++)
{
buff[i]=;
} /* process up to 9 bytes */
for (i=;i<;i++)
{
spi_read(priv->client,&buff[index],);
ret=decodeAR1020Packet(priv,buff, &index, buff[index]);
/* if a one is returned, then we have a full packet */
if (==ret)
{
  break;
}
}
}

I.MX6 ar1020 SPI device driver hacking的更多相关文章

  1. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

  2. I.MX6 AD7606-4 device driver registe hacking

    /********************************************************************** * I.MX6 AD7606-4 device driv ...

  3. I.MX6 gpio-keys driver hacking

    /**************************************************************************** * I.MX6 gpio-keys driv ...

  4. I.MX6 bq27441 driver hacking

    /************************************************************************* * I.MX6 bq27441 driver ha ...

  5. I.MX6 Ar8031 device register hacking

    /***************************************************************************** * I.MX6 Ar8031 device ...

  6. I.MX6 PWM buzzer driver hacking with Demo test

    /***************************************************************************** * I.MX6 PWM buzzer dr ...

  7. linux SPI bus demo hacking

    /********************************************************************** * linux SPI bus demo hacking ...

  8. I.MX6 Linux Serial Baud Rate hacking

    /******************************************************************************** * I.MX6 Linux Seri ...

  9. I.MX6 PHY fixup 调用流程 hacking

    /********************************************************************************** * I.MX6 PHY fixu ...

随机推荐

  1. Oracle数据库常见版本

    Oracle数据库常见版本 在Oracle数据库的发展中,数据库一直处于不断升级状态,有以下几个版本: Oracle 8,Oracle 8i:Oracle 8i表示Oracle正式向Internet上 ...

  2. Python -- Scrapy 框架简单介绍(Scrapy 安装及项目创建)

    Python -- Scrapy 框架简单介绍 最近在学习python 爬虫,先后了解学习urllib.urllib2.requests等,后来发现爬虫也有很多框架,而推荐学习最多就是Scrapy框架 ...

  3. PHP访问Oracle数据库

    说明:Oracle数据库帐号:sticOracle数据库密码:sticOracle数据库实例:orclOracle数据库表:UserInfoOracle表的列:ID,Name 不处理异常的代码如下:/ ...

  4. Eclipse 中 SDK无法更新---解决方法

    在SDK Manager -> tools -> options中: HTTP Proxy Server: mirrors.neusoft.edu.cn HTTP Proxy Port: ...

  5. spring boot: spring-data-jpa (Repository/CrudRepository) 数据库操作, @Entity实体类持久化

    SpringBoot实现的JPA封装了JPA的特性, Repository是封装了jpa的特性(我是这么理解的) 1在pom.xml引入mysql, spring-data-jpa依赖 2.在src/ ...

  6. [Java学习] Java继承的概念与实现

    继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似. 继承可以理解为一个类从另一个类获取方法和属性的过程.如果类B继承于类A,那么B就拥有A的方法和属性. ...

  7. AC自动机技巧

    AC自动机技巧 可以用树上的一些算法来进行优化 对于要求支持插入和删除字符串的题目,可以通过建两个AC自动机,查询的时候作差来实现. 当给出的查询串是一个含有空格的文本时,可以用特殊字符(比如'z'+ ...

  8. Change-free CodeForces - 767E (贪心)

    题目链接 大意:Arseny有m个1元硬币, 无限多100元钞票, 他要按顺序买n个东西, 第i天如果找零x个硬币, 他的不满值会加 w[i]*x, 求最少不满值. 若找零, 则硬币增加 100-ci ...

  9. Connecting Vertices CodeForces - 888F (图论,计数)

    链接 大意: 给定邻接表表示两点是否可以连接, 要求将图连成树, 且边不相交的方案数 n范围比较小, 可以直接区间dp $f[l][r]$表示答案, $g[l][r]$表示区间[l,r]全部连通且l, ...

  10. WinForm下的TabControl控件

    一.TabControl控件介绍 TabControl实现的具体效果: 在实际工作中,我是这么用TabControl控件,实现切换页面效果.比如要实现某个界面进行操作,然后还要查看一下日志,就可以使用 ...