diff options
author | Olof Johansson <olof@lixom.net> | 2018-05-14 16:15:36 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2018-05-14 16:15:36 -0400 |
commit | 8b26d801cfc35448331afc40ebdb406a1730220e (patch) | |
tree | aeef7f00b11122c5c9034e23b85dbf0d6ce838d7 /drivers/bus | |
parent | 7a0b8610d3243fe4fc2422f5e4658676c3d9c6ab (diff) | |
parent | adf3457b4ce6940885be3e5ee832c6949fba4166 (diff) |
Merge tag 'hisi-drivers-for-4.18' of git://github.com/hisilicon/linux-hisi into next/drivers
ARM64: hisi: SoC driver updates for 4.18
- Update hisi LPC bus driver to use the platform driver APIs
other than the MFD APIs to support connected device like UART
* tag 'hisi-drivers-for-4.18' of git://github.com/hisilicon/linux-hisi:
HISI LPC: Add ACPI UART support
HISI LPC: Re-Add ACPI child enumeration support
HISI LPC: Stop using MFD APIs
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/Kconfig | 1 | ||||
-rw-r--r-- | drivers/bus/hisi_lpc.c | 159 |
2 files changed, 97 insertions, 63 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 6dc177bf4c42..d1c0b60e9326 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -33,7 +33,6 @@ config HISILICON_LPC | |||
33 | bool "Support for ISA I/O space on HiSilicon Hip06/7" | 33 | bool "Support for ISA I/O space on HiSilicon Hip06/7" |
34 | depends on ARM64 && (ARCH_HISI || COMPILE_TEST) | 34 | depends on ARM64 && (ARCH_HISI || COMPILE_TEST) |
35 | select INDIRECT_PIO | 35 | select INDIRECT_PIO |
36 | select MFD_CORE if ACPI | ||
37 | help | 36 | help |
38 | Driver to enable I/O access to devices attached to the Low Pin | 37 | Driver to enable I/O access to devices attached to the Low Pin |
39 | Count bus on the HiSilicon Hip06/7 SoC. | 38 | Count bus on the HiSilicon Hip06/7 SoC. |
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 2d4611e4c339..d5f85455fa62 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c | |||
@@ -11,12 +11,12 @@ | |||
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/logic_pio.h> | 13 | #include <linux/logic_pio.h> |
14 | #include <linux/mfd/core.h> | ||
15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
16 | #include <linux/of.h> | 15 | #include <linux/of.h> |
17 | #include <linux/of_address.h> | 16 | #include <linux/of_address.h> |
18 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
19 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/serial_8250.h> | ||
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | 21 | ||
22 | #define DRV_NAME "hisi-lpc" | 22 | #define DRV_NAME "hisi-lpc" |
@@ -341,15 +341,6 @@ static const struct logic_pio_host_ops hisi_lpc_ops = { | |||
341 | }; | 341 | }; |
342 | 342 | ||
343 | #ifdef CONFIG_ACPI | 343 | #ifdef CONFIG_ACPI |
344 | #define MFD_CHILD_NAME_PREFIX DRV_NAME"-" | ||
345 | #define MFD_CHILD_NAME_LEN (ACPI_ID_LEN + sizeof(MFD_CHILD_NAME_PREFIX) - 1) | ||
346 | |||
347 | struct hisi_lpc_mfd_cell { | ||
348 | struct mfd_cell_acpi_match acpi_match; | ||
349 | char name[MFD_CHILD_NAME_LEN]; | ||
350 | char pnpid[ACPI_ID_LEN]; | ||
351 | }; | ||
352 | |||
353 | static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, | 344 | static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, |
354 | struct acpi_device *host, | 345 | struct acpi_device *host, |
355 | struct resource *res) | 346 | struct resource *res) |
@@ -368,7 +359,7 @@ static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, | |||
368 | } | 359 | } |
369 | 360 | ||
370 | /* | 361 | /* |
371 | * hisi_lpc_acpi_set_io_res - set the resources for a child's MFD | 362 | * hisi_lpc_acpi_set_io_res - set the resources for a child |
372 | * @child: the device node to be updated the I/O resource | 363 | * @child: the device node to be updated the I/O resource |
373 | * @hostdev: the device node associated with host controller | 364 | * @hostdev: the device node associated with host controller |
374 | * @res: double pointer to be set to the address of translated resources | 365 | * @res: double pointer to be set to the address of translated resources |
@@ -452,78 +443,122 @@ static int hisi_lpc_acpi_set_io_res(struct device *child, | |||
452 | return 0; | 443 | return 0; |
453 | } | 444 | } |
454 | 445 | ||
446 | static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused) | ||
447 | { | ||
448 | platform_device_unregister(to_platform_device(dev)); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | struct hisi_lpc_acpi_cell { | ||
453 | const char *hid; | ||
454 | const char *name; | ||
455 | void *pdata; | ||
456 | size_t pdata_size; | ||
457 | }; | ||
458 | |||
455 | /* | 459 | /* |
456 | * hisi_lpc_acpi_probe - probe children for ACPI FW | 460 | * hisi_lpc_acpi_probe - probe children for ACPI FW |
457 | * @hostdev: LPC host device pointer | 461 | * @hostdev: LPC host device pointer |
458 | * | 462 | * |
459 | * Returns 0 when successful, and a negative value for failure. | 463 | * Returns 0 when successful, and a negative value for failure. |
460 | * | 464 | * |
461 | * Scan all child devices and create a per-device MFD with | 465 | * Create a platform device per child, fixing up the resources |
462 | * logical PIO translated IO resources. | 466 | * from bus addresses to Logical PIO addresses. |
467 | * | ||
463 | */ | 468 | */ |
464 | static int hisi_lpc_acpi_probe(struct device *hostdev) | 469 | static int hisi_lpc_acpi_probe(struct device *hostdev) |
465 | { | 470 | { |
466 | struct acpi_device *adev = ACPI_COMPANION(hostdev); | 471 | struct acpi_device *adev = ACPI_COMPANION(hostdev); |
467 | struct hisi_lpc_mfd_cell *hisi_lpc_mfd_cells; | ||
468 | struct mfd_cell *mfd_cells; | ||
469 | struct acpi_device *child; | 472 | struct acpi_device *child; |
470 | int size, ret, count = 0, cell_num = 0; | 473 | int ret; |
471 | |||
472 | list_for_each_entry(child, &adev->children, node) | ||
473 | cell_num++; | ||
474 | |||
475 | /* allocate the mfd cell and companion ACPI info, one per child */ | ||
476 | size = sizeof(*mfd_cells) + sizeof(*hisi_lpc_mfd_cells); | ||
477 | mfd_cells = devm_kcalloc(hostdev, cell_num, size, GFP_KERNEL); | ||
478 | if (!mfd_cells) | ||
479 | return -ENOMEM; | ||
480 | 474 | ||
481 | hisi_lpc_mfd_cells = (struct hisi_lpc_mfd_cell *)&mfd_cells[cell_num]; | ||
482 | /* Only consider the children of the host */ | 475 | /* Only consider the children of the host */ |
483 | list_for_each_entry(child, &adev->children, node) { | 476 | list_for_each_entry(child, &adev->children, node) { |
484 | struct mfd_cell *mfd_cell = &mfd_cells[count]; | 477 | const char *hid = acpi_device_hid(child); |
485 | struct hisi_lpc_mfd_cell *hisi_lpc_mfd_cell = | 478 | const struct hisi_lpc_acpi_cell *cell; |
486 | &hisi_lpc_mfd_cells[count]; | 479 | struct platform_device *pdev; |
487 | struct mfd_cell_acpi_match *acpi_match = | 480 | const struct resource *res; |
488 | &hisi_lpc_mfd_cell->acpi_match; | 481 | bool found = false; |
489 | char *name = hisi_lpc_mfd_cell[count].name; | 482 | int num_res; |
490 | char *pnpid = hisi_lpc_mfd_cell[count].pnpid; | 483 | |
491 | struct mfd_cell_acpi_match match = { | 484 | ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res, |
492 | .pnpid = pnpid, | 485 | &num_res); |
486 | if (ret) { | ||
487 | dev_warn(hostdev, "set resource fail (%d)\n", ret); | ||
488 | goto fail; | ||
489 | } | ||
490 | |||
491 | cell = (struct hisi_lpc_acpi_cell []){ | ||
492 | /* ipmi */ | ||
493 | { | ||
494 | .hid = "IPI0001", | ||
495 | .name = "hisi-lpc-ipmi", | ||
496 | }, | ||
497 | /* 8250-compatible uart */ | ||
498 | { | ||
499 | .hid = "HISI1031", | ||
500 | .name = "serial8250", | ||
501 | .pdata = (struct plat_serial8250_port []) { | ||
502 | { | ||
503 | .iobase = res->start, | ||
504 | .uartclk = 1843200, | ||
505 | .iotype = UPIO_PORT, | ||
506 | .flags = UPF_BOOT_AUTOCONF, | ||
507 | }, | ||
508 | {} | ||
509 | }, | ||
510 | .pdata_size = 2 * | ||
511 | sizeof(struct plat_serial8250_port), | ||
512 | }, | ||
513 | {} | ||
493 | }; | 514 | }; |
494 | 515 | ||
495 | /* | 516 | for (; cell && cell->name; cell++) { |
496 | * For any instances of this host controller (Hip06 and Hip07 | 517 | if (!strcmp(cell->hid, hid)) { |
497 | * are the only chipsets), we would not have multiple slaves | 518 | found = true; |
498 | * with the same HID. And in any system we would have just one | 519 | break; |
499 | * controller active. So don't worrry about MFD name clashes. | 520 | } |
500 | */ | ||
501 | snprintf(name, MFD_CHILD_NAME_LEN, MFD_CHILD_NAME_PREFIX"%s", | ||
502 | acpi_device_hid(child)); | ||
503 | snprintf(pnpid, ACPI_ID_LEN, "%s", acpi_device_hid(child)); | ||
504 | |||
505 | memcpy(acpi_match, &match, sizeof(*acpi_match)); | ||
506 | mfd_cell->name = name; | ||
507 | mfd_cell->acpi_match = acpi_match; | ||
508 | |||
509 | ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, | ||
510 | &mfd_cell->resources, | ||
511 | &mfd_cell->num_resources); | ||
512 | if (ret) { | ||
513 | dev_warn(&child->dev, "set resource fail (%d)\n", ret); | ||
514 | return ret; | ||
515 | } | 521 | } |
516 | count++; | ||
517 | } | ||
518 | 522 | ||
519 | ret = mfd_add_devices(hostdev, PLATFORM_DEVID_NONE, | 523 | if (!found) { |
520 | mfd_cells, cell_num, NULL, 0, NULL); | 524 | dev_warn(hostdev, |
521 | if (ret) { | 525 | "could not find cell for child device (%s)\n", |
522 | dev_err(hostdev, "failed to add mfd cells (%d)\n", ret); | 526 | hid); |
523 | return ret; | 527 | ret = -ENODEV; |
528 | goto fail; | ||
529 | } | ||
530 | |||
531 | pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO); | ||
532 | if (!pdev) { | ||
533 | ret = -ENOMEM; | ||
534 | goto fail; | ||
535 | } | ||
536 | |||
537 | pdev->dev.parent = hostdev; | ||
538 | ACPI_COMPANION_SET(&pdev->dev, child); | ||
539 | |||
540 | ret = platform_device_add_resources(pdev, res, num_res); | ||
541 | if (ret) | ||
542 | goto fail; | ||
543 | |||
544 | ret = platform_device_add_data(pdev, cell->pdata, | ||
545 | cell->pdata_size); | ||
546 | if (ret) | ||
547 | goto fail; | ||
548 | |||
549 | ret = platform_device_add(pdev); | ||
550 | if (ret) | ||
551 | goto fail; | ||
552 | |||
553 | acpi_device_set_enumerated(child); | ||
524 | } | 554 | } |
525 | 555 | ||
526 | return 0; | 556 | return 0; |
557 | |||
558 | fail: | ||
559 | device_for_each_child(hostdev, NULL, | ||
560 | hisi_lpc_acpi_remove_subdev); | ||
561 | return ret; | ||
527 | } | 562 | } |
528 | 563 | ||
529 | static const struct acpi_device_id hisi_lpc_acpi_match[] = { | 564 | static const struct acpi_device_id hisi_lpc_acpi_match[] = { |