brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 5f86804 Raw
222 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Regulator controller driver for UniPhier SoC4// Copyright 2018 Socionext Inc.5// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>6 7#include <linux/clk.h>8#include <linux/io.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/regmap.h>13#include <linux/regulator/driver.h>14#include <linux/regulator/of_regulator.h>15#include <linux/reset.h>16 17#define MAX_CLKS	218#define MAX_RSTS	219 20struct uniphier_regulator_soc_data {21	int nclks;22	const char * const *clock_names;23	int nrsts;24	const char * const *reset_names;25	const struct regulator_desc *desc;26	const struct regmap_config *regconf;27};28 29struct uniphier_regulator_priv {30	struct clk_bulk_data clk[MAX_CLKS];31	struct reset_control *rst[MAX_RSTS];32	const struct uniphier_regulator_soc_data *data;33};34 35static const struct regulator_ops uniphier_regulator_ops = {36	.enable     = regulator_enable_regmap,37	.disable    = regulator_disable_regmap,38	.is_enabled = regulator_is_enabled_regmap,39};40 41static int uniphier_regulator_probe(struct platform_device *pdev)42{43	struct device *dev = &pdev->dev;44	struct uniphier_regulator_priv *priv;45	struct regulator_config config = { };46	struct regulator_dev *rdev;47	struct regmap *regmap;48	void __iomem *base;49	const char *name;50	int i, ret, nr;51 52	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);53	if (!priv)54		return -ENOMEM;55 56	priv->data = of_device_get_match_data(dev);57	if (WARN_ON(!priv->data))58		return -EINVAL;59 60	base = devm_platform_ioremap_resource(pdev, 0);61	if (IS_ERR(base))62		return PTR_ERR(base);63 64	for (i = 0; i < priv->data->nclks; i++)65		priv->clk[i].id = priv->data->clock_names[i];66	ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk);67	if (ret)68		return ret;69 70	for (i = 0; i < priv->data->nrsts; i++) {71		name = priv->data->reset_names[i];72		priv->rst[i] = devm_reset_control_get_shared(dev, name);73		if (IS_ERR(priv->rst[i]))74			return PTR_ERR(priv->rst[i]);75	}76 77	ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);78	if (ret)79		return ret;80 81	for (nr = 0; nr < priv->data->nrsts; nr++) {82		ret = reset_control_deassert(priv->rst[nr]);83		if (ret)84			goto out_rst_assert;85	}86 87	regmap = devm_regmap_init_mmio(dev, base, priv->data->regconf);88	if (IS_ERR(regmap)) {89		ret = PTR_ERR(regmap);90		goto out_rst_assert;91	}92 93	config.dev = dev;94	config.driver_data = priv;95	config.of_node = dev->of_node;96	config.regmap = regmap;97	config.init_data = of_get_regulator_init_data(dev, dev->of_node,98						      priv->data->desc);99	rdev = devm_regulator_register(dev, priv->data->desc, &config);100	if (IS_ERR(rdev)) {101		ret = PTR_ERR(rdev);102		goto out_rst_assert;103	}104 105	platform_set_drvdata(pdev, priv);106 107	return 0;108 109out_rst_assert:110	while (nr--)111		reset_control_assert(priv->rst[nr]);112 113	clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);114 115	return ret;116}117 118static void uniphier_regulator_remove(struct platform_device *pdev)119{120	struct uniphier_regulator_priv *priv = platform_get_drvdata(pdev);121	int i;122 123	for (i = 0; i < priv->data->nrsts; i++)124		reset_control_assert(priv->rst[i]);125 126	clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);127}128 129/* USB3 controller data */130#define USB3VBUS_OFFSET		0x0131#define USB3VBUS_REG		BIT(4)132#define USB3VBUS_REG_EN		BIT(3)133static const struct regulator_desc uniphier_usb3_regulator_desc = {134	.name = "vbus",135	.of_match = of_match_ptr("vbus"),136	.ops = &uniphier_regulator_ops,137	.type = REGULATOR_VOLTAGE,138	.owner = THIS_MODULE,139	.enable_reg  = USB3VBUS_OFFSET,140	.enable_mask = USB3VBUS_REG_EN | USB3VBUS_REG,141	.enable_val  = USB3VBUS_REG_EN | USB3VBUS_REG,142	.disable_val = USB3VBUS_REG_EN,143};144 145static const struct regmap_config uniphier_usb3_regulator_regconf = {146	.reg_bits = 32,147	.val_bits = 32,148	.reg_stride = 4,149	.max_register = 1,150};151 152static const char * const uniphier_pro4_clock_reset_names[] = {153	"gio", "link",154};155 156static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data = {157	.nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names),158	.clock_names = uniphier_pro4_clock_reset_names,159	.nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names),160	.reset_names = uniphier_pro4_clock_reset_names,161	.desc = &uniphier_usb3_regulator_desc,162	.regconf = &uniphier_usb3_regulator_regconf,163};164 165static const char * const uniphier_pxs2_clock_reset_names[] = {166	"link",167};168 169static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data = {170	.nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),171	.clock_names = uniphier_pxs2_clock_reset_names,172	.nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),173	.reset_names = uniphier_pxs2_clock_reset_names,174	.desc = &uniphier_usb3_regulator_desc,175	.regconf = &uniphier_usb3_regulator_regconf,176};177 178static const struct of_device_id uniphier_regulator_match[] = {179	/* USB VBUS */180	{181		.compatible = "socionext,uniphier-pro4-usb3-regulator",182		.data = &uniphier_pro4_usb3_data,183	},184	{185		.compatible = "socionext,uniphier-pro5-usb3-regulator",186		.data = &uniphier_pro4_usb3_data,187	},188	{189		.compatible = "socionext,uniphier-pxs2-usb3-regulator",190		.data = &uniphier_pxs2_usb3_data,191	},192	{193		.compatible = "socionext,uniphier-ld20-usb3-regulator",194		.data = &uniphier_pxs2_usb3_data,195	},196	{197		.compatible = "socionext,uniphier-pxs3-usb3-regulator",198		.data = &uniphier_pxs2_usb3_data,199	},200	{201		.compatible = "socionext,uniphier-nx1-usb3-regulator",202		.data = &uniphier_pxs2_usb3_data,203	},204	{ /* Sentinel */ },205};206MODULE_DEVICE_TABLE(of, uniphier_regulator_match);207 208static struct platform_driver uniphier_regulator_driver = {209	.probe = uniphier_regulator_probe,210	.remove_new = uniphier_regulator_remove,211	.driver = {212		.name  = "uniphier-regulator",213		.probe_type = PROBE_PREFER_ASYNCHRONOUS,214		.of_match_table = uniphier_regulator_match,215	},216};217module_platform_driver(uniphier_regulator_driver);218 219MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");220MODULE_DESCRIPTION("UniPhier Regulator Controller Driver");221MODULE_LICENSE("GPL");222