Exemple #1
0
static int dw8250_probe(struct platform_device *pdev)
{
	struct uart_8250_port uart = {};
	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	int irq = platform_get_irq(pdev, 0);
	struct dw8250_data *data;
	int err;

	if (!regs) {
		dev_err(&pdev->dev, "no registers defined\n");
		return -EINVAL;
	}

	if (irq < 0) {
		if (irq != -EPROBE_DEFER)
			dev_err(&pdev->dev, "cannot get irq\n");
		return irq;
	}

	spin_lock_init(&uart.port.lock);
	uart.port.mapbase = regs->start;
	uart.port.irq = irq;
	uart.port.handle_irq = dw8250_handle_irq;
	uart.port.pm = dw8250_do_pm;
	uart.port.type = PORT_8250;
	uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
	uart.port.dev = &pdev->dev;

	uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
					 resource_size(regs));
	if (!uart.port.membase)
		return -ENOMEM;

	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->usr_reg = DW_UART_USR;

	/* Always ask for fixed clock rate from a property. */
	device_property_read_u32(&pdev->dev, "clock-frequency",
				 &uart.port.uartclk);

	/* If there is separate baudclk, get the rate from it. */
	data->clk = devm_clk_get(&pdev->dev, "baudclk");
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
		data->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
	if (!IS_ERR_OR_NULL(data->clk)) {
		err = clk_prepare_enable(data->clk);
		if (err)
			dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
				 err);
		else
			uart.port.uartclk = clk_get_rate(data->clk);
	}

	/* If no clock rate is defined, fail. */
	if (!uart.port.uartclk) {
		dev_err(&pdev->dev, "clock rate not defined\n");
		return -EINVAL;
	}

	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
		err = -EPROBE_DEFER;
		goto err_clk;
	}
	if (!IS_ERR(data->pclk)) {
		err = clk_prepare_enable(data->pclk);
		if (err) {
			dev_err(&pdev->dev, "could not enable apb_pclk\n");
			goto err_clk;
		}
	}

	data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
	if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
		err = -EPROBE_DEFER;
		goto err_pclk;
	}
	if (!IS_ERR(data->rst))
		reset_control_deassert(data->rst);

	data->dma.rx_param = data;
	data->dma.tx_param = data;
	data->dma.fn = dw8250_dma_filter;

	uart.port.iotype = UPIO_MEM;
	uart.port.serial_in = dw8250_serial_in;
	uart.port.serial_out = dw8250_serial_out;
	uart.port.private_data = data;

	if (pdev->dev.of_node) {
		err = dw8250_probe_of(&uart.port, data);
		if (err)
			goto err_reset;
	} else if (ACPI_HANDLE(&pdev->dev)) {
		err = dw8250_probe_acpi(&uart, data);
		if (err)
			goto err_reset;
	} else {
		err = -ENODEV;
		goto err_reset;
	}

	data->line = serial8250_register_8250_port(&uart);
	if (data->line < 0) {
		err = data->line;
		goto err_reset;
	}

	platform_set_drvdata(pdev, data);

	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	return 0;

err_reset:
	if (!IS_ERR(data->rst))
		reset_control_assert(data->rst);

err_pclk:
	if (!IS_ERR(data->pclk))
		clk_disable_unprepare(data->pclk);

