forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mfd: Add support for the Khadas System control Microcontroller
This Microcontroller is present on the Khadas VIM1, VIM2, VIM3 and Edge boards. It has multiple boot control features like password check, power-on options, power-off control and system FAN control on recent boards. This implements a very basic MFD driver with the fan control and User NVMEM cells. Signed-off-by: Neil Armstrong <[email protected]> Signed-off-by: Lee Jones <[email protected]>
- Loading branch information
1 parent
6bcb330
commit 6c27219
Showing
4 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// 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; | ||
} | ||
|
||
static const struct of_device_id khadas_mcu_of_match[] = { | ||
{ .compatible = "khadas,mcu", }, | ||
{}, | ||
}; | ||
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match); | ||
|
||
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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* | ||
* Khadas System control Microcontroller Register map | ||
* | ||
* Copyright (C) 2020 BayLibre SAS | ||
* | ||
* Author(s): Neil Armstrong <[email protected]> | ||
*/ | ||
|
||
#ifndef MFD_KHADAS_MCU_H | ||
#define MFD_KHADAS_MCU_H | ||
|
||
#define KHADAS_MCU_PASSWD_VEN_0_REG 0x00 /* RO */ | ||
#define KHADAS_MCU_PASSWD_VEN_1_REG 0x01 /* RO */ | ||
#define KHADAS_MCU_PASSWD_VEN_2_REG 0x02 /* RO */ | ||
#define KHADAS_MCU_PASSWD_VEN_3_REG 0x03 /* RO */ | ||
#define KHADAS_MCU_PASSWD_VEN_4_REG 0x04 /* RO */ | ||
#define KHADAS_MCU_PASSWD_VEN_5_REG 0x05 /* RO */ | ||
#define KHADAS_MCU_MAC_0_REG 0x06 /* RO */ | ||
#define KHADAS_MCU_MAC_1_REG 0x07 /* RO */ | ||
#define KHADAS_MCU_MAC_2_REG 0x08 /* RO */ | ||
#define KHADAS_MCU_MAC_3_REG 0x09 /* RO */ | ||
#define KHADAS_MCU_MAC_4_REG 0x0a /* RO */ | ||
#define KHADAS_MCU_MAC_5_REG 0x0b /* RO */ | ||
#define KHADAS_MCU_USID_0_REG 0x0c /* RO */ | ||
#define KHADAS_MCU_USID_1_REG 0x0d /* RO */ | ||
#define KHADAS_MCU_USID_2_REG 0x0e /* RO */ | ||
#define KHADAS_MCU_USID_3_REG 0x0f /* RO */ | ||
#define KHADAS_MCU_USID_4_REG 0x10 /* RO */ | ||
#define KHADAS_MCU_USID_5_REG 0x11 /* RO */ | ||
#define KHADAS_MCU_VERSION_0_REG 0x12 /* RO */ | ||
#define KHADAS_MCU_VERSION_1_REG 0x13 /* RO */ | ||
#define KHADAS_MCU_DEVICE_NO_0_REG 0x14 /* RO */ | ||
#define KHADAS_MCU_DEVICE_NO_1_REG 0x15 /* RO */ | ||
#define KHADAS_MCU_FACTORY_TEST_REG 0x16 /* R */ | ||
#define KHADAS_MCU_BOOT_MODE_REG 0x20 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_WOL_REG 0x21 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_RTC_REG 0x22 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_EXP_REG 0x23 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_IR_REG 0x24 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_DCIN_REG 0x25 /* RW */ | ||
#define KHADAS_MCU_BOOT_EN_KEY_REG 0x26 /* RW */ | ||
#define KHADAS_MCU_KEY_MODE_REG 0x27 /* RW */ | ||
#define KHADAS_MCU_LED_MODE_ON_REG 0x28 /* RW */ | ||
#define KHADAS_MCU_LED_MODE_OFF_REG 0x29 /* RW */ | ||
#define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c /* RW */ | ||
#define KHADAS_MCU_MAC_SWITCH_REG 0x2d /* RW */ | ||
#define KHADAS_MCU_MCU_SLEEP_MODE_REG 0x2e /* RW */ | ||
#define KHADAS_MCU_IR_CODE1_0_REG 0x2f /* RW */ | ||
#define KHADAS_MCU_IR_CODE1_1_REG 0x30 /* RW */ | ||
#define KHADAS_MCU_IR_CODE1_2_REG 0x31 /* RW */ | ||
#define KHADAS_MCU_IR_CODE1_3_REG 0x32 /* RW */ | ||
#define KHADAS_MCU_USB_PCIE_SWITCH_REG 0x33 /* RW */ | ||
#define KHADAS_MCU_IR_CODE2_0_REG 0x34 /* RW */ | ||
#define KHADAS_MCU_IR_CODE2_1_REG 0x35 /* RW */ | ||
#define KHADAS_MCU_IR_CODE2_2_REG 0x36 /* RW */ | ||
#define KHADAS_MCU_IR_CODE2_3_REG 0x37 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_0_REG 0x40 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_1_REG 0x41 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_2_REG 0x42 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_3_REG 0x43 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_4_REG 0x44 /* RW */ | ||
#define KHADAS_MCU_PASSWD_USER_5_REG 0x45 /* RW */ | ||
#define KHADAS_MCU_USER_DATA_0_REG 0x46 /* RW 56 bytes */ | ||
#define KHADAS_MCU_PWR_OFF_CMD_REG 0x80 /* WO */ | ||
#define KHADAS_MCU_PASSWD_START_REG 0x81 /* WO */ | ||
#define KHADAS_MCU_CHECK_VEN_PASSWD_REG 0x82 /* WO */ | ||
#define KHADAS_MCU_CHECK_USER_PASSWD_REG 0x83 /* WO */ | ||
#define KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG 0x86 /* RO */ | ||
#define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */ | ||
#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */ | ||
|
||
enum { | ||
KHADAS_BOARD_VIM1 = 0x1, | ||
KHADAS_BOARD_VIM2, | ||
KHADAS_BOARD_VIM3, | ||
KHADAS_BOARD_EDGE = 0x11, | ||
KHADAS_BOARD_EDGE_V, | ||
}; | ||
|
||
/** | ||
* struct khadas_mcu - Khadas MCU structure | ||
* @device: device reference used for logs | ||
* @regmap: register map | ||
*/ | ||
struct khadas_mcu { | ||
struct device *dev; | ||
struct regmap *regmap; | ||
}; | ||
|
||
#endif /* MFD_KHADAS_MCU_H */ |