Merge tag 'xfs-5.19-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[platform/kernel/linux-starfive.git] / drivers / hwmon / asus-ec-sensors.c
index b5cf013..3633ab6 100644 (file)
@@ -54,8 +54,10 @@ static char *mutex_path_override;
 /* ACPI mutex for locking access to the EC for the firmware */
 #define ASUS_HW_ACCESS_MUTEX_ASMX      "\\AMW0.ASMX"
 
-/* There are two variants of the vendor spelling */
-#define VENDOR_ASUS_UPPER_CASE "ASUSTeK COMPUTER INC."
+#define MAX_IDENTICAL_BOARD_VARIATIONS 3
+
+/* Moniker for the ACPI global lock (':' is not allowed in ASL identifiers) */
+#define ACPI_GLOBAL_LOCK_PSEUDO_PATH   ":GLOBAL_LOCK"
 
 typedef union {
        u32 value;
@@ -133,8 +135,44 @@ enum ec_sensors {
 #define SENSOR_TEMP_WATER_IN BIT(ec_sensor_temp_water_in)
 #define SENSOR_TEMP_WATER_OUT BIT(ec_sensor_temp_water_out)
 
+enum board_family {
+       family_unknown,
+       family_amd_400_series,
+       family_amd_500_series,
+};
+
 /* All the known sensors for ASUS EC controllers */
-static const struct ec_sensor_info known_ec_sensors[] = {
+static const struct ec_sensor_info sensors_family_amd_400[] = {
+       [ec_sensor_temp_chipset] =
+               EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
+       [ec_sensor_temp_cpu] =
+               EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
+       [ec_sensor_temp_mb] =
+               EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),
+       [ec_sensor_temp_t_sensor] =
+               EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
+       [ec_sensor_temp_vrm] =
+               EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
+       [ec_sensor_in_cpu_core] =
+               EC_SENSOR("CPU Core", hwmon_in, 2, 0x00, 0xa2),
+       [ec_sensor_fan_cpu_opt] =
+               EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xbc),
+       [ec_sensor_fan_vrm_hs] =
+               EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),
+       [ec_sensor_fan_chipset] =
+               /* no chipset fans in this generation */
+               EC_SENSOR("Chipset", hwmon_fan, 0, 0x00, 0x00),
+       [ec_sensor_fan_water_flow] =
+               EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xb4),
+       [ec_sensor_curr_cpu] =
+               EC_SENSOR("CPU", hwmon_curr, 1, 0x00, 0xf4),
+       [ec_sensor_temp_water_in] =
+               EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x0d),
+       [ec_sensor_temp_water_out] =
+               EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x0b),
+};
+
+static const struct ec_sensor_info sensors_family_amd_500[] = {
        [ec_sensor_temp_chipset] =
                EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
        [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
@@ -164,68 +202,134 @@ static const struct ec_sensor_info known_ec_sensors[] = {
        (SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB)
 #define SENSOR_SET_TEMP_WATER (SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT)
 
-#define DMI_EXACT_MATCH_BOARD(vendor, name, sensors) {                         \
-       .matches = {                                                           \
-               DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor),                     \
-               DMI_EXACT_MATCH(DMI_BOARD_NAME, name),                         \
-       },                                                                     \
-       .driver_data = (void *)(sensors), \
-}
+struct ec_board_info {
+       const char *board_names[MAX_IDENTICAL_BOARD_VARIATIONS];
+       unsigned long sensors;
+       /*
+        * Defines which mutex to use for guarding access to the state and the
+        * hardware. Can be either a full path to an AML mutex or the
+        * pseudo-path ACPI_GLOBAL_LOCK_PSEUDO_PATH to use the global ACPI lock,
+        * or left empty to use a regular mutex object, in which case access to
+        * the hardware is not guarded.
+        */
+       const char *mutex_path;
+       enum board_family family;
+};
 
-static const struct dmi_system_id asus_ec_dmi_table[] __initconst = {
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "PRIME X570-PRO",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
-               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "Pro WS X570-ACE",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
-               SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE,
-                             "ROG CROSSHAIR VIII DARK HERO",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-               SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW |
-               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE,
-                             "ROG CROSSHAIR VIII FORMULA",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
-               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG CROSSHAIR VIII HERO",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-               SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
-               SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE,
-                             "ROG CROSSHAIR VIII HERO (WI-FI)",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-               SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
-               SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE,
-                             "ROG CROSSHAIR VIII IMPACT",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_FAN_CHIPSET |
-               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG STRIX B550-E GAMING",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-               SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_FAN_CPU_OPT),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG STRIX B550-I GAMING",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-               SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_FAN_VRM_HS |
-               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG STRIX X570-E GAMING",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-               SENSOR_TEMP_T_SENSOR |
-               SENSOR_TEMP_VRM | SENSOR_FAN_CHIPSET |
-               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG STRIX X570-F GAMING",
-               SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET),
-       DMI_EXACT_MATCH_BOARD(VENDOR_ASUS_UPPER_CASE, "ROG STRIX X570-I GAMING",
-               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_VRM_HS |
-               SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE),
+static const struct ec_board_info board_info[] = {
+       {
+               .board_names = {"PRIME X470-PRO"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+                       SENSOR_FAN_CPU_OPT |
+                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+               .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
+               .family = family_amd_400_series,
+       },
+       {
+               .board_names = {"PRIME X570-PRO"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ProArt X570-CREATOR WIFI"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
+                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       },
+       {
+               .board_names = {"Pro WS X570-ACE"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |
+                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG CROSSHAIR VIII DARK HERO"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR |
+                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW |
+                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {
+                       "ROG CROSSHAIR VIII FORMULA",
+                       "ROG CROSSHAIR VIII HERO",
+                       "ROG CROSSHAIR VIII HERO (WI-FI)",
+               },
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR |
+                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
+                       SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG CROSSHAIR VIII IMPACT"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX B550-E GAMING"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+                       SENSOR_FAN_CPU_OPT,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX B550-I GAMING"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+                       SENSOR_FAN_VRM_HS | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX X570-E GAMING"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX X570-E GAMING WIFI II"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX X570-F GAMING"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
+       {
+               .board_names = {"ROG STRIX X570-I GAMING"},
+               .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_FAN_VRM_HS |
+                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
+                       SENSOR_IN_CPU_CORE,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_amd_500_series,
+       },
        {}
 };
 
@@ -234,8 +338,49 @@ struct ec_sensor {
        s32 cached_value;
 };
 
+struct lock_data {
+       union {
+               acpi_handle aml;
+               /* global lock handle */
+               u32 glk;
+       } mutex;
+       bool (*lock)(struct lock_data *data);
+       bool (*unlock)(struct lock_data *data);
+};
+
+/*
+ * The next function pairs implement options for locking access to the
+ * state and the EC
+ */
+static bool lock_via_acpi_mutex(struct lock_data *data)
+{
+       /*
+        * ASUS DSDT does not specify that access to the EC has to be guarded,
+        * but firmware does access it via ACPI
+        */
+       return ACPI_SUCCESS(acpi_acquire_mutex(data->mutex.aml,
+                                              NULL, ACPI_LOCK_DELAY_MS));
+}
+
+static bool unlock_acpi_mutex(struct lock_data *data)
+{
+       return ACPI_SUCCESS(acpi_release_mutex(data->mutex.aml, NULL));
+}
+
+static bool lock_via_global_acpi_lock(struct lock_data *data)
+{
+       return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS,
+                                                    &data->mutex.glk));
+}
+
+static bool unlock_global_acpi_lock(struct lock_data *data)
+{
+       return ACPI_SUCCESS(acpi_release_global_lock(data->mutex.glk));
+}
+
 struct ec_sensors_data {
-       unsigned long board_sensors;
+       const struct ec_board_info *board_info;
+       const struct ec_sensor_info *sensors_info;
        struct ec_sensor *sensors;
        /* EC registers to read from */
        u16 *registers;
@@ -244,7 +389,7 @@ struct ec_sensors_data {
        u8 banks[ASUS_EC_MAX_BANK + 1];
        /* in jiffies */
        unsigned long last_updated;
-       acpi_handle aml_mutex;
+       struct lock_data lock_data;
        /* number of board EC sensors */
        u8 nr_sensors;
        /*
@@ -278,7 +423,7 @@ static bool is_sensor_data_signed(const struct ec_sensor_info *si)
 static const struct ec_sensor_info *
 get_sensor_info(const struct ec_sensors_data *state, int index)
 {
-       return &known_ec_sensors[state->sensors[index].info_index];
+       return state->sensors_info + state->sensors[index].info_index;
 }
 
 static int find_ec_sensor_index(const struct ec_sensors_data *ec,
@@ -301,11 +446,6 @@ static int __init bank_compare(const void *a, const void *b)
        return *((const s8 *)a) - *((const s8 *)b);
 }
 
-static int __init board_sensors_count(unsigned long sensors)
-{
-       return hweight_long(sensors);
-}
-
 static void __init setup_sensor_data(struct ec_sensors_data *ec)
 {
        struct ec_sensor *s = ec->sensors;
@@ -316,14 +456,14 @@ static void __init setup_sensor_data(struct ec_sensors_data *ec)
        ec->nr_banks = 0;
        ec->nr_registers = 0;
 
-       for_each_set_bit(i, &ec->board_sensors,
-                         BITS_PER_TYPE(ec->board_sensors)) {
+       for_each_set_bit(i, &ec->board_info->sensors,
+                        BITS_PER_TYPE(ec->board_info->sensors)) {
                s->info_index = i;
                s->cached_value = 0;
                ec->nr_registers +=
-                       known_ec_sensors[s->info_index].addr.components.size;
+                       ec->sensors_info[s->info_index].addr.components.size;
                bank_found = false;
-               bank = known_ec_sensors[s->info_index].addr.components.bank;
+               bank = ec->sensors_info[s->info_index].addr.components.bank;
                for (j = 0; j < ec->nr_banks; j++) {
                        if (ec->banks[j] == bank) {
                                bank_found = true;
@@ -353,23 +493,36 @@ static void __init fill_ec_registers(struct ec_sensors_data *ec)
        }
 }
 
-static acpi_handle __init asus_hw_access_mutex(struct device *dev)
+static int __init setup_lock_data(struct device *dev)
 {
        const char *mutex_path;
-       acpi_handle res;
        int status;
+       struct ec_sensors_data *state = dev_get_drvdata(dev);
 
        mutex_path = mutex_path_override ?
-               mutex_path_override : ASUS_HW_ACCESS_MUTEX_ASMX;
+               mutex_path_override : state->board_info->mutex_path;
 
-       status = acpi_get_handle(NULL, (acpi_string)mutex_path, &res);
-       if (ACPI_FAILURE(status)) {
-               dev_err(dev,
-                       "Could not get hardware access guard mutex '%s': error %d",
-                       mutex_path, status);
-               return NULL;
+       if (!mutex_path || !strlen(mutex_path)) {
+               dev_err(dev, "Hardware access guard mutex name is empty");
+               return -EINVAL;
        }
-       return res;
+       if (!strcmp(mutex_path, ACPI_GLOBAL_LOCK_PSEUDO_PATH)) {
+               state->lock_data.mutex.glk = 0;
+               state->lock_data.lock = lock_via_global_acpi_lock;
+               state->lock_data.unlock = unlock_global_acpi_lock;
+       } else {
+               status = acpi_get_handle(NULL, (acpi_string)mutex_path,
+                                        &state->lock_data.mutex.aml);
+               if (ACPI_FAILURE(status)) {
+                       dev_err(dev,
+                               "Failed to get hardware access guard AML mutex '%s': error %d",
+                               mutex_path, status);
+                       return -ENOENT;
+               }
+               state->lock_data.lock = lock_via_acpi_mutex;
+               state->lock_data.unlock = unlock_acpi_mutex;
+       }
+       return 0;
 }
 
 static int asus_ec_bank_switch(u8 bank, u8 *old)
@@ -457,10 +610,11 @@ static inline s32 get_sensor_value(const struct ec_sensor_info *si, u8 *data)
 static void update_sensor_values(struct ec_sensors_data *ec, u8 *data)
 {
        const struct ec_sensor_info *si;
-       struct ec_sensor *s;
+       struct ec_sensor *s, *sensor_end;
 
-       for (s = ec->sensors; s != ec->sensors + ec->nr_sensors; s++) {
-               si = &known_ec_sensors[s->info_index];
+       sensor_end = ec->sensors + ec->nr_sensors;
+       for (s = ec->sensors; s != sensor_end; s++) {
+               si = ec->sensors_info + s->info_index;
                s->cached_value = get_sensor_value(si, data);
                data += si->addr.components.size;
        }
@@ -471,15 +625,9 @@ static int update_ec_sensors(const struct device *dev,
 {
        int status;
 
-       /*
-        * ASUS DSDT does not specify that access to the EC has to be guarded,
-        * but firmware does access it via ACPI
-        */
-       if (ACPI_FAILURE(acpi_acquire_mutex(ec->aml_mutex, NULL,
-                                           ACPI_LOCK_DELAY_MS))) {
-               dev_err(dev, "Failed to acquire AML mutex");
-               status = -EBUSY;
-               goto cleanup;
+       if (!ec->lock_data.lock(&ec->lock_data)) {
+               dev_warn(dev, "Failed to acquire mutex");
+               return -EBUSY;
        }
 
        status = asus_ec_block_read(dev, ec);
@@ -487,10 +635,10 @@ static int update_ec_sensors(const struct device *dev,
        if (!status) {
                update_sensor_values(ec, ec->read_buffer);
        }
-       if (ACPI_FAILURE(acpi_release_mutex(ec->aml_mutex, NULL))) {
-               dev_err(dev, "Failed to release AML mutex");
-       }
-cleanup:
+
+       if (!ec->lock_data.unlock(&ec->lock_data))
+               dev_err(dev, "Failed to release mutex");
+
        return status;
 }
 
@@ -597,12 +745,24 @@ static struct hwmon_chip_info asus_ec_chip_info = {
        .ops = &asus_ec_hwmon_ops,
 };
 
-static unsigned long __init get_board_sensors(void)
+static const struct ec_board_info * __init get_board_info(void)
 {
-       const struct dmi_system_id *dmi_entry =
-               dmi_first_match(asus_ec_dmi_table);
+       const char *dmi_board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+       const char *dmi_board_name = dmi_get_system_info(DMI_BOARD_NAME);
+       const struct ec_board_info *board;
 
-       return dmi_entry ? (unsigned long)dmi_entry->driver_data : 0;
+       if (!dmi_board_vendor || !dmi_board_name ||
+           strcasecmp(dmi_board_vendor, "ASUSTeK COMPUTER INC."))
+               return NULL;
+
+       for (board = board_info; board->sensors; board++) {
+               if (match_string(board->board_names,
+                                MAX_IDENTICAL_BOARD_VARIATIONS,
+                                dmi_board_name) >= 0)
+                       return board;
+       }
+
+       return NULL;
 }
 
 static int __init asus_ec_probe(struct platform_device *pdev)
@@ -610,17 +770,18 @@ static int __init asus_ec_probe(struct platform_device *pdev)
        const struct hwmon_channel_info **ptr_asus_ec_ci;
        int nr_count[hwmon_max] = { 0 }, nr_types = 0;
        struct hwmon_channel_info *asus_ec_hwmon_chan;
+       const struct ec_board_info *pboard_info;
        const struct hwmon_chip_info *chip_info;
        struct device *dev = &pdev->dev;
        struct ec_sensors_data *ec_data;
        const struct ec_sensor_info *si;
        enum hwmon_sensor_types type;
-       unsigned long board_sensors;
        struct device *hwdev;
        unsigned int i;
+       int status;
 
-       board_sensors = get_board_sensors();
-       if (!board_sensors)
+       pboard_info = get_board_info();
+       if (!pboard_info)
                return -ENODEV;
 
        ec_data = devm_kzalloc(dev, sizeof(struct ec_sensors_data),
@@ -629,11 +790,31 @@ static int __init asus_ec_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dev_set_drvdata(dev, ec_data);
-       ec_data->board_sensors = board_sensors;
-       ec_data->nr_sensors = board_sensors_count(ec_data->board_sensors);
+       ec_data->board_info = pboard_info;
+
+       switch (ec_data->board_info->family) {
+       case family_amd_400_series:
+               ec_data->sensors_info = sensors_family_amd_400;
+               break;
+       case family_amd_500_series:
+               ec_data->sensors_info = sensors_family_amd_500;
+               break;
+       default:
+               dev_err(dev, "Unknown board family: %d",
+                       ec_data->board_info->family);
+               return -EINVAL;
+       }
+
+       ec_data->nr_sensors = hweight_long(ec_data->board_info->sensors);
        ec_data->sensors = devm_kcalloc(dev, ec_data->nr_sensors,
                                        sizeof(struct ec_sensor), GFP_KERNEL);
 
+       status = setup_lock_data(dev);
+       if (status) {
+               dev_err(dev, "Failed to setup state/EC locking: %d", status);
+               return status;
+       }
+
        setup_sensor_data(ec_data);
        ec_data->registers = devm_kcalloc(dev, ec_data->nr_registers,
                                          sizeof(u16), GFP_KERNEL);
@@ -645,8 +826,6 @@ static int __init asus_ec_probe(struct platform_device *pdev)
 
        fill_ec_registers(ec_data);
 
-       ec_data->aml_mutex = asus_hw_access_mutex(dev);
-
        for (i = 0; i < ec_data->nr_sensors; ++i) {
                si = get_sensor_info(ec_data, i);
                if (!nr_count[si->type])
@@ -703,7 +882,14 @@ static struct platform_driver asus_ec_sensors_platform_driver = {
        },
 };
 
-MODULE_DEVICE_TABLE(dmi, asus_ec_dmi_table);
+MODULE_DEVICE_TABLE(acpi, acpi_ec_ids);
+/*
+ * we use module_platform_driver_probe() rather than module_platform_driver()
+ * because the probe function (and its dependants) are marked with __init, which
+ * means we can't put it into the .probe member of the platform_driver struct
+ * above, and we can't mark the asus_ec_sensors_platform_driver object as __init
+ * because the object is referenced from the module exit code.
+ */
 module_platform_driver_probe(asus_ec_sensors_platform_driver, asus_ec_probe);
 
 module_param_named(mutex_path, mutex_path_override, charp, 0);