err_clk:
	if (!IS_ERR(data->clk))
		clk_disable_unprepare(data->clk);

	return err;
}
Exemple #2
0
static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
{
	int i, ret;

	hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
	if (IS_ERR(hsotg->reset)) {
		ret = PTR_ERR(hsotg->reset);
		dev_err(hsotg->dev, "error getting reset control %d\n", ret);
		return ret;
	}

	reset_control_deassert(hsotg->reset);

	/* Set default UTMI width */
	hsotg->phyif = GUSBCFG_PHYIF16;

	/*
	 * Attempt to find a generic PHY, then look for an old style
	 * USB PHY and then fall back to pdata
	 */
	hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
	if (IS_ERR(hsotg->phy)) {
		ret = PTR_ERR(hsotg->phy);
		switch (ret) {
		case -ENODEV:
		case -ENOSYS:
			hsotg->phy = NULL;
			break;
		case -EPROBE_DEFER:
			return ret;
		default:
			dev_err(hsotg->dev, "error getting phy %d\n", ret);
			return ret;
		}
	}

	if (!hsotg->phy) {
		hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
		if (IS_ERR(hsotg->uphy)) {
			ret = PTR_ERR(hsotg->uphy);
			switch (ret) {
			case -ENODEV:
			case -ENXIO:
				hsotg->uphy = NULL;
				break;
			case -EPROBE_DEFER:
				return ret;
			default:
				dev_err(hsotg->dev, "error getting usb phy %d\n",
					ret);
				return ret;
			}
		}
	}

	hsotg->plat = dev_get_platdata(hsotg->dev);

	if (hsotg->phy) {
		/*
		 * If using the generic PHY framework, check if the PHY bus
		 * width is 8-bit and set the phyif appropriately.
		 */
		if (phy_get_bus_width(hsotg->phy) == 8)
			hsotg->phyif = GUSBCFG_PHYIF8;
	}

	/* Clock */
	hsotg->clk = devm_clk_get(hsotg->dev, "otg");
	if (IS_ERR(hsotg->clk)) {
		hsotg->clk = NULL;
		dev_dbg(hsotg->dev, "cannot get otg clock\n");
	}

	/* Regulators */
	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
		hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];

	ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
				      hsotg->supplies);
	if (ret) {
		dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
		return ret;
	}
	return 0;
}
Exemple #3
0
static int ehci_platform_probe(struct platform_device *dev)
{
	struct usb_hcd *hcd;
	struct resource *res_mem;
	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
	struct ehci_platform_priv *priv;
	struct ehci_hcd *ehci;
	int err, irq, phy_num, clk = 0;

	if (usb_disabled())
		return -ENODEV;

	/*
	 * Use reasonable defaults so platforms don't have to provide these
	 * with DT probing on ARM.
	 */
	if (!pdata)
		pdata = &ehci_platform_defaults;

	err = dma_coerce_mask_and_coherent(&dev->dev,
		pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
	if (err)
		return err;

	irq = platform_get_irq(dev, 0);
	if (irq < 0) {
		dev_err(&dev->dev, "no irq provided");
		return irq;
	}

	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
			     dev_name(&dev->dev));
	if (!hcd)
		return -ENOMEM;

	platform_set_drvdata(dev, hcd);
	dev->dev.platform_data = pdata;
	priv = hcd_to_ehci_priv(hcd);
	ehci = hcd_to_ehci(hcd);

	if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
		if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
			ehci->big_endian_mmio = 1;

		if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
			ehci->big_endian_desc = 1;

		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
			ehci->big_endian_mmio = ehci->big_endian_desc = 1;

		if (of_property_read_bool(dev->dev.of_node,
					  "needs-reset-on-resume"))
			priv->reset_on_resume = true;

		if (of_property_read_bool(dev->dev.of_node,
					  "has-transaction-translator"))
			hcd->has_tt = 1;

		priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
				"phys", "#phy-cells");

		if (priv->num_phys > 0) {
			priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
					    sizeof(struct phy *), GFP_KERNEL);
			if (!priv->phys)
				return -ENOMEM;
		} else
			priv->num_phys = 0;

		for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
			priv->phys[phy_num] = devm_of_phy_get_by_index(
					&dev->dev, dev->dev.of_node, phy_num);
			if (IS_ERR(priv->phys[phy_num])) {
				err = PTR_ERR(priv->phys[phy_num]);
					goto err_put_hcd;
			}
		}

		for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
			priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
			if (IS_ERR(priv->clks[clk])) {
				err = PTR_ERR(priv->clks[clk]);
				if (err == -EPROBE_DEFER)
					goto err_put_clks;
				priv->clks[clk] = NULL;
				break;
			}
		}
	}

	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
	if (IS_ERR(priv->rst)) {
		err = PTR_ERR(priv->rst);
		if (err == -EPROBE_DEFER)
			goto err_put_clks;
		priv->rst = NULL;
	} else {
		err = reset_control_deassert(priv->rst);
		if (err)
			goto err_put_clks;
	}

	if (pdata->big_endian_desc)
		ehci->big_endian_desc = 1;
	if (pdata->big_endian_mmio)
		ehci->big_endian_mmio = 1;
	if (pdata->has_tt)
		hcd->has_tt = 1;
	if (pdata->reset_on_resume)
		priv->reset_on_resume = true;

#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
	if (ehci->big_endian_mmio) {
		dev_err(&dev->dev,
			"Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n");
		err = -EINVAL;
		goto err_reset;
	}
