xref: /openbmc/linux/drivers/mfd/khadas-mcu.c (revision 9816d859)
16c27219eSNeil Armstrong // SPDX-License-Identifier: GPL-2.0
26c27219eSNeil Armstrong /*
36c27219eSNeil Armstrong  * Driver for Khadas System control Microcontroller
46c27219eSNeil Armstrong  *
56c27219eSNeil Armstrong  * Copyright (C) 2020 BayLibre SAS
66c27219eSNeil Armstrong  *
76c27219eSNeil Armstrong  * Author(s): Neil Armstrong <narmstrong@baylibre.com>
86c27219eSNeil Armstrong  */
96c27219eSNeil Armstrong #include <linux/bitfield.h>
106c27219eSNeil Armstrong #include <linux/i2c.h>
116c27219eSNeil Armstrong #include <linux/mfd/core.h>
126c27219eSNeil Armstrong #include <linux/mfd/khadas-mcu.h>
136c27219eSNeil Armstrong #include <linux/module.h>
146c27219eSNeil Armstrong #include <linux/regmap.h>
156c27219eSNeil Armstrong 
khadas_mcu_reg_volatile(struct device * dev,unsigned int reg)166c27219eSNeil Armstrong static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
176c27219eSNeil Armstrong {
186c27219eSNeil Armstrong 	if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
196c27219eSNeil Armstrong 	    reg < KHADAS_MCU_PWR_OFF_CMD_REG)
206c27219eSNeil Armstrong 		return true;
216c27219eSNeil Armstrong 
226c27219eSNeil Armstrong 	switch (reg) {
236c27219eSNeil Armstrong 	case KHADAS_MCU_PWR_OFF_CMD_REG:
246c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_START_REG:
256c27219eSNeil Armstrong 	case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
266c27219eSNeil Armstrong 	case KHADAS_MCU_CHECK_USER_PASSWD_REG:
276c27219eSNeil Armstrong 	case KHADAS_MCU_WOL_INIT_START_REG:
286c27219eSNeil Armstrong 	case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
296c27219eSNeil Armstrong 		return true;
306c27219eSNeil Armstrong 	default:
316c27219eSNeil Armstrong 		return false;
326c27219eSNeil Armstrong 	}
336c27219eSNeil Armstrong }
346c27219eSNeil Armstrong 
khadas_mcu_reg_writeable(struct device * dev,unsigned int reg)356c27219eSNeil Armstrong static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
366c27219eSNeil Armstrong {
376c27219eSNeil Armstrong 	switch (reg) {
386c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_0_REG:
396c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_1_REG:
406c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_2_REG:
416c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_3_REG:
426c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_4_REG:
436c27219eSNeil Armstrong 	case KHADAS_MCU_PASSWD_VEN_5_REG:
446c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_0_REG:
456c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_1_REG:
466c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_2_REG:
476c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_3_REG:
486c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_4_REG:
496c27219eSNeil Armstrong 	case KHADAS_MCU_MAC_5_REG:
506c27219eSNeil Armstrong 	case KHADAS_MCU_USID_0_REG:
516c27219eSNeil Armstrong 	case KHADAS_MCU_USID_1_REG:
526c27219eSNeil Armstrong 	case KHADAS_MCU_USID_2_REG:
536c27219eSNeil Armstrong 	case KHADAS_MCU_USID_3_REG:
546c27219eSNeil Armstrong 	case KHADAS_MCU_USID_4_REG:
556c27219eSNeil Armstrong 	case KHADAS_MCU_USID_5_REG:
566c27219eSNeil Armstrong 	case KHADAS_MCU_VERSION_0_REG:
576c27219eSNeil Armstrong 	case KHADAS_MCU_VERSION_1_REG:
586c27219eSNeil Armstrong 	case KHADAS_MCU_DEVICE_NO_0_REG:
596c27219eSNeil Armstrong 	case KHADAS_MCU_DEVICE_NO_1_REG:
606c27219eSNeil Armstrong 	case KHADAS_MCU_FACTORY_TEST_REG:
616c27219eSNeil Armstrong 	case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
626c27219eSNeil Armstrong 		return false;
636c27219eSNeil Armstrong 	default:
646c27219eSNeil Armstrong 		return true;
656c27219eSNeil Armstrong 	}
666c27219eSNeil Armstrong }
676c27219eSNeil Armstrong 
686c27219eSNeil Armstrong static const struct regmap_config khadas_mcu_regmap_config = {
696c27219eSNeil Armstrong 	.reg_bits	= 8,
706c27219eSNeil Armstrong 	.reg_stride	= 1,
716c27219eSNeil Armstrong 	.val_bits	= 8,
726c27219eSNeil Armstrong 	.max_register	= KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
736c27219eSNeil Armstrong 	.volatile_reg	= khadas_mcu_reg_volatile,
746c27219eSNeil Armstrong 	.writeable_reg	= khadas_mcu_reg_writeable,
756c27219eSNeil Armstrong 	.cache_type	= REGCACHE_RBTREE,
766c27219eSNeil Armstrong };
776c27219eSNeil Armstrong 
786c27219eSNeil Armstrong static struct mfd_cell khadas_mcu_fan_cells[] = {
796c27219eSNeil Armstrong 	/* VIM1/2 Rev13+ and VIM3 only */
806c27219eSNeil Armstrong 	{ .name = "khadas-mcu-fan-ctrl", },
816c27219eSNeil Armstrong };
826c27219eSNeil Armstrong 
836c27219eSNeil Armstrong static struct mfd_cell khadas_mcu_cells[] = {
846c27219eSNeil Armstrong 	{ .name = "khadas-mcu-user-mem", },
856c27219eSNeil Armstrong };
866c27219eSNeil Armstrong 
khadas_mcu_probe(struct i2c_client * client)87c88e02daSUwe Kleine-König static int khadas_mcu_probe(struct i2c_client *client)
886c27219eSNeil Armstrong {
896c27219eSNeil Armstrong 	struct device *dev = &client->dev;
906c27219eSNeil Armstrong 	struct khadas_mcu *ddata;
916c27219eSNeil Armstrong 	int ret;
926c27219eSNeil Armstrong 
936c27219eSNeil Armstrong 	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
946c27219eSNeil Armstrong 	if (!ddata)
956c27219eSNeil Armstrong 		return -ENOMEM;
966c27219eSNeil Armstrong 
976c27219eSNeil Armstrong 	i2c_set_clientdata(client, ddata);
986c27219eSNeil Armstrong 
996c27219eSNeil Armstrong 	ddata->dev = dev;
1006c27219eSNeil Armstrong 
1016c27219eSNeil Armstrong 	ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
1026c27219eSNeil Armstrong 	if (IS_ERR(ddata->regmap)) {
1036c27219eSNeil Armstrong 		ret = PTR_ERR(ddata->regmap);
1046c27219eSNeil Armstrong 		dev_err(dev, "Failed to allocate register map: %d\n", ret);
1056c27219eSNeil Armstrong 		return ret;
1066c27219eSNeil Armstrong 	}
1076c27219eSNeil Armstrong 
1086c27219eSNeil Armstrong 	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
1096c27219eSNeil Armstrong 				   khadas_mcu_cells,
1106c27219eSNeil Armstrong 				   ARRAY_SIZE(khadas_mcu_cells),
1116c27219eSNeil Armstrong 				   NULL, 0, NULL);
1126c27219eSNeil Armstrong 	if (ret)
1136c27219eSNeil Armstrong 		return ret;
1146c27219eSNeil Armstrong 
1151ba58fbbSRob Herring 	if (of_property_present(dev->of_node, "#cooling-cells"))
1166c27219eSNeil Armstrong 		return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
1176c27219eSNeil Armstrong 					    khadas_mcu_fan_cells,
1186c27219eSNeil Armstrong 					    ARRAY_SIZE(khadas_mcu_fan_cells),
1196c27219eSNeil Armstrong 					    NULL, 0, NULL);
1206c27219eSNeil Armstrong 
1216c27219eSNeil Armstrong 	return 0;
1226c27219eSNeil Armstrong }
1236c27219eSNeil Armstrong 
124e26ea09bSLee Jones #ifdef CONFIG_OF
1256c27219eSNeil Armstrong static const struct of_device_id khadas_mcu_of_match[] = {
1266c27219eSNeil Armstrong 	{ .compatible = "khadas,mcu", },
1276c27219eSNeil Armstrong 	{},
1286c27219eSNeil Armstrong };
1296c27219eSNeil Armstrong MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
130e26ea09bSLee Jones #endif
1316c27219eSNeil Armstrong 
1326c27219eSNeil Armstrong static struct i2c_driver khadas_mcu_driver = {
1336c27219eSNeil Armstrong 	.driver = {
1346c27219eSNeil Armstrong 		.name = "khadas-mcu-core",
1356c27219eSNeil Armstrong 		.of_match_table = of_match_ptr(khadas_mcu_of_match),
1366c27219eSNeil Armstrong 	},
137*9816d859SUwe Kleine-König 	.probe = khadas_mcu_probe,
1386c27219eSNeil Armstrong };
1396c27219eSNeil Armstrong module_i2c_driver(khadas_mcu_driver);
1406c27219eSNeil Armstrong 
1416c27219eSNeil Armstrong MODULE_DESCRIPTION("Khadas MCU core driver");
1426c27219eSNeil Armstrong MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
1436c27219eSNeil Armstrong MODULE_LICENSE("GPL v2");
144