144 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for Khadas System control Microcontroller4 *5 * Copyright (C) 2020 BayLibre SAS6 *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 16static 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 35static 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 68static 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_MAPLE,76};77 78static struct mfd_cell khadas_mcu_fan_cells[] = {79 /* VIM1/2 Rev13+ and VIM3 only */80 { .name = "khadas-mcu-fan-ctrl", },81};82 83static struct mfd_cell khadas_mcu_cells[] = {84 { .name = "khadas-mcu-user-mem", },85};86 87static int khadas_mcu_probe(struct i2c_client *client)88{89 struct device *dev = &client->dev;90 struct khadas_mcu *ddata;91 int ret;92 93 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);94 if (!ddata)95 return -ENOMEM;96 97 i2c_set_clientdata(client, ddata);98 99 ddata->dev = dev;100 101 ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);102 if (IS_ERR(ddata->regmap)) {103 ret = PTR_ERR(ddata->regmap);104 dev_err(dev, "Failed to allocate register map: %d\n", ret);105 return ret;106 }107 108 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,109 khadas_mcu_cells,110 ARRAY_SIZE(khadas_mcu_cells),111 NULL, 0, NULL);112 if (ret)113 return ret;114 115 if (of_property_present(dev->of_node, "#cooling-cells"))116 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,117 khadas_mcu_fan_cells,118 ARRAY_SIZE(khadas_mcu_fan_cells),119 NULL, 0, NULL);120 121 return 0;122}123 124#ifdef CONFIG_OF125static const struct of_device_id khadas_mcu_of_match[] = {126 { .compatible = "khadas,mcu", },127 {},128};129MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);130#endif131 132static struct i2c_driver khadas_mcu_driver = {133 .driver = {134 .name = "khadas-mcu-core",135 .of_match_table = of_match_ptr(khadas_mcu_of_match),136 },137 .probe = khadas_mcu_probe,138};139module_i2c_driver(khadas_mcu_driver);140 141MODULE_DESCRIPTION("Khadas MCU core driver");142MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");143MODULE_LICENSE("GPL v2");144