#endif
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
	if (ehci->big_endian_desc) {
		dev_err(&dev->dev,
			"Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n");
		err = -EINVAL;
		goto err_reset;
	}
#endif

	if (pdata->power_on) {
		err = pdata->power_on(dev);
		if (err < 0)
			goto err_reset;
	}

	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
	if (IS_ERR(hcd->regs)) {
		err = PTR_ERR(hcd->regs);
		goto err_power;
	}
	hcd->rsrc_start = res_mem->start;
	hcd->rsrc_len = resource_size(res_mem);

	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
	if (err)
		goto err_power;

	device_wakeup_enable(hcd->self.controller);
	platform_set_drvdata(dev, hcd);

	return err;

err_power:
	if (pdata->power_off)
		pdata->power_off(dev);
err_reset:
	if (priv->rst)
		reset_control_assert(priv->rst);
err_put_clks:
	while (--clk >= 0)
		clk_put(priv->clks[clk]);
err_put_hcd:
	if (pdata == &ehci_platform_defaults)
		dev->dev.platform_data = NULL;

	usb_put_hcd(hcd);

	return err;
}
Exemple #4
0
static int st_ehci_platform_probe(struct platform_device *dev)
{
    struct usb_hcd *hcd;
    struct resource *res_mem;
    struct usb_ehci_pdata *pdata = &ehci_platform_defaults;
    struct st_ehci_platform_priv *priv;
    struct ehci_hcd *ehci;
    int err, irq, clk = 0;

    if (usb_disabled())
        return -ENODEV;

    irq = platform_get_irq(dev, 0);
    if (irq < 0) {
        dev_err(&dev->dev, "no irq provided");
        return irq;
    }
    res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
    if (!res_mem) {
        dev_err(&dev->dev, "no memory resource provided");
        return -ENXIO;
    }

    hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
                         dev_name(&dev->dev));
    if (!hcd)
        return -ENOMEM;

    platform_set_drvdata(dev, hcd);
    dev->dev.platform_data = pdata;
    priv = hcd_to_ehci_priv(hcd);
    ehci = hcd_to_ehci(hcd);

    priv->phy = devm_phy_get(&dev->dev, "usb");
    if (IS_ERR(priv->phy)) {
        err = PTR_ERR(priv->phy);
        goto err_put_hcd;
    }

    for (clk = 0; clk < USB_MAX_CLKS; clk++) {
        priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
        if (IS_ERR(priv->clks[clk])) {
            err = PTR_ERR(priv->clks[clk]);
            if (err == -EPROBE_DEFER)
                goto err_put_clks;
            priv->clks[clk] = NULL;
            break;
        }
    }

    /* some SoCs don't have a dedicated 48Mhz clock, but those that
       do need the rate to be explicitly set */
    priv->clk48 = devm_clk_get(&dev->dev, "clk48");
    if (IS_ERR(priv->clk48)) {
        dev_info(&dev->dev, "48MHz clk not found\n");
        priv->clk48 = NULL;
    }

    priv->pwr = devm_reset_control_get_optional(&dev->dev, "power");
    if (IS_ERR(priv->pwr)) {
        err = PTR_ERR(priv->pwr);
        if (err == -EPROBE_DEFER)
            goto err_put_clks;
        priv->pwr = NULL;
    }

    priv->rst = devm_reset_control_get_optional(&dev->dev, "softreset");
    if (IS_ERR(priv->rst)) {
        err = PTR_ERR(priv->rst);
        if (err == -EPROBE_DEFER)
            goto err_put_clks;
        priv->rst = NULL;
    }

    if (pdata->power_on) {
        err = pdata->power_on(dev);
        if (err < 0)
            goto err_put_clks;
    }

    hcd->rsrc_start = res_mem->start;
    hcd->rsrc_len = resource_size(res_mem);

    hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
    if (IS_ERR(hcd->regs)) {
        err = PTR_ERR(hcd->regs);
        goto err_put_clks;
    }

    err = usb_add_hcd(hcd, irq, IRQF_SHARED);
    if (err)
        goto err_put_clks;

    device_wakeup_enable(hcd->self.controller);
    platform_set_drvdata(dev, hcd);

    return err;

err_put_clks:
    while (--clk >= 0)
        clk_put(priv->clks[clk]);
