1*b3dcb5deSRobert Marko // SPDX-License-Identifier: GPL-2.0-only
2*b3dcb5deSRobert Marko /*
3*b3dcb5deSRobert Marko * Delta TN48M CPLD GPIO driver
4*b3dcb5deSRobert Marko *
5*b3dcb5deSRobert Marko * Copyright (C) 2021 Sartura Ltd.
6*b3dcb5deSRobert Marko *
7*b3dcb5deSRobert Marko * Author: Robert Marko <robert.marko@sartura.hr>
8*b3dcb5deSRobert Marko */
9*b3dcb5deSRobert Marko
10*b3dcb5deSRobert Marko #include <linux/device.h>
11*b3dcb5deSRobert Marko #include <linux/gpio/driver.h>
12*b3dcb5deSRobert Marko #include <linux/gpio/regmap.h>
13*b3dcb5deSRobert Marko #include <linux/mod_devicetable.h>
14*b3dcb5deSRobert Marko #include <linux/module.h>
15*b3dcb5deSRobert Marko #include <linux/platform_device.h>
16*b3dcb5deSRobert Marko #include <linux/regmap.h>
17*b3dcb5deSRobert Marko
18*b3dcb5deSRobert Marko enum tn48m_gpio_type {
19*b3dcb5deSRobert Marko TN48M_GP0 = 1,
20*b3dcb5deSRobert Marko TN48M_GPI,
21*b3dcb5deSRobert Marko };
22*b3dcb5deSRobert Marko
23*b3dcb5deSRobert Marko struct tn48m_gpio_config {
24*b3dcb5deSRobert Marko int ngpio;
25*b3dcb5deSRobert Marko int ngpio_per_reg;
26*b3dcb5deSRobert Marko enum tn48m_gpio_type type;
27*b3dcb5deSRobert Marko };
28*b3dcb5deSRobert Marko
29*b3dcb5deSRobert Marko static const struct tn48m_gpio_config tn48m_gpo_config = {
30*b3dcb5deSRobert Marko .ngpio = 4,
31*b3dcb5deSRobert Marko .ngpio_per_reg = 4,
32*b3dcb5deSRobert Marko .type = TN48M_GP0,
33*b3dcb5deSRobert Marko };
34*b3dcb5deSRobert Marko
35*b3dcb5deSRobert Marko static const struct tn48m_gpio_config tn48m_gpi_config = {
36*b3dcb5deSRobert Marko .ngpio = 4,
37*b3dcb5deSRobert Marko .ngpio_per_reg = 4,
38*b3dcb5deSRobert Marko .type = TN48M_GPI,
39*b3dcb5deSRobert Marko };
40*b3dcb5deSRobert Marko
tn48m_gpio_probe(struct platform_device * pdev)41*b3dcb5deSRobert Marko static int tn48m_gpio_probe(struct platform_device *pdev)
42*b3dcb5deSRobert Marko {
43*b3dcb5deSRobert Marko const struct tn48m_gpio_config *gpio_config;
44*b3dcb5deSRobert Marko struct gpio_regmap_config config = {};
45*b3dcb5deSRobert Marko struct regmap *regmap;
46*b3dcb5deSRobert Marko u32 base;
47*b3dcb5deSRobert Marko int ret;
48*b3dcb5deSRobert Marko
49*b3dcb5deSRobert Marko if (!pdev->dev.parent)
50*b3dcb5deSRobert Marko return -ENODEV;
51*b3dcb5deSRobert Marko
52*b3dcb5deSRobert Marko gpio_config = device_get_match_data(&pdev->dev);
53*b3dcb5deSRobert Marko if (!gpio_config)
54*b3dcb5deSRobert Marko return -ENODEV;
55*b3dcb5deSRobert Marko
56*b3dcb5deSRobert Marko ret = device_property_read_u32(&pdev->dev, "reg", &base);
57*b3dcb5deSRobert Marko if (ret)
58*b3dcb5deSRobert Marko return ret;
59*b3dcb5deSRobert Marko
60*b3dcb5deSRobert Marko regmap = dev_get_regmap(pdev->dev.parent, NULL);
61*b3dcb5deSRobert Marko if (!regmap)
62*b3dcb5deSRobert Marko return -ENODEV;
63*b3dcb5deSRobert Marko
64*b3dcb5deSRobert Marko config.regmap = regmap;
65*b3dcb5deSRobert Marko config.parent = &pdev->dev;
66*b3dcb5deSRobert Marko config.ngpio = gpio_config->ngpio;
67*b3dcb5deSRobert Marko config.ngpio_per_reg = gpio_config->ngpio_per_reg;
68*b3dcb5deSRobert Marko switch (gpio_config->type) {
69*b3dcb5deSRobert Marko case TN48M_GP0:
70*b3dcb5deSRobert Marko config.reg_set_base = base;
71*b3dcb5deSRobert Marko break;
72*b3dcb5deSRobert Marko case TN48M_GPI:
73*b3dcb5deSRobert Marko config.reg_dat_base = base;
74*b3dcb5deSRobert Marko break;
75*b3dcb5deSRobert Marko default:
76*b3dcb5deSRobert Marko return -EINVAL;
77*b3dcb5deSRobert Marko }
78*b3dcb5deSRobert Marko
79*b3dcb5deSRobert Marko return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&pdev->dev, &config));
80*b3dcb5deSRobert Marko }
81*b3dcb5deSRobert Marko
82*b3dcb5deSRobert Marko static const struct of_device_id tn48m_gpio_of_match[] = {
83*b3dcb5deSRobert Marko { .compatible = "delta,tn48m-gpo", .data = &tn48m_gpo_config },
84*b3dcb5deSRobert Marko { .compatible = "delta,tn48m-gpi", .data = &tn48m_gpi_config },
85*b3dcb5deSRobert Marko { }
86*b3dcb5deSRobert Marko };
87*b3dcb5deSRobert Marko MODULE_DEVICE_TABLE(of, tn48m_gpio_of_match);
88*b3dcb5deSRobert Marko
89*b3dcb5deSRobert Marko static struct platform_driver tn48m_gpio_driver = {
90*b3dcb5deSRobert Marko .driver = {
91*b3dcb5deSRobert Marko .name = "delta-tn48m-gpio",
92*b3dcb5deSRobert Marko .of_match_table = tn48m_gpio_of_match,
93*b3dcb5deSRobert Marko },
94*b3dcb5deSRobert Marko .probe = tn48m_gpio_probe,
95*b3dcb5deSRobert Marko };
96*b3dcb5deSRobert Marko module_platform_driver(tn48m_gpio_driver);
97*b3dcb5deSRobert Marko
98*b3dcb5deSRobert Marko MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
99*b3dcb5deSRobert Marko MODULE_DESCRIPTION("Delta TN48M CPLD GPIO driver");
100*b3dcb5deSRobert Marko MODULE_LICENSE("GPL");
101