summaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2018-05-14 16:15:36 -0400
committerOlof Johansson <olof@lixom.net>2018-05-14 16:15:36 -0400
commit8b26d801cfc35448331afc40ebdb406a1730220e (patch)
treeaeef7f00b11122c5c9034e23b85dbf0d6ce838d7 /drivers/bus
parent7a0b8610d3243fe4fc2422f5e4658676c3d9c6ab (diff)
parentadf3457b4ce6940885be3e5ee832c6949fba4166 (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/Kconfig1
-rw-r--r--drivers/bus/hisi_lpc.c159
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
347struct 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
353static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, 344static 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
446static 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
452struct 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 */
464static int hisi_lpc_acpi_probe(struct device *hostdev) 469static 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
558fail:
559 device_for_each_child(hostdev, NULL,
560 hisi_lpc_acpi_remove_subdev);
561 return ret;
527} 562}
528 563
529static const struct acpi_device_id hisi_lpc_acpi_match[] = { 564static const struct acpi_device_id hisi_lpc_acpi_match[] = {