/************************************************************************************
* 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. Windows 上安装 MySQL

    Windows 上安装 MySQL https://www.mysql.com/downloads/ 1.下载MySQL安装包(官网下载链接): 选择 DOWNLOADS ——> Communi ...

  2. vue饿了么学习笔记(1)vue-cli开启项目

    一.vue-cli介绍 vue-cli是vue的脚手架工具 ---->  帮助写好vue.js基础代码的工具: ① 搭建目录结构 ② 进行本地调试 ③ 进行代码部署 ④ 热加载 ⑤ 进行单元测试 ...

  3. 【转】float类型在内存中的表示

    http://www.cnblogs.com/onedime/archive/2012/11/19/2778130.html http://blog.csdn.net/adream307/articl ...

  4. STL_算法_中使用的函数对象

    写在前面: STL算法中的 函数对象的功能: (1).都是提供一种比较的函数,比较相邻的左右两个值的 相等/大小 等的关系, (2).返回值都是bool :该返回值 貌似是指明 遍历元素是否还要继续往 ...

  5. c++ primer plus 第二章 课后题答案

    #include<iostream> using namespace std; int main() { cout << "My name is Jiantong C ...

  6. 动态规划-Largest Sum of Averages

    2018-07-12 23:21:53 问题描述: 问题求解: dp[i][j] : 以ai结尾的分j个部分得到的最大值 dp[i][j] = max{dp[k][j - 1] + (ak+1 + . ...

  7. Python 爬虫-获得大学排名

    2017-07-29 23:20:24 主要技术路线:requests+bs4+格式化输出 import requests from bs4 import BeautifulSoup url = 'h ...

  8. Redis之列表类型命令

    Redis 列表(List) Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边) 一个列表最多可以包含 232 - 1 个元素 (4294967 ...

  9. 配置rsync 同步数据 rpm包安装rsync及配置

    [root@Hammer home]# rpm -qa |grep rsync #检查系统是否安装了rsync软件包rsync-2.6.8-3.1[root@Hammer CentOS]# rpm - ...

  10. 【转】ArcGIS API for Silverlight/WPF 2.1学习笔记(四)

      七.Editing ArcGIS Server 10提供了: 通过feature service,在Web上编辑Feature layers的geographic data的功能. 通过geome ...