Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for Khadas System control Microcontroller
  4 *
  5 * Copyright (C) 2020 BayLibre SAS
  6 *
  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_RBTREE,
 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_OF
125static const struct of_device_id khadas_mcu_of_match[] = {
126	{ .compatible = "khadas,mcu", },
127	{},
128};
129MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
130#endif
131
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");