]>
Commit | Line | Data |
---|---|---|
6c27219e NA |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Driver for Khadas System control Microcontroller | |
4 | * | |
5 | * Copyright (C) 2020 BayLibre SAS | |
6 | * | |
7 | * Author(s): Neil Armstrong <narmstrong@baylibre.com> | |
8 | */ | |
9 | #include <linux/bitfield.h> | |
10 | #include <linux/i2c.h> | |
11 | #include <linux/mfd/core.h> | |
12 | #include <linux/mfd/khadas-mcu.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/regmap.h> | |
15 | ||
16 | static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg) | |
17 | { | |
18 | if (reg >= KHADAS_MCU_USER_DATA_0_REG && | |
19 | reg < KHADAS_MCU_PWR_OFF_CMD_REG) | |
20 | return true; | |
21 | ||
22 | switch (reg) { | |
23 | case KHADAS_MCU_PWR_OFF_CMD_REG: | |
24 | case KHADAS_MCU_PASSWD_START_REG: | |
25 | case KHADAS_MCU_CHECK_VEN_PASSWD_REG: | |
26 | case KHADAS_MCU_CHECK_USER_PASSWD_REG: | |
27 | case KHADAS_MCU_WOL_INIT_START_REG: | |
28 | case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG: | |
29 | return true; | |
30 | default: | |
31 | return false; | |
32 | } | |
33 | } | |
34 | ||
35 | static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg) | |
36 | { | |
37 | switch (reg) { | |
38 | case KHADAS_MCU_PASSWD_VEN_0_REG: | |
39 | case KHADAS_MCU_PASSWD_VEN_1_REG: | |
40 | case KHADAS_MCU_PASSWD_VEN_2_REG: | |
41 | case KHADAS_MCU_PASSWD_VEN_3_REG: | |
42 | case KHADAS_MCU_PASSWD_VEN_4_REG: | |
43 | case KHADAS_MCU_PASSWD_VEN_5_REG: | |
44 | case KHADAS_MCU_MAC_0_REG: | |
45 | case KHADAS_MCU_MAC_1_REG: | |
46 | case KHADAS_MCU_MAC_2_REG: | |
47 | case KHADAS_MCU_MAC_3_REG: | |
48 | case KHADAS_MCU_MAC_4_REG: | |
49 | case KHADAS_MCU_MAC_5_REG: | |
50 | case KHADAS_MCU_USID_0_REG: | |
51 | case KHADAS_MCU_USID_1_REG: | |
52 | case KHADAS_MCU_USID_2_REG: | |
53 | case KHADAS_MCU_USID_3_REG: | |
54 | case KHADAS_MCU_USID_4_REG: | |
55 | case KHADAS_MCU_USID_5_REG: | |
56 | case KHADAS_MCU_VERSION_0_REG: | |
57 | case KHADAS_MCU_VERSION_1_REG: | |
58 | case KHADAS_MCU_DEVICE_NO_0_REG: | |
59 | case KHADAS_MCU_DEVICE_NO_1_REG: | |
60 | case KHADAS_MCU_FACTORY_TEST_REG: | |
61 | case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG: | |
62 | return false; | |
63 | default: | |
64 | return true; | |
65 | } | |
66 | } | |
67 | ||
68 | static const struct regmap_config khadas_mcu_regmap_config = { | |
69 | .reg_bits = 8, | |
70 | .reg_stride = 1, | |
71 | .val_bits = 8, | |
72 | .max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG, | |
73 | .volatile_reg = khadas_mcu_reg_volatile, | |
74 | .writeable_reg = khadas_mcu_reg_writeable, | |
75 | .cache_type = REGCACHE_RBTREE, | |
76 | }; | |
77 | ||
78 | static struct mfd_cell khadas_mcu_fan_cells[] = { | |
79 | /* VIM1/2 Rev13+ and VIM3 only */ | |
80 | { .name = "khadas-mcu-fan-ctrl", }, | |
81 | }; | |
82 | ||
83 | static struct mfd_cell khadas_mcu_cells[] = { | |
84 | { .name = "khadas-mcu-user-mem", }, | |
85 | }; | |
86 | ||
87 | static int khadas_mcu_probe(struct i2c_client *client, | |
88 | const struct i2c_device_id *id) | |
89 | { | |
90 | struct device *dev = &client->dev; | |
91 | struct khadas_mcu *ddata; | |
92 | int ret; | |
93 | ||
94 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | |
95 | if (!ddata) | |
96 | return -ENOMEM; | |
97 | ||
98 | i2c_set_clientdata(client, ddata); | |
99 | ||
100 | ddata->dev = dev; | |
101 | ||
102 | ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config); | |
103 | if (IS_ERR(ddata->regmap)) { | |
104 | ret = PTR_ERR(ddata->regmap); | |
105 | dev_err(dev, "Failed to allocate register map: %d\n", ret); | |
106 | return ret; | |
107 | } | |
108 | ||
109 | ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | |
110 | khadas_mcu_cells, | |
111 | ARRAY_SIZE(khadas_mcu_cells), | |
112 | NULL, 0, NULL); | |
113 | if (ret) | |
114 | return ret; | |
115 | ||
116 | if (of_find_property(dev->of_node, "#cooling-cells", NULL)) | |
117 | return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | |
118 | khadas_mcu_fan_cells, | |
119 | ARRAY_SIZE(khadas_mcu_fan_cells), | |
120 | NULL, 0, NULL); | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
125 | static const struct of_device_id khadas_mcu_of_match[] = { | |
126 | { .compatible = "khadas,mcu", }, | |
127 | {}, | |
128 | }; | |
129 | MODULE_DEVICE_TABLE(of, khadas_mcu_of_match); | |
130 | ||
131 | static struct i2c_driver khadas_mcu_driver = { | |
132 | .driver = { | |
133 | .name = "khadas-mcu-core", | |
134 | .of_match_table = of_match_ptr(khadas_mcu_of_match), | |
135 | }, | |
136 | .probe = khadas_mcu_probe, | |
137 | }; | |
138 | module_i2c_driver(khadas_mcu_driver); | |
139 | ||
140 | MODULE_DESCRIPTION("Khadas MCU core driver"); | |
141 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | |
142 | MODULE_LICENSE("GPL v2"); |