Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for Khadas System control Microcontroller
0004  *
0005  * Copyright (C) 2020 BayLibre SAS
0006  *
0007  * Author(s): Neil Armstrong <narmstrong@baylibre.com>
0008  */
0009 #include <linux/bitfield.h>
0010 #include <linux/i2c.h>
0011 #include <linux/mfd/core.h>
0012 #include <linux/mfd/khadas-mcu.h>
0013 #include <linux/module.h>
0014 #include <linux/regmap.h>
0015 
0016 static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
0017 {
0018     if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
0019         reg < KHADAS_MCU_PWR_OFF_CMD_REG)
0020         return true;
0021 
0022     switch (reg) {
0023     case KHADAS_MCU_PWR_OFF_CMD_REG:
0024     case KHADAS_MCU_PASSWD_START_REG:
0025     case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
0026     case KHADAS_MCU_CHECK_USER_PASSWD_REG:
0027     case KHADAS_MCU_WOL_INIT_START_REG:
0028     case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
0029         return true;
0030     default:
0031         return false;
0032     }
0033 }
0034 
0035 static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
0036 {
0037     switch (reg) {
0038     case KHADAS_MCU_PASSWD_VEN_0_REG:
0039     case KHADAS_MCU_PASSWD_VEN_1_REG:
0040     case KHADAS_MCU_PASSWD_VEN_2_REG:
0041     case KHADAS_MCU_PASSWD_VEN_3_REG:
0042     case KHADAS_MCU_PASSWD_VEN_4_REG:
0043     case KHADAS_MCU_PASSWD_VEN_5_REG:
0044     case KHADAS_MCU_MAC_0_REG:
0045     case KHADAS_MCU_MAC_1_REG:
0046     case KHADAS_MCU_MAC_2_REG:
0047     case KHADAS_MCU_MAC_3_REG:
0048     case KHADAS_MCU_MAC_4_REG:
0049     case KHADAS_MCU_MAC_5_REG:
0050     case KHADAS_MCU_USID_0_REG:
0051     case KHADAS_MCU_USID_1_REG:
0052     case KHADAS_MCU_USID_2_REG:
0053     case KHADAS_MCU_USID_3_REG:
0054     case KHADAS_MCU_USID_4_REG:
0055     case KHADAS_MCU_USID_5_REG:
0056     case KHADAS_MCU_VERSION_0_REG:
0057     case KHADAS_MCU_VERSION_1_REG:
0058     case KHADAS_MCU_DEVICE_NO_0_REG:
0059     case KHADAS_MCU_DEVICE_NO_1_REG:
0060     case KHADAS_MCU_FACTORY_TEST_REG:
0061     case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
0062         return false;
0063     default:
0064         return true;
0065     }
0066 }
0067 
0068 static const struct regmap_config khadas_mcu_regmap_config = {
0069     .reg_bits   = 8,
0070     .reg_stride = 1,
0071     .val_bits   = 8,
0072     .max_register   = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
0073     .volatile_reg   = khadas_mcu_reg_volatile,
0074     .writeable_reg  = khadas_mcu_reg_writeable,
0075     .cache_type = REGCACHE_RBTREE,
0076 };
0077 
0078 static struct mfd_cell khadas_mcu_fan_cells[] = {
0079     /* VIM1/2 Rev13+ and VIM3 only */
0080     { .name = "khadas-mcu-fan-ctrl", },
0081 };
0082 
0083 static struct mfd_cell khadas_mcu_cells[] = {
0084     { .name = "khadas-mcu-user-mem", },
0085 };
0086 
0087 static int khadas_mcu_probe(struct i2c_client *client,
0088                const struct i2c_device_id *id)
0089 {
0090     struct device *dev = &client->dev;
0091     struct khadas_mcu *ddata;
0092     int ret;
0093 
0094     ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
0095     if (!ddata)
0096         return -ENOMEM;
0097 
0098     i2c_set_clientdata(client, ddata);
0099 
0100     ddata->dev = dev;
0101 
0102     ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
0103     if (IS_ERR(ddata->regmap)) {
0104         ret = PTR_ERR(ddata->regmap);
0105         dev_err(dev, "Failed to allocate register map: %d\n", ret);
0106         return ret;
0107     }
0108 
0109     ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0110                    khadas_mcu_cells,
0111                    ARRAY_SIZE(khadas_mcu_cells),
0112                    NULL, 0, NULL);
0113     if (ret)
0114         return ret;
0115 
0116     if (of_find_property(dev->of_node, "#cooling-cells", NULL))
0117         return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0118                         khadas_mcu_fan_cells,
0119                         ARRAY_SIZE(khadas_mcu_fan_cells),
0120                         NULL, 0, NULL);
0121 
0122     return 0;
0123 }
0124 
0125 #ifdef CONFIG_OF
0126 static const struct of_device_id khadas_mcu_of_match[] = {
0127     { .compatible = "khadas,mcu", },
0128     {},
0129 };
0130 MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
0131 #endif
0132 
0133 static struct i2c_driver khadas_mcu_driver = {
0134     .driver = {
0135         .name = "khadas-mcu-core",
0136         .of_match_table = of_match_ptr(khadas_mcu_of_match),
0137     },
0138     .probe = khadas_mcu_probe,
0139 };
0140 module_i2c_driver(khadas_mcu_driver);
0141 
0142 MODULE_DESCRIPTION("Khadas MCU core driver");
0143 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0144 MODULE_LICENSE("GPL v2");