err_put_hcd:
    if (pdata == &ehci_platform_defaults)
        dev->dev.platform_data = NULL;

    usb_put_hcd(hcd);

    return err;
}
Exemple #5
0
static int dw8250_probe(struct platform_device *pdev)
{
    struct uart_8250_port uart = {};
    struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    int irq = platform_get_irq(pdev, 0);
    struct uart_port *p = &uart.port;
    struct dw8250_data *data;
    int err;
    u32 val;

    if (!regs) {
        dev_err(&pdev->dev, "no registers defined\n");
        return -EINVAL;
    }

    if (irq < 0) {
        if (irq != -EPROBE_DEFER)
            dev_err(&pdev->dev, "cannot get irq\n");
        return irq;
    }

    spin_lock_init(&p->lock);
    p->mapbase	= regs->start;
    p->irq		= irq;
    p->handle_irq	= dw8250_handle_irq;
    p->pm		= dw8250_do_pm;
    p->type		= PORT_8250;
    p->flags	= UPF_SHARE_IRQ | UPF_FIXED_PORT;
    p->dev		= &pdev->dev;
    p->iotype	= UPIO_MEM;
    p->serial_in	= dw8250_serial_in;
    p->serial_out	= dw8250_serial_out;

    p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
    if (!p->membase)
        return -ENOMEM;

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->dma.fn = dw8250_fallback_dma_filter;
    data->usr_reg = DW_UART_USR;
    p->private_data = data;

    data->uart_16550_compatible = device_property_read_bool(p->dev,
                                  "snps,uart-16550-compatible");

    err = device_property_read_u32(p->dev, "reg-shift", &val);
    if (!err)
        p->regshift = val;

    err = device_property_read_u32(p->dev, "reg-io-width", &val);
    if (!err && val == 4) {
        p->iotype = UPIO_MEM32;
        p->serial_in = dw8250_serial_in32;
        p->serial_out = dw8250_serial_out32;
    }

    if (device_property_read_bool(p->dev, "dcd-override")) {
        /* Always report DCD as active */
        data->msr_mask_on |= UART_MSR_DCD;
        data->msr_mask_off |= UART_MSR_DDCD;
    }

    if (device_property_read_bool(p->dev, "dsr-override")) {
        /* Always report DSR as active */
        data->msr_mask_on |= UART_MSR_DSR;
        data->msr_mask_off |= UART_MSR_DDSR;
    }

    if (device_property_read_bool(p->dev, "cts-override")) {
        /* Always report CTS as active */
        data->msr_mask_on |= UART_MSR_CTS;
        data->msr_mask_off |= UART_MSR_DCTS;
    }

    if (device_property_read_bool(p->dev, "ri-override")) {
        /* Always report Ring indicator as inactive */
        data->msr_mask_off |= UART_MSR_RI;
        data->msr_mask_off |= UART_MSR_TERI;
    }

    /* Always ask for fixed clock rate from a property. */
    device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);

    /* If there is separate baudclk, get the rate from it. */
    data->clk = devm_clk_get(&pdev->dev, "baudclk");
    if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
        data->clk = devm_clk_get(&pdev->dev, NULL);
    if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
        return -EPROBE_DEFER;
    if (!IS_ERR_OR_NULL(data->clk)) {
        err = clk_prepare_enable(data->clk);
        if (err)
            dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
                     err);
        else
            p->uartclk = clk_get_rate(data->clk);
    }

    /* If no clock rate is defined, fail. */
    if (!p->uartclk) {
        dev_err(&pdev->dev, "clock rate not defined\n");
        return -EINVAL;
    }

    data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
    if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
        err = -EPROBE_DEFER;
        goto err_clk;
    }
    if (!IS_ERR(data->pclk)) {
        err = clk_prepare_enable(data->pclk);
        if (err) {
            dev_err(&pdev->dev, "could not enable apb_pclk\n");
            goto err_clk;
        }
    }

    data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
    if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
        err = -EPROBE_DEFER;
        goto err_pclk;
    }
    if (!IS_ERR(data->rst))
        reset_control_deassert(data->rst);

    dw8250_quirks(p, data);

    /* If the Busy Functionality is not implemented, don't handle it */
    if (data->uart_16550_compatible)
        p->handle_irq = NULL;

    if (!data->skip_autocfg)
        dw8250_setup_port(p);

    /* If we have a valid fifosize, try hooking up DMA */
    if (p->fifosize) {
        data->dma.rxconf.src_maxburst = p->fifosize / 4;
        data->dma.txconf.dst_maxburst = p->fifosize / 4;
        uart.dma = &data->dma;
    }

    data->line = serial8250_register_8250_port(&uart);
    if (data->line < 0) {
        err = data->line;
        goto err_reset;
    }

    platform_set_drvdata(pdev, data);

    pm_runtime_set_active(&pdev->dev);
    pm_runtime_enable(&pdev->dev);

    return 0;

