/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include "ec.h" #include "ecdefs.h" uint16_t ec_get_version(void) { return (ec_read(ECRAM_MAJOR_VERSION) << 8) | ec_read(ECRAM_MINOR_VERSION); } static uint8_t get_ec_value_from_option(const char *name, unsigned int fallback, const uint8_t *lut, size_t lut_size) { unsigned int index = get_uint_option(name, fallback); if (index >= lut_size) index = fallback; return lut[index]; } static uint16_t ec_get_chip_id(unsigned int port) { return pnp_read_index(port, NUVOTON_CHIPID); } static void merlin_init(struct device *dev) { if (!dev->enabled) return; /* * The address/data IO port pair for the Nuvoton EC are configurable * through the EC domain and are fixed by the EC's firmware blob. If * the value(s) passed through the "dev" structure don't match the * expected values then output severe warnings. */ if (dev->path.pnp.port != NUVOTON_FIXED_ADDR) { printk(BIOS_ERR, "NUVOTON: Incorrect ports defined in devicetree.cb.\n"); printk(BIOS_ERR, "NUVOTON: Serious operational issues will arise.\n"); return; } const uint16_t chip_id = ec_get_chip_id(dev->path.pnp.port); if (chip_id != NUVOTON_CHIPID_VAL) { printk(BIOS_ERR, "NUVOTON: Expected chip ID 0x%04x, but got 0x%04x instead.\n", NUVOTON_CHIPID_VAL, chip_id); return; } pc_keyboard_init(NO_AUX_DEVICE); /* * Restore settings from CMOS into EC RAM: * * kbl_timeout * fn_ctrl_swap * max_charge * fan_mode * fn_lock_state * trackpad_state * kbl_brightness * kbl_state */ /* * Keyboard Backlight Timeout * * Setting: kbl_timeout * * Values: 30 Seconds, 1 Minute, 3 Minutes, 5 Minutes, Never * Default: 30 Seconds * */ const uint8_t kbl_timeout[] = { SEC_30, MIN_1, MIN_3, MIN_5, NEVER }; ec_write(ECRAM_KBL_TIMEOUT, get_ec_value_from_option("kbl_timeout", 0, kbl_timeout, ARRAY_SIZE(kbl_timeout))); /* * Fn Ctrl Reverse * * Setting: fn_ctrl_swap * * Values: Enabled, Disabled * Default: Disabled * */ const uint8_t fn_ctrl_swap[] = { FN_CTRL, CTRL_FN }; ec_write(ECRAM_FN_CTRL_REVERSE, get_ec_value_from_option("fn_ctrl_swap", 0, fn_ctrl_swap, ARRAY_SIZE(fn_ctrl_swap))); /* * Maximum Charge Level * * Setting: max_charge * * Values: 60%, 80%, 100% * Default: 100% * */ const uint8_t max_charge[] = { CHARGE_100, CHARGE_80, CHARGE_60 }; if (CONFIG(EC_STARLABS_MAX_CHARGE)) ec_write(ECRAM_MAX_CHARGE, get_ec_value_from_option("max_charge", 0, max_charge, ARRAY_SIZE(max_charge))); /* * Fast Charge * * Setting: fast_charge * * Values: Normal, Fast * Default: Normal * */ const uint8_t fast_charge[] = { CHARGE_RATE_NORMAL, CHARGE_RATE_FAST }; if (CONFIG(EC_STARLABS_FAST_CHARGE)) ec_write(ECRAM_FAST_CHARGE, get_ec_value_from_option("fast_charge", 0, fast_charge, ARRAY_SIZE(fast_charge))); /* * Fan Mode * * Setting: fan_mode * * Values: Quiet, Normal, Aggressive * Default: Normal * */ const uint8_t fan_mode[] = { FAN_NORMAL, FAN_AGGRESSIVE, FAN_QUIET }; if (CONFIG(EC_STARLABS_FAN)) ec_write(ECRAM_FAN_MODE, get_ec_value_from_option("fan_mode", 0, fan_mode, ARRAY_SIZE(fan_mode))); /* * Function Lock * * Setting: fn_lock_state * * Values: Locked, Unlocked * Default: Locked * */ const uint8_t fn_lock_state[] = { UNLOCKED, LOCKED }; ec_write(ECRAM_FN_LOCK_STATE, get_ec_value_from_option("fn_lock_state", 1, fn_lock_state, ARRAY_SIZE(fn_lock_state))); /* * Trackpad State * * Setting: trackpad_state * * Values: Enabled, Disabled * Default: Enabled * */ const uint8_t trackpad_state[] = { TRACKPAD_ENABLED, TRACKPAD_DISABLED }; ec_write(ECRAM_TRACKPAD_STATE, get_ec_value_from_option("trackpad_state", 0, trackpad_state, ARRAY_SIZE(trackpad_state))); /* * Keyboard Backlight Brightness * * Setting: kbl_brightness * * Values: Off, Low, High / Off, On * Default: Low * */ const uint8_t kbl_brightness[] = { KBL_ON, KBL_OFF, KBL_LOW, KBL_HIGH }; if (CONFIG(EC_STARLABS_KBL_LEVELS)) ec_write(ECRAM_KBL_BRIGHTNESS, get_ec_value_from_option("kbl_brightness", 2, kbl_brightness, ARRAY_SIZE(kbl_brightness))); else ec_write(ECRAM_KBL_BRIGHTNESS, get_ec_value_from_option("kbl_brightness", 0, kbl_brightness, ARRAY_SIZE(kbl_brightness))); /* * Keyboard Backlight State * * Setting: kbl_state * * Values: Off, On * Default: On * * Note: Always enable, as the brightness level of `off` disables it. * */ ec_write(ECRAM_KBL_STATE, KBL_ENABLED); } static struct device_operations ops = { .init = merlin_init, .read_resources = noop_read_resources, .set_resources = noop_set_resources, }; static struct pnp_info pnp_dev_info[] = { /* System Wake-Up Control (SWUC) */ { NULL, NUVOTON_MSWC, PNP_IO0 | PNP_IRQ0, 0xfff0, }, /* KBC / Mouse Interface */ { NULL, NUVOTON_KBCM, PNP_IRQ0, }, /* KBC / Keyboard Interface */ { NULL, NUVOTON_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, }, /* Shared Memory / Flash Interface (SMFI) */ { NULL, NUVOTON_SHM, PNP_IO0 | PNP_IRQ0, 0xfff0, }, /* Power Management I/F Channel 1 (PMC1) */ { NULL, NUVOTON_PM1, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, }, /* Power Management I/F Channel 2 (PMC2) */ { NULL, NUVOTON_PM2, PNP_IO0 | PNP_IO1 | PNP_IO2 | PNP_IRQ0, 0x07fc, 0x07fc, 0xfff0, }, /* Power Management I/F Channel 3 (PMC3) */ { NULL, NUVOTON_PM3, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, }, /* Extended Shared Memory (ESHM) */ { NULL, NUVOTON_ESHM }, /* Power Management I/F Channel 4 (PMC4) */ { NULL, NUVOTON_PM4, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, }, }; static void enable_dev(struct device *dev) { pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info); } struct chip_operations ec_starlabs_merlin_ops = { .name = "NUVOTON EC", .enable_dev = enable_dev };