| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Emma Mobile GPIO Support - GIO |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012 Magnus Damm |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program; if not, write to the Free Software |
|---|
| 17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | 6 | */ |
|---|
| 19 | 7 | |
|---|
| 20 | 8 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 271 | 259 | .xlate = irq_domain_xlate_twocell, |
|---|
| 272 | 260 | }; |
|---|
| 273 | 261 | |
|---|
| 262 | +static void em_gio_irq_domain_remove(void *data) |
|---|
| 263 | +{ |
|---|
| 264 | + struct irq_domain *domain = data; |
|---|
| 265 | + |
|---|
| 266 | + irq_domain_remove(domain); |
|---|
| 267 | +} |
|---|
| 268 | + |
|---|
| 274 | 269 | static int em_gio_probe(struct platform_device *pdev) |
|---|
| 275 | 270 | { |
|---|
| 276 | 271 | struct em_gio_priv *p; |
|---|
| 277 | | - struct resource *io[2], *irq[2]; |
|---|
| 278 | 272 | struct gpio_chip *gpio_chip; |
|---|
| 279 | 273 | struct irq_chip *irq_chip; |
|---|
| 280 | | - const char *name = dev_name(&pdev->dev); |
|---|
| 274 | + struct device *dev = &pdev->dev; |
|---|
| 275 | + const char *name = dev_name(dev); |
|---|
| 281 | 276 | unsigned int ngpios; |
|---|
| 282 | | - int ret; |
|---|
| 277 | + int irq[2], ret; |
|---|
| 283 | 278 | |
|---|
| 284 | | - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); |
|---|
| 285 | | - if (!p) { |
|---|
| 286 | | - ret = -ENOMEM; |
|---|
| 287 | | - goto err0; |
|---|
| 288 | | - } |
|---|
| 279 | + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); |
|---|
| 280 | + if (!p) |
|---|
| 281 | + return -ENOMEM; |
|---|
| 289 | 282 | |
|---|
| 290 | 283 | p->pdev = pdev; |
|---|
| 291 | 284 | platform_set_drvdata(pdev, p); |
|---|
| 292 | 285 | spin_lock_init(&p->sense_lock); |
|---|
| 293 | 286 | |
|---|
| 294 | | - io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 295 | | - io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
|---|
| 296 | | - irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
|---|
| 297 | | - irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); |
|---|
| 287 | + irq[0] = platform_get_irq(pdev, 0); |
|---|
| 288 | + if (irq[0] < 0) |
|---|
| 289 | + return irq[0]; |
|---|
| 298 | 290 | |
|---|
| 299 | | - if (!io[0] || !io[1] || !irq[0] || !irq[1]) { |
|---|
| 300 | | - dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); |
|---|
| 301 | | - ret = -EINVAL; |
|---|
| 302 | | - goto err0; |
|---|
| 303 | | - } |
|---|
| 291 | + irq[1] = platform_get_irq(pdev, 1); |
|---|
| 292 | + if (irq[1] < 0) |
|---|
| 293 | + return irq[1]; |
|---|
| 304 | 294 | |
|---|
| 305 | | - p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start, |
|---|
| 306 | | - resource_size(io[0])); |
|---|
| 307 | | - if (!p->base0) { |
|---|
| 308 | | - dev_err(&pdev->dev, "failed to remap low I/O memory\n"); |
|---|
| 309 | | - ret = -ENXIO; |
|---|
| 310 | | - goto err0; |
|---|
| 311 | | - } |
|---|
| 295 | + p->base0 = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 296 | + if (IS_ERR(p->base0)) |
|---|
| 297 | + return PTR_ERR(p->base0); |
|---|
| 312 | 298 | |
|---|
| 313 | | - p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start, |
|---|
| 314 | | - resource_size(io[1])); |
|---|
| 315 | | - if (!p->base1) { |
|---|
| 316 | | - dev_err(&pdev->dev, "failed to remap high I/O memory\n"); |
|---|
| 317 | | - ret = -ENXIO; |
|---|
| 318 | | - goto err0; |
|---|
| 319 | | - } |
|---|
| 299 | + p->base1 = devm_platform_ioremap_resource(pdev, 1); |
|---|
| 300 | + if (IS_ERR(p->base1)) |
|---|
| 301 | + return PTR_ERR(p->base1); |
|---|
| 320 | 302 | |
|---|
| 321 | | - if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { |
|---|
| 322 | | - dev_err(&pdev->dev, "Missing ngpios OF property\n"); |
|---|
| 323 | | - ret = -EINVAL; |
|---|
| 324 | | - goto err0; |
|---|
| 303 | + if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { |
|---|
| 304 | + dev_err(dev, "Missing ngpios OF property\n"); |
|---|
| 305 | + return -EINVAL; |
|---|
| 325 | 306 | } |
|---|
| 326 | 307 | |
|---|
| 327 | 308 | gpio_chip = &p->gpio_chip; |
|---|
| 328 | | - gpio_chip->of_node = pdev->dev.of_node; |
|---|
| 309 | + gpio_chip->of_node = dev->of_node; |
|---|
| 329 | 310 | gpio_chip->direction_input = em_gio_direction_input; |
|---|
| 330 | 311 | gpio_chip->get = em_gio_get; |
|---|
| 331 | 312 | gpio_chip->direction_output = em_gio_direction_output; |
|---|
| .. | .. |
|---|
| 334 | 315 | gpio_chip->request = em_gio_request; |
|---|
| 335 | 316 | gpio_chip->free = em_gio_free; |
|---|
| 336 | 317 | gpio_chip->label = name; |
|---|
| 337 | | - gpio_chip->parent = &pdev->dev; |
|---|
| 318 | + gpio_chip->parent = dev; |
|---|
| 338 | 319 | gpio_chip->owner = THIS_MODULE; |
|---|
| 339 | 320 | gpio_chip->base = -1; |
|---|
| 340 | 321 | gpio_chip->ngpio = ngpios; |
|---|
| 341 | 322 | |
|---|
| 342 | 323 | irq_chip = &p->irq_chip; |
|---|
| 343 | | - irq_chip->name = name; |
|---|
| 324 | + irq_chip->name = "gpio-em"; |
|---|
| 344 | 325 | irq_chip->irq_mask = em_gio_irq_disable; |
|---|
| 345 | 326 | irq_chip->irq_unmask = em_gio_irq_enable; |
|---|
| 346 | 327 | irq_chip->irq_set_type = em_gio_irq_set_type; |
|---|
| .. | .. |
|---|
| 348 | 329 | irq_chip->irq_release_resources = em_gio_irq_relres; |
|---|
| 349 | 330 | irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; |
|---|
| 350 | 331 | |
|---|
| 351 | | - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, |
|---|
| 332 | + p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0, |
|---|
| 352 | 333 | &em_gio_irq_domain_ops, p); |
|---|
| 353 | 334 | if (!p->irq_domain) { |
|---|
| 354 | | - ret = -ENXIO; |
|---|
| 355 | | - dev_err(&pdev->dev, "cannot initialize irq domain\n"); |
|---|
| 356 | | - goto err0; |
|---|
| 335 | + dev_err(dev, "cannot initialize irq domain\n"); |
|---|
| 336 | + return -ENXIO; |
|---|
| 357 | 337 | } |
|---|
| 358 | 338 | |
|---|
| 359 | | - if (devm_request_irq(&pdev->dev, irq[0]->start, |
|---|
| 360 | | - em_gio_irq_handler, 0, name, p)) { |
|---|
| 361 | | - dev_err(&pdev->dev, "failed to request low IRQ\n"); |
|---|
| 362 | | - ret = -ENOENT; |
|---|
| 363 | | - goto err1; |
|---|
| 339 | + ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove, |
|---|
| 340 | + p->irq_domain); |
|---|
| 341 | + if (ret) |
|---|
| 342 | + return ret; |
|---|
| 343 | + |
|---|
| 344 | + if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) { |
|---|
| 345 | + dev_err(dev, "failed to request low IRQ\n"); |
|---|
| 346 | + return -ENOENT; |
|---|
| 364 | 347 | } |
|---|
| 365 | 348 | |
|---|
| 366 | | - if (devm_request_irq(&pdev->dev, irq[1]->start, |
|---|
| 367 | | - em_gio_irq_handler, 0, name, p)) { |
|---|
| 368 | | - dev_err(&pdev->dev, "failed to request high IRQ\n"); |
|---|
| 369 | | - ret = -ENOENT; |
|---|
| 370 | | - goto err1; |
|---|
| 349 | + if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) { |
|---|
| 350 | + dev_err(dev, "failed to request high IRQ\n"); |
|---|
| 351 | + return -ENOENT; |
|---|
| 371 | 352 | } |
|---|
| 372 | 353 | |
|---|
| 373 | | - ret = gpiochip_add_data(gpio_chip, p); |
|---|
| 354 | + ret = devm_gpiochip_add_data(dev, gpio_chip, p); |
|---|
| 374 | 355 | if (ret) { |
|---|
| 375 | | - dev_err(&pdev->dev, "failed to add GPIO controller\n"); |
|---|
| 376 | | - goto err1; |
|---|
| 356 | + dev_err(dev, "failed to add GPIO controller\n"); |
|---|
| 357 | + return ret; |
|---|
| 377 | 358 | } |
|---|
| 378 | 359 | |
|---|
| 379 | | - return 0; |
|---|
| 380 | | - |
|---|
| 381 | | -err1: |
|---|
| 382 | | - irq_domain_remove(p->irq_domain); |
|---|
| 383 | | -err0: |
|---|
| 384 | | - return ret; |
|---|
| 385 | | -} |
|---|
| 386 | | - |
|---|
| 387 | | -static int em_gio_remove(struct platform_device *pdev) |
|---|
| 388 | | -{ |
|---|
| 389 | | - struct em_gio_priv *p = platform_get_drvdata(pdev); |
|---|
| 390 | | - |
|---|
| 391 | | - gpiochip_remove(&p->gpio_chip); |
|---|
| 392 | | - |
|---|
| 393 | | - irq_domain_remove(p->irq_domain); |
|---|
| 394 | 360 | return 0; |
|---|
| 395 | 361 | } |
|---|
| 396 | 362 | |
|---|
| .. | .. |
|---|
| 402 | 368 | |
|---|
| 403 | 369 | static struct platform_driver em_gio_device_driver = { |
|---|
| 404 | 370 | .probe = em_gio_probe, |
|---|
| 405 | | - .remove = em_gio_remove, |
|---|
| 406 | 371 | .driver = { |
|---|
| 407 | 372 | .name = "em_gio", |
|---|
| 408 | 373 | .of_match_table = em_gio_dt_ids, |
|---|