linux/drivers/bus/hisi_lpc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
   4 * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
   5 * Author: Zou Rongrong <zourongrong@huawei.com>
   6 * Author: John Garry <john.garry@huawei.com>
   7 */
   8
   9#include <linux/acpi.h>
  10#include <linux/console.h>
  11#include <linux/delay.h>
  12#include <linux/io.h>
  13#include <linux/logic_pio.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/of_address.h>
  17#include <linux/of_platform.h>
  18#include <linux/pci.h>
  19#include <linux/serial_8250.h>
  20#include <linux/slab.h>
  21
  22#define DRV_NAME "hisi-lpc"
  23
  24/*
  25 * Setting this bit means each IO operation will target a different port
  26 * address; 0 means repeated IO operations will use the same port,
  27 * such as BT.
  28 */
  29#define FG_INCRADDR_LPC         0x02
  30
  31struct lpc_cycle_para {
  32        unsigned int opflags;
  33        unsigned int csize; /* data length of each operation */
  34};
  35
  36struct hisi_lpc_dev {
  37        spinlock_t cycle_lock;
  38        void __iomem  *membase;
  39        struct logic_pio_hwaddr *io_host;
  40};
  41
  42/* The max IO cycle counts supported is four per operation at maximum */
  43#define LPC_MAX_DWIDTH  4
  44
  45#define LPC_REG_STARTUP_SIGNAL          0x00
  46#define LPC_REG_STARTUP_SIGNAL_START    BIT(0)
  47#define LPC_REG_OP_STATUS               0x04
  48#define LPC_REG_OP_STATUS_IDLE          BIT(0)
  49#define LPC_REG_OP_STATUS_FINISHED      BIT(1)
  50#define LPC_REG_OP_LEN                  0x10 /* LPC cycles count per start */
  51#define LPC_REG_CMD                     0x14
  52#define LPC_REG_CMD_OP                  BIT(0) /* 0: read, 1: write */
  53#define LPC_REG_CMD_SAMEADDR            BIT(3)
  54#define LPC_REG_ADDR                    0x20 /* target address */
  55#define LPC_REG_WDATA                   0x24 /* write FIFO */
  56#define LPC_REG_RDATA                   0x28 /* read FIFO */
  57
  58/* The minimal nanosecond interval for each query on LPC cycle status */
  59#define LPC_NSEC_PERWAIT        100
  60
  61/*
  62 * The maximum waiting time is about 128us.  It is specific for stream I/O,
  63 * such as ins.
  64 *
  65 * The fastest IO cycle time is about 390ns, but the worst case will wait
  66 * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum burst
  67 * cycles is 16. So, the maximum waiting time is about 128us under worst
  68 * case.
  69 *
  70 * Choose 1300 as the maximum.
  71 */
  72#define LPC_MAX_WAITCNT         1300
  73
  74/* About 10us. This is specific for single IO operations, such as inb */
  75#define LPC_PEROP_WAITCNT       100
  76
  77static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt)
  78{
  79        u32 status;
  80
  81        do {
  82                status = readl(mbase + LPC_REG_OP_STATUS);
  83                if (status & LPC_REG_OP_STATUS_IDLE)
  84                        return (status & LPC_REG_OP_STATUS_FINISHED) ? 0 : -EIO;
  85                ndelay(LPC_NSEC_PERWAIT);
  86        } while (--waitcnt);
  87
  88        return -ETIME;
  89}
  90
  91/*
  92 * hisi_lpc_target_in - trigger a series of LPC cycles for read operation
  93 * @lpcdev: pointer to hisi lpc device
  94 * @para: some parameters used to control the lpc I/O operations
  95 * @addr: the lpc I/O target port address
  96 * @buf: where the read back data is stored
  97 * @opcnt: how many I/O operations required, i.e. data width
  98 *
  99 * Returns 0 on success, non-zero on fail.
 100 */
 101static int hisi_lpc_target_in(struct hisi_lpc_dev *lpcdev,
 102                              struct lpc_cycle_para *para, unsigned long addr,
 103                              unsigned char *buf, unsigned long opcnt)
 104{
 105        unsigned int cmd_word;
 106        unsigned int waitcnt;
 107        unsigned long flags;
 108        int ret;
 109
 110        if (!buf || !opcnt || !para || !para->csize || !lpcdev)
 111                return -EINVAL;
 112
 113        cmd_word = 0; /* IO mode, Read */
 114        waitcnt = LPC_PEROP_WAITCNT;
 115        if (!(para->opflags & FG_INCRADDR_LPC)) {
 116                cmd_word |= LPC_REG_CMD_SAMEADDR;
 117                waitcnt = LPC_MAX_WAITCNT;
 118        }
 119
 120        /* whole operation must be atomic */
 121        spin_lock_irqsave(&lpcdev->cycle_lock, flags);
 122
 123        writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN);
 124        writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
 125        writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR);
 126
 127        writel(LPC_REG_STARTUP_SIGNAL_START,
 128               lpcdev->membase + LPC_REG_STARTUP_SIGNAL);
 129
 130        /* whether the operation is finished */
 131        ret = wait_lpc_idle(lpcdev->membase, waitcnt);
 132        if (ret) {
 133                spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
 134                return ret;
 135        }
 136
 137        readsb(lpcdev->membase + LPC_REG_RDATA, buf, opcnt);
 138
 139        spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
 140
 141        return 0;
 142}
 143
 144/*
 145 * hisi_lpc_target_out - trigger a series of LPC cycles for write operation
 146 * @lpcdev: pointer to hisi lpc device
 147 * @para: some parameters used to control the lpc I/O operations
 148 * @addr: the lpc I/O target port address
 149 * @buf: where the data to be written is stored
 150 * @opcnt: how many I/O operations required, i.e. data width
 151 *
 152 * Returns 0 on success, non-zero on fail.
 153 */
 154static int hisi_lpc_target_out(struct hisi_lpc_dev *lpcdev,
 155                               struct lpc_cycle_para *para, unsigned long addr,
 156                               const unsigned char *buf, unsigned long opcnt)
 157{
 158        unsigned int waitcnt;
 159        unsigned long flags;
 160        u32 cmd_word;
 161        int ret;
 162
 163        if (!buf || !opcnt || !para || !lpcdev)
 164                return -EINVAL;
 165
 166        /* default is increasing address */
 167        cmd_word = LPC_REG_CMD_OP; /* IO mode, write */
 168        waitcnt = LPC_PEROP_WAITCNT;
 169        if (!(para->opflags & FG_INCRADDR_LPC)) {
 170                cmd_word |= LPC_REG_CMD_SAMEADDR;
 171                waitcnt = LPC_MAX_WAITCNT;
 172        }
 173
 174        spin_lock_irqsave(&lpcdev->cycle_lock, flags);
 175
 176        writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN);
 177        writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
 178        writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR);
 179
 180        writesb(lpcdev->membase + LPC_REG_WDATA, buf, opcnt);
 181
 182        writel(LPC_REG_STARTUP_SIGNAL_START,
 183               lpcdev->membase + LPC_REG_STARTUP_SIGNAL);
 184
 185        /* whether the operation is finished */
 186        ret = wait_lpc_idle(lpcdev->membase, waitcnt);
 187
 188        spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
 189
 190        return ret;
 191}
 192
 193static unsigned long hisi_lpc_pio_to_addr(struct hisi_lpc_dev *lpcdev,
 194                                          unsigned long pio)
 195{
 196        return pio - lpcdev->io_host->io_start + lpcdev->io_host->hw_start;
 197}
 198
 199/*
 200 * hisi_lpc_comm_in - input the data in a single operation
 201 * @hostdata: pointer to the device information relevant to LPC controller
 202 * @pio: the target I/O port address
 203 * @dwidth: the data length required to read from the target I/O port
 204 *
 205 * When success, data is returned. Otherwise, ~0 is returned.
 206 */
 207static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth)
 208{
 209        struct hisi_lpc_dev *lpcdev = hostdata;
 210        struct lpc_cycle_para iopara;
 211        unsigned long addr;
 212        u32 rd_data = 0;
 213        int ret;
 214
 215        if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
 216                return ~0;
 217
 218        addr = hisi_lpc_pio_to_addr(lpcdev, pio);
 219
 220        iopara.opflags = FG_INCRADDR_LPC;
 221        iopara.csize = dwidth;
 222
 223        ret = hisi_lpc_target_in(lpcdev, &iopara, addr,
 224                                 (unsigned char *)&rd_data, dwidth);
 225        if (ret)
 226                return ~0;
 227
 228        return le32_to_cpu(rd_data);
 229}
 230
 231/*
 232 * hisi_lpc_comm_out - output the data in a single operation
 233 * @hostdata: pointer to the device information relevant to LPC controller
 234 * @pio: the target I/O port address
 235 * @val: a value to be output from caller, maximum is four bytes
 236 * @dwidth: the data width required writing to the target I/O port
 237 *
 238 * This function corresponds to out(b,w,l) only.
 239 */
 240static void hisi_lpc_comm_out(void *hostdata, unsigned long pio,
 241                              u32 val, size_t dwidth)
 242{
 243        struct hisi_lpc_dev *lpcdev = hostdata;
 244        struct lpc_cycle_para iopara;
 245        const unsigned char *buf;
 246        unsigned long addr;
 247
 248        if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
 249                return;
 250
 251        val = cpu_to_le32(val);
 252
 253        buf = (const unsigned char *)&val;
 254        addr = hisi_lpc_pio_to_addr(lpcdev, pio);
 255
 256        iopara.opflags = FG_INCRADDR_LPC;
 257        iopara.csize = dwidth;
 258
 259        hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth);
 260}
 261
 262/*
 263 * hisi_lpc_comm_ins - input the data in the buffer in multiple operations
 264 * @hostdata: pointer to the device information relevant to LPC controller
 265 * @pio: the target I/O port address
 266 * @buffer: a buffer where read/input data bytes are stored
 267 * @dwidth: the data width required writing to the target I/O port
 268 * @count: how many data units whose length is dwidth will be read
 269 *
 270 * When success, the data read back is stored in buffer pointed by buffer.
 271 * Returns 0 on success, -errno otherwise.
 272 */
 273static u32 hisi_lpc_comm_ins(void *hostdata, unsigned long pio, void *buffer,
 274                             size_t dwidth, unsigned int count)
 275{
 276        struct hisi_lpc_dev *lpcdev = hostdata;
 277        unsigned char *buf = buffer;
 278        struct lpc_cycle_para iopara;
 279        unsigned long addr;
 280
 281        if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH)
 282                return -EINVAL;
 283
 284        iopara.opflags = 0;
 285        if (dwidth > 1)
 286                iopara.opflags |= FG_INCRADDR_LPC;
 287        iopara.csize = dwidth;
 288
 289        addr = hisi_lpc_pio_to_addr(lpcdev, pio);
 290
 291        do {
 292                int ret;
 293
 294                ret = hisi_lpc_target_in(lpcdev, &iopara, addr, buf, dwidth);
 295                if (ret)
 296                        return ret;
 297                buf += dwidth;
 298        } while (--count);
 299
 300        return 0;
 301}
 302
 303/*
 304 * hisi_lpc_comm_outs - output the data in the buffer in multiple operations
 305 * @hostdata: pointer to the device information relevant to LPC controller
 306 * @pio: the target I/O port address
 307 * @buffer: a buffer where write/output data bytes are stored
 308 * @dwidth: the data width required writing to the target I/O port
 309 * @count: how many data units whose length is dwidth will be written
 310 */
 311static void hisi_lpc_comm_outs(void *hostdata, unsigned long pio,
 312                               const void *buffer, size_t dwidth,
 313                               unsigned int count)
 314{
 315        struct hisi_lpc_dev *lpcdev = hostdata;
 316        struct lpc_cycle_para iopara;
 317        const unsigned char *buf = buffer;
 318        unsigned long addr;
 319
 320        if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH)
 321                return;
 322
 323        iopara.opflags = 0;
 324        if (dwidth > 1)
 325                iopara.opflags |= FG_INCRADDR_LPC;
 326        iopara.csize = dwidth;
 327
 328        addr = hisi_lpc_pio_to_addr(lpcdev, pio);
 329        do {
 330                if (hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth))
 331                        break;
 332                buf += dwidth;
 333        } while (--count);
 334}
 335
 336static const struct logic_pio_host_ops hisi_lpc_ops = {
 337        .in = hisi_lpc_comm_in,
 338        .out = hisi_lpc_comm_out,
 339        .ins = hisi_lpc_comm_ins,
 340        .outs = hisi_lpc_comm_outs,
 341};
 342
 343#ifdef CONFIG_ACPI
 344static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev,
 345                                     struct acpi_device *host,
 346                                     struct resource *res)
 347{
 348        unsigned long sys_port;
 349        resource_size_t len = resource_size(res);
 350
 351        sys_port = logic_pio_trans_hwaddr(&host->fwnode, res->start, len);
 352        if (sys_port == ~0UL)
 353                return -EFAULT;
 354
 355        res->start = sys_port;
 356        res->end = sys_port + len;
 357
 358        return 0;
 359}
 360
 361/*
 362 * hisi_lpc_acpi_set_io_res - set the resources for a child
 363 * @child: the device node to be updated the I/O resource
 364 * @hostdev: the device node associated with host controller
 365 * @res: double pointer to be set to the address of translated resources
 366 * @num_res: pointer to variable to hold the number of translated resources
 367 *
 368 * Returns 0 when successful, and a negative value for failure.
 369 *
 370 * For a given host controller, each child device will have an associated
 371 * host-relative address resource.  This function will return the translated
 372 * logical PIO addresses for each child devices resources.
 373 */
 374static int hisi_lpc_acpi_set_io_res(struct device *child,
 375                                    struct device *hostdev,
 376                                    const struct resource **res, int *num_res)
 377{
 378        struct acpi_device *adev;
 379        struct acpi_device *host;
 380        struct resource_entry *rentry;
 381        LIST_HEAD(resource_list);
 382        struct resource *resources;
 383        int count;
 384        int i;
 385
 386        if (!child || !hostdev)
 387                return -EINVAL;
 388
 389        host = to_acpi_device(hostdev);
 390        adev = to_acpi_device(child);
 391
 392        if (!adev->status.present) {
 393                dev_dbg(child, "device is not present\n");
 394                return -EIO;
 395        }
 396
 397        if (acpi_device_enumerated(adev)) {
 398                dev_dbg(child, "has been enumerated\n");
 399                return -EIO;
 400        }
 401
 402        /*
 403         * The following code segment to retrieve the resources is common to
 404         * acpi_create_platform_device(), so consider a common helper function
 405         * in future.
 406         */
 407        count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
 408        if (count <= 0) {
 409                dev_dbg(child, "failed to get resources\n");
 410                return count ? count : -EIO;
 411        }
 412
 413        resources = devm_kcalloc(hostdev, count, sizeof(*resources),
 414                                 GFP_KERNEL);
 415        if (!resources) {
 416                dev_warn(hostdev, "could not allocate memory for %d resources\n",
 417                         count);
 418                acpi_dev_free_resource_list(&resource_list);
 419                return -ENOMEM;
 420        }
 421        count = 0;
 422        list_for_each_entry(rentry, &resource_list, node)
 423                resources[count++] = *rentry->res;
 424
 425        acpi_dev_free_resource_list(&resource_list);
 426
 427        /* translate the I/O resources */
 428        for (i = 0; i < count; i++) {
 429                int ret;
 430
 431                if (!(resources[i].flags & IORESOURCE_IO))
 432                        continue;
 433                ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]);
 434                if (ret) {
 435                        dev_err(child, "translate IO range %pR failed (%d)\n",
 436                                &resources[i], ret);
 437                        return ret;
 438                }
 439        }
 440        *res = resources;
 441        *num_res = count;
 442
 443        return 0;
 444}
 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
 459static void hisi_lpc_acpi_remove(struct device *hostdev)
 460{
 461        struct acpi_device *adev = ACPI_COMPANION(hostdev);
 462        struct acpi_device *child;
 463
 464        device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev);
 465
 466        list_for_each_entry(child, &adev->children, node)
 467                acpi_device_clear_enumerated(child);
 468}
 469
 470/*
 471 * hisi_lpc_acpi_probe - probe children for ACPI FW
 472 * @hostdev: LPC host device pointer
 473 *
 474 * Returns 0 when successful, and a negative value for failure.
 475 *
 476 * Create a platform device per child, fixing up the resources
 477 * from bus addresses to Logical PIO addresses.
 478 *
 479 */
 480static int hisi_lpc_acpi_probe(struct device *hostdev)
 481{
 482        struct acpi_device *adev = ACPI_COMPANION(hostdev);
 483        struct acpi_device *child;
 484        int ret;
 485
 486        /* Only consider the children of the host */
 487        list_for_each_entry(child, &adev->children, node) {
 488                const char *hid = acpi_device_hid(child);
 489                const struct hisi_lpc_acpi_cell *cell;
 490                struct platform_device *pdev;
 491                const struct resource *res;
 492                bool found = false;
 493                int num_res;
 494
 495                ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res,
 496                                               &num_res);
 497                if (ret) {
 498                        dev_warn(hostdev, "set resource fail (%d)\n", ret);
 499                        goto fail;
 500                }
 501
 502                cell = (struct hisi_lpc_acpi_cell []){
 503                        /* ipmi */
 504                        {
 505                                .hid = "IPI0001",
 506                                .name = "hisi-lpc-ipmi",
 507                        },
 508                        /* 8250-compatible uart */
 509                        {
 510                                .hid = "HISI1031",
 511                                .name = "serial8250",
 512                                .pdata = (struct plat_serial8250_port []) {
 513                                        {
 514                                                .iobase = res->start,
 515                                                .uartclk = 1843200,
 516                                                .iotype = UPIO_PORT,
 517                                                .flags = UPF_BOOT_AUTOCONF,
 518                                        },
 519                                        {}
 520                                },
 521                                .pdata_size = 2 *
 522                                        sizeof(struct plat_serial8250_port),
 523                        },
 524                        {}
 525                };
 526
 527                for (; cell && cell->name; cell++) {
 528                        if (!strcmp(cell->hid, hid)) {
 529                                found = true;
 530                                break;
 531                        }
 532                }
 533
 534                if (!found) {
 535                        dev_warn(hostdev,
 536                                 "could not find cell for child device (%s), discarding\n",
 537                                 hid);
 538                        continue;
 539                }
 540
 541                pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
 542                if (!pdev) {
 543                        ret = -ENOMEM;
 544                        goto fail;
 545                }
 546
 547                pdev->dev.parent = hostdev;
 548                ACPI_COMPANION_SET(&pdev->dev, child);
 549
 550                ret = platform_device_add_resources(pdev, res, num_res);
 551                if (ret)
 552                        goto fail;
 553
 554                ret = platform_device_add_data(pdev, cell->pdata,
 555                                               cell->pdata_size);
 556                if (ret)
 557                        goto fail;
 558
 559                ret = platform_device_add(pdev);
 560                if (ret)
 561                        goto fail;
 562
 563                acpi_device_set_enumerated(child);
 564        }
 565
 566        return 0;
 567
 568fail:
 569        hisi_lpc_acpi_remove(hostdev);
 570        return ret;
 571}
 572
 573static const struct acpi_device_id hisi_lpc_acpi_match[] = {
 574        {"HISI0191"},
 575        {}
 576};
 577#else
 578static int hisi_lpc_acpi_probe(struct device *dev)
 579{
 580        return -ENODEV;
 581}
 582
 583static void hisi_lpc_acpi_remove(struct device *hostdev)
 584{
 585}
 586#endif // CONFIG_ACPI
 587
 588/*
 589 * hisi_lpc_probe - the probe callback function for hisi lpc host,
 590 *                 will finish all the initialization.
 591 * @pdev: the platform device corresponding to hisi lpc host
 592 *
 593 * Returns 0 on success, non-zero on fail.
 594 */
 595static int hisi_lpc_probe(struct platform_device *pdev)
 596{
 597        struct device *dev = &pdev->dev;
 598        struct acpi_device *acpi_device = ACPI_COMPANION(dev);
 599        struct logic_pio_hwaddr *range;
 600        struct hisi_lpc_dev *lpcdev;
 601        resource_size_t io_end;
 602        struct resource *res;
 603        int ret;
 604
 605        lpcdev = devm_kzalloc(dev, sizeof(*lpcdev), GFP_KERNEL);
 606        if (!lpcdev)
 607                return -ENOMEM;
 608
 609        spin_lock_init(&lpcdev->cycle_lock);
 610
 611        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 612        lpcdev->membase = devm_ioremap_resource(dev, res);
 613        if (IS_ERR(lpcdev->membase))
 614                return PTR_ERR(lpcdev->membase);
 615
 616        range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
 617        if (!range)
 618                return -ENOMEM;
 619
 620        range->fwnode = dev->fwnode;
 621        range->flags = LOGIC_PIO_INDIRECT;
 622        range->size = PIO_INDIRECT_SIZE;
 623        range->hostdata = lpcdev;
 624        range->ops = &hisi_lpc_ops;
 625        lpcdev->io_host = range;
 626
 627        ret = logic_pio_register_range(range);
 628        if (ret) {
 629                dev_err(dev, "register IO range failed (%d)!\n", ret);
 630                return ret;
 631        }
 632
 633        /* register the LPC host PIO resources */
 634        if (acpi_device)
 635                ret = hisi_lpc_acpi_probe(dev);
 636        else
 637                ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 638        if (ret) {
 639                logic_pio_unregister_range(range);
 640                return ret;
 641        }
 642
 643        dev_set_drvdata(dev, lpcdev);
 644
 645        io_end = lpcdev->io_host->io_start + lpcdev->io_host->size;
 646        dev_info(dev, "registered range [%pa - %pa]\n",
 647                 &lpcdev->io_host->io_start, &io_end);
 648
 649        return ret;
 650}
 651
 652static int hisi_lpc_remove(struct platform_device *pdev)
 653{
 654        struct device *dev = &pdev->dev;
 655        struct acpi_device *acpi_device = ACPI_COMPANION(dev);
 656        struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev);
 657        struct logic_pio_hwaddr *range = lpcdev->io_host;
 658
 659        if (acpi_device)
 660                hisi_lpc_acpi_remove(dev);
 661        else
 662                of_platform_depopulate(dev);
 663
 664        logic_pio_unregister_range(range);
 665
 666        return 0;
 667}
 668
 669static const struct of_device_id hisi_lpc_of_match[] = {
 670        { .compatible = "hisilicon,hip06-lpc", },
 671        { .compatible = "hisilicon,hip07-lpc", },
 672        {}
 673};
 674
 675static struct platform_driver hisi_lpc_driver = {
 676        .driver = {
 677                .name           = DRV_NAME,
 678                .of_match_table = hisi_lpc_of_match,
 679                .acpi_match_table = ACPI_PTR(hisi_lpc_acpi_match),
 680        },
 681        .probe = hisi_lpc_probe,
 682        .remove = hisi_lpc_remove,
 683};
 684builtin_platform_driver(hisi_lpc_driver);
 685