brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · f6756a6 Raw
372 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Samsung S5P/Exynos SoC series MIPI CSIS/DSIM DPHY driver4 *5 * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>7 */8 9#include <linux/err.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/phy/phy.h>15#include <linux/platform_device.h>16#include <linux/regmap.h>17#include <linux/spinlock.h>18#include <linux/soc/samsung/exynos-regs-pmu.h>19#include <linux/mfd/syscon.h>20 21enum exynos_mipi_phy_id {22	EXYNOS_MIPI_PHY_ID_NONE = -1,23	EXYNOS_MIPI_PHY_ID_CSIS0,24	EXYNOS_MIPI_PHY_ID_DSIM0,25	EXYNOS_MIPI_PHY_ID_CSIS1,26	EXYNOS_MIPI_PHY_ID_DSIM1,27	EXYNOS_MIPI_PHY_ID_CSIS2,28	EXYNOS_MIPI_PHYS_NUM29};30 31enum exynos_mipi_phy_regmap_id {32	EXYNOS_MIPI_REGMAP_PMU,33	EXYNOS_MIPI_REGMAP_DISP,34	EXYNOS_MIPI_REGMAP_CAM0,35	EXYNOS_MIPI_REGMAP_CAM1,36	EXYNOS_MIPI_REGMAPS_NUM37};38 39struct mipi_phy_device_desc {40	int num_phys;41	int num_regmaps;42	const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM];43	struct exynos_mipi_phy_desc {44		enum exynos_mipi_phy_id	coupled_phy_id;45		u32 enable_val;46		unsigned int enable_reg;47		enum exynos_mipi_phy_regmap_id enable_map;48		u32 resetn_val;49		unsigned int resetn_reg;50		enum exynos_mipi_phy_regmap_id resetn_map;51	} phys[EXYNOS_MIPI_PHYS_NUM];52};53 54static const struct mipi_phy_device_desc s5pv210_mipi_phy = {55	.num_regmaps = 1,56	.regmap_names = {"syscon"},57	.num_phys = 4,58	.phys = {59		{60			/* EXYNOS_MIPI_PHY_ID_CSIS0 */61			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,62			.enable_val = EXYNOS4_PHY_ENABLE,63			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),64			.enable_map = EXYNOS_MIPI_REGMAP_PMU,65			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,66			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),67			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,68		}, {69			/* EXYNOS_MIPI_PHY_ID_DSIM0 */70			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,71			.enable_val = EXYNOS4_PHY_ENABLE,72			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),73			.enable_map = EXYNOS_MIPI_REGMAP_PMU,74			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,75			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),76			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,77		}, {78			/* EXYNOS_MIPI_PHY_ID_CSIS1 */79			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,80			.enable_val = EXYNOS4_PHY_ENABLE,81			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),82			.enable_map = EXYNOS_MIPI_REGMAP_PMU,83			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,84			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),85			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,86		}, {87			/* EXYNOS_MIPI_PHY_ID_DSIM1 */88			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,89			.enable_val = EXYNOS4_PHY_ENABLE,90			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),91			.enable_map = EXYNOS_MIPI_REGMAP_PMU,92			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,93			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),94			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,95		},96	},97};98 99static const struct mipi_phy_device_desc exynos5420_mipi_phy = {100	.num_regmaps = 1,101	.regmap_names = {"syscon"},102	.num_phys = 5,103	.phys = {104		{105			/* EXYNOS_MIPI_PHY_ID_CSIS0 */106			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,107			.enable_val = EXYNOS4_PHY_ENABLE,108			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),109			.enable_map = EXYNOS_MIPI_REGMAP_PMU,110			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,111			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),112			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,113		}, {114			/* EXYNOS_MIPI_PHY_ID_DSIM0 */115			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,116			.enable_val = EXYNOS4_PHY_ENABLE,117			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),118			.enable_map = EXYNOS_MIPI_REGMAP_PMU,119			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,120			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),121			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,122		}, {123			/* EXYNOS_MIPI_PHY_ID_CSIS1 */124			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,125			.enable_val = EXYNOS4_PHY_ENABLE,126			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),127			.enable_map = EXYNOS_MIPI_REGMAP_PMU,128			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,129			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),130			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,131		}, {132			/* EXYNOS_MIPI_PHY_ID_DSIM1 */133			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,134			.enable_val = EXYNOS4_PHY_ENABLE,135			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),136			.enable_map = EXYNOS_MIPI_REGMAP_PMU,137			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,138			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),139			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,140		}, {141			/* EXYNOS_MIPI_PHY_ID_CSIS2 */142			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,143			.enable_val = EXYNOS4_PHY_ENABLE,144			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),145			.enable_map = EXYNOS_MIPI_REGMAP_PMU,146			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,147			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),148			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,149		},150	},151};152 153#define EXYNOS5433_SYSREG_DISP_MIPI_PHY		0x100C154#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON	0x1014155#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON	0x1020156 157static const struct mipi_phy_device_desc exynos5433_mipi_phy = {158	.num_regmaps = 4,159	.regmap_names = {160		"samsung,pmu-syscon",161		"samsung,disp-sysreg",162		"samsung,cam0-sysreg",163		"samsung,cam1-sysreg"164	},165	.num_phys = 5,166	.phys = {167		{168			/* EXYNOS_MIPI_PHY_ID_CSIS0 */169			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,170			.enable_val = EXYNOS4_PHY_ENABLE,171			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),172			.enable_map = EXYNOS_MIPI_REGMAP_PMU,173			.resetn_val = BIT(0),174			.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,175			.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,176		}, {177			/* EXYNOS_MIPI_PHY_ID_DSIM0 */178			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,179			.enable_val = EXYNOS4_PHY_ENABLE,180			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),181			.enable_map = EXYNOS_MIPI_REGMAP_PMU,182			.resetn_val = BIT(0),183			.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,184			.resetn_map = EXYNOS_MIPI_REGMAP_DISP,185		}, {186			/* EXYNOS_MIPI_PHY_ID_CSIS1 */187			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,188			.enable_val = EXYNOS4_PHY_ENABLE,189			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),190			.enable_map = EXYNOS_MIPI_REGMAP_PMU,191			.resetn_val = BIT(1),192			.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,193			.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,194		}, {195			/* EXYNOS_MIPI_PHY_ID_DSIM1 */196			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,197			.enable_val = EXYNOS4_PHY_ENABLE,198			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),199			.enable_map = EXYNOS_MIPI_REGMAP_PMU,200			.resetn_val = BIT(1),201			.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,202			.resetn_map = EXYNOS_MIPI_REGMAP_DISP,203		}, {204			/* EXYNOS_MIPI_PHY_ID_CSIS2 */205			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,206			.enable_val = EXYNOS4_PHY_ENABLE,207			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(2),208			.enable_map = EXYNOS_MIPI_REGMAP_PMU,209			.resetn_val = BIT(0),210			.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,211			.resetn_map = EXYNOS_MIPI_REGMAP_CAM1,212		},213	},214};215 216struct exynos_mipi_video_phy {217	struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM];218	int num_phys;219	struct video_phy_desc {220		struct phy *phy;221		unsigned int index;222		const struct exynos_mipi_phy_desc *data;223	} phys[EXYNOS_MIPI_PHYS_NUM];224	spinlock_t slock;225};226 227static int __set_phy_state(const struct exynos_mipi_phy_desc *data,228			   struct exynos_mipi_video_phy *state, unsigned int on)229{230	struct regmap *enable_map = state->regmaps[data->enable_map];231	struct regmap *resetn_map = state->regmaps[data->resetn_map];232 233	spin_lock(&state->slock);234 235	/* disable in PMU sysreg */236	if (!on && data->coupled_phy_id >= 0 &&237	    state->phys[data->coupled_phy_id].phy->power_count == 0)238		regmap_update_bits(enable_map, data->enable_reg,239				   data->enable_val, 0);240	/* PHY reset */241	if (on)242		regmap_update_bits(resetn_map, data->resetn_reg,243				   data->resetn_val, data->resetn_val);244	else245		regmap_update_bits(resetn_map, data->resetn_reg,246				   data->resetn_val, 0);247	/* enable in PMU sysreg */248	if (on)249		regmap_update_bits(enable_map, data->enable_reg,250				   data->enable_val, data->enable_val);251 252	spin_unlock(&state->slock);253 254	return 0;255}256 257#define to_mipi_video_phy(desc) \258	container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index])259 260static int exynos_mipi_video_phy_power_on(struct phy *phy)261{262	struct video_phy_desc *phy_desc = phy_get_drvdata(phy);263	struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);264 265	return __set_phy_state(phy_desc->data, state, 1);266}267 268static int exynos_mipi_video_phy_power_off(struct phy *phy)269{270	struct video_phy_desc *phy_desc = phy_get_drvdata(phy);271	struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);272 273	return __set_phy_state(phy_desc->data, state, 0);274}275 276static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,277					const struct of_phandle_args *args)278{279	struct exynos_mipi_video_phy *state = dev_get_drvdata(dev);280 281	if (WARN_ON(args->args[0] >= state->num_phys))282		return ERR_PTR(-ENODEV);283 284	return state->phys[args->args[0]].phy;285}286 287static const struct phy_ops exynos_mipi_video_phy_ops = {288	.power_on	= exynos_mipi_video_phy_power_on,289	.power_off	= exynos_mipi_video_phy_power_off,290	.owner		= THIS_MODULE,291};292 293static int exynos_mipi_video_phy_probe(struct platform_device *pdev)294{295	const struct mipi_phy_device_desc *phy_dev;296	struct exynos_mipi_video_phy *state;297	struct device *dev = &pdev->dev;298	struct device_node *np = dev->of_node;299	struct phy_provider *phy_provider;300	unsigned int i = 0;301 302	phy_dev = of_device_get_match_data(dev);303	if (!phy_dev)304		return -ENODEV;305 306	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);307	if (!state)308		return -ENOMEM;309 310	state->regmaps[i] = syscon_node_to_regmap(dev->parent->of_node);311	if (!IS_ERR(state->regmaps[i]))312		i++;313	for (; i < phy_dev->num_regmaps; i++) {314		state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,315						phy_dev->regmap_names[i]);316		if (IS_ERR(state->regmaps[i]))317			return PTR_ERR(state->regmaps[i]);318	}319	state->num_phys = phy_dev->num_phys;320	spin_lock_init(&state->slock);321 322	dev_set_drvdata(dev, state);323 324	for (i = 0; i < state->num_phys; i++) {325		struct phy *phy = devm_phy_create(dev, NULL,326						  &exynos_mipi_video_phy_ops);327		if (IS_ERR(phy)) {328			dev_err(dev, "failed to create PHY %d\n", i);329			return PTR_ERR(phy);330		}331 332		state->phys[i].phy = phy;333		state->phys[i].index = i;334		state->phys[i].data = &phy_dev->phys[i];335		phy_set_drvdata(phy, &state->phys[i]);336	}337 338	phy_provider = devm_of_phy_provider_register(dev,339					exynos_mipi_video_phy_xlate);340 341	return PTR_ERR_OR_ZERO(phy_provider);342}343 344static const struct of_device_id exynos_mipi_video_phy_of_match[] = {345	{346		.compatible = "samsung,s5pv210-mipi-video-phy",347		.data = &s5pv210_mipi_phy,348	}, {349		.compatible = "samsung,exynos5420-mipi-video-phy",350		.data = &exynos5420_mipi_phy,351	}, {352		.compatible = "samsung,exynos5433-mipi-video-phy",353		.data = &exynos5433_mipi_phy,354	},355	{ /* sentinel */ },356};357MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);358 359static struct platform_driver exynos_mipi_video_phy_driver = {360	.probe	= exynos_mipi_video_phy_probe,361	.driver = {362		.of_match_table	= exynos_mipi_video_phy_of_match,363		.name  = "exynos-mipi-video-phy",364		.suppress_bind_attrs = true,365	}366};367module_platform_driver(exynos_mipi_video_phy_driver);368 369MODULE_DESCRIPTION("Samsung S5P/Exynos SoC MIPI CSI-2/DSI PHY driver");370MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");371MODULE_LICENSE("GPL v2");372