1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for Khadas System control Microcontroller
5 * Copyright (C) 2020 BayLibre SAS
7 * Author(s): Neil Armstrong <narmstrong@baylibre.com>
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>
16 static bool khadas_mcu_reg_volatile(struct device
*dev
, unsigned int reg
)
18 if (reg
>= KHADAS_MCU_USER_DATA_0_REG
&&
19 reg
< KHADAS_MCU_PWR_OFF_CMD_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
:
35 static bool khadas_mcu_reg_writeable(struct device
*dev
, unsigned int 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
:
68 static const struct regmap_config khadas_mcu_regmap_config
= {
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
,
78 static struct mfd_cell khadas_mcu_fan_cells
[] = {
79 /* VIM1/2 Rev13+ and VIM3 only */
80 { .name
= "khadas-mcu-fan-ctrl", },
83 static struct mfd_cell khadas_mcu_cells
[] = {
84 { .name
= "khadas-mcu-user-mem", },
87 static int khadas_mcu_probe(struct i2c_client
*client
,
88 const struct i2c_device_id
*id
)
90 struct device
*dev
= &client
->dev
;
91 struct khadas_mcu
*ddata
;
94 ddata
= devm_kzalloc(dev
, sizeof(*ddata
), GFP_KERNEL
);
98 i2c_set_clientdata(client
, ddata
);
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
);
109 ret
= devm_mfd_add_devices(dev
, PLATFORM_DEVID_NONE
,
111 ARRAY_SIZE(khadas_mcu_cells
),
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
),
126 static const struct of_device_id khadas_mcu_of_match
[] = {
127 { .compatible
= "khadas,mcu", },
130 MODULE_DEVICE_TABLE(of
, khadas_mcu_of_match
);
133 static struct i2c_driver khadas_mcu_driver
= {
135 .name
= "khadas-mcu-core",
136 .of_match_table
= of_match_ptr(khadas_mcu_of_match
),
138 .probe
= khadas_mcu_probe
,
140 module_i2c_driver(khadas_mcu_driver
);
142 MODULE_DESCRIPTION("Khadas MCU core driver");
143 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
144 MODULE_LICENSE("GPL v2");