Lines Matching +full:exynos +full:- +full:usi

1 // SPDX-License-Identifier: GPL-2.0
6 * Samsung Exynos USI driver (Universal Serial Interface).
17 #include <dt-bindings/soc/samsung,exynos-usi.h>
27 /* USIv2: USI register offsets */
31 /* USIv2: USI register bits */
41 enum exynos_usi_ver ver; /* USI IP-core version */
51 void __iomem *regs; /* USI register map */
52 struct clk_bulk_data *clks; /* USI clocks */
54 size_t mode; /* current USI SW_CONF mode index */
88 .compatible = "samsung,exynos850-usi",
96 * exynos_usi_set_sw_conf - Set USI block configuration mode
97 * @usi: USI driver object
100 * Select underlying serial protocol (UART/SPI/I2C) in USI IP-core.
104 static int exynos_usi_set_sw_conf(struct exynos_usi *usi, size_t mode) in exynos_usi_set_sw_conf() argument
109 if (mode < usi->data->min_mode || mode > usi->data->max_mode) in exynos_usi_set_sw_conf()
110 return -EINVAL; in exynos_usi_set_sw_conf()
113 ret = regmap_update_bits(usi->sysreg, usi->sw_conf, in exynos_usi_set_sw_conf()
114 usi->data->sw_conf_mask, val); in exynos_usi_set_sw_conf()
118 usi->mode = mode; in exynos_usi_set_sw_conf()
119 dev_dbg(usi->dev, "protocol: %s\n", exynos_usi_modes[usi->mode].name); in exynos_usi_set_sw_conf()
125 * exynos_usi_enable - Initialize USI block
126 * @usi: USI driver object
128 * USI IP-core start state is "reset" (on startup and after CPU resume). This
129 * routine enables the USI block by clearing the reset flag. It also configures
135 static int exynos_usi_enable(const struct exynos_usi *usi) in exynos_usi_enable() argument
140 ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks); in exynos_usi_enable()
144 /* Enable USI block */ in exynos_usi_enable()
145 val = readl(usi->regs + USI_CON); in exynos_usi_enable()
147 writel(val, usi->regs + USI_CON); in exynos_usi_enable()
150 /* Continuously provide the clock to USI IP w/o gating */ in exynos_usi_enable()
151 if (usi->clkreq_on) { in exynos_usi_enable()
152 val = readl(usi->regs + USI_OPTION); in exynos_usi_enable()
155 writel(val, usi->regs + USI_OPTION); in exynos_usi_enable()
158 clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks); in exynos_usi_enable()
163 static int exynos_usi_configure(struct exynos_usi *usi) in exynos_usi_configure() argument
167 ret = exynos_usi_set_sw_conf(usi, usi->mode); in exynos_usi_configure()
171 if (usi->data->ver == USI_VER2) in exynos_usi_configure()
172 return exynos_usi_enable(usi); in exynos_usi_configure()
177 static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi) in exynos_usi_parse_dt() argument
185 if (mode < usi->data->min_mode || mode > usi->data->max_mode) in exynos_usi_parse_dt()
186 return -EINVAL; in exynos_usi_parse_dt()
187 usi->mode = mode; in exynos_usi_parse_dt()
189 usi->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg"); in exynos_usi_parse_dt()
190 if (IS_ERR(usi->sysreg)) in exynos_usi_parse_dt()
191 return PTR_ERR(usi->sysreg); in exynos_usi_parse_dt()
194 &usi->sw_conf); in exynos_usi_parse_dt()
198 usi->clkreq_on = of_property_read_bool(np, "samsung,clkreq-on"); in exynos_usi_parse_dt()
203 static int exynos_usi_get_clocks(struct exynos_usi *usi) in exynos_usi_get_clocks() argument
205 const size_t num = usi->data->num_clks; in exynos_usi_get_clocks()
206 struct device *dev = usi->dev; in exynos_usi_get_clocks()
212 usi->clks = devm_kcalloc(dev, num, sizeof(*usi->clks), GFP_KERNEL); in exynos_usi_get_clocks()
213 if (!usi->clks) in exynos_usi_get_clocks()
214 return -ENOMEM; in exynos_usi_get_clocks()
217 usi->clks[i].id = usi->data->clk_names[i]; in exynos_usi_get_clocks()
219 return devm_clk_bulk_get(dev, num, usi->clks); in exynos_usi_get_clocks()
224 struct device *dev = &pdev->dev; in exynos_usi_probe()
225 struct device_node *np = dev->of_node; in exynos_usi_probe()
226 struct exynos_usi *usi; in exynos_usi_probe() local
229 usi = devm_kzalloc(dev, sizeof(*usi), GFP_KERNEL); in exynos_usi_probe()
230 if (!usi) in exynos_usi_probe()
231 return -ENOMEM; in exynos_usi_probe()
233 usi->dev = dev; in exynos_usi_probe()
234 platform_set_drvdata(pdev, usi); in exynos_usi_probe()
236 usi->data = of_device_get_match_data(dev); in exynos_usi_probe()
237 if (!usi->data) in exynos_usi_probe()
238 return -EINVAL; in exynos_usi_probe()
240 ret = exynos_usi_parse_dt(np, usi); in exynos_usi_probe()
244 ret = exynos_usi_get_clocks(usi); in exynos_usi_probe()
248 if (usi->data->ver == USI_VER2) { in exynos_usi_probe()
249 usi->regs = devm_platform_ioremap_resource(pdev, 0); in exynos_usi_probe()
250 if (IS_ERR(usi->regs)) in exynos_usi_probe()
251 return PTR_ERR(usi->regs); in exynos_usi_probe()
254 ret = exynos_usi_configure(usi); in exynos_usi_probe()
258 /* Make it possible to embed protocol nodes into USI np */ in exynos_usi_probe()
264 struct exynos_usi *usi = dev_get_drvdata(dev); in exynos_usi_resume_noirq() local
266 return exynos_usi_configure(usi); in exynos_usi_resume_noirq()
275 .name = "exynos-usi",
283 MODULE_DESCRIPTION("Samsung USI driver");