err_reset:
    if (!IS_ERR(data->rst))
        reset_control_assert(data->rst);

err_pclk:
    if (!IS_ERR(data->pclk))
        clk_disable_unprepare(data->pclk);

err_clk:
    if (!IS_ERR(data->clk))
        clk_disable_unprepare(data->clk);

    return err;
}
Exemple #6
0
static int dw_apb_raw_uart_probe(struct platform_device *pdev)
{
  int err;
  u32 val;
  struct device *dev = &pdev->dev;
  struct resource *ioresource;

  dw_apb_port = kzalloc(sizeof(struct dw_apb_port_s), GFP_KERNEL);
  if (!dw_apb_port) {
    err = -ENOMEM;
    goto failed_inst_alloc;
  }

  /* Get mapbase and membase */
  ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  if (ioresource) {
    dw_apb_port->mapbase = ioresource->start;
    dw_apb_port->membase = ioremap(ioresource->start, resource_size(ioresource));
  } else {
    dev_err(dev, "failed to get IO resource\n");
    err = -ENOENT;
    goto failed_get_resource;
  }

  /* get irq */
  dw_apb_port->irq = platform_get_irq(pdev, 0);
  if (dw_apb_port->irq <= 0) {
    dev_err(dev, "failed to get irq\n");
    err = -ENOENT;
    goto failed_get_resource;
  }

  /* get clock */
  dw_apb_port->sclk = devm_clk_get(&pdev->dev, "baudclk");
  if (IS_ERR(dw_apb_port->sclk) && PTR_ERR(dw_apb_port->sclk) != -EPROBE_DEFER)
    dw_apb_port->sclk = devm_clk_get(&pdev->dev, NULL);
  if (IS_ERR(dw_apb_port->sclk)) {
    dev_err(dev, "failed to get sclk\n");
    err = PTR_ERR(dw_apb_port->sclk);
    goto failed_get_clock;
  }
  clk_prepare_enable(dw_apb_port->sclk);

  dw_apb_port->pclk = devm_clk_get(dev, "apb_pclk");
  if (IS_ERR(dw_apb_port->pclk) && PTR_ERR(dw_apb_port->pclk) == -EPROBE_DEFER) {
    dev_err(dev, "failed to get pclk\n");
    err = -EPROBE_DEFER;
    goto failed_get_pclock;
  }
  if (!IS_ERR(dw_apb_port->pclk)) {
    clk_prepare_enable(dw_apb_port->pclk);
  }

  dw_apb_port->rst = devm_reset_control_get_optional(dev, NULL);
  if (IS_ERR(dw_apb_port->rst)) {
    err = PTR_ERR(dw_apb_port->rst);
    goto failed_get_rst;
  }
  reset_control_deassert(dw_apb_port->rst);

  err = device_property_read_u32(dev, "reg-shift", &val);
  if (!err)
    dw_apb_port->regshift = val;

  dw_apb_port->dev = dev;

  dw_apb_raw_uart_init_uart();

  dev_info(dev, "Initialized dw_apb device; mapbase=0x%08lx; irq=%lu; sclk rate=%lu; pclk rate=%ld",
    dw_apb_port->mapbase,
    dw_apb_port->irq,
    clk_get_rate(dw_apb_port->sclk),
    IS_ERR(dw_apb_port->pclk) ? -1 : clk_get_rate(dw_apb_port->pclk) );

  return 0;

failed_get_rst:
  reset_control_assert(dw_apb_port->rst);
failed_get_pclock:
  clk_disable_unprepare(dw_apb_port->sclk);
failed_get_clock:
failed_get_resource:
  kfree(dw_apb_port);
failed_inst_alloc:
  return err;
}
static int sunxi_ir_probe(struct platform_device *pdev)
{
    int ret = 0;
    unsigned long tmp = 0;

    struct device *dev = &pdev->dev;
    struct device_node *dn = dev->of_node;
    struct resource *res;
    struct sunxi_ir *ir;

    ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL);
    if (!ir)
        return -ENOMEM;

    if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir"))
        ir->fifo_size = 64;
    else
        ir->fifo_size = 16;

    /* Clock */
    ir->apb_clk = devm_clk_get(dev, "apb");
    if (IS_ERR(ir->apb_clk)) {
        dev_err(dev, "failed to get a apb clock.\n");
        return PTR_ERR(ir->apb_clk);
    }
    ir->clk = devm_clk_get(dev, "ir");
    if (IS_ERR(ir->clk)) {
        dev_err(dev, "failed to get a ir clock.\n");
        return PTR_ERR(ir->clk);
    }

    /* Reset (optional) */
    ir->rst = devm_reset_control_get_optional(dev, NULL);
    if (IS_ERR(ir->rst)) {
        ret = PTR_ERR(ir->rst);
        if (ret == -EPROBE_DEFER)
            return ret;
        ir->rst = NULL;
    } else {
        ret = reset_control_deassert(ir->rst);
        if (ret)
            return ret;
    }

    ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK);
    if (ret) {
        dev_err(dev, "set ir base clock failed!\n");
        goto exit_reset_assert;
    }

    if (clk_prepare_enable(ir->apb_clk)) {
        dev_err(dev, "try to enable apb_ir_clk failed\n");
        ret = -EINVAL;
        goto exit_reset_assert;
    }

    if (clk_prepare_enable(ir->clk)) {
        dev_err(dev, "try to enable ir_clk failed\n");
        ret = -EINVAL;
        goto exit_clkdisable_apb_clk;
    }

    /* IO */
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    ir->base = devm_ioremap_resource(dev, res);
    if (IS_ERR(ir->base)) {
        dev_err(dev, "failed to map registers\n");
        ret = PTR_ERR(ir->base);
        goto exit_clkdisable_clk;
    }

    ir->rc = rc_allocate_device();
    if (!ir->rc) {
        dev_err(dev, "failed to allocate device\n");
        ret = -ENOMEM;
        goto exit_clkdisable_clk;
    }

    ir->rc->priv = ir;
    ir->rc->input_name = SUNXI_IR_DEV;
    ir->rc->input_phys = "sunxi-ir/input0";
    ir->rc->input_id.bustype = BUS_HOST;
    ir->rc->input_id.vendor = 0x0001;
    ir->rc->input_id.product = 0x0001;
    ir->rc->input_id.version = 0x0100;
    ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
    ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
    ir->rc->dev.parent = dev;
    ir->rc->driver_type = RC_DRIVER_IR_RAW;
    ir->rc->allowed_protocols = RC_BIT_ALL;
    ir->rc->rx_resolution = SUNXI_IR_SAMPLE;
    ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
    ir->rc->driver_name = SUNXI_IR_DEV;

    ret = rc_register_device(ir->rc);
    if (ret) {
        dev_err(dev, "failed to register rc device\n");
        goto exit_free_dev;
    }

    platform_set_drvdata(pdev, ir);

    /* IRQ */
    ir->irq = platform_get_irq(pdev, 0);
    if (ir->irq < 0) {
        dev_err(dev, "no irq resource\n");
        ret = ir->irq;
        goto exit_free_dev;
    }

    ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir);
    if (ret) {
        dev_err(dev, "failed request irq\n");
        goto exit_free_dev;
    }

    /* Enable CIR Mode */
    writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);

    /* Set noise threshold and idle threshold */
    writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE),
           ir->base + SUNXI_IR_CIR_REG);

    /* Invert Input Signal */
    writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);

    /* Clear All Rx Interrupt Status */
    writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);

    /*
     * Enable IRQ on overflow, packet end, FIFO available with trigger
     * level
     */
    writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
           REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
           ir->base + SUNXI_IR_RXINT_REG);

    /* Enable IR Module */
    tmp = readl(ir->base + SUNXI_IR_CTL_REG);
    writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);

    dev_info(dev, "initialized sunXi IR driver\n");
    return 0;

exit_free_dev:
    rc_free_device(ir->rc);
exit_clkdisable_clk:
    clk_disable_unprepare(ir->clk);
exit_clkdisable_apb_clk:
    clk_disable_unprepare(ir->apb_clk);
exit_reset_assert:
    if (ir->rst)
        reset_control_assert(ir->rst);

    return ret;
}