123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Driver for Khadas System control Microcontroller
- *
- * Copyright (C) 2020 BayLibre SAS
- *
- * Author(s): Neil Armstrong <[email protected]>
- */
- #include <linux/bitfield.h>
- #include <linux/i2c.h>
- #include <linux/mfd/core.h>
- #include <linux/mfd/khadas-mcu.h>
- #include <linux/module.h>
- #include <linux/regmap.h>
- static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
- {
- if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
- reg < KHADAS_MCU_PWR_OFF_CMD_REG)
- return true;
- switch (reg) {
- case KHADAS_MCU_PWR_OFF_CMD_REG:
- case KHADAS_MCU_PASSWD_START_REG:
- case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
- case KHADAS_MCU_CHECK_USER_PASSWD_REG:
- case KHADAS_MCU_WOL_INIT_START_REG:
- case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
- return true;
- default:
- return false;
- }
- }
- static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
- {
- switch (reg) {
- case KHADAS_MCU_PASSWD_VEN_0_REG:
- case KHADAS_MCU_PASSWD_VEN_1_REG:
- case KHADAS_MCU_PASSWD_VEN_2_REG:
- case KHADAS_MCU_PASSWD_VEN_3_REG:
- case KHADAS_MCU_PASSWD_VEN_4_REG:
- case KHADAS_MCU_PASSWD_VEN_5_REG:
- case KHADAS_MCU_MAC_0_REG:
- case KHADAS_MCU_MAC_1_REG:
- case KHADAS_MCU_MAC_2_REG:
- case KHADAS_MCU_MAC_3_REG:
- case KHADAS_MCU_MAC_4_REG:
- case KHADAS_MCU_MAC_5_REG:
- case KHADAS_MCU_USID_0_REG:
- case KHADAS_MCU_USID_1_REG:
- case KHADAS_MCU_USID_2_REG:
- case KHADAS_MCU_USID_3_REG:
- case KHADAS_MCU_USID_4_REG:
- case KHADAS_MCU_USID_5_REG:
- case KHADAS_MCU_VERSION_0_REG:
- case KHADAS_MCU_VERSION_1_REG:
- case KHADAS_MCU_DEVICE_NO_0_REG:
- case KHADAS_MCU_DEVICE_NO_1_REG:
- case KHADAS_MCU_FACTORY_TEST_REG:
- case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
- return false;
- default:
- return true;
- }
- }
- static const struct regmap_config khadas_mcu_regmap_config = {
- .reg_bits = 8,
- .reg_stride = 1,
- .val_bits = 8,
- .max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
- .volatile_reg = khadas_mcu_reg_volatile,
- .writeable_reg = khadas_mcu_reg_writeable,
- .cache_type = REGCACHE_RBTREE,
- };
- static struct mfd_cell khadas_mcu_fan_cells[] = {
- /* VIM1/2 Rev13+ and VIM3 only */
- { .name = "khadas-mcu-fan-ctrl", },
- };
- static struct mfd_cell khadas_mcu_cells[] = {
- { .name = "khadas-mcu-user-mem", },
- };
- static int khadas_mcu_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct device *dev = &client->dev;
- struct khadas_mcu *ddata;
- int ret;
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
- i2c_set_clientdata(client, ddata);
- ddata->dev = dev;
- ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
- if (IS_ERR(ddata->regmap)) {
- ret = PTR_ERR(ddata->regmap);
- dev_err(dev, "Failed to allocate register map: %d\n", ret);
- return ret;
- }
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_cells,
- ARRAY_SIZE(khadas_mcu_cells),
- NULL, 0, NULL);
- if (ret)
- return ret;
- if (of_find_property(dev->of_node, "#cooling-cells", NULL))
- return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_fan_cells,
- ARRAY_SIZE(khadas_mcu_fan_cells),
- NULL, 0, NULL);
- return 0;
- }
- #ifdef CONFIG_OF
- static const struct of_device_id khadas_mcu_of_match[] = {
- { .compatible = "khadas,mcu", },
- {},
- };
- MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
- #endif
- static struct i2c_driver khadas_mcu_driver = {
- .driver = {
- .name = "khadas-mcu-core",
- .of_match_table = of_match_ptr(khadas_mcu_of_match),
- },
- .probe = khadas_mcu_probe,
- };
- module_i2c_driver(khadas_mcu_driver);
- MODULE_DESCRIPTION("Khadas MCU core driver");
- MODULE_AUTHOR("Neil Armstrong <[email protected]>");
- MODULE_LICENSE("GPL v2");
|