/** * xgpiops_irq_mask - Disable the interrupts for a gpio pin * @irq: irq number of gpio pin for which interrupt is to be disabled * * This function calculates gpio pin number from irq number and sets the * bit in the Interrupt Disable register of the corresponding bank to disable * interrupts for that pin. */ static void xgpiops_irq_mask(struct irq_data *irq_data) { struct xgpiops *gpio = (struct xgpiops *)irq_data_get_irq_chip_data(irq_data); unsigned int device_pin_num, bank_num, bank_pin_num; device_pin_num = irq_to_gpio(irq_data->irq); /* get pin num within the device */ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); xgpiops_writereg(1 << bank_pin_num, gpio->base_addr + XGPIOPS_INTDIS_OFFSET(bank_num)); }
/** * xgpiops_probe - Initialization method for a xgpiops device * @pdev: platform device instance * * This function allocates memory resources for the gpio device and registers * all the banks of the device. It will also set up interrupts for the gpio * pins. * Note: Interrupts are disabled for all the banks during initialization. * Returns 0 on success, negative error otherwise. */ static int xgpiops_probe(struct platform_device *pdev) { int ret; unsigned int irq_num; struct xgpiops *gpio; struct gpio_chip *chip; resource_size_t remap_size; struct resource *mem_res = NULL; int pin_num, bank_num, gpio_irq; gpio = kzalloc(sizeof(struct xgpiops), GFP_KERNEL); if (!gpio) { dev_err(&pdev->dev, "couldn't allocate memory for gpio private data\n"); return -ENOMEM; } spin_lock_init(&gpio->gpio_lock); platform_set_drvdata(pdev, gpio); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "No memory resource\n"); ret = -ENODEV; goto err_free_gpio; } remap_size = mem_res->end - mem_res->start + 1; if (!request_mem_region(mem_res->start, remap_size, pdev->name)) { dev_err(&pdev->dev, "Cannot request IO\n"); ret = -ENXIO; goto err_free_gpio; } gpio->base_addr = ioremap(mem_res->start, remap_size); if (gpio->base_addr == NULL) { dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n", (unsigned long)mem_res->start); ret = -ENOMEM; goto err_release_region; } irq_num = platform_get_irq(pdev, 0); gpio->irq = irq_num; /* configure the gpio chip */ chip = &gpio->chip; chip->label = "xgpiops"; chip->owner = THIS_MODULE; chip->dev = &pdev->dev; chip->get = xgpiops_get_value; chip->set = xgpiops_set_value; chip->request = xgpiops_request; chip->free = xgpiops_free; chip->direction_input = xgpiops_dir_in; chip->direction_output = xgpiops_dir_out; chip->to_irq = xgpiops_to_irq; chip->dbg_show = NULL; chip->base = 0; /* default pin base */ chip->ngpio = XGPIOPS_NR_GPIOS; chip->can_sleep = 0; gpio->irq_base = irq_alloc_descs(-1, 0, chip->ngpio, 0); if (gpio->irq_base < 0) { dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); ret = -ENODEV; goto err_iounmap; } irq_domain = irq_domain_add_legacy(pdev->dev.of_node, chip->ngpio, gpio->irq_base, 0, &irq_domain_simple_ops, NULL); /* report a bug if gpio chip registration fails */ ret = gpiochip_add(chip); if (ret < 0) { dev_err(&pdev->dev, "gpio chip registration failed\n"); goto err_iounmap; } else { dev_info(&pdev->dev, "gpio at 0x%08lx mapped to 0x%08lx\n", (unsigned long)mem_res->start, (unsigned long)gpio->base_addr); } /* Enable GPIO clock */ gpio->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(gpio->clk)) { dev_err(&pdev->dev, "input clock not found.\n"); ret = PTR_ERR(gpio->clk); goto err_chip_remove; } ret = clk_prepare_enable(gpio->clk); if (ret) { dev_err(&pdev->dev, "Unable to enable clock.\n"); goto err_clk_put; } /* disable interrupts for all banks */ for (bank_num = 0; bank_num < 4; bank_num++) { xgpiops_writereg(0xffffffff, gpio->base_addr + XGPIOPS_INTDIS_OFFSET(bank_num)); } /* * set the irq chip, handler and irq chip data for callbacks for * each pin */ for (pin_num = 0; pin_num < min_t(int, XGPIOPS_NR_GPIOS, (int)chip->ngpio); pin_num++) { gpio_irq = irq_find_mapping(irq_domain, pin_num); irq_set_chip_and_handler(gpio_irq, &xgpiops_irqchip, handle_simple_irq); irq_set_chip_data(gpio_irq, (void *)gpio); set_irq_flags(gpio_irq, IRQF_VALID); } irq_set_handler_data(irq_num, (void *)gpio); irq_set_chained_handler(irq_num, xgpiops_irqhandler); xgpiops_pm_runtime_init(pdev); device_set_wakeup_capable(&pdev->dev, 1); return 0; err_clk_put: clk_put(gpio->clk); err_chip_remove: gpiochip_remove(chip); err_iounmap: iounmap(gpio->base_addr); err_release_region: release_mem_region(mem_res->start, remap_size); err_free_gpio: platform_set_drvdata(pdev, NULL); kfree(gpio); return ret; }