Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17 150 lines 3.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Toradex Embedded Controller driver 4 * 5 * Copyright (C) 2025 Toradex 6 * 7 * Author: Emanuele Ghidoli <emanuele.ghidoli@toradex.com> 8 */ 9 10#include <linux/array_size.h> 11#include <linux/device.h> 12#include <linux/err.h> 13#include <linux/i2c.h> 14#include <linux/mod_devicetable.h> 15#include <linux/module.h> 16#include <linux/reboot.h> 17#include <linux/regmap.h> 18#include <linux/types.h> 19 20#define EC_CHIP_ID_REG 0x00 21#define EC_CHIP_ID_SMARC_IMX95 0x11 22#define EC_CHIP_ID_SMARC_IMX8MP 0x12 23 24#define EC_VERSION_REG_MAJOR 0x01 25#define EC_VERSION_REG_MINOR 0x02 26#define EC_ID_VERSION_LEN 3 27 28#define EC_CMD_REG 0xD0 29#define EC_CMD_POWEROFF 0x01 30#define EC_CMD_RESET 0x02 31 32#define EC_REG_MAX 0xD0 33 34static const struct regmap_range volatile_ranges[] = { 35 regmap_reg_range(EC_CMD_REG, EC_CMD_REG), 36}; 37 38static const struct regmap_access_table volatile_table = { 39 .yes_ranges = volatile_ranges, 40 .n_yes_ranges = ARRAY_SIZE(volatile_ranges), 41}; 42 43static const struct regmap_range read_ranges[] = { 44 regmap_reg_range(EC_CHIP_ID_REG, EC_VERSION_REG_MINOR), 45}; 46 47static const struct regmap_access_table read_table = { 48 .yes_ranges = read_ranges, 49 .n_yes_ranges = ARRAY_SIZE(read_ranges), 50}; 51 52static const struct regmap_config regmap_config = { 53 .reg_bits = 8, 54 .val_bits = 8, 55 .max_register = EC_REG_MAX, 56 .cache_type = REGCACHE_RBTREE, 57 .rd_table = &read_table, 58 .volatile_table = &volatile_table, 59}; 60 61static int tdx_ec_cmd(struct regmap *regmap, u8 cmd) 62{ 63 int err = regmap_write(regmap, EC_CMD_REG, cmd); 64 65 if (err) 66 dev_err(regmap_get_device(regmap), "Failed to send command 0x%02X: %d\n", cmd, err); 67 68 return err; 69} 70 71static int tdx_ec_power_off(struct sys_off_data *data) 72{ 73 struct regmap *regmap = data->cb_data; 74 int err; 75 76 err = tdx_ec_cmd(regmap, EC_CMD_POWEROFF); 77 78 return err ? NOTIFY_BAD : NOTIFY_DONE; 79} 80 81static int tdx_ec_restart(struct sys_off_data *data) 82{ 83 struct regmap *regmap = data->cb_data; 84 int err; 85 86 err = tdx_ec_cmd(regmap, EC_CMD_RESET); 87 88 return err ? NOTIFY_BAD : NOTIFY_DONE; 89} 90 91static int tdx_ec_register_power_off_restart(struct device *dev, struct regmap *regmap) 92{ 93 int err; 94 95 err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART, 96 SYS_OFF_PRIO_FIRMWARE, 97 tdx_ec_restart, regmap); 98 if (err) 99 return err; 100 101 return devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, 102 SYS_OFF_PRIO_FIRMWARE, 103 tdx_ec_power_off, regmap); 104} 105 106static int tdx_ec_probe(struct i2c_client *client) 107{ 108 struct device *dev = &client->dev; 109 u8 reg_val[EC_ID_VERSION_LEN]; 110 struct regmap *regmap; 111 int err; 112 113 regmap = devm_regmap_init_i2c(client, &regmap_config); 114 if (IS_ERR(regmap)) 115 return PTR_ERR(regmap); 116 117 err = regmap_bulk_read(regmap, EC_CHIP_ID_REG, &reg_val, EC_ID_VERSION_LEN); 118 if (err) 119 return dev_err_probe(dev, err, 120 "Cannot read id and version registers\n"); 121 122 dev_info(dev, "Toradex Embedded Controller id %x - Firmware %u.%u\n", 123 reg_val[0], reg_val[1], reg_val[2]); 124 125 err = tdx_ec_register_power_off_restart(dev, regmap); 126 if (err) 127 return dev_err_probe(dev, err, 128 "Cannot register system restart handler\n"); 129 130 return 0; 131} 132 133static const struct of_device_id __maybe_unused of_tdx_ec_match[] = { 134 { .compatible = "toradex,smarc-ec" }, 135 {} 136}; 137MODULE_DEVICE_TABLE(of, of_tdx_ec_match); 138 139static struct i2c_driver tdx_ec_driver = { 140 .probe = tdx_ec_probe, 141 .driver = { 142 .name = "toradex-smarc-ec", 143 .of_match_table = of_tdx_ec_match, 144 }, 145}; 146module_i2c_driver(tdx_ec_driver); 147 148MODULE_AUTHOR("Emanuele Ghidoli <emanuele.ghidoli@toradex.com>"); 149MODULE_DESCRIPTION("Toradex SMARC Embedded Controller driver"); 150MODULE_LICENSE("GPL");