in gpio-htc-egpio.c [263:365]
static int __init egpio_probe(struct platform_device *pdev)
{
struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct resource *res;
struct egpio_info *ei;
struct gpio_chip *chip;
unsigned int irq, irq_end;
int i;
/* Initialize ei data structure. */
ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
if (!ei)
return -ENOMEM;
spin_lock_init(&ei->lock);
/* Find chained irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res)
ei->chained_irq = res->start;
/* Map egpio chip into virtual address space. */
ei->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ei->base_addr))
return PTR_ERR(ei->base_addr);
if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
return -EINVAL;
ei->bus_shift = fls(pdata->bus_width - 1) - 3;
pr_debug("bus_shift = %d\n", ei->bus_shift);
if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
return -EINVAL;
ei->reg_shift = fls(pdata->reg_width - 1);
pr_debug("reg_shift = %d\n", ei->reg_shift);
ei->reg_mask = (1 << pdata->reg_width) - 1;
platform_set_drvdata(pdev, ei);
ei->nchips = pdata->num_chips;
ei->chip = devm_kcalloc(&pdev->dev,
ei->nchips, sizeof(struct egpio_chip),
GFP_KERNEL);
if (!ei->chip)
return -ENOMEM;
for (i = 0; i < ei->nchips; i++) {
ei->chip[i].reg_start = pdata->chip[i].reg_start;
ei->chip[i].cached_values = pdata->chip[i].initial_values;
ei->chip[i].is_out = pdata->chip[i].direction;
ei->chip[i].dev = &(pdev->dev);
chip = &(ei->chip[i].chip);
chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"htc-egpio-%d",
i);
if (!chip->label)
return -ENOMEM;
chip->parent = &pdev->dev;
chip->owner = THIS_MODULE;
chip->get = egpio_get;
chip->set = egpio_set;
chip->direction_input = egpio_direction_input;
chip->direction_output = egpio_direction_output;
chip->get_direction = egpio_get_direction;
chip->base = pdata->chip[i].gpio_base;
chip->ngpio = pdata->chip[i].num_gpios;
gpiochip_add_data(chip, &ei->chip[i]);
}
/* Set initial pin values */
egpio_write_cache(ei);
ei->irq_start = pdata->irq_base;
ei->nirqs = pdata->num_irqs;
ei->ack_register = pdata->ack_register;
if (ei->chained_irq) {
/* Setup irq handlers */
ei->ack_write = 0xFFFF;
if (pdata->invert_acks)
ei->ack_write = 0;
irq_end = ei->irq_start + ei->nirqs;
for (irq = ei->irq_start; irq < irq_end; irq++) {
irq_set_chip_and_handler(irq, &egpio_muxed_chip,
handle_simple_irq);
irq_set_chip_data(irq, ei);
irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
}
irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
irq_set_chained_handler_and_data(ei->chained_irq,
egpio_handler, ei);
ack_irqs(ei);
device_init_wakeup(&pdev->dev, 1);
}
return 0;
}