Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
Note: File does not exist in v4.17.
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) 2023 Nuvoton Technology corporation.
  3
  4#include <linux/module.h>
  5#include <linux/platform_device.h>
  6#include <linux/pm_runtime.h>
  7#include <linux/usb/chipidea.h>
  8#include <linux/clk.h>
  9#include <linux/io.h>
 10#include <linux/reset-controller.h>
 11#include <linux/of.h>
 12
 13#include "ci.h"
 14
 15struct npcm_udc_data {
 16	struct platform_device	*ci;
 17	struct clk		*core_clk;
 18	struct ci_hdrc_platform_data pdata;
 19};
 20
 21static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned int event)
 22{
 23	struct device *dev = ci->dev->parent;
 24
 25	switch (event) {
 26	case CI_HDRC_CONTROLLER_RESET_EVENT:
 27		/* clear all mode bits */
 28		hw_write(ci, OP_USBMODE, 0xffffffff, 0x0);
 29		break;
 30	default:
 31		dev_dbg(dev, "unknown ci_hdrc event (%d)\n", event);
 32		break;
 33	}
 34
 35	return 0;
 36}
 37
 38static int npcm_udc_probe(struct platform_device *pdev)
 39{
 40	int ret;
 41	struct npcm_udc_data *ci;
 42	struct platform_device *plat_ci;
 43	struct device *dev = &pdev->dev;
 44
 45	ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
 46	if (!ci)
 47		return -ENOMEM;
 48	platform_set_drvdata(pdev, ci);
 49
 50	ci->core_clk = devm_clk_get_optional(dev, NULL);
 51	if (IS_ERR(ci->core_clk))
 52		return PTR_ERR(ci->core_clk);
 53
 54	ret = clk_prepare_enable(ci->core_clk);
 55	if (ret)
 56		return dev_err_probe(dev, ret, "failed to enable the clock: %d\n", ret);
 57
 58	ci->pdata.name = dev_name(dev);
 59	ci->pdata.capoffset = DEF_CAPOFFSET;
 60	ci->pdata.flags	= CI_HDRC_REQUIRES_ALIGNED_DMA |
 61		CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS;
 62	ci->pdata.phy_mode = USBPHY_INTERFACE_MODE_UTMI;
 63	ci->pdata.notify_event = npcm_udc_notify_event;
 64
 65	plat_ci = ci_hdrc_add_device(dev, pdev->resource, pdev->num_resources,
 66				     &ci->pdata);
 67	if (IS_ERR(plat_ci)) {
 68		ret = PTR_ERR(plat_ci);
 69		dev_err(dev, "failed to register HDRC NPCM device: %d\n", ret);
 70		goto clk_err;
 71	}
 72
 73	pm_runtime_no_callbacks(dev);
 74	pm_runtime_enable(dev);
 75
 76	return 0;
 77
 78clk_err:
 79	clk_disable_unprepare(ci->core_clk);
 80	return ret;
 81}
 82
 83static void npcm_udc_remove(struct platform_device *pdev)
 84{
 85	struct npcm_udc_data *ci = platform_get_drvdata(pdev);
 86
 87	pm_runtime_disable(&pdev->dev);
 88	ci_hdrc_remove_device(ci->ci);
 89	clk_disable_unprepare(ci->core_clk);
 90}
 91
 92static const struct of_device_id npcm_udc_dt_match[] = {
 93	{ .compatible = "nuvoton,npcm750-udc", },
 94	{ .compatible = "nuvoton,npcm845-udc", },
 95	{ }
 96};
 97MODULE_DEVICE_TABLE(of, npcm_udc_dt_match);
 98
 99static struct platform_driver npcm_udc_driver = {
100	.probe = npcm_udc_probe,
101	.remove = npcm_udc_remove,
102	.driver = {
103		.name = "npcm_udc",
104		.of_match_table = npcm_udc_dt_match,
105	},
106};
107
108module_platform_driver(npcm_udc_driver);
109
110MODULE_DESCRIPTION("NPCM USB device controller driver");
111MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
112MODULE_LICENSE("GPL v2");