/************************************************************************************
* 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. MAC下安装npm和node

    Step1: 在官网下载适合mac的版本的nodejs,官网地址https://nodejs.org/en/ Step2: 上述方法我试了,但是不管用.安装完毕且重启均不能显示我安装的版本.哭 下面重 ...

  2. cookie(2)

    转载,原文地址 https://segmentfault.com/a/1190000004743454 一.引言 随着浏览器的处理能力不断增强,越来越多的网站开始考虑将数据存储在「客户端」,那就不得不 ...

  3. 字符集(编码)转换_Qt532_QString

    1.网上的资料: 1.1.参考网址:http://blog.csdn.net/changsheng230/article/details/6588447 1.2.网页内容: “ Qt 使用Unicod ...

  4. string 和 wstring

    区别: char* wchar_t 一个字节 两个字节 ACSII编码 unicode编码 转换: 1.Windows API WideCharToMultiByte() MultiByteToWid ...

  5. Android中的JSON详细总结

    1.JSON(JavaScript Object Notation) 定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式, ...

  6. Codeforces 847B - Preparing for Merge Sort

    847B - Preparing for Merge Sort 思路:前面的排序的最后一个一定大于后面的排序的最后一个.所以判断要不要开始新的排序只要拿当前值和上一个排序最后一个比较就可以了. 代码: ...

  7. 雷林鹏分享:C# 集合(Collection)

    C# 集合(Collection) 集合(Collection)类是专门用于数据存储和检索的类.这些类提供了对栈(stack).队列(queue).列表(list)和哈希表(hash table)的支 ...

  8. 利用Py-Socket模块做的一个不登陆windows服务器自动实现替换或者调用自动拨号功能

    xu言: 最近,有个朋友让我帮忙“搞点事情”,然后正好在学习socket模块,这个模块666啊,基本上可以实现远程服务器cmd shell的大部分功能.好,话不多说,直接上码~ 由于很多电信运营商都会 ...

  9. English trip -- Phonics 1 ar

    Xu言: Learning is not a happy thing, but happiness always comes with learning...    - loki.valentine ...

  10. 12月16日 增加一个购物车内product数量的功能, 自定义method,在helper中定义,计算代码Refactor到Model中。

    仿照Rails实战:购物网站 教材:5-6 step5:计算总价,做出在nav上显示购物车内product的数量. 遇到的❌: 1. <% sum = 0 %> <% current ...